Browse Source

Delete the Role hierarchy; key the child API on SlotKind

Slot identity already lived in node.Slot/CSharpSlotInfo/SlotKind after
the storage flip, so the parallel Role/Role<T> child model was redundant.
The Role-keyed mutation/query API is reexpressed over SlotKind, and the
role-index packing on AstNode flags is gone.

Because a node's Slot is now derived from its index in its parent rather
than stored on the child, the located-AST reattach in
InsertMissingTokensDecorator must capture the child's slot kind before
Remove() detaches it.

Assisted-by: Claude:claude-opus-4-8:Claude Code
pull/3807/head
Siegfried Pammer 3 weeks ago committed by Siegfried Pammer
parent
commit
9285a7328d
  1. 26
      ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs
  2. 24
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  3. 10
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs
  4. 2
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  5. 5
      ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertMissingTokensDecorator.cs
  6. 161
      ICSharpCode.Decompiler/CSharp/Syntax/AstNode.cs
  7. 22
      ICSharpCode.Decompiler/CSharp/Syntax/AstNodeCollection.cs
  8. 4
      ICSharpCode.Decompiler/CSharp/Syntax/ComposedType.cs
  9. 2
      ICSharpCode.Decompiler/CSharp/Syntax/DocumentationReference.cs
  10. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/AnonymousMethodExpression.cs
  11. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/AnonymousTypeCreateExpression.cs
  12. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/ArrayCreateExpression.cs
  13. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/AsExpression.cs
  14. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/AssignmentExpression.cs
  15. 6
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/BinaryOperatorExpression.cs
  16. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/CastExpression.cs
  17. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/CheckedExpression.cs
  18. 9
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/ConditionalExpression.cs
  19. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/DefaultValueExpression.cs
  20. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/DirectionExpression.cs
  21. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IdentifierExpression.cs
  22. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IndexerExpression.cs
  23. 1
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/InterpolatedStringExpression.cs
  24. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/InvocationExpression.cs
  25. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IsExpression.cs
  26. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/LambdaExpression.cs
  27. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/MemberReferenceExpression.cs
  28. 5
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/ObjectCreateExpression.cs
  29. 11
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/QueryExpression.cs
  30. 1
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/RecursivePatternExpression.cs
  31. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/SizeOfExpression.cs
  32. 1
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/StackAllocExpression.cs
  33. 3
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/SwitchExpression.cs
  34. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/ThrowExpression.cs
  35. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/TypeOfExpression.cs
  36. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/TypeReferenceExpression.cs
  37. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/UncheckedExpression.cs
  38. 1
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/WithInitializerExpression.cs
  39. 1
      ICSharpCode.Decompiler/CSharp/Syntax/FunctionPointerAstType.cs
  40. 4
      ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/AttributeSection.cs
  41. 4
      ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/NamespaceDeclaration.cs
  42. 1
      ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/PreProcessorDirective.cs
  43. 1
      ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/TypeParameterDeclaration.cs
  44. 10
      ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/UsingAliasDeclaration.cs
  45. 5
      ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/UsingDeclaration.cs
  46. 3
      ICSharpCode.Decompiler/CSharp/Syntax/MemberType.cs
  47. 112
      ICSharpCode.Decompiler/CSharp/Syntax/Role.cs
  48. 21
      ICSharpCode.Decompiler/CSharp/Syntax/Roles.cs
  49. 4
      ICSharpCode.Decompiler/CSharp/Syntax/SimpleType.cs
  50. 5
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/BlockStatement.cs
  51. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/CheckedStatement.cs
  52. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/ForStatement.cs
  53. 3
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/IfElseStatement.cs
  54. 3
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/LocalFunctionDeclarationStatement.cs
  55. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/ReturnStatement.cs
  56. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/SwitchStatement.cs
  57. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/ThrowStatement.cs
  58. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/TryCatchStatement.cs
  59. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/UncheckedStatement.cs
  60. 1
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/UsingStatement.cs
  61. 1
      ICSharpCode.Decompiler/CSharp/Syntax/SyntaxTree.cs
  62. 1
      ICSharpCode.Decompiler/CSharp/Syntax/TupleAstType.cs
  63. 1
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/ConstructorDeclaration.cs
  64. 16
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/EntityDeclaration.cs
  65. 1
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/EnumMemberDeclaration.cs
  66. 2
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/EventDeclaration.cs
  67. 1
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/FixedFieldDeclaration.cs
  68. 3
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/IndexerDeclaration.cs
  69. 2
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/MethodDeclaration.cs
  70. 1
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/ParameterDeclaration.cs
  71. 3
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/PropertyDeclaration.cs
  72. 4
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  73. 2
      ICSharpCode.Decompiler/CSharp/Transforms/AddCheckedBlocks.cs
  74. 8
      ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs
  75. 4
      ICSharpCode.Decompiler/CSharp/Transforms/FixNameCollisions.cs
  76. 2
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs
  77. 2
      ICSharpCode.Decompiler/CSharp/Transforms/PatternStatementTransform.cs
  78. 4
      ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs
  79. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  80. 2
      ICSharpCode.Decompiler/Output/TextTokenWriter.cs
  81. 8
      ILSpy/Languages/CSharpHighlightingTokenWriter.cs

26
ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs

@ -314,7 +314,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -314,7 +314,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
if (isCollection)
{
builder.AppendLine($"\tAstNodeCollection<{elementType}>? {field};");
builder.AppendLine($"\tpublic {(isOverride ? "override " : "")}{partialKw}AstNodeCollection<{elementType}> {name} => {field} ??= new AstNodeCollection<{elementType}>(this, {roleExpr});");
builder.AppendLine($"\tpublic {(isOverride ? "override " : "")}{partialKw}AstNodeCollection<{elementType}> {name} => {field} ??= new AstNodeCollection<{elementType}>(this, SlotKind.{kindName});");
}
else
{
@ -322,7 +322,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -322,7 +322,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
builder.AppendLine($"\tpublic {(isOverride ? "override " : "")}{partialKw}{type}{(isNullable ? "?" : "")} {name}");
builder.AppendLine("\t{");
builder.AppendLine($"\t\tget => {field}{(isNullable ? "" : "!")};");
builder.AppendLine($"\t\tset => SetChildNode(ref {field}, value, {roleExpr});");
builder.AppendLine($"\t\tset => SetChildNode(ref {field}, value);");
builder.AppendLine("\t}");
}
builder.AppendLine();
@ -389,27 +389,13 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -389,27 +389,13 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
}
else
{
builder.AppendLine($"\t\tif (i == 0) {{ SetChildNode(ref {FieldName(s.PropertyName)}, ({s.PropertyType}?)value, {s.RoleExpr}); return; }} i -= 1;");
builder.AppendLine($"\t\tif (i == 0) {{ SetChildNode(ref {FieldName(s.PropertyName)}, ({s.PropertyType}?)value); return; }} i -= 1;");
}
}
builder.AppendLine("\t\tthrow new System.ArgumentOutOfRangeException(nameof(index));");
builder.AppendLine("\t}");
builder.AppendLine();
builder.AppendLine("\tinternal override Role GetChildSlot(int index)");
builder.AppendLine("\t{");
builder.AppendLine("\t\tint i = index;");
foreach (var s in slots)
{
if (s.IsCollection)
builder.AppendLine($"\t\t{{ int n = {FieldName(s.PropertyName)}?.Count ?? 0; if (i < n) return {s.RoleExpr}; i -= n; }}");
else
builder.AppendLine($"\t\tif (i == 0) return {s.RoleExpr}; i -= 1;");
}
builder.AppendLine("\t\tthrow new System.ArgumentOutOfRangeException(nameof(index));");
builder.AppendLine("\t}");
builder.AppendLine();
// One CSharpSlotInfo static per slot; node.Slot compares against these by object identity.
foreach (var s in slots)
builder.AppendLine($"\tpublic static readonly CSharpSlotInfo {s.PropertyName}Slot = new CSharpSlotInfo(\"{s.PropertyName}\", typeof({s.ElementType}), {(s.IsCollection ? "true" : "false")}, SlotKind.{s.KindName});");
@ -431,11 +417,11 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator @@ -431,11 +417,11 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator
if (slots.Any(s => s.IsCollection))
{
builder.AppendLine("\tinternal override AstNodeCollection? GetCollectionByRole(Role role)");
builder.AppendLine("\tinternal override AstNodeCollection? GetCollectionByKind(SlotKind kind)");
builder.AppendLine("\t{");
foreach (var s in slots.Where(s => s.IsCollection))
builder.AppendLine($"\t\tif (role == {s.RoleExpr}) return {s.PropertyName};");
builder.AppendLine("\t\treturn base.GetCollectionByRole(role);");
builder.AppendLine($"\t\tif (kind == SlotKind.{s.KindName}) return {s.PropertyName};");
builder.AppendLine("\t\treturn base.GetCollectionByKind(kind);");
builder.AppendLine("\t}");
builder.AppendLine();
}

