Browse Source

Enable nullable reference types across the C# transforms

Turn on #nullable enable across the AST transform pipeline, ahead of
annotating the slot properties themselves. TransformContext now exposes the
nullable CurrentMember/CurrentTypeDefinition/CurrentModule contract already
declared by ITypeResolveContext, and the generated pattern-to-node conversion
returns a non-null node so patterns can be used in collection initializers
without warnings. No IL changes.
Assisted-by: Claude:claude-opus-4-8:Claude Code
pull/3807/head
Siegfried Pammer 3 weeks ago committed by Siegfried Pammer
parent
commit
785e36712d
  1. 12
      ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs
  2. 5
      ICSharpCode.Decompiler/CSharp/Syntax/AstNodeCollection.cs
  3. 46
      ICSharpCode.Decompiler/CSharp/Transforms/AddCheckedBlocks.cs
  4. 6
      ICSharpCode.Decompiler/CSharp/Transforms/AddXmlDocumentationTransform.cs
  5. 12
      ICSharpCode.Decompiler/CSharp/Transforms/CombineQueryExpressions.cs
  6. 8
      ICSharpCode.Decompiler/CSharp/Transforms/ContextTrackingVisitor.cs
  7. 10
      ICSharpCode.Decompiler/CSharp/Transforms/CustomPatterns.cs
  8. 48
      ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
  9. 2
      ICSharpCode.Decompiler/CSharp/Transforms/EscapeInvalidIdentifiers.cs
  10. 4
      ICSharpCode.Decompiler/CSharp/Transforms/FixNameCollisions.cs
  11. 2
      ICSharpCode.Decompiler/CSharp/Transforms/FlattenSwitchBlocks.cs
  12. 2
      ICSharpCode.Decompiler/CSharp/Transforms/IAstTransform.cs
  13. 18
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs
  14. 76
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceQueryExpressions.cs
  15. 8
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs
  16. 8
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs
  17. 9
      ICSharpCode.Decompiler/CSharp/Transforms/NormalizeBlockStatements.cs
  18. 93
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
  19. 14
      ICSharpCode.Decompiler/CSharp/Transforms/PrettifyAssignments.cs
  20. 2
      ICSharpCode.Decompiler/CSharp/Transforms/RemoveCLSCompliantAttribute.cs
  21. 6
      ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs
  22. 8
      ICSharpCode.Decompiler/CSharp/Transforms/TransformContext.cs

12
ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs

