diff --git a/ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs b/ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs index 5dd97d844..6f56641ac 100644 --- a/ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs +++ b/ICSharpCode.Decompiler.Generators/DecompilerSyntaxTreeGenerator.cs @@ -30,7 +30,7 @@ namespace ICSharpCode.Decompiler.Generators; [Generator] internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator { - record AstNodeAdditions(string NodeName, bool NeedsAcceptImpls, bool NeedsVisitor, bool NeedsNullNode, bool NeedsPatternPlaceholder, int NullNodeBaseCtorParamCount, bool IsTypeNode, string VisitMethodName, string VisitMethodParamType, EquatableArray<(string Member, string TypeName, bool RecursiveMatch, bool MatchAny, bool Nullable)>? MembersToMatch, EquatableArray<(string RoleExpr, bool IsCollection, string PropertyName, string PropertyType, string ElementType, bool IsOverride, bool IsNullable, string KindName)>? Slots); + record AstNodeAdditions(string NodeName, bool NeedsAcceptImpls, bool NeedsVisitor, bool NeedsNullNode, bool NeedsPatternPlaceholder, int NullNodeBaseCtorParamCount, bool IsTypeNode, string VisitMethodName, string VisitMethodParamType, EquatableArray<(string Member, string TypeName, bool RecursiveMatch, bool MatchAny, bool Nullable)>? MembersToMatch, EquatableArray<(string RoleExpr, bool IsCollection, string PropertyName, string PropertyType, string ElementType, bool IsOverride, bool IsNullable, string KindName, bool IsPartial)>? Slots, EquatableArray<(string StringName, string TokenName, bool NullOnEmpty)>? NameSlots); // Derives the shared SlotKind name from a [Slot] role expression: the last dotted segment with a // trailing "Role" removed (e.g. "Roles.EmbeddedStatement" -> "EmbeddedStatement", "LeftRole" -> @@ -107,27 +107,45 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator } } - // Collect the slot schema: child properties tagged [Slot], in declaration order. The - // attribute names the Role expression to use; single vs collection comes from the type. - List<(string RoleExpr, bool IsCollection, string PropertyName, string PropertyType, string ElementType, bool IsOverride, bool IsNullable, string KindName)>? slots = null; + // Collect the slot schema: child properties tagged [Slot] or [NameSlot], in declaration order + // (the order is the node's child layout, so it must follow the source, not be grouped by kind). + // [Slot] names the Role expression and infers single vs collection from the type. [NameSlot("role")] + // string X declares only the convenience string; the generator owns the backing Identifier XToken + // child slot (emitted like a [Slot], but non-partial since the source does not declare it) plus the + // string body. DoMatch matches X (a string) and never sees XToken. + List<(string RoleExpr, bool IsCollection, string PropertyName, string PropertyType, string ElementType, bool IsOverride, bool IsNullable, string KindName, bool IsPartial)>? slots = null; + List<(string StringName, string TokenName, bool NullOnEmpty)>? nameSlots = null; foreach (var m in targetSymbol.GetMembers()) { if (m is not IPropertySymbol property) continue; var slotAttr = property.GetAttributes().FirstOrDefault(a => a.AttributeClass?.Name == "SlotAttribute"); - if (slotAttr == null) + if (slotAttr != null) + { + slots ??= new(); + string roleExpr = (string)slotAttr.ConstructorArguments[0].Value!; + bool isCollection = property.Type.MetadataName == "AstNodeCollection`1"; + bool isNullable = property.Type.NullableAnnotation == NullableAnnotation.Annotated; + var unannotated = property.Type.WithNullableAnnotation(NullableAnnotation.NotAnnotated); + string propertyType = unannotated.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); + // For a collection slot, the element type is the single type argument of AstNodeCollection. + string elementType = isCollection + ? ((INamedTypeSymbol)property.Type).TypeArguments[0].ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) + : propertyType; + slots.Add((roleExpr, isCollection, property.Name, propertyType, elementType, property.IsOverride, isNullable, SlotKindName(roleExpr), true)); continue; - slots ??= new(); - string roleExpr = (string)slotAttr.ConstructorArguments[0].Value!; - bool isCollection = property.Type.MetadataName == "AstNodeCollection`1"; - bool isNullable = property.Type.NullableAnnotation == NullableAnnotation.Annotated; - var unannotated = property.Type.WithNullableAnnotation(NullableAnnotation.NotAnnotated); - string propertyType = unannotated.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat); - // For a collection slot, the element type is the single type argument of AstNodeCollection. - string elementType = isCollection - ? ((INamedTypeSymbol)property.Type).TypeArguments[0].ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) - : propertyType; - slots.Add((roleExpr, isCollection, property.Name, propertyType, elementType, property.IsOverride, isNullable, SlotKindName(roleExpr))); + } + var nameSlotAttr = property.GetAttributes().FirstOrDefault(a => a.AttributeClass?.Name == "NameSlotAttribute"); + if (nameSlotAttr != null) + { + nameSlots ??= new(); + slots ??= new(); + string roleExpr = (string)nameSlotAttr.ConstructorArguments[0].Value!; + bool nullOnEmpty = nameSlotAttr.ConstructorArguments.Length > 1 && (bool)nameSlotAttr.ConstructorArguments[1].Value!; + string tokenName = property.Name + "Token"; + slots.Add((roleExpr, false, tokenName, "Identifier", "Identifier", false, false, SlotKindName(roleExpr), false)); + nameSlots.Add((property.Name, tokenName, nullOnEmpty)); + } } return new(targetSymbol.Name, !targetSymbol.MemberNames.Contains("AcceptVisitor"), @@ -136,7 +154,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator NeedsPatternPlaceholder: (bool)attribute.ConstructorArguments[1].Value!, NullNodeBaseCtorParamCount: targetSymbol.InstanceConstructors.Min(m => m.Parameters.Length), IsTypeNode: targetSymbol.Name == "AstType" || targetSymbol.BaseType?.Name == "AstType", - visitMethodName, paramTypeName, membersToMatch?.ToEquatableArray(), slots?.ToEquatableArray()); + visitMethodName, paramTypeName, membersToMatch?.ToEquatableArray(), slots?.ToEquatableArray(), nameSlots?.ToEquatableArray()); } // Backing-field name for a slot property. Prefixed to avoid colliding with hand-written fields @@ -333,18 +351,19 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator // substitutes the role's null object when empty (pre-NRT); a collection slot owns a lazily // created AstNodeCollection bound to this node. A slot re-declared from an inherited contract // member (Part I.3 flatten) is an override. - foreach (var (roleExpr, isCollection, name, type, elementType, isOverride, isNullable, kindName) in slots) + foreach (var (roleExpr, isCollection, name, type, elementType, isOverride, isNullable, kindName, isPartial) in slots) { string field = FieldName(name); + string partialKw = isPartial ? "partial " : ""; if (isCollection) { builder.AppendLine($"\tAstNodeCollection<{elementType}>? {field};"); - builder.AppendLine($"\tpublic {(isOverride ? "override " : "")}partial AstNodeCollection<{elementType}> {name} => {field} ??= new AstNodeCollection<{elementType}>(this, {roleExpr});"); + builder.AppendLine($"\tpublic {(isOverride ? "override " : "")}{partialKw}AstNodeCollection<{elementType}> {name} => {field} ??= new AstNodeCollection<{elementType}>(this, {roleExpr});"); } else { builder.AppendLine($"\t{type}? {field};"); - builder.AppendLine($"\tpublic {(isOverride ? "override " : "")}partial {type} {name}"); + builder.AppendLine($"\tpublic {(isOverride ? "override " : "")}{partialKw}{type} {name}"); builder.AppendLine("\t{"); builder.AppendLine($"\t\tget => {field}{(isNullable ? "" : $" ?? {roleExpr}.NullObject")};"); builder.AppendLine($"\t\tset => SetChildNode(ref {field}, value, {roleExpr});"); @@ -353,6 +372,23 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator builder.AppendLine(); } + // A [NameSlot] string is a convenience accessor over its generated Identifier token slot. + if (source.NameSlots is { } nameSlotsArray) + { + foreach (var (stringName, tokenName, nullOnEmpty) in nameSlotsArray) + { + builder.AppendLine($"\tpublic partial string {stringName}"); + builder.AppendLine("\t{"); + builder.AppendLine($"\t\tget => {tokenName}.Name;"); + if (nullOnEmpty) + builder.AppendLine($"\t\tset => {tokenName} = string.IsNullOrEmpty(value) ? null! : global::ICSharpCode.Decompiler.CSharp.Syntax.Identifier.Create(value);"); + else + builder.AppendLine($"\t\tset => {tokenName} = global::ICSharpCode.Decompiler.CSharp.Syntax.Identifier.Create(value);"); + builder.AppendLine("\t}"); + builder.AppendLine(); + } + } + // Flattened child-index space: slots in declaration order, a single slot occupying one index // (even when empty), a collection slot a contiguous run of its current length. builder.Append("\tinternal override int GetChildCount() => "); @@ -471,7 +507,7 @@ internal class DecompilerSyntaxTreeGenerator : IIncrementalGenerator builder.AppendLine("namespace ICSharpCode.Decompiler.CSharp.Syntax;"); source = source - .Concat([new("NullNode", false, true, false, false, 0, false, "NullNode", "AstNode", null, null), new("PatternPlaceholder", false, true, false, false, 0, false, "PatternPlaceholder", "AstNode", null, null)]) + .Concat([new("NullNode", false, true, false, false, 0, false, "NullNode", "AstNode", null, null, null), new("PatternPlaceholder", false, true, false, false, 0, false, "PatternPlaceholder", "AstNode", null, null, null)]) .ToImmutableArray(); WriteInterface("IAstVisitor", "void", ""); @@ -549,6 +585,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax { public SlotAttribute(string role) { } } + + [global::Microsoft.CodeAnalysis.EmbeddedAttribute] + [global::System.AttributeUsage(global::System.AttributeTargets.Property)] + sealed class NameSlotAttribute : global::System.Attribute + { + public NameSlotAttribute(string role, bool nullOnEmpty = false) { } + } } ")); diff --git a/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs b/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs index e455af233..d6619a7cf 100644 --- a/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs +++ b/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs @@ -1870,7 +1870,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor { StartNode(gotoStatement); WriteKeyword(GotoStatement.GotoKeywordRole); - WriteIdentifier(gotoStatement.NameToken); + WriteIdentifier(gotoStatement.LabelToken); Semicolon(); EndNode(gotoStatement); } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IdentifierExpression.cs b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IdentifierExpression.cs index b6ab3e0c2..db16890f7 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IdentifierExpression.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/IdentifierExpression.cs @@ -46,19 +46,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax SetChildByRole(Roles.Identifier, Decompiler.CSharp.Syntax.Identifier.Create(identifier, location)); } - public string Identifier { - get { - return GetChildByRole(Roles.Identifier).Name; - } - set { - SetChildByRole(Roles.Identifier, Decompiler.CSharp.Syntax.Identifier.Create(value)); - } - } - - // The Identifier string is what DoMatch compares; the token slot is excluded to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier IdentifierToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string Identifier { get; set; } [Slot("Roles.TypeArgument")] public partial AstNodeCollection TypeArguments { get; } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/MemberReferenceExpression.cs b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/MemberReferenceExpression.cs index d281de319..1097efc7e 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/MemberReferenceExpression.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/MemberReferenceExpression.cs @@ -37,19 +37,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax [Slot("Roles.TargetExpression")] public partial Expression Target { get; set; } - public string MemberName { - get { - return GetChildByRole(Roles.Identifier).Name; - } - set { - SetChildByRole(Roles.Identifier, Identifier.Create(value)); - } - } - - // DoMatch compares the MemberName string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier MemberNameToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string MemberName { get; set; } [Slot("Roles.TypeArgument")] public partial AstNodeCollection TypeArguments { get; } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/NamedArgumentExpression.cs b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/NamedArgumentExpression.cs index 1ced81192..0305b92d1 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/NamedArgumentExpression.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/NamedArgumentExpression.cs @@ -35,19 +35,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax this.Expression = expression; } - public string Name { - get { - return GetChildByRole(Roles.Identifier).Name; - } - set { - SetChildByRole(Roles.Identifier, Identifier.Create(value)); - } - } - - // DoMatch compares the Name string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier NameToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string Name { get; set; } [Slot("Roles.Expression")] public partial Expression Expression { get; set; } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/NamedExpression.cs b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/NamedExpression.cs index 1f385fa50..543c019a0 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/NamedExpression.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/NamedExpression.cs @@ -43,19 +43,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax this.Expression = expression; } - public string Name { - get { - return GetChildByRole(Roles.Identifier).Name; - } - set { - SetChildByRole(Roles.Identifier, Identifier.Create(value)); - } - } - - // DoMatch compares the Name string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier NameToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string Name { get; set; } [Slot("Roles.Expression")] public partial Expression Expression { get; set; } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/PointerReferenceExpression.cs b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/PointerReferenceExpression.cs index 8872544cb..7d5f0cf53 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/PointerReferenceExpression.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/PointerReferenceExpression.cs @@ -37,19 +37,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax [Slot("Roles.TargetExpression")] public partial Expression Target { get; set; } - public string MemberName { - get { - return GetChildByRole(Roles.Identifier).Name; - } - set { - SetChildByRole(Roles.Identifier, Identifier.Create(value)); - } - } - - // DoMatch compares the MemberName string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier MemberNameToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string MemberName { get; set; } [Slot("Roles.TypeArgument")] public partial AstNodeCollection TypeArguments { get; } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/QueryExpression.cs b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/QueryExpression.cs index 3bf5ab2e5..a79c10f84 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/QueryExpression.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/Expressions/QueryExpression.cs @@ -49,19 +49,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax [Slot("PrecedingQueryRole")] public partial QueryExpression PrecedingQuery { get; set; } - public string Identifier { - get { - return IdentifierToken.Name; - } - set { - IdentifierToken = Decompiler.CSharp.Syntax.Identifier.Create(value); - } - } - - // DoMatch compares the Identifier string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier IdentifierToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string Identifier { get; set; } } /// @@ -76,19 +65,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax [Slot("Roles.Type")] public partial AstType Type { get; set; } - public string Identifier { - get { - return IdentifierToken.Name; - } - set { - IdentifierToken = Decompiler.CSharp.Syntax.Identifier.Create(value); - } - } - - // DoMatch compares the Identifier string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier IdentifierToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string Identifier { get; set; } [Slot("Roles.Expression")] public partial Expression Expression { get; set; } @@ -102,19 +80,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax { public readonly static TokenRole LetKeywordRole = new TokenRole("let"); - public string Identifier { - get { - return IdentifierToken.Name; - } - set { - IdentifierToken = Decompiler.CSharp.Syntax.Identifier.Create(value); - } - } - - // DoMatch compares the Identifier string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier IdentifierToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string Identifier { get; set; } [Slot("Roles.Expression")] public partial Expression Expression { get; set; } @@ -166,19 +133,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax [Slot("TypeRole")] public partial AstType Type { get; set; } - public string JoinIdentifier { - get { - return JoinIdentifierToken.Name; - } - set { - JoinIdentifierToken = Identifier.Create(value); - } - } - - // DoMatch compares the JoinIdentifier string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("JoinIdentifierRole")] - public partial Identifier JoinIdentifierToken { get; set; } + [NameSlot("JoinIdentifierRole")] + public partial string JoinIdentifier { get; set; } [Slot("InExpressionRole")] public partial Expression InExpression { get; set; } @@ -189,19 +145,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax [Slot("EqualsExpressionRole")] public partial Expression EqualsExpression { get; set; } - public string IntoIdentifier { - get { - return IntoIdentifierToken.Name; - } - set { - IntoIdentifierToken = Identifier.Create(value); - } - } - - // DoMatch compares the IntoIdentifier string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("IntoIdentifierRole")] - public partial Identifier IntoIdentifierToken { get; set; } + [NameSlot("IntoIdentifierRole")] + public partial string IntoIdentifier { get; set; } } /// diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/ExternAliasDeclaration.cs b/ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/ExternAliasDeclaration.cs index fd7bed8fc..8147ee2bc 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/ExternAliasDeclaration.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/ExternAliasDeclaration.cs @@ -33,18 +33,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax public partial class ExternAliasDeclaration : AstNode { - public string Name { - get { - return GetChildByRole(Roles.Identifier).Name; - } - set { - SetChildByRole(Roles.Identifier, Identifier.Create(value)); - } - } - - // DoMatch compares the name string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier NameToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string Name { get; set; } } } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/TypeParameterDeclaration.cs b/ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/TypeParameterDeclaration.cs index d6e119e50..f9ffcc200 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/TypeParameterDeclaration.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/TypeParameterDeclaration.cs @@ -43,19 +43,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax set { variance = value; } } - public string Name { - get { - return GetChildByRole(Roles.Identifier).Name; - } - set { - SetChildByRole(Roles.Identifier, Identifier.Create(value)); - } - } - - // DoMatch compares the name string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier NameToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string Name { get; set; } public TypeParameterDeclaration() { diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/UsingAliasDeclaration.cs b/ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/UsingAliasDeclaration.cs index b501a0480..772206fb8 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/UsingAliasDeclaration.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/UsingAliasDeclaration.cs @@ -36,19 +36,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax public static readonly Role AliasRole = new Role("Alias", Identifier.Null); public static readonly Role ImportRole = UsingDeclaration.ImportRole; - public string Alias { - get { - return AliasToken.Name; - } - set { - AliasToken = Identifier.Create(value); - } - } - - // DoMatch compares the name string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("AliasRole")] - public partial Identifier AliasToken { get; set; } + [NameSlot("AliasRole")] + public partial string Alias { get; set; } [Slot("ImportRole")] public partial AstType Import { get; set; } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/MemberType.cs b/ICSharpCode.Decompiler/CSharp/Syntax/MemberType.cs index 3ef05e0e0..1ab2c4c6b 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/MemberType.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/MemberType.cs @@ -48,19 +48,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax [Slot("TargetRole")] public partial AstType Target { get; set; } - public string MemberName { - get { - return GetChildByRole(Roles.Identifier).Name; - } - set { - SetChildByRole(Roles.Identifier, Identifier.Create(value)); - } - } - - // DoMatch compares the name string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier MemberNameToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string MemberName { get; set; } [Slot("Roles.TypeArgument")] public partial AstNodeCollection TypeArguments { get; } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/SimpleType.cs b/ICSharpCode.Decompiler/CSharp/Syntax/SimpleType.cs index c6c100271..fd6e9ffb9 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/SimpleType.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/SimpleType.cs @@ -66,19 +66,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax { } - public string Identifier { - get { - return GetChildByRole(Roles.Identifier).Name; - } - set { - SetChildByRole(Roles.Identifier, Syntax.Identifier.Create(value)); - } - } - - // DoMatch compares the name string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier IdentifierToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string Identifier { get; set; } [Slot("Roles.TypeArgument")] public partial AstNodeCollection TypeArguments { get; } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/Statements/GotoStatement.cs b/ICSharpCode.Decompiler/CSharp/Syntax/Statements/GotoStatement.cs index 14674968c..71d1a1d08 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/Statements/GotoStatement.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/Statements/GotoStatement.cs @@ -43,22 +43,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax this.Label = label; } - public string Label { - get { - return NameToken.Name; - } - set { - if (string.IsNullOrEmpty(value)) - NameToken = null; - else - NameToken = Identifier.Create(value); - } - } - - // DoMatch compares the name string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier NameToken { get; set; } + [NameSlot("Roles.Identifier", nullOnEmpty: true)] + public partial string Label { get; set; } } /// diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/Statements/LabelStatement.cs b/ICSharpCode.Decompiler/CSharp/Syntax/Statements/LabelStatement.cs index 9824a35d6..b794579a9 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/Statements/LabelStatement.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/Statements/LabelStatement.cs @@ -32,18 +32,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax [DecompilerAstNode(hasNullNode: false)] public partial class LabelStatement : Statement { - public string Label { - get { - return GetChildByRole(Roles.Identifier).Name; - } - set { - SetChildByRole(Roles.Identifier, Identifier.Create(value)); - } - } - - // DoMatch compares the name string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier LabelToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string Label { get; set; } } } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/Statements/TryCatchStatement.cs b/ICSharpCode.Decompiler/CSharp/Syntax/Statements/TryCatchStatement.cs index 5d249343d..a46a703cc 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/Statements/TryCatchStatement.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/Statements/TryCatchStatement.cs @@ -63,20 +63,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax [Slot("Roles.Type")] public partial AstType Type { get; set; } - public string VariableName { - get { return GetChildByRole(Roles.Identifier).Name; } - set { - if (string.IsNullOrEmpty(value)) - SetChildByRole(Roles.Identifier, null); - else - SetChildByRole(Roles.Identifier, Identifier.Create(value)); - } - } - - // DoMatch compares the name string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier VariableNameToken { get; set; } + [NameSlot("Roles.Identifier", nullOnEmpty: true)] + public partial string VariableName { get; set; } [Slot("ConditionRole")] public partial Expression Condition { get; set; } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TupleAstType.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TupleAstType.cs index d1e1be331..19fea03ae 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TupleAstType.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TupleAstType.cs @@ -39,15 +39,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax [Slot("Roles.Type")] public partial AstType Type { get; set; } - public string Name { - get { return GetChildByRole(Roles.Identifier).Name; } - set { SetChildByRole(Roles.Identifier, Identifier.Create(value)); } - } - - // DoMatch compares the name string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier NameToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string Name { get; set; } } } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/FixedVariableInitializer.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/FixedVariableInitializer.cs index 90c74ceaa..086dfbde8 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/FixedVariableInitializer.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/FixedVariableInitializer.cs @@ -43,19 +43,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax this.CountExpression = initializer; } - public string Name { - get { - return GetChildByRole(Roles.Identifier).Name; - } - set { - SetChildByRole(Roles.Identifier, Identifier.Create(value)); - } - } - - // DoMatch compares the Name string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier NameToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string Name { get; set; } [Slot("Roles.Expression")] public partial Expression CountExpression { get; set; } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/ParameterDeclaration.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/ParameterDeclaration.cs index da9d6176d..a8feea53c 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/ParameterDeclaration.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/ParameterDeclaration.cs @@ -86,19 +86,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax [Slot("Roles.Type")] public partial AstType Type { get; set; } - public string Name { - get { - return GetChildByRole(Roles.Identifier).Name; - } - set { - SetChildByRole(Roles.Identifier, Identifier.Create(value)); - } - } - - // DoMatch compares the Name string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier NameToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string Name { get; set; } [Slot("Roles.Expression")] public partial Expression DefaultExpression { get; set; } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/VariableInitializer.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/VariableInitializer.cs index f1056817f..890f19f02 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/VariableInitializer.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/VariableInitializer.cs @@ -43,19 +43,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax this.Initializer = initializer; } - public string Name { - get { - return GetChildByRole(Roles.Identifier).Name; - } - set { - SetChildByRole(Roles.Identifier, Identifier.Create(value)); - } - } - - // DoMatch compares the Name string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier NameToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string Name { get; set; } [Slot("Roles.Expression")] public partial Expression Initializer { get; set; } diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/VariableDesignation.cs b/ICSharpCode.Decompiler/CSharp/Syntax/VariableDesignation.cs index e60b966f5..504d263b9 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/VariableDesignation.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/VariableDesignation.cs @@ -29,15 +29,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax [DecompilerAstNode(hasNullNode: false)] public partial class SingleVariableDesignation : VariableDesignation { - public string Identifier { - get { return GetChildByRole(Roles.Identifier).Name; } - set { SetChildByRole(Roles.Identifier, Syntax.Identifier.Create(value)); } - } - - // DoMatch compares the name string; exclude the token slot to avoid matching it twice. - [ExcludeFromMatch] - [Slot("Roles.Identifier")] - public partial Identifier IdentifierToken { get; set; } + [NameSlot("Roles.Identifier")] + public partial string Identifier { get; set; } } ///