24
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -806,7 +806,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -806,7 +806,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
currentNamespace = typeDef.Namespace;
var typeDecl = DoDecompile(typeDef, decompileRun, decompilationContext.WithCurrentTypeDefinition(typeDef));
groupNode.AddChild(typeDecl, SyntaxTree.MemberRole);
groupNode.AddChild(typeDecl, SlotKind.Member);
}
}
@ -1349,11 +1349,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1349,11 +1349,11 @@ namespace ICSharpCode.Decompiler.CSharp
RemoveAttribute(prop, KnownAttribute.ExtensionMarker);
if (propDef.Getter != null)
{
RemoveAttribute(prop.GetChildByRole(PropertyDeclaration.GetterRole), KnownAttribute.ExtensionMarker);
RemoveAttribute(prop.GetChildByRole<Accessor>(SlotKind.Getter), KnownAttribute.ExtensionMarker);
}
if (propDef.Setter != null)
{
RemoveAttribute(prop.GetChildByRole(PropertyDeclaration.SetterRole), KnownAttribute.ExtensionMarker);
RemoveAttribute(prop.GetChildByRole<Accessor>(SlotKind.Setter), KnownAttribute.ExtensionMarker);
}
RunTransforms(syntaxTree, decompileRun, new SimpleTypeResolveContext(propDef.DeclaringTypeDefinition));
break;
@ -1406,7 +1406,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1406,7 +1406,7 @@ namespace ICSharpCode.Decompiler.CSharp
EntityDeclaration memberDecl, IMethod method,
TypeSystemAstBuilder astBuilder)
{
if (memberDecl.GetChildByRole(EntityDeclaration.PrivateImplementationTypeRole) is not null)
if (memberDecl.GetChildByRole<AstType>(SlotKind.PrivateImplementationType) is not null)
{
yield break; // cannot create forwarder for existing explicit interface impl
}
@ -1430,9 +1430,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1430,9 +1430,9 @@ namespace ICSharpCode.Decompiler.CSharp
methodDecl.ReturnType = memberDecl.ReturnType?.Clone();
methodDecl.PrivateImplementationType = astBuilder.ConvertType(m.DeclaringType);
methodDecl.Name = m.Name;
methodDecl.TypeParameters.AddRange(memberDecl.GetChildrenByRole(Roles.TypeParameter)
methodDecl.TypeParameters.AddRange(memberDecl.GetChildrenByRole<TypeParameterDeclaration>(SlotKind.TypeParameter)
.Select(n => (TypeParameterDeclaration)n.Clone()));
methodDecl.Parameters.AddRange(memberDecl.GetChildrenByRole(Roles.Parameter).Select(n => n.Clone()));
methodDecl.Parameters.AddRange(memberDecl.GetChildrenByRole<ParameterDeclaration>(SlotKind.Parameter).Select(n => n.Clone()));
// Constraints are not copied because explicit interface implementations cannot have constraints. CS0460
methodDecl.Body = new BlockStatement();
@ -1548,7 +1548,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1548,7 +1548,7 @@ namespace ICSharpCode.Decompiler.CSharp
void FixParameterNames(EntityDeclaration entity)
{
int i = 0;
foreach (var parameter in entity.GetChildrenByRole(Roles.Parameter))
foreach (var parameter in entity.GetChildrenByRole<ParameterDeclaration>(SlotKind.Parameter))
{
if (string.IsNullOrWhiteSpace(parameter.Name) && !parameter.Type.IsArgList())
{
@ -1845,11 +1845,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1845,11 +1845,11 @@ namespace ICSharpCode.Decompiler.CSharp
RemoveAttribute(prop, KnownAttribute.ExtensionMarker);
if (p.Getter != null)
{
RemoveAttribute(prop.GetChildByRole(PropertyDeclaration.GetterRole), KnownAttribute.ExtensionMarker);
RemoveAttribute(prop.GetChildByRole<Accessor>(SlotKind.Getter), KnownAttribute.ExtensionMarker);
}
if (p.Setter != null)
{
RemoveAttribute(prop.GetChildByRole(PropertyDeclaration.SetterRole), KnownAttribute.ExtensionMarker);
RemoveAttribute(prop.GetChildByRole<Accessor>(SlotKind.Setter), KnownAttribute.ExtensionMarker);
}
extMemberDecl = prop;
break;
@ -2053,7 +2053,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2053,7 +2053,7 @@ namespace ICSharpCode.Decompiler.CSharp
var commentStatement = new EmptyStatement();
commentStatement.AddTrailingTrivia(new Comment("Invalid MethodBodyBlock: " + ex.Message));
body.Statements.Add(commentStatement);
entityDecl.AddChild(body, Roles.Body);
entityDecl.AddChild(body, SlotKind.Body);
return;
}
var function = ilReader.ReadIL((MethodDefinitionHandle)method.MetadataToken, methodBody, cancellationToken: CancellationToken);
@ -2112,7 +2112,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2112,7 +2112,7 @@ namespace ICSharpCode.Decompiler.CSharp
body.Statements.Add(warningStatement);
}
entityDecl.AddChild(body, Roles.Body);
entityDecl.AddChild(body, SlotKind.Body);
}
CleanUpMethodDeclaration(entityDecl, body, function, localSettings.DecompileMemberBodies);
@ -2127,7 +2127,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2127,7 +2127,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
int i = parameterOffset;
var parameters = function.Variables.Where(v => v.Kind == VariableKind.Parameter).ToDictionary(v => v.Index);
foreach (var parameter in entityDecl.GetChildrenByRole(Roles.Parameter))
foreach (var parameter in entityDecl.GetChildrenByRole<ParameterDeclaration>(SlotKind.Parameter))
{
if (parameters.TryGetValue(i, out var v))
parameter.AddAnnotation(new ILVariableResolveResult(v, method.Parameters[i].Type));

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

@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -123,7 +123,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
if ((ConversionFlags & ConversionFlags.PlaceReturnTypeAfterParameterList) != ConversionFlags.PlaceReturnTypeAfterParameterList
&& (ConversionFlags & ConversionFlags.ShowReturnType) == ConversionFlags.ShowReturnType)
{
var rt = node.GetChildByRole(Roles.Type);
var rt = node.GetChildByRole<AstType>(SlotKind.Type);
if (rt is not null)
{
rt.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy));
@ -150,7 +150,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -150,7 +150,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
}
else
{
parameters = node.GetChildrenByRole(Roles.Parameter);
parameters = node.GetChildrenByRole<ParameterDeclaration>(SlotKind.Parameter);
}
foreach (var param in parameters)
{
@ -181,7 +181,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -181,7 +181,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
if ((ConversionFlags & ConversionFlags.PlaceReturnTypeAfterParameterList) == ConversionFlags.PlaceReturnTypeAfterParameterList
&& (ConversionFlags & ConversionFlags.ShowReturnType) == ConversionFlags.ShowReturnType)
{
var rt = node.GetChildByRole(Roles.Type);
var rt = node.GetChildByRole<AstType>(SlotKind.Type);
if (rt is not null)
{
writer.Space();
@ -309,7 +309,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -309,7 +309,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
else
{
writer.WriteIdentifier(node.NameToken);
WriteTypeParameters(node.GetChildrenByRole(Roles.TypeParameter), writer, formattingPolicy);
WriteTypeParameters(node.GetChildrenByRole<TypeParameterDeclaration>(SlotKind.TypeParameter), writer, formattingPolicy);
}
}
@ -412,7 +412,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -412,7 +412,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
writer.WriteIdentifier(Identifier.Create(name));
break;
}
WriteTypeParameters(node.GetChildrenByRole(Roles.TypeParameter), writer, formattingPolicy);
WriteTypeParameters(node.GetChildrenByRole<TypeParameterDeclaration>(SlotKind.TypeParameter), writer, formattingPolicy);
}
void WriteTypeParameters(IEnumerable<TypeParameterDeclaration> typeParameters, TokenWriter writer, CSharpFormattingOptions formattingPolicy)

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

@ -1910,7 +1910,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -1910,7 +1910,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
public virtual void VisitLabelStatement(LabelStatement labelStatement)
{
StartNode(labelStatement);
WriteIdentifier(labelStatement.GetChildByRole(Roles.Identifier));
WriteIdentifier(labelStatement.GetChildByRole<Identifier>(SlotKind.Identifier));
WriteToken(Roles.Colon);
bool foundLabelledStatement = false;
for (AstNode tmp = labelStatement.NextSibling; tmp != null; tmp = tmp.NextSibling)

5
ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertMissingTokensDecorator.cs

@ -91,8 +91,11 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -91,8 +91,11 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
foreach (var child in currentList)
{
System.Diagnostics.Debug.Assert(child.Parent == null || node == child.Parent);
// Slot is derived from the child's index in its parent, so it must be read before
// Remove() detaches the child (which would otherwise leave it as SlotKind.None).
SlotKind kind = child.Slot?.Kind ?? SlotKind.None;
child.Remove();
node.AddChildWithExistingRole(child);
node.AddChildUnsafe(child, kind);
}
currentList = nodes.Pop();
}

161
ICSharpCode.Decompiler/CSharp/Syntax/AstNode.cs

@ -40,22 +40,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -40,22 +40,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: true, hasPatternPlaceholder: true)]
public abstract partial class AstNode : AbstractAnnotatable, IFreezable, INode, ICloneable
{
// the Root role must be available when creating the null nodes, so we can't put it in the Roles class
internal static readonly Role<AstNode?> RootRole = new Role<AstNode?>("Root", null);
AstNode? parent;
// Flattened index of this node within its parent's child-index space (-1 when unparented).
// Recomputed lazily by the parent (EnsureChildIndices) after a structural mutation.
internal int childIndex = -1;
// Flags, from least significant to most significant bits:
// - Role.RoleIndexBits: role index
protected uint flags = RootRole.Index;
// Derived classes may also use a few bits,
// for example Identifier uses 1 bit for IsVerbatim
// Flag bits used by derived classes (e.g. Identifier uses 1 bit for IsVerbatim).
protected uint flags = 0;
const uint roleIndexMask = (1u << Role.RoleIndexBits) - 1;
protected const int AstNodeFlagsUsedBits = Role.RoleIndexBits;
protected const int AstNodeFlagsUsedBits = 0;
TextLocation startLocation = TextLocation.Empty;
TextLocation endLocation = TextLocation.Empty;
@ -158,28 +151,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -158,28 +151,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
get { return parent; }
}
public Role Role {
get {
return Role.GetByIndex(flags & roleIndexMask);
}
set {
if (value == null)
throw new ArgumentNullException(nameof(value));
if (!value.IsValid(this))
throw new ArgumentException("This node is not valid in the new role.");
SetRole(value);
}
}
internal uint RoleIndex {
get { return flags & roleIndexMask; }
}
void SetRole(Role role)
{
flags = (flags & ~roleIndexMask) | role.Index;
}
public AstNode? NextSibling {
get {
if (parent == null)
@ -336,20 +307,18 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -336,20 +307,18 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// Gets the first child with the specified role.
/// Returns the role's null object if the child is not found.
/// </summary>
public T GetChildByRole<T>(Role<T> role) where T : AstNode?
public T GetChildByRole<T>(SlotKind kind) where T : AstNode?
{
if (role == null)
throw new ArgumentNullException(nameof(role));
int count = GetChildCount();
for (int i = 0; i < count; i++)
{
if (GetChildSlot(i) == role)
if (GetChildSlotInfo(i).Kind == kind)
{
AstNode? c = GetChild(i);
return c != null ? (T)c : role.NullObject;
return c != null ? (T)c : default!;
}
}
return role.NullObject;
return default!;
}
public T? GetParent<T>() where T : AstNode
@ -362,20 +331,18 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -362,20 +331,18 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return pred != null ? Ancestors.FirstOrDefault(pred) : Ancestors.FirstOrDefault();
}
public AstNodeCollection<T> GetChildrenByRole<T>(Role<T> role) where T : AstNode
public AstNodeCollection<T> GetChildrenByRole<T>(SlotKind kind) where T : AstNode
{
if (role == null)
throw new ArgumentNullException(nameof(role));
AstNodeCollection? collection = GetCollectionByRole(role);
// A node has no children of a role it does not declare a collection slot for. Reads of such
// a role (e.g. the parameters of a non-indexer property) get a detached empty collection;
// writes go through AddChild/SetChildByRole, which reject a missing role.
return collection != null ? (AstNodeCollection<T>)collection : new AstNodeCollection<T>(this, role);
AstNodeCollection? collection = GetCollectionByKind(kind);
// A node has no children of a kind it does not declare a collection slot for. Reads of such
// a kind (e.g. the parameters of a non-indexer property) get a detached empty collection;
// writes go through AddChild/SetChildByRole, which reject a missing slot.
return collection != null ? (AstNodeCollection<T>)collection : new AstNodeCollection<T>(this, kind);
}
protected void SetChildByRole<T>(Role<T> role, T? newChild) where T : AstNode
protected void SetChildByRole<T>(SlotKind kind, T? newChild) where T : AstNode
{
SetChildByRoleUntyped(role, newChild);
SetChildByRoleUntyped(kind, newChild);
}
#region Slot storage contract
@ -391,8 +358,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -391,8 +358,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
internal virtual void SetChild(int index, AstNode? value) => throw new ArgumentOutOfRangeException(nameof(index));
internal virtual Role GetChildSlot(int index) => throw new ArgumentOutOfRangeException(nameof(index));
// The CSharpSlotInfo for the slot at the given flattened index; generator-emitted per leaf.
internal virtual CSharpSlotInfo GetChildSlotInfo(int index) => throw new ArgumentOutOfRangeException(nameof(index));
@ -409,9 +374,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -409,9 +374,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
}
// Returns the collection occupying the slot with the given role, or null if there is none.
// Returns the collection occupying the slot with the given kind, or null if there is none.
// Overridden by the generator for nodes that have collection slots.
internal virtual AstNodeCollection? GetCollectionByRole(Role role) => null;
internal virtual AstNodeCollection? GetCollectionByKind(SlotKind kind) => null;
// Deep-copies this node's children into the (memberwise-cloned) copy, which initially shares
// this node's child references. Overridden by the generator for nodes that have slots.
@ -465,14 +430,14 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -465,14 +430,14 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
continue; // empty optional single slot
Debug.Assert(child.parent == this, "child's Parent must point back to this node");
Debug.Assert(child.childIndex == i, "child's flattened index must match its slot position");
Debug.Assert(GetChildSlot(i).IsValid(child), "child's type must be valid in its slot's role");
Debug.Assert(GetChildSlotInfo(i).ChildType.IsInstanceOfType(child), "child's type must be valid in its slot");
child.CheckInvariant();
}
}
// Writes a single-slot backing field: detaches the old child, attaches the new one, renumbers.
// A null or null-object value empties the slot. Called by generated single-slot property setters.
internal void SetChildNode<T>(ref T? field, T? value, Role role) where T : AstNode
internal void SetChildNode<T>(ref T? field, T? value) where T : AstNode
{
T? newValue = value;
if (field == newValue)
@ -493,14 +458,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -493,14 +458,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
field?.ClearParentAndIndex();
field = newValue;
newValue?.SetParentAndRole(this, role);
newValue?.SetParent(this);
InvalidateChildIndices();
}
internal void SetParentAndRole(AstNode newParent, Role role)
internal void SetParent(AstNode newParent)
{
parent = newParent;
SetRole(role);
}
internal void ClearParentAndIndex()
@ -510,85 +474,72 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -510,85 +474,72 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
#endregion
public void AddChild<T>(T child, Role<T> role) where T : AstNode
{
if (role == null)
throw new ArgumentNullException(nameof(role));
if (child == null)
return;
AddChildUnsafe(child, role);
}
public void AddChildWithExistingRole(AstNode? child)
public void AddChild<T>(T child, SlotKind kind) where T : AstNode
{
if (child == null)
return;
AddChildUnsafe(child, child.Role);
AddChildUnsafe(child, kind);
}
/// <summary>
/// Adds a child into the slot matching <paramref name="role"/> (appending to a collection slot,
/// Adds a child into the slot matching <paramref name="kind"/> (appending to a collection slot,
/// or filling a single slot).
/// </summary>
internal void AddChildUnsafe(AstNode child, Role role)
internal void AddChildUnsafe(AstNode child, SlotKind kind)
{
AstNodeCollection? collection = GetCollectionByRole(role);
AstNodeCollection? collection = GetCollectionByKind(kind);
if (collection != null)
collection.AddNode(child);
else
SetChildByRoleUntyped(role, child);
SetChildByRoleUntyped(kind, child);
}
// Sets the single slot matching the role (used by the non-generic mutation API). Symmetric with
// GetChildByRole, which returns the null object for a role this node does not declare a slot for:
// a node has no child of a role it has no slot for, so writing one is a no-op.
internal void SetChildByRoleUntyped(Role role, AstNode? child)
internal void SetChildByRoleUntyped(SlotKind kind, AstNode? child)
{
int count = GetChildCount();
for (int i = 0; i < count; i++)
{
if (GetChildSlot(i) == role)
if (GetChildSlotInfo(i).Kind == kind)
{
SetChild(i, child);
return;
}
}
throw new InvalidOperationException($"{GetType().Name} has no slot for role '{role}'.");
throw new InvalidOperationException($"{GetType().Name} has no slot of kind '{kind}'.");
}
public void InsertChildBefore<T>(AstNode? nextSibling, T child, Role<T> role) where T : AstNode
public void InsertChildBefore<T>(AstNode? nextSibling, T child, SlotKind kind) where T : AstNode
{
if (role == null)
throw new ArgumentNullException(nameof(role));
if (child == null)
return;
AstNodeCollection? collection = GetCollectionByRole(role);
AstNodeCollection? collection = GetCollectionByKind(kind);
if (collection != null)
collection.InsertNodeBefore(nextSibling, child);
else
SetChildByRoleUntyped(role, child);
SetChildByRoleUntyped(kind, child);
}
internal void InsertChildBeforeUnsafe(AstNode nextSibling, AstNode child, Role role)
internal void InsertChildBeforeUnsafe(AstNode nextSibling, AstNode child, SlotKind kind)
{
AstNodeCollection? collection = GetCollectionByRole(role);
AstNodeCollection? collection = GetCollectionByKind(kind);
if (collection != null)
collection.InsertNodeBefore(nextSibling, child);
else
SetChildByRoleUntyped(role, child);
SetChildByRoleUntyped(kind, child);
}
public void InsertChildAfter<T>(AstNode? prevSibling, T child, Role<T> role) where T : AstNode
public void InsertChildAfter<T>(AstNode? prevSibling, T child, SlotKind kind) where T : AstNode
{
if (role == null)
throw new ArgumentNullException(nameof(role));
if (child == null)
return;
AstNodeCollection? collection = GetCollectionByRole(role);
AstNodeCollection? collection = GetCollectionByKind(kind);
if (collection != null)
collection.InsertNodeAfter(prevSibling, child);
else
SetChildByRoleUntyped(role, child);
SetChildByRoleUntyped(kind, child);
}
/// <summary>
@ -599,8 +550,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -599,8 +550,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
if (parent == null)
return;
parent.EnsureChildIndices();
Role role = parent.GetChildSlot(childIndex);
AstNodeCollection? collection = parent.GetCollectionByRole(role);
SlotKind kind = parent.GetChildSlotInfo(childIndex).Kind;
AstNodeCollection? collection = parent.GetCollectionByKind(kind);
if (collection != null)
collection.RemoveNode(this);
else
@ -624,12 +575,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -624,12 +575,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
throw new InvalidOperationException("Cannot replace the root node");
}
parent.EnsureChildIndices();
Role role = parent.GetChildSlot(childIndex);
// Because this method doesn't statically check the new node's type with the role,
CSharpSlotInfo slot = parent.GetChildSlotInfo(childIndex);
// Because this method doesn't statically check the new node's type with the slot,
// we perform a runtime test:
if (!role.IsValid(newNode))
if (!slot.ChildType.IsInstanceOfType(newNode))
{
throw new ArgumentException(string.Format("The new node '{0}' is not valid in the role {1}", newNode.GetType().Name, role.ToString()), nameof(newNode));
throw new ArgumentException(string.Format("The new node '{0}' is not valid in the slot {1}", newNode.GetType().Name, slot.ToString()), nameof(newNode));
}
if (newNode.parent != null)
{
@ -658,7 +609,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -658,7 +609,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
AstNode oldParent = parent;
AstNode? oldSuccessor = NextSibling;
Role oldRole = this.Role;
CSharpSlotInfo? oldSlot = this.Slot;
SlotKind oldKind = oldSlot?.Kind ?? SlotKind.None;
Remove();
AstNode? replacement = replaceFunction(this);
if (oldSuccessor != null && oldSuccessor.parent != oldParent)
@ -667,15 +619,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -667,15 +619,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
if (replacement.parent != null)
throw new InvalidOperationException("replace function must return the root of a tree");
if (!oldRole.IsValid(replacement))
if (oldSlot != null && !oldSlot.ChildType.IsInstanceOfType(replacement))
{
throw new InvalidOperationException(string.Format("The new node '{0}' is not valid in the role {1}", replacement.GetType().Name, oldRole.ToString()));
throw new InvalidOperationException(string.Format("The new node '{0}' is not valid in the slot {1}", replacement.GetType().Name, oldSlot.ToString()));
}
if (oldSuccessor != null)
oldParent.InsertChildBeforeUnsafe(oldSuccessor, replacement, oldRole);
oldParent.InsertChildBeforeUnsafe(oldSuccessor, replacement, oldKind);
else
oldParent.AddChildUnsafe(replacement, oldRole);
oldParent.AddChildUnsafe(replacement, oldKind);
}
return replacement;
}
@ -786,17 +738,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -786,17 +738,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
prev = prev.GetPrevNode();
return prev;
}
// filters all non c# nodes (comments, white spaces or pre processor directives)
// Comments and directives are trivia, not sibling nodes, so the previous sibling is always a C# node.
public AstNode? GetCSharpNodeBefore(AstNode node)
{
var n = node.PrevSibling;
while (n != null)
{
if (n.Role != Roles.Comment)
return n;
n = n.GetPrevNode();
}
return null;
return node.PrevSibling;
}
/// <summary>

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