@ -197,10 +197,18 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -197,10 +197,18 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
if (source.NeedsPatternPlaceholder)
{
// The placeholder conversion is part of the pattern-construction DSL, where a non-null
// pattern is the invariant; the result is therefore non-nullable for the specific node
// types. AstNode (the base) and ParameterDeclaration keep the nullable contract, and only
// AstNode also accepts a nullable pattern.
bool nullableReturn = source.NodeName is "AstNode" or "ParameterDeclaration";
string returnQ = nullableReturn ? "?" : "";
string paramQ = source.NodeName == "AstNode" ? "?" : "";
string forgive = nullableReturn ? "" : "!";
builder.Append(
$@" public static implicit operator {source.NodeName}?(PatternMatching.Pattern? pattern)
$@" public static implicit operator {source.NodeName}{returnQ}(PatternMatching.Pattern{paramQ} pattern)
{{
return pattern != null ? new PatternPlaceholder(pattern) : null;
return pattern != null ? new PatternPlaceholder(pattern) : null{forgive};
}}
sealed class PatternPlaceholder : {source.NodeName}, INode

5
ICSharpCode.Decompiler/CSharp/Syntax/AstNodeCollection.cs

@ -304,9 +304,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -304,9 +304,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return Pattern.DoMatchCollection(AsNodeList(), other.AsNodeList(), match);
}
public void InsertAfter(T existingItem, T newItem)
public void InsertAfter(T? existingItem, T newItem)
{
Insert(IndexOf(existingItem) + 1, newItem);
// A null existingItem yields IndexOf == -1, so the new item is inserted at the front.
Insert(IndexOf(existingItem!) + 1, newItem);
}
public void InsertBefore(T existingItem, T newItem)

46
ICSharpCode.Decompiler/CSharp/Transforms/AddCheckedBlocks.cs

@ -16,7 +16,10 @@ @@ -16,7 +16,10 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Syntax;
@ -143,7 +146,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -143,7 +146,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// </summary>
abstract class InsertedNode
{
public static InsertedNode operator +(InsertedNode a, InsertedNode b)
public static InsertedNode? operator +(InsertedNode? a, InsertedNode? b)
{
if (a == null)
return b;
@ -194,11 +197,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -194,11 +197,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
class InsertedBlock : InsertedNode
{
readonly Statement firstStatement; // inclusive
readonly Statement lastStatement; // exclusive
readonly Statement? firstStatement; // inclusive
readonly Statement? lastStatement; // exclusive
readonly bool isChecked;
public InsertedBlock(Statement firstStatement, Statement lastStatement, bool isChecked)
public InsertedBlock(Statement? firstStatement, Statement? lastStatement, bool isChecked)
{
this.firstStatement = firstStatement;
this.lastStatement = lastStatement;
@ -207,10 +210,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -207,10 +210,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public override void Insert()
{
// An InsertedBlock with a null start has infinite cost in the search and is never
// selected for insertion, so by the time Insert runs firstStatement is non-null.
Debug.Assert(firstStatement != null);
BlockStatement newBlock = new BlockStatement();
// Move all statements except for the first
Statement next;
for (Statement stmt = firstStatement.GetNextStatement(); stmt != lastStatement; stmt = next)
Statement? next;
for (Statement? stmt = firstStatement.GetNextStatement(); stmt != null && stmt != lastStatement; stmt = next)
{
next = stmt.GetNextStatement();
newBlock.Add(stmt.Detach());
@ -233,18 +239,18 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -233,18 +239,18 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
class Result
{
public Cost CostInCheckedContext;
public InsertedNode NodesToInsertInCheckedContext;
public InsertedNode? NodesToInsertInCheckedContext;
public Cost CostInUncheckedContext;
public InsertedNode NodesToInsertInUncheckedContext;
public InsertedNode? NodesToInsertInUncheckedContext;
}
#endregion
public void Run(AstNode node, TransformContext context)
{
BlockStatement block = node as BlockStatement;
BlockStatement? block = node as BlockStatement;
if (block == null)
{
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling)
for (AstNode? child = node.FirstChild; child != null; child = child.NextSibling)
{
Run(child, context);
}
@ -268,20 +274,20 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -268,20 +274,20 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
// For a block, we are tracking 4 possibilities:
// a) context is checked, no unchecked block open
Cost costCheckedContext = new Cost(0, 0);
InsertedNode nodesCheckedContext = null;
InsertedNode? nodesCheckedContext = null;
// b) context is checked, an unchecked block is open
Cost costCheckedContextUncheckedBlockOpen = Cost.Infinite;
InsertedNode nodesCheckedContextUncheckedBlockOpen = null;
Statement uncheckedBlockStart = null;
InsertedNode? nodesCheckedContextUncheckedBlockOpen = null;
Statement? uncheckedBlockStart = null;
// c) context is unchecked, no checked block open
Cost costUncheckedContext = new Cost(0, 0);
InsertedNode nodesUncheckedContext = null;
InsertedNode? nodesUncheckedContext = null;
// d) context is unchecked, a checked block is open
Cost costUncheckedContextCheckedBlockOpen = Cost.Infinite;
InsertedNode nodesUncheckedContextCheckedBlockOpen = null;
Statement checkedBlockStart = null;
InsertedNode? nodesUncheckedContextCheckedBlockOpen = null;
Statement? checkedBlockStart = null;
Statement statement = block.Statements.FirstOrDefault();
Statement? statement = block.Statements.FirstOrDefault();
while (true)
{
// Blocks can be closed 'for free'. We use '<=' so that blocks are closed as late as possible (goal 4b)
@ -346,7 +352,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -346,7 +352,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (node is BlockStatement)
return GetResultFromBlock((BlockStatement)node);
Result result = new Result();
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling)
for (AstNode? child = node.FirstChild; child != null; child = child.NextSibling)
{
Result childResult = GetResult(child);
result.CostInCheckedContext += childResult.CostInCheckedContext;
@ -354,10 +360,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -354,10 +360,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
result.CostInUncheckedContext += childResult.CostInUncheckedContext;
result.NodesToInsertInUncheckedContext += childResult.NodesToInsertInUncheckedContext;
}
Expression expr = node as Expression;
Expression? expr = node as Expression;
if (expr != null)
{
CheckedUncheckedAnnotation annotation = expr.Annotation<CheckedUncheckedAnnotation>();
CheckedUncheckedAnnotation? annotation = expr.Annotation<CheckedUncheckedAnnotation>();
if (annotation != null)
{
if (annotation.IsExplicit)

6
ICSharpCode.Decompiler/CSharp/Transforms/AddXmlDocumentationTransform.cs

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System;
using System.IO;
using System.Linq;
@ -62,7 +64,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -62,7 +64,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
static void InsertXmlDocumentation(AstNode node, StringReader r)
{
// Find the first non-empty line:
string firstLine;
string? firstLine;
do
{
firstLine = r.ReadLine();
@ -70,7 +72,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -70,7 +72,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return;
} while (string.IsNullOrWhiteSpace(firstLine));
string indentation = firstLine.Substring(0, firstLine.Length - firstLine.TrimStart().Length);
string line = firstLine;
string? line = firstLine;
int skippedWhitespaceLines = 0;
// Copy all lines from input to output, except for empty lines at the end.
while (line != null)

12
ICSharpCode.Decompiler/CSharp/Transforms/CombineQueryExpressions.cs

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System.Collections.Generic;
using System.Linq;
@ -47,8 +49,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -47,8 +49,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
void CombineQueries(AstNode node, Dictionary<string, object> fromOrLetIdentifiers)
{
AstNode next;
for (AstNode child = node.FirstChild; child != null; child = next)
AstNode? next;
for (AstNode? child = node.FirstChild; child != null; child = next)
{
// store reference to next child before transformation
next = child.NextSibling;
@ -105,7 +107,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -105,7 +107,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
if (!CSharpDecompiler.IsTransparentIdentifier(fromClause.Identifier))
return false;
QuerySelectClause selectClause = innerQuery.Clauses.Last() as QuerySelectClause;
QuerySelectClause? selectClause = innerQuery.Clauses.Last() as QuerySelectClause;
if (selectClause == null)
return false;
Match match = selectTransparentIdentifierPattern.Match(selectClause);
if (!match.Success)
return false;
@ -116,7 +120,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -116,7 +120,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
fromClause.Remove();
selectClause.Remove();
// Move clauses from innerQuery to query
QueryClause insertionPos = null;
QueryClause? insertionPos = null;
foreach (var clause in innerQuery.Clauses)
{
query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach());

8
ICSharpCode.Decompiler/CSharp/Transforms/ContextTrackingVisitor.cs

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System.Diagnostics;
using ICSharpCode.Decompiler.CSharp.Syntax;
@ -28,8 +30,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -28,8 +30,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// </summary>
public abstract class ContextTrackingVisitor<TResult> : DepthFirstAstVisitor<TResult>
{
protected ITypeDefinition currentTypeDefinition;
protected IMethod currentMethod;
protected ITypeDefinition? currentTypeDefinition;
protected IMethod? currentMethod;
protected void Initialize(TransformContext context)
{
@ -45,7 +47,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -45,7 +47,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public override TResult VisitTypeDeclaration(TypeDeclaration typeDeclaration)
{
ITypeDefinition oldType = currentTypeDefinition;
ITypeDefinition? oldType = currentTypeDefinition;
try
{
currentTypeDefinition = typeDeclaration.GetSymbol() as ITypeDefinition;

10
ICSharpCode.Decompiler/CSharp/Transforms/CustomPatterns.cs

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System;
using System.Linq;
@ -27,7 +29,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -27,7 +29,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
sealed class TypePattern : Pattern
{
readonly string ns;
readonly string? ns;
readonly string name;
public TypePattern(Type type)
@ -38,8 +40,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -38,8 +40,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public override bool DoMatch(INode other, Match match)
{
ComposedType ct = other as ComposedType;
AstType o;
ComposedType? ct = other as ComposedType;
AstType? o;
if (ct != null && !ct.HasRefSpecifier && !ct.HasNullableSpecifier && ct.PointerRank == 0 && !ct.ArraySpecifiers.Any())
{
// Special case: ILSpy sometimes produces a ComposedType but then removed all array specifiers
@ -73,7 +75,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -73,7 +75,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public override bool DoMatch(INode other, Match match)
{
InvocationExpression ie = other as InvocationExpression;
InvocationExpression? ie = other as InvocationExpression;
if (ie != null && ie.Annotation<LdTokenAnnotation>() != null && ie.Arguments.Count == 1)
{
return childNode.DoMatch(ie.Arguments.Single(), match);

48
ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs

@ -16,9 +16,12 @@ @@ -16,9 +16,12 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Syntax;
@ -54,7 +57,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -54,7 +57,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
return new InsertionPoint {
level = level - 1,
nextNode = nextNode.Parent
// Insertion points live inside a method body, so walking up always finds a parent.
nextNode = nextNode.Parent!
};
}
@ -63,7 +67,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -63,7 +67,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
InsertionPoint result = this;
while (result.level > targetLevel)
{
result.nextNode = result.nextNode.Parent;
result.nextNode = result.nextNode.Parent!;
result.level -= 1;
}
return result;
@ -82,7 +86,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -82,7 +86,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
public readonly ILVariable ILVariable;
public IType Type => ILVariable.Type;
public string Name => ILVariable.Name;
// Variables reaching this transform have already been assigned a name.
public string Name => ILVariable.Name!;
/// <summary>
/// Whether the variable needs to be default-initialized.
@ -108,7 +113,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -108,7 +113,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// </summary>
public IdentifierExpression FirstUse;
public VariableToDeclare ReplacementDueToCollision;
public VariableToDeclare? ReplacementDueToCollision;
public bool InvolvedInCollision;
public bool RemovedDueToCollision => ReplacementDueToCollision != null;
public bool DeclaredInDeconstruction;
@ -138,6 +143,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -138,6 +143,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
readonly Dictionary<ILVariable, VariableToDeclare> variableDict = new Dictionary<ILVariable, VariableToDeclare>();
[AllowNull]
TransformContext context;
public void Run(AstNode rootNode, TransformContext context)
@ -284,7 +290,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -284,7 +290,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// </remarks>
void FindInsertionPoints(AstNode node, int nodeLevel)
{
BlockContainer scope = node.Annotation<BlockContainer>();
BlockContainer? scope = node.Annotation<BlockContainer>();
if (scope != null && IsRelevantScope(scope))
{
// track loops and function bodies as scopes, for comparison with CaptureScope.
@ -305,7 +311,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -305,7 +311,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
try
{
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling)
for (AstNode? child = node.FirstChild; child != null; child = child.NextSibling)
{
FindInsertionPoints(child, nodeLevel + 1);
}
@ -329,7 +335,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -329,7 +335,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
InsertionPoint newPoint;
int startIndex = scopeTracking.Count - 1;
BlockContainer captureScope = variable.CaptureScope;
BlockContainer? captureScope = variable.CaptureScope;
while (captureScope != null && !IsRelevantScope(captureScope))
{
captureScope = BlockContainer.FindClosestContainer(captureScope.Parent);
@ -364,7 +370,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -364,7 +370,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
}
if (variableDict.TryGetValue(variable, out VariableToDeclare v))
if (variableDict.TryGetValue(variable, out var v))
{
v.InsertionPoint = FindCommonParent(v.InsertionPoint, newPoint);
}
@ -561,7 +567,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -561,7 +567,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
bool IsMatchingAssignment(VariableToDeclare v, out AssignmentExpression assignment)
bool IsMatchingAssignment(VariableToDeclare v, [NotNullWhen(true)] out AssignmentExpression? assignment)
{
assignment = v.InsertionPoint.nextNode as AssignmentExpression;
if (assignment == null)
@ -595,7 +601,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -595,7 +601,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (v.RemovedDueToCollision || v.DeclaredInDeconstruction)
continue;
if (CombineDeclarationAndInitializer(v, context) && IsMatchingAssignment(v, out AssignmentExpression assignment))
if (CombineDeclarationAndInitializer(v, context) && IsMatchingAssignment(v, out var assignment))
{
// 'int v; v = expr;' can be combined to 'int v = expr;'
AstType type;
@ -674,7 +680,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -674,7 +680,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
else
{
// Insert a separate declaration statement.
Expression initializer = null;
Expression? initializer = null;
AstType type = context.TypeSystemAstBuilder.ConvertType(v.Type);
if (v.DefaultInitialization == VariableInitKind.NeedsDefaultValue)
{
@ -694,6 +700,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -694,6 +700,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
v.InsertionPoint = v.InsertionPoint.Up();
}
Debug.Assert(v.InsertionPoint.nextNode.Slot?.Kind == SlotKind.Statement);
// The insertion point is a statement within a block, so it always has a parent.
AstNode insertionNode = v.InsertionPoint.nextNode;
AstNode insertionParent = insertionNode.Parent
?? throw new InvalidOperationException("Variable insertion point has no parent.");
if (v.DefaultInitialization == VariableInitKind.NeedsSkipInit)
{
AstType unsafeType = context.TypeSystemAstBuilder.ConvertType(
@ -702,7 +712,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -702,7 +712,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
var outVarDecl = new OutVarDeclarationExpression(type.Clone(), v.Name);
outVarDecl.Variable.AddAnnotation(new ILVariableResolveResult(ilVariable));
v.InsertionPoint.nextNode.Parent.InsertChildBefore(
insertionParent.InsertChildBefore(
v.InsertionPoint.nextNode,
new ExpressionStatement {
Expression = new InvocationExpression {
@ -719,11 +729,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -719,11 +729,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
else
{
v.InsertionPoint.nextNode.Parent.InsertChildBefore(
insertionParent.InsertChildBefore(
v.InsertionPoint.nextNode,
vds,
BlockStatement.StatementRole);
v.InsertionPoint.nextNode.Parent.InsertChildBefore(
insertionParent.InsertChildBefore(
v.InsertionPoint.nextNode,
new ExpressionStatement {
Expression = new InvocationExpression {
@ -745,7 +755,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -745,7 +755,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
else
{
v.InsertionPoint.nextNode.Parent.InsertChildBefore(
insertionParent.InsertChildBefore(
v.InsertionPoint.nextNode,
vds,
BlockStatement.StatementRole);
@ -759,7 +769,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -759,7 +769,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
private bool CanBeDeclaredAsOutVariable(VariableToDeclare v, out DirectionExpression dirExpr)
private bool CanBeDeclaredAsOutVariable(VariableToDeclare v, [NotNullWhen(true)] out DirectionExpression? dirExpr)
{
dirExpr = v.FirstUse.Parent as DirectionExpression;
if (dirExpr == null || dirExpr.FieldDirection != FieldDirection.Out)
@ -768,7 +778,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -768,7 +778,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return false;
if (v.DefaultInitialization != VariableInitKind.None)
return false;
for (AstNode node = v.FirstUse; node != null; node = node.Parent)
for (AstNode? node = v.FirstUse; node != null; node = node.Parent)
{
if (node.Slot?.Kind == SlotKind.EmbeddedStatement)
{
@ -812,9 +822,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -812,9 +822,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var v = variableDict[ilVar];
if (!v.RemovedDueToCollision)
continue;
while (v.RemovedDueToCollision)
while (v.ReplacementDueToCollision is { } replacement)
{
v = v.ReplacementDueToCollision;
v = replacement;
}
node.RemoveAnnotations<ILVariableResolveResult>();
node.AddAnnotation(new ILVariableResolveResult(v.ILVariable, v.Type));

2
ICSharpCode.Decompiler/CSharp/Transforms/EscapeInvalidIdentifiers.cs

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System.Collections.Generic;
using System.Linq;

4
ICSharpCode.Decompiler/CSharp/Transforms/FixNameCollisions.cs

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System.Collections.Generic;
using System.Linq;
@ -68,7 +70,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -68,7 +70,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (node is IdentifierExpression || node is MemberReferenceExpression)
{
ISymbol symbol = node.GetSymbol();
if (symbol != null && renamedSymbols.TryGetValue(symbol, out string newName))
if (symbol != null && renamedSymbols.TryGetValue(symbol, out string? newName))
{
node.GetChildByRole(Roles.Identifier).Name = newName;
}

2
ICSharpCode.Decompiler/CSharp/Transforms/FlattenSwitchBlocks.cs

@ -1,3 +1,5 @@ @@ -1,3 +1,5 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;

2
ICSharpCode.Decompiler/CSharp/Transforms/IAstTransform.cs

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using ICSharpCode.Decompiler.CSharp.Syntax;
namespace ICSharpCode.Decompiler.CSharp.Transforms

18
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs

@ -16,8 +16,11 @@ @@ -16,8 +16,11 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Resolver;
@ -34,8 +37,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -34,8 +37,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// </summary>
public class IntroduceExtensionMethods : DepthFirstAstVisitor, IAstTransform
{
[AllowNull]
TransformContext context;
[AllowNull]
CSharpResolver resolver;
[AllowNull]
CSharpConversions conversions;
public void Run(AstNode rootNode, TransformContext context)
@ -122,7 +128,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -122,7 +128,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
else
{
memberRefExpr.Target = firstArgument.Detach();
// The target is not an IdentifierExpression, so CanTransformToExtensionMethodCall
// matched the MemberReferenceExpression case and memberRefExpr is non-null.
memberRefExpr!.Target = firstArgument.Detach();
}
if (invocationExpression.GetResolveResult() is CSharpInvocationResolveResult irr)
{
@ -137,9 +145,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -137,9 +145,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
static bool CanTransformToExtensionMethodCall(CSharpResolver resolver,
InvocationExpression invocationExpression, out MemberReferenceExpression memberRefExpr,
out ResolveResult target,
out Expression firstArgument)
InvocationExpression invocationExpression, out MemberReferenceExpression? memberRefExpr,
[NotNullWhen(true)] out ResolveResult? target,
[NotNullWhen(true)] out Expression? firstArgument)
{
var method = invocationExpression.GetSymbol() as IMethod;
memberRefExpr = null;
@ -176,7 +184,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -176,7 +184,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
Debug.Assert(target != null);
ResolveResult[] args = new ResolveResult[invocationExpression.Arguments.Count - 1];
string[] argNames = null;
string[]? argNames = null;
int pos = 0;
foreach (var arg in invocationExpression.Arguments.Skip(1))
{

76
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceQueryExpressions.cs

@ -16,7 +16,11 @@ @@ -16,7 +16,11 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Syntax;
@ -30,6 +34,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -30,6 +34,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// </summary>
public class IntroduceQueryExpressions : IAstTransform
{
[AllowNull]
TransformContext context;
public void Run(AstNode rootNode, TransformContext context)
@ -50,15 +55,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -50,15 +55,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
// See if the data source of this query is a degenerate query,
// and combine the queries if possible.
QueryExpression innerQuery = fromClause.Expression as QueryExpression;
while (IsDegenerateQuery(innerQuery))
QueryExpression? innerQuery = fromClause.Expression as QueryExpression;
while (innerQuery != null && IsDegenerateQuery(innerQuery))
{
QueryFromClause innerFromClause = (QueryFromClause)innerQuery.Clauses.First();
ILVariable innerVariable = innerFromClause.Annotation<ILVariableResolveResult>()?.Variable;
ILVariable rangeVariable = fromClause.Annotation<ILVariableResolveResult>()?.Variable;
ILVariable? innerVariable = innerFromClause.Annotation<ILVariableResolveResult>()?.Variable;
ILVariable? rangeVariable = fromClause.Annotation<ILVariableResolveResult>()?.Variable;
// Replace the fromClause with all clauses from the inner query
fromClause.Remove();
QueryClause insertionPos = null;
QueryClause? insertionPos = null;
foreach (var clause in innerQuery.Clauses)
{
CombineRangeVariables(clause, innerVariable, rangeVariable);
@ -70,21 +75,26 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -70,21 +75,26 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
private void CombineRangeVariables(QueryClause clause, ILVariable oldVariable, ILVariable newVariable)
private void CombineRangeVariables(QueryClause clause, ILVariable? oldVariable, ILVariable? newVariable)
{
if (oldVariable == null || newVariable == null)
return;
foreach (var identifier in clause.DescendantNodes().OfType<Identifier>())
{
var variable = identifier.Parent.Annotation<ILVariableResolveResult>()?.Variable;
var parent = identifier.Parent;
if (parent == null)
continue;
var variable = parent.Annotation<ILVariableResolveResult>()?.Variable;
if (variable == oldVariable)
{
identifier.Parent.RemoveAnnotations<ILVariableResolveResult>();
identifier.Parent.AddAnnotation(new ILVariableResolveResult(newVariable));
parent.RemoveAnnotations<ILVariableResolveResult>();
parent.AddAnnotation(new ILVariableResolveResult(newVariable));
identifier.ReplaceWith(Identifier.Create(newVariable.Name));
}
}
}
bool IsDegenerateQuery(QueryExpression query)
bool IsDegenerateQuery(QueryExpression? query)
{
if (query == null)
return false;
@ -94,7 +104,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -94,7 +104,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
void DecompileQueries(AstNode node)
{
Expression query = DecompileQuery(node as InvocationExpression);
Expression? query = DecompileQuery(node as InvocationExpression);
if (query != null)
{
if (node.Parent is ExpressionStatement && CanUseDiscardAssignment())
@ -102,8 +112,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -102,8 +112,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
node.ReplaceWith(query);
}
AstNode next;
for (AstNode child = (query ?? node).FirstChild; child != null; child = next)
AstNode? next;
for (AstNode? child = (query ?? node).FirstChild; child != null; child = next)
{
// store reference to next child before transformation
next = child.NextSibling;
@ -117,11 +127,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -117,11 +127,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return context.Settings.Discards;
}
QueryExpression DecompileQuery(InvocationExpression invocation)
QueryExpression? DecompileQuery(InvocationExpression? invocation)
{
if (invocation == null)
return null;
MemberReferenceExpression mre = invocation.Target as MemberReferenceExpression;
MemberReferenceExpression? mre = invocation.Target as MemberReferenceExpression;
if (mre == null || IsNullConditional(mre.Target))
return null;
switch (mre.MemberName)
@ -133,7 +143,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -133,7 +143,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (!IsComplexQuery(mre))
return null;
Expression expr = invocation.Arguments.Single();
if (MatchSimpleLambda(expr, out ParameterDeclaration parameter, out Expression body))
if (MatchSimpleLambda(expr, out var parameter, out var body))
{
QueryExpression query = new QueryExpression();
query.Clauses.Add(MakeFromClause(parameter, mre.Target.Detach()));
@ -148,8 +158,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -148,8 +158,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
Expression keyLambda = invocation.Arguments.ElementAt(0);
Expression projectionLambda = invocation.Arguments.ElementAt(1);
if (MatchSimpleLambda(keyLambda, out ParameterDeclaration parameter1, out Expression keySelector)
&& MatchSimpleLambda(projectionLambda, out ParameterDeclaration parameter2, out Expression elementSelector)
if (MatchSimpleLambda(keyLambda, out var parameter1, out var keySelector)
&& MatchSimpleLambda(projectionLambda, out var parameter2, out var elementSelector)
&& parameter1.Name == parameter2.Name)
{
QueryExpression query = new QueryExpression();
@ -166,7 +176,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -166,7 +176,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
else if (invocation.Arguments.Count == 1)
{
Expression lambda = invocation.Arguments.Single();
if (MatchSimpleLambda(lambda, out ParameterDeclaration parameter, out Expression keySelector))
if (MatchSimpleLambda(lambda, out var parameter, out var keySelector))
{
QueryExpression query = new QueryExpression();
query.Clauses.Add(MakeFromClause(parameter, mre.Target.Detach()));
@ -181,11 +191,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -181,11 +191,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (invocation.Arguments.Count != 2)
return null;
var fromExpressionLambda = invocation.Arguments.ElementAt(0);
if (!MatchSimpleLambda(fromExpressionLambda, out ParameterDeclaration parameter, out Expression collectionSelector))
if (!MatchSimpleLambda(fromExpressionLambda, out var parameter, out var collectionSelector))
return null;
if (IsNullConditional(collectionSelector))
return null;
LambdaExpression lambda = invocation.Arguments.ElementAt(1) as LambdaExpression;
LambdaExpression? lambda = invocation.Arguments.ElementAt(1) as LambdaExpression;
if (lambda != null && lambda.Parameters.Count == 2 && lambda.Body is Expression)
{
ParameterDeclaration p1 = lambda.Parameters.ElementAt(0);
@ -208,7 +218,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -208,7 +218,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (!IsComplexQuery(mre))
return null;
Expression expr = invocation.Arguments.Single();
if (MatchSimpleLambda(expr, out ParameterDeclaration parameter, out Expression body))
if (MatchSimpleLambda(expr, out var parameter, out var body))
{
QueryExpression query = new QueryExpression();
query.Clauses.Add(MakeFromClause(parameter, mre.Target.Detach()));
@ -227,7 +237,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -227,7 +237,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (!IsComplexQuery(mre))
return null;
var lambda = invocation.Arguments.Single();
if (MatchSimpleLambda(lambda, out ParameterDeclaration parameter, out Expression orderExpression))
if (MatchSimpleLambda(lambda, out var parameter, out var orderExpression))
{
if (ValidateThenByChain(invocation, parameter.Name))
{
@ -244,8 +254,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -244,8 +254,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
InvocationExpression tmp = (InvocationExpression)mre.Target;
mre = (MemberReferenceExpression)tmp.Target;
lambda = tmp.Arguments.Single();
MatchSimpleLambda(lambda, out parameter, out orderExpression);
// ValidateThenByChain already confirmed every clause in the chain is a simple
// lambda, so this match always succeeds.
bool matched = MatchSimpleLambda(lambda, out parameter, out orderExpression);
Debug.Assert(matched);
}
// The chain was validated and every iteration re-matched a simple lambda,
// so the final range-variable parameter is set.
Debug.Assert(parameter != null);
// insert new ordering at beginning
orderClause.Orderings.InsertAfter(
null, new QueryOrdering {
@ -271,12 +287,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -271,12 +287,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (IsNullConditional(source2))
return null;
Expression outerLambda = invocation.Arguments.ElementAt(1);
if (!MatchSimpleLambda(outerLambda, out ParameterDeclaration element1, out Expression key1))
if (!MatchSimpleLambda(outerLambda, out var element1, out var key1))
return null;
Expression innerLambda = invocation.Arguments.ElementAt(2);
if (!MatchSimpleLambda(innerLambda, out ParameterDeclaration element2, out Expression key2))
if (!MatchSimpleLambda(innerLambda, out var element2, out var key2))
return null;
LambdaExpression lambda = invocation.Arguments.ElementAt(3) as LambdaExpression;
LambdaExpression? lambda = invocation.Arguments.ElementAt(3) as LambdaExpression;
if (lambda != null && lambda.Parameters.Count == 2 && lambda.Body is Expression)
{
ParameterDeclaration p1 = lambda.Parameters.ElementAt(0);
@ -365,13 +381,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -365,13 +381,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// <summary>
/// Ensure that all ThenBy's are correct, and that the list of ThenBy's is terminated by an 'OrderBy' invocation.
/// </summary>
bool ValidateThenByChain(InvocationExpression invocation, string expectedParameterName)
bool ValidateThenByChain(InvocationExpression? invocation, string expectedParameterName)
{
if (invocation == null || invocation.Arguments.Count != 1)
return false;
if (!(invocation.Target is MemberReferenceExpression mre))
return false;
if (!MatchSimpleLambda(invocation.Arguments.Single(), out ParameterDeclaration parameter, out _))
if (!MatchSimpleLambda(invocation.Arguments.Single(), out var parameter, out _))
return false;
if (parameter.Name != expectedParameterName)
return false;
@ -385,7 +401,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -385,7 +401,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
/// <summary>Matches simple lambdas of the form "a => b"</summary>
bool MatchSimpleLambda(Expression expr, out ParameterDeclaration parameter, out Expression body)
bool MatchSimpleLambda(Expression expr, [NotNullWhen(true)] out ParameterDeclaration? parameter, [NotNullWhen(true)] out Expression? body)
{
if (expr is LambdaExpression lambda && lambda.Parameters.Count == 1 && lambda.Body is Expression)
{

8
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Resolver;
@ -40,8 +42,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -40,8 +42,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
protected override bool VisitChildren(AstNode node)
{
bool result = false;
AstNode next;
for (AstNode child = node.FirstChild; child != null; child = next)
AstNode? next;
for (AstNode? child = node.FirstChild; child != null; child = next)
{
// Store next to allow the loop to continue
// if the visitor removes/replaces child.
@ -116,7 +118,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -116,7 +118,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public override bool VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression)
{
bool result = base.VisitMemberReferenceExpression(memberReferenceExpression);
UnaryOperatorExpression uoe = memberReferenceExpression.Target as UnaryOperatorExpression;
UnaryOperatorExpression? uoe = memberReferenceExpression.Target as UnaryOperatorExpression;
if (uoe != null && uoe.Operator == UnaryOperatorType.Dereference)
{
PointerReferenceExpression pre = new PointerReferenceExpression();

8
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
@ -49,7 +51,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -49,7 +51,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
// #define directives are leading trivia on the SyntaxTree, not children, so using
// declarations go at the very start of the member list.
AstNode insertionPoint = null;
AstNode? insertionPoint = null;
// Now add using declarations for those namespaces:
IOrderedEnumerable<string> sortedImports = requiredImports.ImportedNamespaces
@ -119,7 +121,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -119,7 +121,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
base.VisitSimpleType(simpleType); // also visit type arguments
}
private void AddImportedNamespace(IType type)
private void AddImportedNamespace(IType? type)
{
if (type != null && !IsParentOfCurrentNamespace(type.Namespace))
{
@ -214,7 +216,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -214,7 +216,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
this.astBuilder = CreateAstBuilder(resolver);
}
TypeSystemAstBuilder CreateAstBuilder(CSharpResolver resolver, IL.ILFunction function = null)
TypeSystemAstBuilder CreateAstBuilder(CSharpResolver resolver, IL.ILFunction? function = null)
{
if (function != null)
{

9
ICSharpCode.Decompiler/CSharp/Transforms/NormalizeBlockStatements.cs

@ -1,8 +1,12 @@ @@ -1,8 +1,12 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.CodeAnalysis;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
@ -10,9 +14,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -10,9 +14,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
class NormalizeBlockStatements : DepthFirstAstVisitor, IAstTransform
{
[AllowNull]
TransformContext context;
bool hasNamespace;
NamespaceDeclaration singleNamespaceDeclaration;
NamespaceDeclaration? singleNamespaceDeclaration;
public override void VisitSyntaxTree(SyntaxTree syntaxTree)
{
@ -196,7 +201,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -196,7 +201,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
Attributes = { new Repeat(new AnyNode()) },
Modifiers = Modifiers.Any,
PrivateImplementationType = new AnyNodeOrNull(),
Parameters = { new Repeat(new AnyNode()) },
Parameters = { new Repeat(new AnyNode())! },
ReturnType = new AnyNode(),
Getter = new Accessor() {
Modifiers = Modifiers.Any,

93
ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs

@ -16,8 +16,11 @@ @@ -16,8 +16,11 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
@ -35,6 +38,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -35,6 +38,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public sealed class PatternStatementTransform : ContextTrackingVisitor<AstNode>, IAstTransform
{
readonly DeclareVariables declareVariables = new DeclareVariables();
[AllowNull]
TransformContext context;
public void Run(AstNode rootNode, TransformContext context)
@ -62,7 +66,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -62,7 +66,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
// Go through the children, and keep visiting a node as long as it changes.
// Because some transforms delete/replace nodes before and after the node being transformed, we rely
// on the transform's return value to know where we need to keep iterating.
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling)
for (AstNode? child = node.FirstChild; child != null; child = child.NextSibling)
{
AstNode oldChild;
do
@ -77,7 +81,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -77,7 +81,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public override AstNode VisitExpressionStatement(ExpressionStatement expressionStatement)
{
AstNode result = TransformForeachOnMultiDimArray(expressionStatement);
AstNode? result = TransformForeachOnMultiDimArray(expressionStatement);
if (result != null)
return result;
result = TransformFor(expressionStatement);
@ -88,7 +92,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -88,7 +92,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public override AstNode VisitForStatement(ForStatement forStatement)
{
AstNode result = TransformForeachOnArray(forStatement);
AstNode? result = TransformForeachOnArray(forStatement);
if (result != null)
return result;
return base.VisitForStatement(forStatement);
@ -96,7 +100,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -96,7 +100,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public override AstNode VisitIfElseStatement(IfElseStatement ifElseStatement)
{
AstNode simplifiedIfElse = SimplifyCascadingIfElseStatements(ifElseStatement);
AstNode? simplifiedIfElse = SimplifyCascadingIfElseStatements(ifElseStatement);
if (simplifiedIfElse != null)
return simplifiedIfElse;
return base.VisitIfElseStatement(ifElseStatement);
@ -107,7 +111,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -107,7 +111,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (context.Settings.AutomaticProperties
&& (!propertyDeclaration.Setter.IsNull || context.Settings.GetterOnlyAutomaticProperties))
{
AstNode result = TransformAutomaticProperty(propertyDeclaration);
AstNode? result = TransformAutomaticProperty(propertyDeclaration);
if (result != null)
return result;
}
@ -120,7 +124,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -120,7 +124,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
base.VisitCustomEventDeclaration(eventDeclaration);
if (context.Settings.AutomaticEvents)
{
AstNode result = TransformAutomaticEvents(eventDeclaration);
AstNode? result = TransformAutomaticEvents(eventDeclaration);
if (result != null)
return result;
}
@ -174,7 +178,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -174,7 +178,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
};
public ForStatement TransformFor(ExpressionStatement node)
public ForStatement? TransformFor(ExpressionStatement node)
{
if (!context.Settings.ForStatement)
return null;
@ -182,7 +186,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -182,7 +186,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (!m1.Success)
return null;
var variable = m1.Get<IdentifierExpression>("variable").Single().GetILVariable();
AstNode next = node.NextSibling;
AstNode? next = node.NextSibling;
if (next == null)
return null;
if (next is ForStatement forStatement && ForStatementUsesVariable(forStatement, variable))
{
node.Remove();
@ -339,7 +345,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -339,7 +345,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return false;
}
Statement TransformForeachOnArray(ForStatement forStatement)
Statement? TransformForeachOnArray(ForStatement forStatement)
{
if (!context.Settings.ForEachStatement)
return null;
@ -432,7 +438,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -432,7 +438,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
)
)));
bool MatchLowerBound(int indexNum, out IL.ILVariable index, IL.ILVariable collection, Statement statement)
bool MatchLowerBound(int indexNum, [NotNullWhen(true)] out IL.ILVariable? index, IL.ILVariable collection, Statement statement)
{
index = null;
var m = variableAssignLowerBoundPattern.Match(statement);
@ -444,7 +450,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -444,7 +450,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return m.Get<IdentifierExpression>("collection").Single().GetILVariable() == collection;
}
bool MatchForeachOnMultiDimArray(IL.ILVariable[] upperBounds, IL.ILVariable collection, Statement firstInitializerStatement, out IdentifierExpression foreachVariable, out IList<Statement> statements, out IL.ILVariable[] lowerBounds)
bool MatchForeachOnMultiDimArray(IL.ILVariable[] upperBounds, IL.ILVariable collection, Statement firstInitializerStatement, [NotNullWhen(true)] out IdentifierExpression? foreachVariable, [NotNullWhen(true)] out IList<Statement>? statements, out IL.ILVariable[] lowerBounds)
{
int i = 0;
foreachVariable = null;
@ -452,7 +458,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -452,7 +458,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
lowerBounds = new IL.ILVariable[upperBounds.Length];
Statement stmt = firstInitializerStatement;
Match m = default(Match);
while (i < upperBounds.Length && MatchLowerBound(i, out IL.ILVariable indexVariable, collection, stmt))
while (i < upperBounds.Length && MatchLowerBound(i, out var indexVariable, collection, stmt))
{
m = forOnArrayMultiDimPattern.Match(stmt.GetNextStatement());
if (!m.Success)
@ -477,14 +483,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -477,14 +483,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return true;
}
Statement TransformForeachOnMultiDimArray(ExpressionStatement expressionStatement)
Statement? TransformForeachOnMultiDimArray(ExpressionStatement expressionStatement)
{
if (!context.Settings.ForEachStatement)
return null;
Match m;
Statement stmt = expressionStatement;
IL.ILVariable collection = null;
IL.ILVariable[] upperBounds = null;
Statement? stmt = expressionStatement;
IL.ILVariable? collection = null;
IL.ILVariable[]? upperBounds = null;
List<Statement> statementsToDelete = new List<Statement>();
int i = 0;
// first we look for all the upper bound initializations
@ -512,9 +518,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -512,9 +518,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
upperBounds[i] = m.Get<IdentifierExpression>("variable").Single().GetILVariable();
stmt = stmt.GetNextStatement();
i++;
} while (stmt != null && i < upperBounds.Length);
} while (stmt != null && upperBounds != null && i < upperBounds.Length);
if (upperBounds?.LastOrDefault() == null || collection == null)
if (upperBounds?.LastOrDefault() == null || collection == null || stmt == null)
return null;
if (!MatchForeachOnMultiDimArray(upperBounds, collection, stmt, out var foreachVariable, out var statements, out var lowerBounds))
return null;
@ -609,12 +615,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -609,12 +615,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return true;
}
PropertyDeclaration TransformAutomaticProperty(PropertyDeclaration propertyDeclaration)
PropertyDeclaration? TransformAutomaticProperty(PropertyDeclaration propertyDeclaration)
{
IProperty property = propertyDeclaration.GetSymbol() as IProperty;
if (!CanTransformToAutomaticProperty(property, !property.DeclaringTypeDefinition.Fields.Any(f => f.Name == "_" + property.Name && f.IsCompilerGenerated())))
IProperty? property = propertyDeclaration.GetSymbol() as IProperty;
if (property == null)
return null;
if (!CanTransformToAutomaticProperty(property, !(property.DeclaringTypeDefinition?.Fields.Any(f => f.Name == "_" + property.Name && f.IsCompilerGenerated()) ?? false)))
return null;
IField field = null;
IField? field = null;
Match m = automaticPropertyPattern.Match(propertyDeclaration);
if (m.Success)
{
@ -636,8 +644,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -636,8 +644,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
RemoveCompilerGeneratedAttribute(propertyDeclaration.Getter.Attributes);
RemoveCompilerGeneratedAttribute(propertyDeclaration.Setter.Attributes);
propertyDeclaration.Getter.Body = null;
propertyDeclaration.Setter.Body = null;
// Clearing the accessor body turns it into an auto-property accessor; the slot setter
// tolerates null until optional slots become nullable in the AST declarations.
propertyDeclaration.Getter.Body = null!;
propertyDeclaration.Setter.Body = null!;
propertyDeclaration.Modifiers &= ~Modifiers.Readonly;
propertyDeclaration.Getter.Modifiers &= ~Modifiers.Readonly;
@ -703,14 +713,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -703,14 +713,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return base.VisitIdentifier(identifier);
}
internal static bool IsBackingFieldOfAutomaticProperty(IField field, out IProperty property)
internal static bool IsBackingFieldOfAutomaticProperty(IField field, [NotNullWhen(true)] out IProperty? property)
{
property = null;
if (!NameCouldBeBackingFieldOfAutomaticProperty(field.Name, out string propertyName))
if (!NameCouldBeBackingFieldOfAutomaticProperty(field.Name, out var propertyName))
return false;
if (!field.IsCompilerGenerated())
return false;
property = field.DeclaringTypeDefinition
property = field.DeclaringTypeDefinition?
.GetProperties(p => p.Name == propertyName, GetMemberOptions.IgnoreInheritedMembers)
.FirstOrDefault();
return property != null;
@ -726,7 +736,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -726,7 +736,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
static readonly System.Text.RegularExpressions.Regex automaticPropertyBackingFieldNameRegex
= new System.Text.RegularExpressions.Regex(@"^(<(?<name>.+)>k__BackingField|_(?<name>.+))$");
static bool NameCouldBeBackingFieldOfAutomaticProperty(string name, out string propertyName)
static bool NameCouldBeBackingFieldOfAutomaticProperty(string name, [NotNullWhen(true)] out string? propertyName)
{
propertyName = null;
var m = automaticPropertyBackingFieldNameRegex.Match(name);
@ -736,16 +746,17 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -736,16 +746,17 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return true;
}
Identifier ReplaceBackingFieldUsage(Identifier identifier)
Identifier? ReplaceBackingFieldUsage(Identifier identifier)
{
if (NameCouldBeBackingFieldOfAutomaticProperty(identifier.Name, out _))
{
var parent = identifier.Parent;
if (parent == null)
return null;
var mrr = parent.Annotation<MemberResolveResult>();
var field = mrr?.Member as IField;
if (field != null && IsBackingFieldOfAutomaticProperty(field, out var property)
if (mrr?.Member is IField field && IsBackingFieldOfAutomaticProperty(field, out var property)
&& CanTransformToAutomaticProperty(property, !(field.IsCompilerGenerated() && field.Name == "_" + property.Name))
&& currentMethod.AccessorOwner != property)
&& currentMethod?.AccessorOwner != property)
{
if (!property.CanSet && !context.Settings.GetterOnlyAutomaticProperties)
return null;
@ -757,9 +768,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -757,9 +768,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return null;
}
Identifier ReplaceEventFieldAnnotation(Identifier identifier)
Identifier? ReplaceEventFieldAnnotation(Identifier identifier)
{
var parent = identifier.Parent;
if (parent == null)
return null;
var mrr = parent.Annotation<MemberResolveResult>();
if (mrr?.Member is not IField field || field.Accessibility != Accessibility.Private)
return null;
@ -769,7 +782,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -769,7 +782,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (module.MetadataFile.PropertyAndEventBackingFieldLookup.IsEventBackingField((FieldDefinitionHandle)field.MetadataToken, out var eventHandle))
{
var eventDef = module.ResolveEntity(eventHandle) as IEvent;
if (eventDef != null && currentMethod.AccessorOwner != eventDef)
if (eventDef != null && currentMethod?.AccessorOwner != eventDef)
{
parent.RemoveAnnotations<MemberResolveResult>();
parent.AddAnnotation(new MemberResolveResult(mrr.TargetResult, eventDef));
@ -914,7 +927,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -914,7 +927,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (!m.Success)
return false;
Expression fieldExpression = m.Get<Expression>("field").Single();
IField eventField = fieldExpression.GetSymbol() as IField;
IField? eventField = fieldExpression.GetSymbol() as IField;
if (eventField == null)
return false;
var module = eventField.ParentModule as MetadataModule;
@ -990,7 +1003,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -990,7 +1003,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return true;
}
EventDeclaration TransformAutomaticEvents(CustomEventDeclaration ev)
EventDeclaration? TransformAutomaticEvents(CustomEventDeclaration ev)
{
if (!ev.PrivateImplementationType.IsNull)
return null;
@ -1065,7 +1078,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -1065,7 +1078,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
Body = destructorBodyPattern
};
DestructorDeclaration TransformDestructor(MethodDeclaration methodDef)
DestructorDeclaration? TransformDestructor(MethodDeclaration methodDef)
{
Match m = destructorPattern.Match(methodDef);
if (m.Success)
@ -1082,7 +1095,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -1082,7 +1095,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return null;
}
DestructorDeclaration TransformDestructorBody(DestructorDeclaration dtorDef)
DestructorDeclaration? TransformDestructorBody(DestructorDeclaration dtorDef)
{
Match m = destructorBodyPattern.Match(dtorDef.Body);
if (m.Success)
@ -1109,7 +1122,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -1109,7 +1122,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// Simplify nested 'try { try {} catch {} } finally {}'.
/// This transformation must run after the using/lock tranformations.
/// </summary>
TryCatchStatement TransformTryCatchFinally(TryCatchStatement tryFinally)
TryCatchStatement? TransformTryCatchFinally(TryCatchStatement tryFinally)
{
if (tryCatchFinallyPattern.IsMatch(tryFinally))
{
@ -1140,7 +1153,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -1140,7 +1153,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
};
AstNode SimplifyCascadingIfElseStatements(IfElseStatement node)
AstNode? SimplifyCascadingIfElseStatements(IfElseStatement node)
{
Match m = cascadingIfElsePattern.Match(node);
if (m.Success)

14
ICSharpCode.Decompiler/CSharp/Transforms/PrettifyAssignments.cs

@ -16,7 +16,10 @@ @@ -16,7 +16,10 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Resolver;
@ -39,6 +42,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -39,6 +42,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// </remarks>
class PrettifyAssignments : DepthFirstAstVisitor, IAstTransform
{
[AllowNull]
TransformContext context;
public override void VisitAssignmentExpression(AssignmentExpression assignment)
@ -48,7 +52,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -48,7 +52,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
// Also supports "x = (T)(x op y)" -> "x op= y", if x.GetType() == T
// and y is implicitly convertible to T.
Expression rhs = assignment.Right;
IType expectedType = null;
IType? expectedType = null;
if (assignment.Right is CastExpression { Type: var astType } cast)
{
rhs = cast.Expression;
@ -89,7 +93,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -89,7 +93,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
bool IsImplicitlyConvertible(Expression rhs, IType expectedType)
bool IsImplicitlyConvertible(Expression rhs, IType? expectedType)
{
if (expectedType == null)
return true;
@ -132,13 +136,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -132,13 +136,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
static bool CanConvertToCompoundAssignment(Expression left)
{
MemberReferenceExpression mre = left as MemberReferenceExpression;
MemberReferenceExpression? mre = left as MemberReferenceExpression;
if (mre != null)
return IsWithoutSideEffects(mre.Target);
IndexerExpression ie = left as IndexerExpression;
IndexerExpression? ie = left as IndexerExpression;
if (ie != null)
return IsWithoutSideEffects(ie.Target) && ie.Arguments.All(IsWithoutSideEffects);
UnaryOperatorExpression uoe = left as UnaryOperatorExpression;
UnaryOperatorExpression? uoe = left as UnaryOperatorExpression;
if (uoe != null && uoe.Operator == UnaryOperatorType.Dereference)
return IsWithoutSideEffects(uoe.Expression);
return IsWithoutSideEffects(left);

2
ICSharpCode.Decompiler/CSharp/Transforms/RemoveCLSCompliantAttribute.cs

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;

6
ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs

@ -16,7 +16,10 @@ @@ -16,7 +16,10 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
@ -41,6 +44,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -41,6 +44,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
MemberName = "TypeHandle"
};
[AllowNull]
TransformContext context;
public override void VisitInvocationExpression(InvocationExpression invocationExpression)
@ -508,7 +512,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -508,7 +512,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
Match m = getMethodOrConstructorFromHandlePattern.Match(castExpression);
if (m.Success)
{
IMethod method = m.Get<AstNode>("method").Single().GetSymbol() as IMethod;
IMethod? method = m.Get<AstNode>("method").Single().GetSymbol() as IMethod;
if (m.Has("declaringType") && method != null)
{
Expression newNode = new MemberReferenceExpression(new TypeReferenceExpression(m.Get<AstType>("declaringType").Single().Detach()), method.Name);

8
ICSharpCode.Decompiler/CSharp/Transforms/TransformContext.cs

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#nullable enable
using System.Collections.Immutable;
using System.Threading;
@ -40,17 +42,17 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -40,17 +42,17 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// <summary>
/// Returns the current member; or null if a whole type or module is being decompiled.
/// </summary>
public IMember CurrentMember => decompilationContext.CurrentMember;
public IMember? CurrentMember => decompilationContext.CurrentMember;
/// <summary>
/// Returns the current type definition; or null if a module is being decompiled.
/// </summary>
public ITypeDefinition CurrentTypeDefinition => decompilationContext.CurrentTypeDefinition;
public ITypeDefinition? CurrentTypeDefinition => decompilationContext.CurrentTypeDefinition;
/// <summary>
/// Returns the module that is being decompiled.
/// </summary>
public IModule CurrentModule => decompilationContext.CurrentModule;
public IModule? CurrentModule => decompilationContext.CurrentModule;
/// <summary>
/// Returns the max possible set of namespaces that will be used during decompilation.

Loading…
Cancel
Save