Browse Source

Make optional AST slots nullable

Optional single-child slots return T? with a real null instead of a role
null-object, taking the C# grammar as the oracle for which slots are optional.
The generator emits the property type as T? and matches it with MatchOptional,
and consumers move from .IsNull to is null / ?.. This covers the optional
statement, member, try-catch, creation-initializer and pattern slots and the
optional NameSlot tokens. A few slots the grammar marks required but the
decompiler legitimately leaves empty (the implicit-element-access target, an
implicitly-typed lambda parameter's type) are flipped to nullable as well.
Assisted-by: Claude:claude-opus-4-8:Claude Code
pull/3807/head
Siegfried Pammer 3 weeks ago committed by Siegfried Pammer
parent
commit
1f4fd68b3f
  1. 15
      ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs
  2. 2
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  3. 7
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  4. 6
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  5. 2
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs
  6. 78
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  7. 26
      ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs
  8. 12
      ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs
  9. 4
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  10. 8
      ICSharpCode.Decompiler/CSharp/Syntax/DocumentationReference.cs
  11. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/ArrayCreateExpression.cs
  12. 10
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IndexerExpression.cs
  13. 6
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/ObjectCreateExpression.cs
  14. 6
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/RecursivePatternExpression.cs
  15. 10
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/StackAllocExpression.cs
  16. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/ForStatement.cs
  17. 6
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/IfElseStatement.cs
  18. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/ReturnStatement.cs
  19. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/SwitchStatement.cs
  20. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/ThrowStatement.cs
  21. 8
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/TryCatchStatement.cs
  22. 2
      ICSharpCode.Decompiler/CSharp/Syntax/TupleAstType.cs
  23. 2
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/Accessor.cs
  24. 6
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/ConstructorDeclaration.cs
  25. 4
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/DestructorDeclaration.cs
  26. 4
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/EnumMemberDeclaration.cs
  27. 8
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/EventDeclaration.cs
  28. 10
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/IndexerDeclaration.cs
  29. 6
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/MethodDeclaration.cs
  30. 10
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/OperatorDeclaration.cs
  31. 4
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/ParameterDeclaration.cs
  32. 14
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/PropertyDeclaration.cs
  33. 6
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/VariableInitializer.cs
  34. 4
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  35. 24
      ICSharpCode.Decompiler/CSharp/Transforms/NormalizeBlockStatements.cs
  36. 36
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
  37. 2
      ICSharpCode.Decompiler/CSharp/Transforms/PrettifyAssignments.cs
  38. 4
      ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs
  39. 22
      ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs
  40. 4
      ICSharpCode.Decompiler/DebugInfo/DebugInfoGenerator.cs
  41. 6
      ILSpy/Languages/CSharpLanguage.cs

15
ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs

@ -143,7 +143,8 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -143,7 +143,8 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
string roleExpr = (string)nameSlotAttr.ConstructorArguments[0].Value!;
bool nullOnEmpty = nameSlotAttr.ConstructorArguments.Length > 1 && (bool)nameSlotAttr.ConstructorArguments[1].Value!;
string tokenName = property.Name + "Token";
slots.Add((roleExpr, false, tokenName, "Identifier", "Identifier", false, false, SlotKindName(roleExpr), false));
// An optional name (nullOnEmpty) makes the backing token a real nullable slot: an absent name is a null token.
slots.Add((roleExpr, false, tokenName, "Identifier", "Identifier", false, nullOnEmpty, SlotKindName(roleExpr), false));
nameSlots.Add((property.Name, tokenName, nullOnEmpty));
}
}
@ -363,7 +364,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -363,7 +364,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
else
{
builder.AppendLine($"\t{type}? {field};");
builder.AppendLine($"\tpublic {(isOverride ? "override " : "")}{partialKw}{type} {name}");
builder.AppendLine($"\tpublic {(isOverride ? "override " : "")}{partialKw}{type}{(isNullable ? "?" : "")} {name}");
builder.AppendLine("\t{");
builder.AppendLine($"\t\tget => {field}{(isNullable ? "" : $" ?? {roleExpr}.NullObject")};");
builder.AppendLine($"\t\tset => SetChildNode(ref {field}, value, {roleExpr});");
@ -379,11 +380,17 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -379,11 +380,17 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
{
builder.AppendLine($"\tpublic partial string {stringName}");
builder.AppendLine("\t{");
builder.AppendLine($"\t\tget => {tokenName}.Name;");
if (nullOnEmpty)
builder.AppendLine($"\t\tset => {tokenName} = string.IsNullOrEmpty(value) ? null! : global::ICSharpCode.Decompiler.CSharp.Syntax.Identifier.Create(value);");
{
// The token is a nullable slot, so guard the read and clear it (to null) on an empty name.
builder.AppendLine($"\t\tget => {tokenName}?.Name ?? string.Empty;");
builder.AppendLine($"\t\tset => {tokenName} = string.IsNullOrEmpty(value) ? null : global::ICSharpCode.Decompiler.CSharp.Syntax.Identifier.Create(value);");
}
else
{
builder.AppendLine($"\t\tget => {tokenName}.Name;");
builder.AppendLine($"\t\tset => {tokenName} = global::ICSharpCode.Decompiler.CSharp.Syntax.Identifier.Create(value);");
}
builder.AppendLine("\t}");
builder.AppendLine();
}

2
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -1663,7 +1663,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1663,7 +1663,7 @@ namespace ICSharpCode.Decompiler.CSharp
typeDecl.Members.AddRange(entityMap[member]);
}
if (typeDecl.Members.OfType<IndexerDeclaration>().Any(idx => idx.PrivateImplementationType.IsNull))
if (typeDecl.Members.OfType<IndexerDeclaration>().Any(idx => idx.PrivateImplementationType is null))
{
// Remove the [DefaultMember] attribute if the class contains indexers
RemoveAttribute(typeDecl, KnownAttribute.DefaultMember);

7
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -731,7 +731,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -731,7 +731,7 @@ namespace ICSharpCode.Decompiler.CSharp
var assignment = HandleAccessorCall(expectedTargetDetails, method, unused,
argumentList.Arguments.ToList(), argumentList.ArgumentNames);
if (((AssignmentExpression)assignment).Left is IndexerExpression indexer && !indexer.Target.IsNull)
if (((AssignmentExpression)assignment).Left is IndexerExpression indexer && indexer.Target is not null)
indexer.Target.Remove();
if (value != null)
@ -1093,7 +1093,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1093,7 +1093,7 @@ namespace ICSharpCode.Decompiler.CSharp
return false;
case ArrayCreateResolveResult { Type: ArrayType { ElementType: var type3 }, SizeArguments: [{ ConstantValue: int arrayLength }] }:
elementType = type3;
arguments = new(((ArrayCreateExpression)paramsArgument.Expression).Initializer.Elements.Select(e => new TranslatedExpression(e)));
arguments = new(((ArrayCreateExpression)paramsArgument.Expression).Initializer?.Elements.Select(e => new TranslatedExpression(e)) ?? []);
parameters = new List<IParameter>(arrayLength);
for (int i = 0; i < arrayLength; i++)
{
@ -1423,7 +1423,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1423,7 +1423,8 @@ namespace ICSharpCode.Decompiler.CSharp
continue;
if (child is ReturnStatement ret)
{
ret.Expression = new TranslatedExpression(ret.Expression.Detach()).ConvertTo(returnType, expressionBuilder);
if (ret.Expression is not null)
ret.Expression = new TranslatedExpression(ret.Expression.Detach()).ConvertTo(returnType, expressionBuilder);
continue;
}
ModifyReturnStatementInsideLambda(returnType, child);

6
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -2469,7 +2469,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2469,7 +2469,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
bool isLambda = false;
if (ame.Parameters.Any(p => p.Type.IsNull))
if (ame.Parameters.Any(p => p.Type is null))
{
// if there is an anonymous type involved, we are forced to use a lambda expression.
isLambda = true;
@ -2532,7 +2532,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2532,7 +2532,7 @@ namespace ICSharpCode.Decompiler.CSharp
function, delegateType, inferredReturnType,
hasParameterList: isLambda || ame.HasParameterList,
isAnonymousMethod: !isLambda,
isImplicitlyTyped: ame.Parameters.Any(p => p.Type.IsNull));
isImplicitlyTyped: ame.Parameters.Any(p => p.Type is null));
TranslatedExpression translatedLambda = replacement.WithILInstruction(function).WithRR(rr);
return new CastExpression(ConvertType(delegateType), translatedLambda)
@ -2558,7 +2558,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2558,7 +2558,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
if (node is ReturnStatement ret)
{
if (!ret.Expression.IsNull)
if (ret.Expression is not null)
{
returnExpressions.Add(ret.Expression.GetResolveResult());
}

2
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs

@ -162,7 +162,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -162,7 +162,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
}
if ((ConversionFlags & ConversionFlags.ShowParameterDefaultValues) == 0)
{
param.DefaultExpression.Detach();
param.DefaultExpression?.Detach();
}
if (first)
{

78
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -244,7 +244,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -244,7 +244,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
return false;
if (!(kind == SlotKind.Getter || kind == SlotKind.Setter))
return false;
bool isAutoProperty = accessor.Body.IsNull
bool isAutoProperty = accessor.Body is null
&& !accessor.Attributes.Any()
&& policy.AutoPropertyFormatting == PropertyFormatting.SingleLine;
return isAutoProperty;
@ -531,7 +531,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -531,7 +531,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
protected virtual void WriteMethodBody(BlockStatement body, BraceStyle style, bool newLine = true)
{
if (body.IsNull)
if (body is null || body.IsNull)
{
Semicolon();
}
@ -552,7 +552,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -552,7 +552,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
protected virtual void WritePrivateImplementationType(AstType privateImplementationType)
{
if (!privateImplementationType.IsNull)
if (privateImplementationType is not null && !privateImplementationType.IsNull)
{
privateImplementationType.AcceptVisitor(this);
WriteToken(Roles.Dot);
@ -620,7 +620,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -620,7 +620,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
specifier.AcceptVisitor(this);
}
arrayCreateExpression.Initializer.AcceptVisitor(this);
arrayCreateExpression.Initializer?.AcceptVisitor(this);
EndNode(arrayCreateExpression);
}
@ -925,7 +925,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -925,7 +925,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
StartNode(recursivePatternExpression);
recursivePatternExpression.Type.AcceptVisitor(this);
recursivePatternExpression.Type?.AcceptVisitor(this);
Space();
if (recursivePatternExpression.IsPositional)
{
@ -946,7 +946,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -946,7 +946,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
WriteToken(Roles.RBrace);
}
if (!recursivePatternExpression.Designation.IsNull)
if (recursivePatternExpression.Designation is not null)
{
Space();
recursivePatternExpression.Designation.AcceptVisitor(this);
@ -979,7 +979,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -979,7 +979,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
public virtual void VisitIndexerExpression(IndexerExpression indexerExpression)
{
StartNode(indexerExpression);
indexerExpression.Target.AcceptVisitor(this);
indexerExpression.Target?.AcceptVisitor(this);
Space(policy.SpaceBeforeMethodCallParentheses);
WriteCommaSeparatedListInBrackets(indexerExpression.Arguments);
EndNode(indexerExpression);
@ -1050,7 +1050,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -1050,7 +1050,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
return true;
}
var p = lambdaExpression.Parameters.Single();
return !(p.Type.IsNull && p.ParameterModifier == ReferenceKind.None && !p.IsParams);
return !(p.Type is null && p.ParameterModifier == ReferenceKind.None && !p.IsParams);
}
public virtual void VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression)
@ -1102,13 +1102,13 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -1102,13 +1102,13 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
StartNode(objectCreateExpression);
WriteKeyword(ObjectCreateExpression.NewKeywordRole);
objectCreateExpression.Type.AcceptVisitor(this);
bool useParenthesis = objectCreateExpression.Arguments.Any() || objectCreateExpression.Initializer.IsNull;
bool useParenthesis = objectCreateExpression.Arguments.Any() || objectCreateExpression.Initializer is null;
if (useParenthesis)
{
Space(policy.SpaceBeforeMethodCallParentheses);
WriteCommaSeparatedListInParenthesis(objectCreateExpression.Arguments, policy.SpaceWithinMethodCallParentheses);
}
objectCreateExpression.Initializer.AcceptVisitor(this);
objectCreateExpression.Initializer?.AcceptVisitor(this);
EndNode(objectCreateExpression);
}
@ -1212,9 +1212,9 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -1212,9 +1212,9 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
StartNode(stackAllocExpression);
WriteKeyword(StackAllocExpression.StackallocKeywordRole);
stackAllocExpression.Type.AcceptVisitor(this);
WriteCommaSeparatedListInBrackets(new[] { stackAllocExpression.CountExpression });
stackAllocExpression.Initializer.AcceptVisitor(this);
stackAllocExpression.Type?.AcceptVisitor(this);
WriteCommaSeparatedListInBrackets(stackAllocExpression.CountExpression is { } stackAllocCount ? new[] { stackAllocCount } : Array.Empty<Expression>());
stackAllocExpression.Initializer?.AcceptVisitor(this);
EndNode(stackAllocExpression);
}
@ -1831,7 +1831,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -1831,7 +1831,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
WriteToken(Roles.Semicolon);
Space(policy.SpaceAfterForSemicolon);
forStatement.Condition.AcceptVisitor(this);
forStatement.Condition?.AcceptVisitor(this);
Space(policy.SpaceBeforeForSemicolon);
WriteToken(Roles.Semicolon);
if (forStatement.Iterators.Any())
@ -1886,7 +1886,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -1886,7 +1886,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
Space(policy.SpacesWithinIfParentheses);
RPar();
if (ifElseStatement.FalseStatement.IsNull)
if (ifElseStatement.FalseStatement is null)
{
WriteEmbeddedStatement(ifElseStatement.TrueStatement);
}
@ -1947,7 +1947,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -1947,7 +1947,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
StartNode(returnStatement);
WriteKeyword(ReturnStatement.ReturnKeywordRole);
if (!returnStatement.Expression.IsNull)
if (returnStatement.Expression is not null)
{
Space();
returnStatement.Expression.AcceptVisitor(this);
@ -2024,7 +2024,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2024,7 +2024,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
public virtual void VisitCaseLabel(CaseLabel caseLabel)
{
StartNode(caseLabel);
if (caseLabel.Expression.IsNull)
if (caseLabel.Expression is null)
{
WriteKeyword(CaseLabel.DefaultKeywordRole);
}
@ -2070,7 +2070,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2070,7 +2070,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
StartNode(throwStatement);
WriteKeyword(ThrowStatement.ThrowKeywordRole);
if (!throwStatement.Expression.IsNull)
if (throwStatement.Expression is not null)
{
Space();
throwStatement.Expression.AcceptVisitor(this);
@ -2092,7 +2092,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2092,7 +2092,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
NewLine();
catchClause.AcceptVisitor(this);
}
if (!tryCatchStatement.FinallyBlock.IsNull)
if (tryCatchStatement.FinallyBlock is not null)
{
if (policy.FinallyNewLinePlacement == NewLinePlacement.SameLine)
Space();
@ -2109,7 +2109,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2109,7 +2109,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
StartNode(catchClause);
WriteKeyword(CatchClause.CatchKeywordRole);
if (!catchClause.Type.IsNull)
if (catchClause.Type is not null)
{
Space(policy.SpaceBeforeCatchParentheses);
LPar();
@ -2123,7 +2123,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2123,7 +2123,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
Space(policy.SpacesWithinCatchParentheses);
RPar();
}
if (!catchClause.Condition.IsNull)
if (catchClause.Condition is not null)
{
Space();
WriteKeyword(CatchClause.WhenKeywordRole);
@ -2313,7 +2313,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2313,7 +2313,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
WriteIdentifier(constructorDeclaration.NameToken);
Space(policy.SpaceBeforeConstructorDeclarationParentheses);
WriteCommaSeparatedListInParenthesis(constructorDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
if (!constructorDeclaration.Initializer.IsNull)
if (constructorDeclaration.Initializer is not null)
{
NewLine();
writer.Indent();
@ -2370,7 +2370,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2370,7 +2370,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
WriteAttributes(enumMemberDeclaration.Attributes);
WriteModifiers(enumMemberDeclaration.Modifiers);
WriteIdentifier(enumMemberDeclaration.NameToken);
if (!enumMemberDeclaration.Initializer.IsNull)
if (enumMemberDeclaration.Initializer is not null)
{
Space(policy.SpaceAroundAssignment);
WriteToken(Roles.Assign);
@ -2500,14 +2500,14 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2500,14 +2500,14 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
Space(policy.SpaceBeforeMethodDeclarationParentheses);
WriteCommaSeparatedListInBrackets(indexerDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
if (indexerDeclaration.ExpressionBody.IsNull)
if (indexerDeclaration.ExpressionBody is null)
{
bool isSingleLine =
(policy.AutoPropertyFormatting == PropertyFormatting.SingleLine)
&& (indexerDeclaration.Getter.IsNull || indexerDeclaration.Getter.Body.IsNull)
&& (indexerDeclaration.Setter.IsNull || indexerDeclaration.Setter.Body.IsNull)
&& !indexerDeclaration.Getter.Attributes.Any()
&& !indexerDeclaration.Setter.Attributes.Any();
&& (indexerDeclaration.Getter is null || indexerDeclaration.Getter.Body is null)
&& (indexerDeclaration.Setter is null || indexerDeclaration.Setter.Body is null)
&& (indexerDeclaration.Getter is null || !indexerDeclaration.Getter.Attributes.Any())
&& (indexerDeclaration.Setter is null || !indexerDeclaration.Setter.Attributes.Any());
OpenBrace(isSingleLine ? BraceStyle.EndOfLine : policy.PropertyBraceStyle, newLine: !isSingleLine);
if (isSingleLine)
Space();
@ -2634,8 +2634,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2634,8 +2634,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
Space();
break;
}
parameterDeclaration.Type.AcceptVisitor(this);
if (!parameterDeclaration.Type.IsNull && !string.IsNullOrEmpty(parameterDeclaration.Name))
parameterDeclaration.Type?.AcceptVisitor(this);
if (parameterDeclaration.Type is not null && !string.IsNullOrEmpty(parameterDeclaration.Name))
{
Space();
}
@ -2643,7 +2643,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2643,7 +2643,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
WriteIdentifier(parameterDeclaration.NameToken);
}
if (!parameterDeclaration.DefaultExpression.IsNull)
if (parameterDeclaration.DefaultExpression is not null)
{
Space(policy.SpaceAroundAssignment);
WriteToken(Roles.Assign);
@ -2662,14 +2662,14 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2662,14 +2662,14 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
Space();
WritePrivateImplementationType(propertyDeclaration.PrivateImplementationType);
WriteIdentifier(propertyDeclaration.NameToken);
if (propertyDeclaration.ExpressionBody.IsNull)
if (propertyDeclaration.ExpressionBody is null)
{
bool isSingleLine =
(policy.AutoPropertyFormatting == PropertyFormatting.SingleLine)
&& (propertyDeclaration.Getter.IsNull || propertyDeclaration.Getter.Body.IsNull)
&& (propertyDeclaration.Setter.IsNull || propertyDeclaration.Setter.Body.IsNull)
&& !propertyDeclaration.Getter.Attributes.Any()
&& !propertyDeclaration.Setter.Attributes.Any();
&& (propertyDeclaration.Getter is null || propertyDeclaration.Getter.Body is null)
&& (propertyDeclaration.Setter is null || propertyDeclaration.Setter.Body is null)
&& (propertyDeclaration.Getter is null || !propertyDeclaration.Getter.Attributes.Any())
&& (propertyDeclaration.Setter is null || !propertyDeclaration.Setter.Attributes.Any());
OpenBrace(isSingleLine ? BraceStyle.EndOfLine : policy.PropertyBraceStyle, newLine: !isSingleLine);
if (isSingleLine)
Space();
@ -2714,7 +2714,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2714,7 +2714,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
StartNode(variableInitializer);
WriteIdentifier(variableInitializer.NameToken);
if (!variableInitializer.Initializer.IsNull)
if (variableInitializer.Initializer is not null)
{
Space(policy.SpaceAroundAssignment);
WriteToken(Roles.Assign);
@ -2788,7 +2788,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2788,7 +2788,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
StartNode(tupleTypeElement);
tupleTypeElement.Type.AcceptVisitor(this);
if (!tupleTypeElement.NameToken.IsNull)
if (tupleTypeElement.NameToken is not null)
{
Space();
tupleTypeElement.NameToken.AcceptVisitor(this);
@ -3098,7 +3098,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -3098,7 +3098,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
public virtual void VisitDocumentationReference(DocumentationReference documentationReference)
{
StartNode(documentationReference);
if (!documentationReference.DeclaringType.IsNull)
if (documentationReference.DeclaringType is not null)
{
documentationReference.DeclaringType.AcceptVisitor(this);
if (documentationReference.SymbolKind != SymbolKind.TypeDefinition)

26
ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs

@ -199,17 +199,21 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -199,17 +199,21 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
public override void VisitIndexerExpression(IndexerExpression indexerExpression)
{
ParenthesizeIfRequired(indexerExpression.Target, PrecedenceLevel.Primary);
switch (indexerExpression.Target)
// An implicit-element-access indexer (e.g. the '[i]' in a dictionary initializer) has no target.
if (indexerExpression.Target is not null)
{
case ArrayCreateExpression ace when InsertParenthesesForReadability || ace.Initializer.IsNull:
// require parentheses for "(new int[1])[0]"
Parenthesize(indexerExpression.Target);
break;
case StackAllocExpression sae when InsertParenthesesForReadability || sae.Initializer.IsNull:
// require parentheses for "(stackalloc int[1])[0]"
Parenthesize(indexerExpression.Target);
break;
ParenthesizeIfRequired(indexerExpression.Target, PrecedenceLevel.Primary);
switch (indexerExpression.Target)
{
case ArrayCreateExpression ace when InsertParenthesesForReadability || ace.Initializer is null:
// require parentheses for "(new int[1])[0]"
Parenthesize(indexerExpression.Target);
break;
case StackAllocExpression sae when InsertParenthesesForReadability || sae.Initializer is null:
// require parentheses for "(stackalloc int[1])[0]"
Parenthesize(indexerExpression.Target);
break;
}
}
base.VisitIndexerExpression(indexerExpression);
}
@ -487,7 +491,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -487,7 +491,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
public override void VisitVariableInitializer(VariableInitializer variableInitializer)
{
if (!variableInitializer.Initializer.IsNull)
if (variableInitializer.Initializer is not null)
HandleAssignmentRHS(variableInitializer.Initializer);
base.VisitVariableInitializer(variableInitializer);
}

12
ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs

@ -96,7 +96,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -96,7 +96,7 @@ namespace ICSharpCode.Decompiler.CSharp
void VisitAsSequencePoint(AstNode node)
{
if (node.IsNull)
if (node is null || node.IsNull)
return;
StartSequencePoint(node);
node.AcceptVisitor(this);
@ -165,7 +165,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -165,7 +165,7 @@ namespace ICSharpCode.Decompiler.CSharp
public override void VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration)
{
if (!propertyDeclaration.ExpressionBody.IsNull)
if (propertyDeclaration.ExpressionBody is not null)
{
VisitAsSequencePoint(propertyDeclaration.ExpressionBody);
}
@ -177,7 +177,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -177,7 +177,7 @@ namespace ICSharpCode.Decompiler.CSharp
public override void VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration)
{
if (!indexerDeclaration.ExpressionBody.IsNull)
if (indexerDeclaration.ExpressionBody is not null)
{
VisitAsSequencePoint(indexerDeclaration.ExpressionBody);
}
@ -385,7 +385,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -385,7 +385,7 @@ namespace ICSharpCode.Decompiler.CSharp
public override void VisitCatchClause(CatchClause catchClause)
{
if (catchClause.Condition.IsNull)
if (catchClause.Condition is null)
{
var tryCatchHandler = catchClause.Annotation<TryCatchHandler>();
if (tryCatchHandler != null && !tryCatchHandler.ExceptionSpecifierILRange.IsEmpty)
@ -432,9 +432,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -432,9 +432,9 @@ namespace ICSharpCode.Decompiler.CSharp
// the 'catch' keyword when there is no exception specifier.
static TextLocation CatchHeaderEnd(CatchClause catchClause)
{
if (catchClause.Type.IsNull)
if (catchClause.Type is null)
return Offset(catchClause.StartLocation, "catch".Length);
AstNode beforeRParen = catchClause.VariableNameToken.IsNull ? catchClause.Type : catchClause.VariableNameToken;
AstNode beforeRParen = catchClause.VariableNameToken is null ? catchClause.Type : catchClause.VariableNameToken;
return Offset(beforeRParen.EndLocation, 1);
}

4
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -268,7 +268,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -268,7 +268,7 @@ namespace ICSharpCode.Decompiler.CSharp
ConvertSwitchSectionBody(astSection, section.Body);
break;
case Leave leave:
if (astSection.CaseLabels.Count == 1 && astSection.CaseLabels.First().Expression.IsNull && leave.TargetContainer == switchContainer)
if (astSection.CaseLabels.Count == 1 && astSection.CaseLabels.First().Expression is null && leave.TargetContainer == switchContainer)
{
stmt.SwitchSections.Remove(astSection);
break;
@ -442,7 +442,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -442,7 +442,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
var tryBlockConverted = Convert(tryBlock);
var tryCatch = tryBlockConverted as TryCatchStatement;
if (tryCatch != null && tryCatch.FinallyBlock.IsNull)
if (tryCatch != null && tryCatch.FinallyBlock is null)
return tryCatch; // extend existing try-catch
tryCatch = new TryCatchStatement();
tryCatch.TryBlock = tryBlockConverted as BlockStatement ?? new BlockStatement { tryBlockConverted };

8
ICSharpCode.Decompiler/CSharp/Syntax/DocumentationReference.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.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Syntax
@ -79,7 +81,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -79,7 +81,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// Gets/Sets the declaring type.
/// </summary>
[Slot("DeclaringTypeRole")]
public partial AstType DeclaringType { get; set; }
public partial AstType? DeclaringType { get; set; }
/// <summary>
/// Gets/sets the member name.
@ -106,9 +108,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -106,9 +108,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[Slot("Roles.Parameter")]
public partial AstNodeCollection<ParameterDeclaration> Parameters { get; }
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
protected internal override bool DoMatch(AstNode? other, PatternMatching.Match match)
{
DocumentationReference o = other as DocumentationReference;
DocumentationReference? o = other as DocumentationReference;
if (!(o != null && this.SymbolKind == o.SymbolKind && this.HasParameterList == o.HasParameterList))
return false;
if (this.SymbolKind == SymbolKind.Operator)

4
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/ArrayCreateExpression.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
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
@ -42,6 +44,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -42,6 +44,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial AstNodeCollection<ArraySpecifier> AdditionalArraySpecifiers { get; }
[Slot("InitializerRole")]
public partial ArrayInitializerExpression Initializer { get; set; }
public partial ArrayInitializerExpression? Initializer { get; set; }
}
}

10
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IndexerExpression.cs

@ -26,6 +26,8 @@ @@ -26,6 +26,8 @@
using System.Collections.Generic;
#nullable enable
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
@ -35,7 +37,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -35,7 +37,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class IndexerExpression : Expression
{
[Slot("Roles.TargetExpression")]
public partial Expression Target { get; set; }
public partial Expression? Target { get; set; }
[Slot("Roles.Argument")]
public partial AstNodeCollection<Expression> Arguments { get; }
@ -44,9 +46,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -44,9 +46,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
}
public IndexerExpression(Expression target, IEnumerable<Expression> arguments)
public IndexerExpression(Expression? target, IEnumerable<Expression>? arguments)
{
AddChild(target, Roles.TargetExpression);
Target = target;
if (arguments != null)
{
foreach (var arg in arguments)
@ -56,7 +58,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -56,7 +58,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
}
public IndexerExpression(Expression target, params Expression[] arguments) : this(target, (IEnumerable<Expression>)arguments)
public IndexerExpression(Expression? target, params Expression[] arguments) : this(target, (IEnumerable<Expression>)arguments)
{
}
}

6
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/ObjectCreateExpression.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
using System.Collections.Generic;
namespace ICSharpCode.Decompiler.CSharp.Syntax
@ -44,13 +46,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -44,13 +46,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial AstNodeCollection<Expression> Arguments { get; }
[Slot("InitializerRole")]
public partial ArrayInitializerExpression Initializer { get; set; }
public partial ArrayInitializerExpression? Initializer { get; set; }
public ObjectCreateExpression()
{
}
public ObjectCreateExpression(AstType type, IEnumerable<Expression> arguments = null)
public ObjectCreateExpression(AstType type, IEnumerable<Expression>? arguments = null)
{
AddChild(type, Roles.Type);
if (arguments != null)

6
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/RecursivePatternExpression.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
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
@ -32,13 +34,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -32,13 +34,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public static readonly Role<Expression> SubPatternRole = new Role<Expression>("SubPattern", Syntax.Expression.Null);
[Slot("Roles.Type")]
public partial AstType Type { get; set; }
public partial AstType? Type { get; set; }
[Slot("SubPatternRole")]
public partial AstNodeCollection<Expression> SubPatterns { get; }
[Slot("Roles.VariableDesignationRole")]
public partial VariableDesignation Designation { get; set; }
public partial VariableDesignation? Designation { get; set; }
public bool IsPositional { get; set; }
}

10
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/StackAllocExpression.cs

@ -24,6 +24,10 @@ @@ -24,6 +24,10 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
using System.Diagnostics.CodeAnalysis;
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
@ -41,12 +45,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -41,12 +45,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public readonly static Role<ArrayInitializerExpression> InitializerRole = new Role<ArrayInitializerExpression>("Initializer", ArrayInitializerExpression.Null);
[Slot("Roles.Type")]
public partial AstType Type { get; set; }
public partial AstType? Type { get; set; }
[Slot("Roles.Expression")]
public partial Expression CountExpression { get; set; }
public partial Expression? CountExpression { get; set; }
[Slot("InitializerRole")]
public partial ArrayInitializerExpression Initializer { get; set; }
public partial ArrayInitializerExpression? Initializer { get; set; }
}
}

4
ICSharpCode.Decompiler/CSharp/Syntax/Statements/ForStatement.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
@ -45,7 +47,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -45,7 +47,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial AstNodeCollection<Statement> Initializers { get; }
[Slot("Roles.Condition")]
public partial Expression Condition { get; set; }
public partial Expression? Condition { get; set; }
[Slot("IteratorRole")]
public partial AstNodeCollection<Statement> Iterators { get; }

6
ICSharpCode.Decompiler/CSharp/Syntax/Statements/IfElseStatement.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
@ -45,13 +47,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -45,13 +47,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial Statement TrueStatement { get; set; }
[Slot("FalseRole")]
public partial Statement FalseStatement { get; set; }
public partial Statement? FalseStatement { get; set; }
public IfElseStatement()
{
}
public IfElseStatement(Expression condition, Statement trueStatement, Statement falseStatement = null)
public IfElseStatement(Expression condition, Statement trueStatement, Statement? falseStatement = null)
{
this.Condition = condition;
this.TrueStatement = trueStatement;

4
ICSharpCode.Decompiler/CSharp/Syntax/Statements/ReturnStatement.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
@ -35,7 +37,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -35,7 +37,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public static readonly TokenRole ReturnKeywordRole = new TokenRole("return");
[Slot("Roles.Expression")]
public partial Expression Expression { get; set; }
public partial Expression? Expression { get; set; }
public ReturnStatement()
{

4
ICSharpCode.Decompiler/CSharp/Syntax/Statements/SwitchStatement.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
@ -70,7 +72,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -70,7 +72,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// Gets or sets the expression. The expression can be null - if the expression is null, it's the default switch section.
/// </summary>
[Slot("Roles.Expression")]
public partial Expression Expression { get; set; }
public partial Expression? Expression { get; set; }
public CaseLabel()
{

4
ICSharpCode.Decompiler/CSharp/Syntax/Statements/ThrowStatement.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
@ -35,7 +37,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -35,7 +37,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public static readonly TokenRole ThrowKeywordRole = new TokenRole("throw");
[Slot("Roles.Expression")]
public partial Expression Expression { get; set; }
public partial Expression? Expression { get; set; }
public ThrowStatement()
{

8
ICSharpCode.Decompiler/CSharp/Syntax/Statements/TryCatchStatement.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
@ -45,7 +47,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -45,7 +47,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial AstNodeCollection<CatchClause> CatchClauses { get; }
[Slot("FinallyBlockRole")]
public partial BlockStatement FinallyBlock { get; set; }
public partial BlockStatement? FinallyBlock { get; set; }
}
/// <summary>
@ -61,13 +63,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -61,13 +63,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public static readonly TokenRole CondRPar = new TokenRole(")");
[Slot("Roles.Type")]
public partial AstType Type { get; set; }
public partial AstType? Type { get; set; }
[NameSlot("Roles.Identifier", nullOnEmpty: true)]
public partial string VariableName { get; set; }
[Slot("ConditionRole")]
public partial Expression Condition { get; set; }
public partial Expression? Condition { get; set; }
[Slot("Roles.Body")]
public partial BlockStatement Body { get; set; }

2
ICSharpCode.Decompiler/CSharp/Syntax/TupleAstType.cs

@ -39,7 +39,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -39,7 +39,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[Slot("Roles.Type")]
public partial AstType Type { get; set; }
[NameSlot("Roles.Identifier")]
[NameSlot("Roles.Identifier", nullOnEmpty: true)]
public partial string Name { get; set; }
}

2
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/Accessor.cs

@ -71,7 +71,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -71,7 +71,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public override partial AstNodeCollection<AttributeSection> Attributes { get; }
[Slot("Roles.Body")]
public partial BlockStatement Body { get; set; }
public partial BlockStatement? Body { get; set; }
public static TokenRole? GetAccessorKeywordRole(AccessorKind kind)
{

6
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/ConstructorDeclaration.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Syntax
@ -52,10 +54,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -52,10 +54,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial AstNodeCollection<ParameterDeclaration> Parameters { get; }
[Slot("InitializerRole")]
public partial ConstructorInitializer Initializer { get; set; }
public partial ConstructorInitializer? Initializer { get; set; }
[Slot("Roles.Body")]
public partial BlockStatement Body { get; set; }
public partial BlockStatement? Body { get; set; }
}
public enum ConstructorInitializerType

4
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/DestructorDeclaration.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Syntax
@ -49,6 +51,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -49,6 +51,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public override partial Identifier NameToken { get; set; }
[Slot("Roles.Body")]
public partial BlockStatement Body { get; set; }
public partial BlockStatement? Body { get; set; }
}
}

4
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/EnumMemberDeclaration.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Syntax
@ -47,7 +49,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -47,7 +49,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public override partial Identifier NameToken { get; set; }
[Slot("InitializerRole")]
public partial Expression Initializer { get; set; }
public partial Expression? Initializer { get; set; }
}
}

8
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/EventDeclaration.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
using System;
using System.ComponentModel;
@ -95,15 +97,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -95,15 +97,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// Null node if this member is not an explicit interface implementation.
/// </summary>
[Slot("PrivateImplementationTypeRole")]
public partial AstType PrivateImplementationType { get; set; }
public partial AstType? PrivateImplementationType { get; set; }
[Slot("Roles.Identifier")]
public override partial Identifier NameToken { get; set; }
[Slot("AddAccessorRole")]
public partial Accessor AddAccessor { get; set; }
public partial Accessor? AddAccessor { get; set; }
[Slot("RemoveAccessorRole")]
public partial Accessor RemoveAccessor { get; set; }
public partial Accessor? RemoveAccessor { get; set; }
}
}

10
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/IndexerDeclaration.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
using System;
using System.ComponentModel;
@ -62,7 +64,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -62,7 +64,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public override partial AstType ReturnType { get; set; }
[Slot("PrivateImplementationTypeRole")]
public partial AstType PrivateImplementationType { get; set; }
public partial AstType? PrivateImplementationType { get; set; }
public override string Name {
get { return "Item"; }
@ -79,12 +81,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -79,12 +81,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial AstNodeCollection<ParameterDeclaration> Parameters { get; }
[Slot("GetterRole")]
public partial Accessor Getter { get; set; }
public partial Accessor? Getter { get; set; }
[Slot("SetterRole")]
public partial Accessor Setter { get; set; }
public partial Accessor? Setter { get; set; }
[Slot("ExpressionBodyRole")]
public partial Expression ExpressionBody { get; set; }
public partial Expression? ExpressionBody { get; set; }
}
}

6
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/MethodDeclaration.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Syntax
@ -51,7 +53,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -51,7 +53,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// Null node if this member is not an explicit interface implementation.
/// </summary>
[Slot("PrivateImplementationTypeRole")]
public partial AstType PrivateImplementationType { get; set; }
public partial AstType? PrivateImplementationType { get; set; }
[Slot("Roles.Identifier")]
public override partial Identifier NameToken { get; set; }
@ -66,7 +68,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -66,7 +68,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial AstNodeCollection<Constraint> Constraints { get; }
[Slot("Roles.Body")]
public partial BlockStatement Body { get; set; }
public partial BlockStatement? Body { get; set; }
public bool IsExtensionMethod {
get {

10
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/OperatorDeclaration.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
using System;
using System.ComponentModel;
@ -174,7 +176,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -174,7 +176,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public override partial AstType ReturnType { get; set; }
[Slot("PrivateImplementationTypeRole")]
public partial AstType PrivateImplementationType { get; set; }
public partial AstType? PrivateImplementationType { get; set; }
OperatorType operatorType;
@ -189,7 +191,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -189,7 +191,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial AstNodeCollection<ParameterDeclaration> Parameters { get; }
[Slot("Roles.Body")]
public partial BlockStatement Body { get; set; }
public partial BlockStatement? Body { get; set; }
/// <summary>
/// Gets the operator type from the method name, or null, if the method does not represent one of the known operator types.
@ -281,7 +283,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -281,7 +283,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// <summary>
/// Gets the method name for the operator type. ("op_Addition", "op_Implicit", etc.)
/// </summary>
public static string GetName(OperatorType? type)
public static string? GetName(OperatorType? type)
{
if (type == null)
return null;
@ -316,7 +318,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -316,7 +318,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
public override string Name {
get { return GetName(this.OperatorType); }
get { return GetName(this.OperatorType)!; }
set { throw new NotSupportedException(); }
}

4
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/ParameterDeclaration.cs

@ -84,13 +84,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -84,13 +84,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
[Slot("Roles.Type")]
public partial AstType Type { get; set; }
public partial AstType? Type { get; set; }
[NameSlot("Roles.Identifier")]
public partial string Name { get; set; }
[Slot("Roles.Expression")]
public partial Expression DefaultExpression { get; set; }
public partial Expression? DefaultExpression { get; set; }
public ParameterDeclaration()
{

14
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/PropertyDeclaration.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Syntax
@ -64,28 +66,28 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -64,28 +66,28 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public override partial Identifier NameToken { get; set; }
[Slot("PrivateImplementationTypeRole")]
public partial AstType PrivateImplementationType { get; set; }
public partial AstType? PrivateImplementationType { get; set; }
[Slot("GetterRole")]
public partial Accessor Getter { get; set; }
public partial Accessor? Getter { get; set; }
[Slot("SetterRole")]
public partial Accessor Setter { get; set; }
public partial Accessor? Setter { get; set; }
[Slot("Roles.Expression")]
public partial Expression Initializer { get; set; }
[Slot("ExpressionBodyRole")]
public partial Expression ExpressionBody { get; set; }
public partial Expression? ExpressionBody { get; set; }
public bool IsAutomaticProperty {
get {
if (!Getter.IsNull && !Getter.Body.IsNull)
if (Getter is { Body: not null })
{
return false;
}
if (!Setter.IsNull && !Setter.Body.IsNull)
if (Setter is { Body: not null })
{
return false;
}

6
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/VariableInitializer.cs

@ -24,6 +24,8 @@ @@ -24,6 +24,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#nullable enable
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
@ -37,7 +39,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -37,7 +39,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
}
public VariableInitializer(string name, Expression initializer = null)
public VariableInitializer(string name, Expression? initializer = null)
{
this.Name = name;
this.Initializer = initializer;
@ -47,6 +49,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -47,6 +49,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial string Name { get; set; }
[Slot("Roles.Expression")]
public partial Expression Initializer { get; set; }
public partial Expression? Initializer { get; set; }
}
}

4
ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

@ -2157,7 +2157,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -2157,7 +2157,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
static void MergeReadOnlyModifiers(EntityDeclaration decl, Accessor accessor1, Accessor accessor2)
{
if (accessor1.HasModifier(Modifiers.Readonly) && accessor2.IsNull)
if (accessor1 is null)
return;
if (accessor1.HasModifier(Modifiers.Readonly) && accessor2 is null)
{
accessor1.Modifiers &= ~Modifiers.Readonly;
decl.Modifiers |= Modifiers.Readonly;

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

@ -91,9 +91,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -91,9 +91,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
DoTransform(usingStatement.EmbeddedStatement, usingStatement);
}
void DoTransform(Statement statement, Statement parent)
void DoTransform(Statement? statement, Statement parent)
{
if (statement.IsNull)
if (statement is null || statement.IsNull)
return;
if (context.Settings.AlwaysUseBraces)
{
@ -219,12 +219,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -219,12 +219,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var m = CalculatedGetterOnlyPropertyPattern.Match(propertyDeclaration);
if (!m.Success)
return;
if ((propertyDeclaration.Getter.Modifiers & ~movableModifiers) != 0)
if (propertyDeclaration.Getter is not { } getter)
return;
if ((getter.Modifiers & ~movableModifiers) != 0)
return;
propertyDeclaration.Modifiers |= propertyDeclaration.Getter.Modifiers;
propertyDeclaration.Modifiers |= getter.Modifiers;
propertyDeclaration.ExpressionBody = m.Get<Expression>("expression").Single().Detach();
propertyDeclaration.CopyAnnotationsFrom(propertyDeclaration.Getter);
propertyDeclaration.Getter.Remove();
propertyDeclaration.CopyAnnotationsFrom(getter);
getter.Remove();
}
void SimplifyIndexerDeclaration(IndexerDeclaration indexerDeclaration)
@ -232,12 +234,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -232,12 +234,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var m = CalculatedGetterOnlyIndexerPattern.Match(indexerDeclaration);
if (!m.Success)
return;
if ((indexerDeclaration.Getter.Modifiers & ~movableModifiers) != 0)
if (indexerDeclaration.Getter is not { } getter)
return;
if ((getter.Modifiers & ~movableModifiers) != 0)
return;
indexerDeclaration.Modifiers |= indexerDeclaration.Getter.Modifiers;
indexerDeclaration.Modifiers |= getter.Modifiers;
indexerDeclaration.ExpressionBody = m.Get<Expression>("expression").Single().Detach();
indexerDeclaration.CopyAnnotationsFrom(indexerDeclaration.Getter);
indexerDeclaration.Getter.Remove();
indexerDeclaration.CopyAnnotationsFrom(getter);
getter.Remove();
}
}
}

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

@ -109,7 +109,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -109,7 +109,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public override AstNode VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration)
{
if (context.Settings.AutomaticProperties
&& (!propertyDeclaration.Setter.IsNull || context.Settings.GetterOnlyAutomaticProperties))
&& (propertyDeclaration.Setter is not null || context.Settings.GetterOnlyAutomaticProperties))
{
AstNode? result = TransformAutomaticProperty(propertyDeclaration);
if (result != null)
@ -237,7 +237,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -237,7 +237,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
bool ForStatementUsesVariable(ForStatement statement, IL.ILVariable variable)
{
if (statement.Condition.DescendantsAndSelf.OfType<IdentifierExpression>().Any(ie => ie.GetILVariable() == variable))
if (statement.Condition?.DescendantsAndSelf.OfType<IdentifierExpression>().Any(ie => ie.GetILVariable() == variable) == true)
return true;
if (statement.Iterators.Any(i => i.DescendantsAndSelf.OfType<IdentifierExpression>().Any(ie => ie.GetILVariable() == variable)))
return true;
@ -638,18 +638,26 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -638,18 +638,26 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
if (field == null || !NameCouldBeBackingFieldOfAutomaticProperty(field.Name, out _))
return null;
if (propertyDeclaration.Setter.HasModifier(Modifiers.Readonly) || (propertyDeclaration.HasModifier(Modifiers.Readonly) && !propertyDeclaration.Setter.IsNull))
if (propertyDeclaration.Setter?.HasModifier(Modifiers.Readonly) == true || (propertyDeclaration.HasModifier(Modifiers.Readonly) && propertyDeclaration.Setter is not null))
return null;
if (field.IsCompilerGenerated() && field.DeclaringTypeDefinition == property.DeclaringTypeDefinition)
{
RemoveCompilerGeneratedAttribute(propertyDeclaration.Getter.Attributes);
RemoveCompilerGeneratedAttribute(propertyDeclaration.Setter.Attributes);
// 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!;
// Clearing the accessor body turns it into an auto-property accessor.
var getter = propertyDeclaration.Getter;
var setter = propertyDeclaration.Setter;
if (getter is not null)
{
RemoveCompilerGeneratedAttribute(getter.Attributes);
getter.Body = null;
}
if (setter is not null)
{
RemoveCompilerGeneratedAttribute(setter.Attributes);
setter.Body = null;
}
propertyDeclaration.Modifiers &= ~Modifiers.Readonly;
propertyDeclaration.Getter.Modifiers &= ~Modifiers.Readonly;
if (getter is not null)
getter.Modifiers &= ~Modifiers.Readonly;
var fieldDecl = propertyDeclaration.Parent?.Children.OfType<FieldDeclaration>()
.FirstOrDefault(fd => field.Equals(fd.GetSymbol()));
@ -1005,7 +1013,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -1005,7 +1013,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
EventDeclaration? TransformAutomaticEvents(CustomEventDeclaration ev)
{
if (!ev.PrivateImplementationType.IsNull)
if (ev.PrivateImplementationType is not null)
return null;
const Modifiers withoutBody = Modifiers.Abstract | Modifiers.Extern;
if (ev.GetSymbol() is not IEvent symbol)
@ -1015,10 +1023,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -1015,10 +1023,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (!CheckAutomaticEventV4AggressivelyInlined(ev) && !CheckAutomaticEventV4(ev) && !CheckAutomaticEventV2(ev) && !CheckAutomaticEventV4MCS(ev))
return null;
}
RemoveCompilerGeneratedAttribute(ev.AddAccessor.Attributes, attributeTypesToRemoveFromAutoEvents);
if (ev.AddAccessor is not { } addAccessor)
return null;
RemoveCompilerGeneratedAttribute(addAccessor.Attributes, attributeTypesToRemoveFromAutoEvents);
EventDeclaration ed = new EventDeclaration();
ev.Attributes.MoveTo(ed.Attributes);
foreach (var attr in ev.AddAccessor.Attributes)
foreach (var attr in addAccessor.Attributes)
{
attr.AttributeTarget = "method";
ed.Attributes.Add(attr.Detach());

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

@ -148,7 +148,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -148,7 +148,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return IsWithoutSideEffects(left);
}
static bool IsWithoutSideEffects(Expression left)
static bool IsWithoutSideEffects(Expression? left)
{
return left is ThisReferenceExpression || left is IdentifierExpression || left is TypeReferenceExpression || left is BaseReferenceExpression;
}

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

@ -63,9 +63,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -63,9 +63,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
// Reduce "String.Concat(a, b)" to "a + b"
if (IsStringConcat(method) && context.Settings.StringConcat)
{
if (arguments is [ArrayCreateExpression ace] && method.Parameters is [{ Type: ArrayType }])
if (arguments is [ArrayCreateExpression { Initializer: { } aceInitializer }] && method.Parameters is [{ Type: ArrayType }])
{
arguments = ace.Initializer.Elements.ToArray();
arguments = aceInitializer.Elements.ToArray();
}
if (!CheckArgumentsForStringConcat(arguments))

22
ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs

@ -131,7 +131,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -131,7 +131,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
bool skippedStmts = false;
Statement? stmt;
for (stmt = ctor.Body.Statements.FirstOrDefault(); stmt != null; stmt = stmt.GetNextStatement())
for (stmt = ctor.Body?.Statements.FirstOrDefault(); stmt != null; stmt = stmt.GetNextStatement())
{
var m = memberInitializerPattern.Match(stmt);
if (!m.Success)
@ -200,6 +200,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -200,6 +200,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public bool IsMatch(ConstructorDeclaration ctor)
{
if (ctor.Body is null)
return false;
var stmts = ctor.Body.Statements;
var otherStmt = stmts.FirstOrDefault();
foreach (var (stmt, member, initializer, _) in Statements)
@ -326,7 +328,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -326,7 +328,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
else
{
// find this-ctor call
var stmt = ctor.Body.Statements.FirstOrDefault();
var stmt = ctor.Body?.Statements.FirstOrDefault();
var m = ctorMethod.DeclaringType.Kind == TypeKind.Struct
? ThisCallStructPattern.Match(stmt)
: ThisCallClassPattern.Match(stmt);
@ -449,6 +451,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -449,6 +451,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public bool MoveConstructorInitializer(ConstructorDeclaration constructorDeclaration, IMethod ctorMethod)
{
if (constructorDeclaration.Body is null)
return false;
Statement stmt = constructorDeclaration.Body.Statements.FirstOrDefault()!;
var isValueType = ctorMethod.DeclaringType.Kind == TypeKind.Struct;
@ -512,7 +516,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -512,7 +516,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
case FieldDeclaration fd:
v = fd.Variables.Single();
if (v.Initializer.IsNull)
if (v.Initializer is null)
{
v.Initializer = initializer.Detach();
}
@ -554,7 +558,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -554,7 +558,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
break;
case EventDeclaration ev:
v = ev.Variables.Single();
if (v.Initializer.IsNull)
if (v.Initializer is null)
{
v.Initializer = initializer.Detach();
}
@ -603,7 +607,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -603,7 +607,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
Debug.Assert(PrimaryConstructorDecl != null);
this.TypeDeclaration.HasPrimaryConstructor = PrimaryConstructor.Parameters.Any()
|| !PrimaryConstructorDecl.Initializer.IsNull
|| PrimaryConstructorDecl.Initializer is not null
|| TypeDefinition.Kind == TypeKind.Struct;
// HACK: because our current AST model doesn't allow specifying an explicit order of roles,
@ -671,15 +675,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -671,15 +675,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
this.TypeDeclaration.Modifiers |= Modifiers.Unsafe;
}
if (!PrimaryConstructorDecl.Initializer.IsNull && TypeDeclaration is { BaseTypes.Count: > 0 })
if (PrimaryConstructorDecl.Initializer is { } initializer && TypeDeclaration is { BaseTypes.Count: > 0 })
{
Debug.Assert(PrimaryConstructorDecl.Initializer is { ConstructorInitializerType: ConstructorInitializerType.Base });
Debug.Assert(initializer.ConstructorInitializerType == ConstructorInitializerType.Base);
var baseType = TypeDeclaration.BaseTypes.First();
var newBaseType = new InvocationAstType();
baseType.ReplaceWith(newBaseType);
newBaseType.BaseType = baseType;
PrimaryConstructorDecl.Initializer.Arguments.MoveTo(newBaseType.Arguments);
initializer.Arguments.MoveTo(newBaseType.Arguments);
}
PrimaryConstructorDecl.Remove();
@ -690,7 +694,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -690,7 +694,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
Debug.Assert(StaticConstructorDecl != null);
if (IsBeforeFieldInit && StaticConstructorDecl.Body.Statements.Count == 0)
if (IsBeforeFieldInit && StaticConstructorDecl.Body is { Statements.Count: 0 })
{
StaticConstructorDecl.Remove();
}

4
ICSharpCode.Decompiler/DebugInfo/DebugInfoGenerator.cs

@ -135,7 +135,7 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -135,7 +135,7 @@ namespace ICSharpCode.Decompiler.DebugInfo
public override void VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration)
{
if (!propertyDeclaration.ExpressionBody.IsNull)
if (propertyDeclaration.ExpressionBody is not null)
{
HandleMethod(propertyDeclaration.ExpressionBody, propertyDeclaration.Annotation<ILFunction>());
}
@ -147,7 +147,7 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -147,7 +147,7 @@ namespace ICSharpCode.Decompiler.DebugInfo
public override void VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration)
{
if (!indexerDeclaration.ExpressionBody.IsNull)
if (indexerDeclaration.ExpressionBody is not null)
{
HandleMethod(indexerDeclaration.ExpressionBody, indexerDeclaration.Annotation<ILFunction>());
}

6
ILSpy/Languages/CSharpLanguage.cs

@ -613,14 +613,14 @@ namespace ICSharpCode.ILSpy.Languages @@ -613,14 +613,14 @@ namespace ICSharpCode.ILSpy.Languages
}
break;
case FieldDeclaration fd:
if (fd.Variables.All(v => v.Initializer.IsNull))
if (fd.Variables.All(v => v.Initializer is null))
{
fd.Remove();
removedSymbols.Add(fd.GetSymbol());
}
break;
case EventDeclaration ed:
if (ed.Variables.All(v => v.Initializer.IsNull))
if (ed.Variables.All(v => v.Initializer is null))
{
ed.Remove();
removedSymbols.Add(ed.GetSymbol());
@ -640,7 +640,7 @@ namespace ICSharpCode.ILSpy.Languages @@ -640,7 +640,7 @@ namespace ICSharpCode.ILSpy.Languages
break;
}
}
if (ctorDecl?.Initializer.ConstructorInitializerType == ConstructorInitializerType.This)
if (ctorDecl?.Initializer?.ConstructorInitializerType == ConstructorInitializerType.This)
{
foreach (var node in rootNode.Children)
{

Loading…
Cancel
Save