@ -72,13 +72,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -72,13 +72,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
where T : AstNode
{
readonly AstNode parent;
readonly Role<T> role;
readonly SlotKind kind;
readonly List<T> list = new List<T>();
public AstNodeCollection(AstNode parent, Role<T> role)
public AstNodeCollection(AstNode parent, SlotKind kind)
{
this.parent = parent ?? throw new ArgumentNullException(nameof(parent));
this.role = role ?? throw new ArgumentNullException(nameof(role));
this.kind = kind;
}
public int Count {
@ -97,7 +97,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -97,7 +97,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
ValidateNewChild(value);
old.ClearParentAndIndex();
list[index] = value;
value.SetParentAndRole(parent, role);
value.SetParent(parent);
parent.InvalidateChildIndices();
}
}
@ -118,7 +118,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -118,7 +118,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return;
ValidateNewChild(element);
list.Add(element);
element.SetParentAndRole(parent, role);
element.SetParent(parent);
parent.InvalidateChildIndices();
}
@ -169,7 +169,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -169,7 +169,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public bool Contains(T element)
{
return element != null && element.Parent == parent && element.RoleIndex == role.Index;
return element != null && element.Parent == parent && list.Contains(element);
}
public int IndexOf(T element)
@ -247,7 +247,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -247,7 +247,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
foreach (T item in list)
if (predicate == null || predicate(item))
return item;
return role.NullObject;
return null!;
}
/// <summary>
@ -256,7 +256,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -256,7 +256,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary>
public T LastOrNullObject(Func<T, bool>? predicate = null)
{
T result = role.NullObject;
T result = null!;
foreach (T item in list)
if (predicate == null || predicate(item))
result = item;
@ -289,12 +289,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -289,12 +289,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
#region Equals and GetHashCode implementation
public override int GetHashCode()
{
return parent.GetHashCode() ^ role.GetHashCode();
return parent.GetHashCode() ^ kind.GetHashCode();
}
public override bool Equals(object? obj)
{
return obj is AstNodeCollection<T> other && this.parent == other.parent && this.role == other.role;
return obj is AstNodeCollection<T> other && this.parent == other.parent && this.kind == other.kind;
}
#endregion
@ -322,7 +322,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -322,7 +322,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return;
ValidateNewChild(newItem);
list.Insert(index, newItem);
newItem.SetParentAndRole(parent, role);
newItem.SetParent(parent);
parent.InvalidateChildIndices();
}

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

@ -41,12 +41,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -41,12 +41,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class ComposedType : AstType
{
public static readonly Role<AttributeSection> AttributeRole = EntityDeclaration.AttributeRole;
public static readonly TokenRole RefRole = new TokenRole("ref");
public static readonly TokenRole ReadonlyRole = new TokenRole("readonly");
public static readonly TokenRole NullableRole = new TokenRole("?");
public static readonly TokenRole PointerRole = new TokenRole("*");
public static readonly Role<ArraySpecifier> ArraySpecifierRole = new Role<ArraySpecifier>("ArraySpecifier", null);
[Slot("AttributeRole")]
public partial AstNodeCollection<AttributeSection> Attributes { get; }
@ -120,7 +118,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -120,7 +118,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public override AstType MakeArrayType(int dimensions)
{
InsertChildBefore(this.ArraySpecifiers.FirstOrDefault(), new ArraySpecifier(dimensions), ArraySpecifierRole);
InsertChildBefore(this.ArraySpecifiers.FirstOrDefault(), new ArraySpecifier(dimensions), SlotKind.ArraySpecifier);
return this;
}

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

@ -34,8 +34,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -34,8 +34,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class DocumentationReference : AstNode
{
public static readonly Role<AstType> DeclaringTypeRole = new Role<AstType>("DeclaringType", null);
public static readonly Role<AstType> ConversionOperatorReturnTypeRole = new Role<AstType>("ConversionOperatorReturnType", null);
SymbolKind symbolKind;
OperatorType operatorType;

4
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/AnonymousMethodExpression.cs

@ -70,10 +70,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -70,10 +70,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
hasParameterList = true;
foreach (var parameter in parameters)
{
AddChild(parameter, Roles.Parameter);
AddChild(parameter, SlotKind.Parameter);
}
}
AddChild(body, Roles.Body);
AddChild(body, SlotKind.Body);
}
public AnonymousMethodExpression(BlockStatement body, params ParameterDeclaration[] parameters) : this(body, (IEnumerable<ParameterDeclaration>)parameters)

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/AnonymousTypeCreateExpression.cs

@ -46,7 +46,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -46,7 +46,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
foreach (var ini in initializers)
{
AddChild(ini, Roles.Expression);
AddChild(ini, SlotKind.Expression);
}
}

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/ArrayCreateExpression.cs

@ -27,8 +27,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -27,8 +27,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class ArrayCreateExpression : Expression
{
public readonly static TokenRole NewKeywordRole = new TokenRole("new");
public readonly static Role<ArraySpecifier> AdditionalArraySpecifierRole = new Role<ArraySpecifier>("AdditionalArraySpecifier", null);
public readonly static Role<ArrayInitializerExpression> InitializerRole = new Role<ArrayInitializerExpression>("Initializer", null);
[Slot("Roles.Type")]
public partial AstType? Type { get; set; }

4
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/AsExpression.cs

@ -46,8 +46,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -46,8 +46,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public AsExpression(Expression expression, AstType type)
{
AddChild(expression, Roles.Expression);
AddChild(type, Roles.Type);
AddChild(expression, SlotKind.Expression);
AddChild(type, SlotKind.Type);
}
}
}

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/AssignmentExpression.cs

@ -38,8 +38,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -38,8 +38,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class AssignmentExpression : Expression
{
// reuse roles from BinaryOperatorExpression
public readonly static Role<Expression> LeftRole = BinaryOperatorExpression.LeftRole;
public readonly static Role<Expression> RightRole = BinaryOperatorExpression.RightRole;
public readonly static TokenRole AssignRole = new TokenRole("=");
public readonly static TokenRole AddRole = new TokenRole("+=");

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

@ -62,8 +62,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -62,8 +62,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public readonly static TokenRole RangeRole = new TokenRole("..");
public readonly static TokenRole IsKeywordRole = IsExpression.IsKeywordRole;
public readonly static Role<Expression> LeftRole = new Role<Expression>("Left", null);
public readonly static Role<Expression> RightRole = new Role<Expression>("Right", null);
public BinaryOperatorExpression()
{
@ -81,10 +79,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -81,10 +79,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
set;
}
[Slot(nameof(LeftRole))]
[Slot("LeftRole")]
public partial Expression? Left { get; set; }
[Slot(nameof(RightRole))]
[Slot("RightRole")]
public partial Expression? Right { get; set; }
public static TokenRole GetOperatorRole(BinaryOperatorType op)

4
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/CastExpression.cs

@ -43,8 +43,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -43,8 +43,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public CastExpression(AstType castToType, Expression expression)
{
AddChild(castToType, Roles.Type);
AddChild(expression, Roles.Expression);
AddChild(castToType, SlotKind.Type);
AddChild(expression, SlotKind.Expression);
}
}
}

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/CheckedExpression.cs

@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public CheckedExpression(Expression expression)
{
AddChild(expression, Roles.Expression);
AddChild(expression, SlotKind.Expression);
}
}
}

9
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/ConditionalExpression.cs

@ -32,11 +32,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -32,11 +32,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class ConditionalExpression : Expression
{
public readonly static Role<Expression> ConditionRole = Roles.Condition;
public readonly static TokenRole QuestionMarkRole = new TokenRole("?");
public readonly static Role<Expression> TrueRole = new Role<Expression>("True", null);
public readonly static TokenRole ColonRole = Roles.Colon;
public readonly static Role<Expression> FalseRole = new Role<Expression>("False", null);
[Slot("ConditionRole")]
public partial Expression Condition { get; set; }
@ -53,9 +50,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -53,9 +50,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public ConditionalExpression(Expression condition, Expression trueExpression, Expression falseExpression)
{
AddChild(condition, ConditionRole);
AddChild(trueExpression, TrueRole);
AddChild(falseExpression, FalseRole);
AddChild(condition, SlotKind.Condition);
AddChild(trueExpression, SlotKind.True);
AddChild(falseExpression, SlotKind.False);
}
}
}

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/DefaultValueExpression.cs

@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public DefaultValueExpression(AstType type)
{
AddChild(type, Roles.Type);
AddChild(type, SlotKind.Type);
}
}
}

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/DirectionExpression.cs

@ -59,7 +59,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -59,7 +59,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public DirectionExpression(FieldDirection direction, Expression expression)
{
this.FieldDirection = direction;
AddChild(expression, Roles.Expression);
AddChild(expression, SlotKind.Expression);
}
}
}

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IdentifierExpression.cs

@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public IdentifierExpression(string identifier, TextLocation location)
{
SetChildByRole(Roles.Identifier, Decompiler.CSharp.Syntax.Identifier.Create(identifier, location));
SetChildByRole(SlotKind.Identifier, Decompiler.CSharp.Syntax.Identifier.Create(identifier, location));
}
[NameSlot("Roles.Identifier")]

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

@ -53,7 +53,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -53,7 +53,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
foreach (var arg in arguments)
{
AddChild(arg, Roles.Argument);
AddChild(arg, SlotKind.Argument);
}
}
}

1
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/InterpolatedStringExpression.cs

@ -36,7 +36,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -36,7 +36,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: true)]
public abstract partial class InterpolatedStringContent : AstNode
{
public new static readonly Role<InterpolatedStringContent> Role = new Role<InterpolatedStringContent>("InterpolatedStringContent", null);
}

4
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/InvocationExpression.cs

@ -46,12 +46,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -46,12 +46,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public InvocationExpression(Expression target, IEnumerable<Expression> arguments)
{
AddChild(target, Roles.TargetExpression);
AddChild(target, SlotKind.TargetExpression);
if (arguments != null)
{
foreach (var arg in arguments)
{
AddChild(arg, Roles.Argument);
AddChild(arg, SlotKind.Argument);
}
}
}

4
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IsExpression.cs

@ -47,8 +47,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -47,8 +47,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public IsExpression(Expression expression, AstType type)
{
AddChild(expression, Roles.Expression);
AddChild(type, Roles.Type);
AddChild(expression, SlotKind.Expression);
AddChild(type, SlotKind.Type);
}
}
}

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/LambdaExpression.cs

@ -32,9 +32,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -32,9 +32,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class LambdaExpression : Expression
{
public static readonly Role<AttributeSection> AttributeRole = new Role<AttributeSection>("Attribute", null);
public readonly static TokenRole AsyncModifierRole = new TokenRole("async");
public static readonly Role<AstNode> BodyRole = new Role<AstNode>("Body", null);
bool isAsync;

4
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/MemberReferenceExpression.cs

@ -49,13 +49,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -49,13 +49,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public MemberReferenceExpression(Expression target, string memberName, IEnumerable<AstType> arguments = null)
{
AddChild(target, Roles.TargetExpression);
AddChild(target, SlotKind.TargetExpression);
MemberName = memberName;
if (arguments != null)
{
foreach (var arg in arguments)
{
AddChild(arg, Roles.TypeArgument);
AddChild(arg, SlotKind.TypeArgument);
}
}
}

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

@ -37,7 +37,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -37,7 +37,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class ObjectCreateExpression : Expression
{
public readonly static TokenRole NewKeywordRole = new TokenRole("new");
public readonly static Role<ArrayInitializerExpression> InitializerRole = ArrayCreateExpression.InitializerRole;
[Slot("Roles.Type")]
public partial AstType Type { get; set; }
@ -54,12 +53,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -54,12 +53,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public ObjectCreateExpression(AstType type, IEnumerable<Expression>? arguments = null)
{
AddChild(type, Roles.Type);
AddChild(type, SlotKind.Type);
if (arguments != null)
{
foreach (var arg in arguments)
{
AddChild(arg, Roles.Argument);
AddChild(arg, SlotKind.Argument);
}
}
}

11
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/QueryExpression.cs

@ -26,7 +26,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -26,7 +26,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: true)]
public partial class QueryExpression : Expression
{
public static readonly Role<QueryClause> ClauseRole = new Role<QueryClause>("Clause", null);
[Slot("ClauseRole")]
public partial AstNodeCollection<QueryClause> Clauses { get; }
@ -45,7 +44,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -45,7 +44,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class QueryContinuationClause : QueryClause
{
public static readonly Role<QueryExpression> PrecedingQueryRole = new Role<QueryExpression>("PrecedingQuery", null);
public static readonly TokenRole IntoKeywordRole = new TokenRole("into");
[Slot("PrecedingQueryRole")]
@ -115,16 +113,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -115,16 +113,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class QueryJoinClause : QueryClause
{
public static readonly TokenRole JoinKeywordRole = new TokenRole("join");
public static readonly Role<AstType> TypeRole = Roles.Type;
public static readonly Role<Identifier> JoinIdentifierRole = Roles.Identifier;
public static readonly TokenRole InKeywordRole = new TokenRole("in");
public static readonly Role<Expression> InExpressionRole = Roles.Expression;
public static readonly TokenRole OnKeywordRole = new TokenRole("on");
public static readonly Role<Expression> OnExpressionRole = new Role<Expression>("OnExpression", null);
public static readonly TokenRole EqualsKeywordRole = new TokenRole("equals");
public static readonly Role<Expression> EqualsExpressionRole = new Role<Expression>("EqualsExpression", null);
public static readonly TokenRole IntoKeywordRole = new TokenRole("into");
public static readonly Role<Identifier> IntoIdentifierRole = new Role<Identifier>("IntoIdentifier", null);
// Derived from IntoIdentifier (which DoMatch already compares); exclude it to avoid a redundant compare.
[ExcludeFromMatch]
@ -158,7 +150,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -158,7 +150,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class QueryOrderClause : QueryClause
{
public static readonly TokenRole OrderbyKeywordRole = new TokenRole("orderby");
public static readonly Role<QueryOrdering> OrderingRole = new Role<QueryOrdering>("Ordering", null);
[Slot("OrderingRole")]
public partial AstNodeCollection<QueryOrdering> Orderings { get; }
@ -208,9 +199,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -208,9 +199,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class QueryGroupClause : QueryClause
{
public static readonly TokenRole GroupKeywordRole = new TokenRole("group");
public static readonly Role<Expression> ProjectionRole = new Role<Expression>("Projection", null);
public static readonly TokenRole ByKeywordRole = new TokenRole("by");
public static readonly Role<Expression> KeyRole = new Role<Expression>("Key", null);
[Slot("ProjectionRole")]
public partial Expression Projection { get; set; }

1
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/RecursivePatternExpression.cs

@ -31,7 +31,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -31,7 +31,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class RecursivePatternExpression : Expression
{
public static readonly Role<Expression> SubPatternRole = new Role<Expression>("SubPattern", null);
[Slot("Roles.Type")]
public partial AstType? Type { get; set; }

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/SizeOfExpression.cs

@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public SizeOfExpression(AstType type)
{
AddChild(type, Roles.Type);
AddChild(type, SlotKind.Type);
}
}
}

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

@ -42,7 +42,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -42,7 +42,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class StackAllocExpression : Expression
{
public readonly static TokenRole StackallocKeywordRole = new TokenRole("stackalloc");
public readonly static Role<ArrayInitializerExpression> InitializerRole = new Role<ArrayInitializerExpression>("Initializer", null);
[Slot("Roles.Type")]
public partial AstType? Type { get; set; }

3
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/SwitchExpression.cs

@ -26,7 +26,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -26,7 +26,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class SwitchExpression : Expression
{
public static readonly TokenRole SwitchKeywordRole = new TokenRole("switch");
public static readonly Role<SwitchExpressionSection> SwitchSectionRole = new Role<SwitchExpressionSection>("SwitchSection", null);
[Slot("Roles.Expression")]
public partial Expression Expression { get; set; }
@ -41,8 +40,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -41,8 +40,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class SwitchExpressionSection : AstNode
{
public static readonly Role<Expression> PatternRole = new Role<Expression>("Pattern", null);
public static readonly Role<Expression> BodyRole = new Role<Expression>("Body", null);
[Slot("PatternRole")]
public partial Expression Pattern { get; set; }

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/ThrowExpression.cs

@ -35,7 +35,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -35,7 +35,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public ThrowExpression(Expression expression)
{
AddChild(expression, Roles.Expression);
AddChild(expression, SlotKind.Expression);
}
}
}

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/TypeOfExpression.cs

@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public TypeOfExpression(AstType type)
{
AddChild(type, Roles.Type);
AddChild(type, SlotKind.Type);
}
}
}

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/TypeReferenceExpression.cs

@ -34,7 +34,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -34,7 +34,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public TypeReferenceExpression(AstType type)
{
AddChild(type, Roles.Type);
AddChild(type, SlotKind.Type);
}
}
}

2
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/UncheckedExpression.cs

@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public UncheckedExpression(Expression expression)
{
AddChild(expression, Roles.Expression);
AddChild(expression, SlotKind.Expression);
}
}
}

1
ICSharpCode.Decompiler/CSharp/Syntax/Expressions/WithInitializerExpression.cs

@ -26,7 +26,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -26,7 +26,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class WithInitializerExpression : Expression
{
public readonly static TokenRole WithKeywordRole = new TokenRole("with");
public readonly static Role<ArrayInitializerExpression> InitializerRole = ArrayCreateExpression.InitializerRole;
[Slot("Roles.Expression")]
public partial Expression Expression { get; set; }

1
ICSharpCode.Decompiler/CSharp/Syntax/FunctionPointerAstType.cs

@ -33,7 +33,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -33,7 +33,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class FunctionPointerAstType : AstType
{
public static readonly TokenRole PointerRole = new TokenRole("*");
public static readonly Role<AstType> CallingConventionRole = new Role<AstType>("CallConv", null);
public bool HasUnmanagedCallingConvention { get; set; }

4
ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/AttributeSection.cs

@ -35,10 +35,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -35,10 +35,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public string AttributeTarget {
get {
return GetChildByRole(Roles.Identifier)?.Name ?? string.Empty;
return GetChildByRole<Identifier>(SlotKind.Identifier)?.Name ?? string.Empty;
}
set {
SetChildByRole(Roles.Identifier, Identifier.Create(value));
SetChildByRole(SlotKind.Identifier, Identifier.Create(value));
}
}

4
ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/NamespaceDeclaration.cs

@ -39,8 +39,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -39,8 +39,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class NamespaceDeclaration : AstNode
{
public static readonly Role<AstNode> MemberRole = SyntaxTree.MemberRole;
public static readonly Role<AstType> NamespaceNameRole = new Role<AstType>("NamespaceName", null);
public bool IsFileScoped { get; set; }
@ -123,7 +121,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -123,7 +121,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public void AddMember(AstNode child)
{
AddChild(child, MemberRole);
AddChild(child, SlotKind.Member);
}
}
};

1
ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/PreProcessorDirective.cs

@ -67,7 +67,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -67,7 +67,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class PragmaWarningPreprocessorDirective : PreProcessorDirective
{
public static readonly Role<PrimitiveExpression> WarningRole = new Role<PrimitiveExpression>("Warning", null);
public static readonly TokenRole PragmaKeywordRole = new TokenRole("#pragma");
public static readonly TokenRole WarningKeywordRole = new TokenRole("warning");

1
ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/TypeParameterDeclaration.cs

@ -29,7 +29,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -29,7 +29,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class TypeParameterDeclaration : AstNode
{
public static readonly Role<AttributeSection> AttributeRole = EntityDeclaration.AttributeRole;
public static readonly TokenRole OutVarianceKeywordRole = new TokenRole("out");
public static readonly TokenRole InVarianceKeywordRole = new TokenRole("in");

10
ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/UsingAliasDeclaration.cs

@ -33,8 +33,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -33,8 +33,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class UsingAliasDeclaration : AstNode
{
public static readonly TokenRole UsingKeywordRole = new TokenRole("using");
public static readonly Role<Identifier> AliasRole = new Role<Identifier>("Alias", null);
public static readonly Role<AstType> ImportRole = UsingDeclaration.ImportRole;
[NameSlot("AliasRole")]
public partial string Alias { get; set; }
@ -48,14 +46,14 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -48,14 +46,14 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public UsingAliasDeclaration(string alias, string nameSpace)
{
AddChild(Identifier.Create(alias), AliasRole);
AddChild(new SimpleType(nameSpace), ImportRole);
AddChild(Identifier.Create(alias), SlotKind.Alias);
AddChild(new SimpleType(nameSpace), SlotKind.Import);
}
public UsingAliasDeclaration(string alias, AstType import)
{
AddChild(Identifier.Create(alias), AliasRole);
AddChild(import, ImportRole);
AddChild(Identifier.Create(alias), SlotKind.Alias);
AddChild(import, SlotKind.Import);
}
}
}

5
ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/UsingDeclaration.cs

@ -41,7 +41,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -41,7 +41,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class UsingDeclaration : AstNode
{
public static readonly TokenRole UsingKeywordRole = new TokenRole("using");
public static readonly Role<AstType> ImportRole = new Role<AstType>("Import", null);
[Slot("ImportRole")]
public partial AstType Import { get; set; }
@ -84,12 +83,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -84,12 +83,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public UsingDeclaration(string nameSpace)
{
AddChild(AstType.Create(nameSpace), ImportRole);
AddChild(AstType.Create(nameSpace), SlotKind.Import);
}
public UsingDeclaration(AstType import)
{
AddChild(import, ImportRole);
AddChild(import, SlotKind.Import);
}
}
}

3
ICSharpCode.Decompiler/CSharp/Syntax/MemberType.cs

@ -34,7 +34,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -34,7 +34,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class MemberType : AstType
{
public static readonly Role<AstType> TargetRole = new Role<AstType>("Target", null);
bool isDoubleColon;
@ -70,7 +69,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -70,7 +69,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
this.MemberName = memberName;
foreach (var arg in typeArguments)
{
AddChild(arg, Roles.TypeArgument);
AddChild(arg, SlotKind.TypeArgument);
}
}

112
ICSharpCode.Decompiler/CSharp/Syntax/Role.cs

@ -1,112 +0,0 @@ @@ -1,112 +0,0 @@
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// 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.Threading;
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
/// <summary>
/// Represents the role a node plays within its parent.
/// </summary>
public abstract class Role
{
public const int RoleIndexBits = 9;
static readonly Role[] roles = new Role[1 << RoleIndexBits];
static int nextRoleIndex = 0;
readonly uint index;
public uint Index {
get { return index; }
}
// don't allow NRefactory consumers to derive from Role
internal Role()
{
this.index = (uint)Interlocked.Increment(ref nextRoleIndex);
if (this.index >= roles.Length)
throw new InvalidOperationException("Too many roles");
roles[this.index] = this;
}
/// <summary>
/// Gets whether the specified node is valid in this role.
/// </summary>
public abstract bool IsValid(object node);
/// <summary>
/// Gets the role's null object as a non-generic reference, or null if the role has none.
/// Used by the transitional slot layer, which works with the non-generic <see cref="Role"/> base type.
/// </summary>
internal abstract object? NullObjectUntyped { get; }
/// <summary>
/// Gets the role with the specified index.
/// </summary>
public static Role GetByIndex(uint index)
{
return roles[index];
}
}
/// <summary>
/// Represents the role a node plays within its parent.
/// All nodes with this role have type T.
/// </summary>
public class Role<T> : Role where T : class?
{
readonly string name; // helps with debugging the AST
readonly T nullObject;
/// <summary>
/// Gets the null object used when there's no node with this role.
/// Not every role has a null object; this property returns null for roles without a null object.
/// </summary>
/// <remarks>
/// Roles used for non-collections should always have a null object, so that no AST property returns null.
/// However, if a role used for collections only, it may leave out the null object.
/// </remarks>
public T NullObject {
get { return nullObject; }
}
internal override object? NullObjectUntyped => nullObject;
public override bool IsValid(object node)
{
return node is T;
}
public Role(string name, T? nullObject)
{
this.name = name ?? throw new ArgumentNullException(nameof(name));
// Roles used only for collections may omit the null object (pass null); NullObject then
// returns null, matching the documented contract. Single-value roles always pass one.
this.nullObject = nullObject!;
}
public override string ToString()
{
return name;
}
}
}

21
ICSharpCode.Decompiler/CSharp/Syntax/Roles.cs

@ -28,25 +28,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -28,25 +28,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
public static class Roles
{
public static readonly Role<AstNode> Root = AstNode.RootRole;
// some pre defined constants for common roles
public static readonly Role<Identifier> Identifier = new Role<Identifier>("Identifier", null);
public static readonly Role<BlockStatement> Body = new Role<BlockStatement>("Body", null);
public static readonly Role<ParameterDeclaration> Parameter = new Role<ParameterDeclaration>("Parameter", null);
public static readonly Role<Expression> Argument = new Role<Expression>("Argument", null);
public static readonly Role<AstType> Type = new Role<AstType>("Type", null);
public static readonly Role<Expression> Expression = new Role<Expression>("Expression", null);
public static readonly Role<Expression> TargetExpression = new Role<Expression>("Target", null);
public readonly static Role<Expression> Condition = new Role<Expression>("Condition", null);
public static readonly Role<TypeParameterDeclaration> TypeParameter = new Role<TypeParameterDeclaration>("TypeParameter", null);
public static readonly Role<AstType> TypeArgument = new Role<AstType>("TypeArgument", null);
public readonly static Role<Constraint> Constraint = new Role<Constraint>("Constraint", null);
public static readonly Role<VariableInitializer> Variable = new Role<VariableInitializer>("Variable", null);
public static readonly Role<Statement> EmbeddedStatement = new Role<Statement>("EmbeddedStatement", null);
public readonly static Role<EntityDeclaration> TypeMemberRole = new Role<EntityDeclaration>("TypeMember", null);
public static readonly Role<VariableDesignation> VariableDesignationRole = new Role<VariableDesignation>("VariableDesignation", null);
// some pre defined constants for most used punctuation
public static readonly TokenRole LPar = new TokenRole("(");
@ -64,15 +48,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -64,15 +48,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public static readonly TokenRole Colon = new TokenRole(":");
public static readonly TokenRole DoubleColon = new TokenRole("::");
public static readonly TokenRole Arrow = new TokenRole("=>");
public static readonly Role<Comment> Comment = new Role<Comment>("Comment", null);
public static readonly Role<PreProcessorDirective> PreProcessorDirective = new Role<PreProcessorDirective>("PreProcessorDirective", null);
public readonly static Role<AstType> BaseType = new Role<AstType>("BaseType", null);
public static readonly Role<Attribute> Attribute = new Role<Attribute>("Attribute", null);
public readonly static TokenRole WhereKeyword = new TokenRole("where");
public readonly static Role<SimpleType> ConstraintTypeParameter = new Role<SimpleType>("TypeParameter", null);
public readonly static TokenRole DelegateKeyword = new TokenRole("delegate");
public static readonly TokenRole ExternKeyword = new TokenRole("extern");
public static readonly TokenRole AliasKeyword = new TokenRole("alias");

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

@ -50,7 +50,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -50,7 +50,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public SimpleType(string identifier, TextLocation location)
{
SetChildByRole(Roles.Identifier, Syntax.Identifier.Create(identifier, location));
SetChildByRole(SlotKind.Identifier, Syntax.Identifier.Create(identifier, location));
}
public SimpleType(string identifier, IEnumerable<AstType> typeArguments)
@ -58,7 +58,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -58,7 +58,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
this.Identifier = identifier;
foreach (var arg in typeArguments)
{
AddChild(arg, Roles.TypeArgument);
AddChild(arg, SlotKind.TypeArgument);
}
}

5
ICSharpCode.Decompiler/CSharp/Syntax/Statements/BlockStatement.cs

@ -34,19 +34,18 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -34,19 +34,18 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: true, hasPatternPlaceholder: true)]
public partial class BlockStatement : Statement, IEnumerable<Statement>
{
public static readonly Role<Statement> StatementRole = new Role<Statement>("Statement", null);
[Slot("StatementRole")]
public partial AstNodeCollection<Statement> Statements { get; }
public void Add(Statement statement)
{
AddChild(statement, StatementRole);
AddChild(statement, SlotKind.Statement);
}
public void Add(Expression expression)
{
AddChild(new ExpressionStatement(expression), StatementRole);
AddChild(new ExpressionStatement(expression), SlotKind.Statement);
}
IEnumerator<Statement> IEnumerable<Statement>.GetEnumerator()

2
ICSharpCode.Decompiler/CSharp/Syntax/Statements/CheckedStatement.cs

@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public CheckedStatement(BlockStatement body)
{
AddChild(body, Roles.Body);
AddChild(body, SlotKind.Body);
}
}
}

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

@ -35,8 +35,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -35,8 +35,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class ForStatement : Statement
{
public static readonly TokenRole ForKeywordRole = new TokenRole("for");
public readonly static Role<Statement> InitializerRole = new Role<Statement>("Initializer", null);
public readonly static Role<Statement> IteratorRole = new Role<Statement>("Iterator", null);
/// <summary>
/// Gets the list of initializer statements.

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

@ -35,10 +35,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -35,10 +35,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class IfElseStatement : Statement
{
public readonly static TokenRole IfKeywordRole = new TokenRole("if");
public readonly static Role<Expression> ConditionRole = Roles.Condition;
public readonly static Role<Statement> TrueRole = new Role<Statement>("True", null);
public readonly static TokenRole ElseKeywordRole = new TokenRole("else");
public readonly static Role<Statement> FalseRole = new Role<Statement>("False", null);
[Slot("ConditionRole")]
public partial Expression Condition { get; set; }

3
ICSharpCode.Decompiler/CSharp/Syntax/Statements/LocalFunctionDeclarationStatement.cs

@ -24,14 +24,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -24,14 +24,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class LocalFunctionDeclarationStatement : Statement
{
public static readonly Role<MethodDeclaration> MethodDeclarationRole = new Role<MethodDeclaration>("Method", null);
[Slot("MethodDeclarationRole")]
public partial MethodDeclaration Declaration { get; set; }
public LocalFunctionDeclarationStatement(MethodDeclaration methodDeclaration)
{
AddChild(methodDeclaration, MethodDeclarationRole);
AddChild(methodDeclaration, SlotKind.MethodDeclaration);
}
}
}

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

@ -45,7 +45,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -45,7 +45,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public ReturnStatement(Expression returnExpression)
{
AddChild(returnExpression, Roles.Expression);
AddChild(returnExpression, SlotKind.Expression);
}
}
}

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

@ -35,7 +35,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -35,7 +35,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class SwitchStatement : Statement
{
public static readonly TokenRole SwitchKeywordRole = new TokenRole("switch");
public static readonly Role<SwitchSection> SwitchSectionRole = new Role<SwitchSection>("SwitchSection", null);
[Slot("Roles.Expression")]
public partial Expression Expression { get; set; }
@ -50,7 +49,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -50,7 +49,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false, hasPatternPlaceholder: true)]
public partial class SwitchSection : AstNode
{
public static readonly Role<CaseLabel> CaseLabelRole = new Role<CaseLabel>("CaseLabel", null);
[Slot("CaseLabelRole")]
public partial AstNodeCollection<CaseLabel> CaseLabels { get; }

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

@ -45,7 +45,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -45,7 +45,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public ThrowStatement(Expression expression)
{
AddChild(expression, Roles.Expression);
AddChild(expression, SlotKind.Expression);
}
}
}

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

@ -35,10 +35,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -35,10 +35,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class TryCatchStatement : Statement
{
public static readonly TokenRole TryKeywordRole = new TokenRole("try");
public static readonly Role<BlockStatement> TryBlockRole = new Role<BlockStatement>("TryBlock", null);
public static readonly Role<CatchClause> CatchClauseRole = new Role<CatchClause>("CatchClause", null);
public static readonly TokenRole FinallyKeywordRole = new TokenRole("finally");
public static readonly Role<BlockStatement> FinallyBlockRole = new Role<BlockStatement>("FinallyBlock", null);
[Slot("TryBlockRole")]
public partial BlockStatement TryBlock { get; set; }
@ -58,7 +55,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -58,7 +55,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
public static readonly TokenRole CatchKeywordRole = new TokenRole("catch");
public static readonly TokenRole WhenKeywordRole = new TokenRole("when");
public static readonly Role<Expression> ConditionRole = Roles.Condition;
public static readonly TokenRole CondLPar = new TokenRole("(");
public static readonly TokenRole CondRPar = new TokenRole(")");

2
ICSharpCode.Decompiler/CSharp/Syntax/Statements/UncheckedStatement.cs

@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public UncheckedStatement(BlockStatement body)
{
AddChild(body, Roles.Body);
AddChild(body, SlotKind.Body);
}
}
}

1
ICSharpCode.Decompiler/CSharp/Syntax/Statements/UsingStatement.cs

@ -34,7 +34,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -34,7 +34,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
public static readonly TokenRole UsingKeywordRole = new TokenRole("using");
public static readonly TokenRole AwaitRole = UnaryOperatorExpression.AwaitRole;
public static readonly Role<AstNode> ResourceAcquisitionRole = new Role<AstNode>("ResourceAcquisition", null);
public bool IsAsync { get; set; }

1
ICSharpCode.Decompiler/CSharp/Syntax/SyntaxTree.cs

@ -36,7 +36,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -36,7 +36,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class SyntaxTree : AstNode
{
public static readonly Role<AstNode> MemberRole = new Role<AstNode>("Member", null);
[Slot("MemberRole")]
public partial AstNodeCollection<AstNode> Members { get; }

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

@ -24,7 +24,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -24,7 +24,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class TupleAstType : AstType
{
public static readonly Role<TupleTypeElement> ElementRole = new Role<TupleTypeElement>("Element", null);
[Slot("ElementRole")]
public partial AstNodeCollection<TupleTypeElement> Elements { get; }

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

@ -36,7 +36,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -36,7 +36,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class ConstructorDeclaration : EntityDeclaration
{
public static readonly Role<ConstructorInitializer> InitializerRole = new Role<ConstructorInitializer>("Initializer", null);
public override SymbolKind SymbolKind {
get { return SymbolKind.Constructor; }

16
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/EntityDeclaration.cs

@ -25,18 +25,16 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -25,18 +25,16 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
public abstract class EntityDeclaration : AstNode
{
public static readonly Role<AttributeSection> AttributeRole = new Role<AttributeSection>("Attribute", null);
// Modifiers are stored in the Modifiers scalar; this role only tags the keyword tokens the
// output visitor emits (e.g. for the override-link reference in TextTokenWriter).
// Identity marker for modifier keywords in the output (modifiers are scalars, not child nodes);
// the token writer uses it to make the 'override' modifier a go-to-definition reference.
public static readonly TokenRole ModifierRole = new TokenRole("modifier");
public static readonly Role<AstType> PrivateImplementationTypeRole = new Role<AstType>("PrivateImplementationType", null);
public abstract SymbolKind SymbolKind { get; }
public virtual AstNodeCollection<AttributeSection> Attributes {
get { return base.GetChildrenByRole(AttributeRole); }
get { return base.GetChildrenByRole<AttributeSection>(SlotKind.Attribute); }
}
public Modifiers Modifiers { get; set; }
@ -48,21 +46,21 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -48,21 +46,21 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public virtual string Name {
get {
return GetChildByRole(Roles.Identifier)?.Name ?? string.Empty;
return GetChildByRole<Identifier>(SlotKind.Identifier)?.Name ?? string.Empty;
}
set {
SetChildByRole(Roles.Identifier, Identifier.Create(value, TextLocation.Empty));
SetChildByRole(SlotKind.Identifier, Identifier.Create(value, TextLocation.Empty));
}
}
public virtual Identifier NameToken {
get { return GetChildByRole(Roles.Identifier); }
set { SetChildByRole(Roles.Identifier, value); }
get { return GetChildByRole<Identifier>(SlotKind.Identifier); }
set { SetChildByRole(SlotKind.Identifier, value); }
}
public virtual AstType ReturnType {
get { return GetChildByRole(Roles.Type); }
set { SetChildByRole(Roles.Type, value); }
get { return GetChildByRole<AstType>(SlotKind.Type); }
set { SetChildByRole(SlotKind.Type, value); }
}
protected bool MatchAttributesAndModifiers(EntityDeclaration o, PatternMatching.Match match)

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

@ -36,7 +36,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -36,7 +36,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false)]
public partial class EnumMemberDeclaration : EntityDeclaration
{
public static readonly Role<Expression> InitializerRole = new Role<Expression>("Initializer", null);
public override SymbolKind SymbolKind {
get { return SymbolKind.Field; }

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

@ -79,8 +79,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -79,8 +79,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public static readonly TokenRole AddKeywordRole = new TokenRole("add");
public static readonly TokenRole RemoveKeywordRole = new TokenRole("remove");
public static readonly Role<Accessor> AddAccessorRole = new Role<Accessor>("AddAccessor", null);
public static readonly Role<Accessor> RemoveAccessorRole = new Role<Accessor>("RemoveAccessor", null);
public override SymbolKind SymbolKind {
get { return SymbolKind.Event; }

1
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/FixedFieldDeclaration.cs

@ -34,7 +34,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -34,7 +34,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class FixedFieldDeclaration : EntityDeclaration
{
public static readonly TokenRole FixedKeywordRole = new TokenRole("fixed");
public static readonly Role<FixedVariableInitializer> VariableRole = new Role<FixedVariableInitializer>("FixedVariable", null);
public override SymbolKind SymbolKind {
get { return SymbolKind.Field; }

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

@ -45,9 +45,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -45,9 +45,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public partial class IndexerDeclaration : EntityDeclaration
{
public static readonly TokenRole ThisKeywordRole = new TokenRole("this");
public static readonly Role<Accessor> GetterRole = PropertyDeclaration.GetterRole;
public static readonly Role<Accessor> SetterRole = PropertyDeclaration.SetterRole;
public static readonly Role<Expression> ExpressionBodyRole = new Role<Expression>("ExpressionBody", null);
public override SymbolKind SymbolKind {
get { return SymbolKind.Indexer; }

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

@ -72,7 +72,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -72,7 +72,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public bool IsExtensionMethod {
get {
ParameterDeclaration pd = (ParameterDeclaration)GetChildByRole(Roles.Parameter);
ParameterDeclaration pd = (ParameterDeclaration)GetChildByRole<ParameterDeclaration>(SlotKind.Parameter);
return pd != null && pd.HasThisModifier;
}
}

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

@ -37,7 +37,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -37,7 +37,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
[DecompilerAstNode(hasNullNode: false, hasPatternPlaceholder: true)]
public partial class ParameterDeclaration : AstNode
{
public static readonly Role<AttributeSection> AttributeRole = EntityDeclaration.AttributeRole;
public static readonly TokenRole ThisModifierRole = new TokenRole("this");
public static readonly TokenRole ScopedRefRole = new TokenRole("scoped");
public static readonly TokenRole RefModifierRole = new TokenRole("ref");

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

@ -44,9 +44,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -44,9 +44,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public static readonly TokenRole GetKeywordRole = new TokenRole("get");
public static readonly TokenRole SetKeywordRole = new TokenRole("set");
public static readonly TokenRole InitKeywordRole = new TokenRole("init");
public static readonly Role<Accessor> GetterRole = new Role<Accessor>("Getter", null);
public static readonly Role<Accessor> SetterRole = new Role<Accessor>("Setter", null);
public static readonly Role<Expression> ExpressionBodyRole = new Role<Expression>("ExpressionBody", null);
public override SymbolKind SymbolKind {
get { return SymbolKind.Property; }

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

@ -633,11 +633,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -633,11 +633,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
if (ConvertUnboundTypeArguments && typeArguments[i].Kind == TypeKind.UnboundTypeArgument)
{
result.AddChild(MakeSimpleType(typeParameters[i].Name), Roles.TypeArgument);
result.AddChild(MakeSimpleType(typeParameters[i].Name), SlotKind.TypeArgument);
}
else
{
result.AddChild(ConvertType(typeArguments[i]), Roles.TypeArgument);
result.AddChild(ConvertType(typeArguments[i]), SlotKind.TypeArgument);
}
}
}

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

@ -393,7 +393,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -393,7 +393,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
// We cannot use checked/unchecked for top-level-expressions.
}
else if (expr.Role is Role<Expression> || expr.Role is Role<AstNode>)
else if (expr.Slot?.ChildType is Type ct && ct.IsAssignableFrom(typeof(Expression)))
{
// We use '<' so that expressions are introduced on the deepest level possible (goal 3)
var costIfWrapWithChecked = result.CostInCheckedContext.WrapInCheckedExpr();

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

@ -725,14 +725,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -725,14 +725,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
},
BlockStatement.StatementRole);
SlotKind.Statement);
}
else
{
insertionParent.InsertChildBefore(
v.InsertionPoint.nextNode,
vds,
BlockStatement.StatementRole);
SlotKind.Statement);
insertionParent.InsertChildBefore(
v.InsertionPoint.nextNode,
new ExpressionStatement {
@ -750,7 +750,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -750,7 +750,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
},
BlockStatement.StatementRole);
SlotKind.Statement);
}
}
else
@ -758,7 +758,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -758,7 +758,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
insertionParent.InsertChildBefore(
v.InsertionPoint.nextNode,
vds,
BlockStatement.StatementRole);
SlotKind.Statement);
}
}
}

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

@ -42,7 +42,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -42,7 +42,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
foreach (var typeDecl in rootNode.DescendantsAndSelf.OfType<TypeDeclaration>())
{
var memberNames = typeDecl.Members.Select(m => {
var type = m.GetChildByRole(EntityDeclaration.PrivateImplementationTypeRole);
var type = m.GetChildByRole<AstType>(SlotKind.PrivateImplementationType);
return type is null ? m.Name : type + "." + m.Name;
}).ToHashSet();
// memberNames does not include fields or non-custom events because those
@ -72,7 +72,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -72,7 +72,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
ISymbol symbol = node.GetSymbol();
if (symbol != null && renamedSymbols.TryGetValue(symbol, out string? newName))
{
node.GetChildByRole(Roles.Identifier).Name = newName;
node.GetChildByRole<Identifier>(SlotKind.Identifier).Name = newName;
}
}
}

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

@ -73,7 +73,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -73,7 +73,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
resolvedNamespaces.Add(resolvedNamespace);
}
rootNode.InsertChildAfter(insertionPoint, new UsingDeclaration { Import = nsType }, SyntaxTree.MemberRole);
rootNode.InsertChildAfter(insertionPoint, new UsingDeclaration { Import = nsType }, SlotKind.Member);
}
}

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

@ -192,7 +192,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -192,7 +192,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (next is ForStatement forStatement && ForStatementUsesVariable(forStatement, variable))
{
node.Remove();
next.InsertChildAfter(null, node, ForStatement.InitializerRole);
next.InsertChildAfter(null, node, SlotKind.Initializer);
return (ForStatement)next;
}
Match m3 = forPattern.Match(next);

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

@ -482,7 +482,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -482,7 +482,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var ci = new ConstructorInitializer { ConstructorInitializerType = type };
// Move arguments from invocation to initializer:
invocation.GetChildrenByRole(Roles.Argument).MoveTo(ci.Arguments);
invocation.GetChildrenByRole<Expression>(SlotKind.Argument).MoveTo(ci.Arguments);
// Add the initializer: (unless it is the default 'base()')
if (!(ci.ConstructorInitializerType == ConstructorInitializerType.Base && ci.Arguments.Count == 0))
constructorDeclaration.Initializer = ci.CopyAnnotationsFrom(invocation);
@ -619,7 +619,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -619,7 +619,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
foreach (var param in PrimaryConstructorDecl.Parameters)
{
param.Remove();
this.TypeDeclaration.InsertChildAfter(insertionPoint, param, Roles.Parameter);
this.TypeDeclaration.InsertChildAfter(insertionPoint, param, SlotKind.Parameter);
insertionPoint = param;
}
}

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -264,7 +264,6 @@ @@ -264,7 +264,6 @@
<Compile Include="CSharp\Syntax\PatternMatching\Pattern.cs" />
<Compile Include="CSharp\Syntax\PatternMatching\Repeat.cs" />
<Compile Include="CSharp\Syntax\PrimitiveType.cs" />
<Compile Include="CSharp\Syntax\Role.cs" />
<Compile Include="CSharp\Syntax\Roles.cs" />
<Compile Include="CSharp\Syntax\SimpleType.cs" />
<Compile Include="CSharp\Syntax\Statements\BlockStatement.cs" />

2
ICSharpCode.Decompiler/Output/TextTokenWriter.cs

@ -300,7 +300,7 @@ namespace ICSharpCode.Decompiler @@ -300,7 +300,7 @@ namespace ICSharpCode.Decompiler
// Attach member reference to token only if there's no identifier in the current node.
var member = GetCurrentMemberReference();
var node = nodeStack.Peek();
if (member != null && node.GetChildByRole(Roles.Identifier) is null)
if (member != null && node.GetChildByRole<Identifier>(SlotKind.Identifier) is null)
{
switch (member)
{

8
ILSpy/Languages/CSharpHighlightingTokenWriter.cs

@ -350,7 +350,7 @@ namespace ICSharpCode.ILSpy.Languages @@ -350,7 +350,7 @@ namespace ICSharpCode.ILSpy.Languages
{
if (identifier.Name == "value"
&& identifier.Ancestors.OfType<Accessor>().FirstOrDefault() is { } accessor
&& accessor.Role != PropertyDeclaration.GetterRole)
&& accessor.Slot?.Kind != SlotKind.Getter)
{
color = valueKeywordColor;
}
@ -476,17 +476,17 @@ namespace ICSharpCode.ILSpy.Languages @@ -476,17 +476,17 @@ namespace ICSharpCode.ILSpy.Languages
AstNode node = nodeStack.Peek();
var symbol = node.GetSymbol();
if (symbol == null && node.Role == Roles.TargetExpression && node.Parent is InvocationExpression)
if (symbol == null && node.Slot?.Kind == SlotKind.TargetExpression && node.Parent is InvocationExpression)
{
symbol = node.Parent.GetSymbol();
}
if (symbol != null && node.Role == Roles.Type && node.Parent is ObjectCreateExpression)
if (symbol != null && node.Slot?.Kind == SlotKind.Type && node.Parent is ObjectCreateExpression)
{
var ctorSymbol = node.Parent.GetSymbol();
if (ctorSymbol != null)
symbol = ctorSymbol;
}
if (node is IdentifierExpression && node.Role == Roles.TargetExpression && node.Parent is InvocationExpression && symbol is IMember member)
if (node is IdentifierExpression && node.Slot?.Kind == SlotKind.TargetExpression && node.Parent is InvocationExpression && symbol is IMember member)
{
var declaringType = member.DeclaringType;
if (declaringType != null && declaringType.Kind == TypeKind.Delegate)

Loading…
Cancel
Save