Browse Source

Store member modifiers and composed-type specifiers as scalar fields

Member and local modifiers were stored as modifier token children, and a
ComposedType's ref/readonly/nullable/pointer specifiers and an array rank as
token and comma children. The output visitor already derived all of these
from scalar accessors, so move them to plain enum/bool/int fields. This
removes another dependency on token children ahead of deleting the token
nodes; the emitted keyword and specifier sequences are unchanged.
Assisted-by: Claude:claude-opus-4-8:Claude Code
pull/3807/head
Siegfried Pammer 3 weeks ago committed by Siegfried Pammer
parent
commit
fbfc93bb41
  1. 47
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  2. 69
      ICSharpCode.Decompiler/CSharp/Syntax/ComposedType.cs
  3. 5
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/VariableDeclarationStatement.cs
  4. 51
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/EntityDeclaration.cs

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

@ -489,12 +489,15 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
} }
} }
protected virtual void WriteModifiers(IEnumerable<CSharpModifierToken> modifierTokens) protected virtual void WriteModifiers(Modifiers modifiers)
{ {
foreach (CSharpModifierToken modifier in modifierTokens) foreach (Modifiers modifier in CSharpModifierToken.AllModifiers)
{ {
modifier.AcceptVisitor(this); if ((modifiers & modifier) == modifier)
Space(); {
WriteKeyword(CSharpModifierToken.GetModifierName(modifier), EntityDeclaration.ModifierRole);
Space();
}
} }
} }
@ -1556,7 +1559,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(delegateDeclaration); StartNode(delegateDeclaration);
WriteAttributes(delegateDeclaration.Attributes); WriteAttributes(delegateDeclaration.Attributes);
WriteModifiers(delegateDeclaration.ModifierTokens); WriteModifiers(delegateDeclaration.Modifiers);
WriteKeyword(Roles.DelegateKeyword); WriteKeyword(Roles.DelegateKeyword);
delegateDeclaration.ReturnType.AcceptVisitor(this); delegateDeclaration.ReturnType.AcceptVisitor(this);
Space(); Space();
@ -1604,7 +1607,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(typeDeclaration); StartNode(typeDeclaration);
WriteAttributes(typeDeclaration.Attributes); WriteAttributes(typeDeclaration.Attributes);
WriteModifiers(typeDeclaration.ModifierTokens); WriteModifiers(typeDeclaration.Modifiers);
BraceStyle braceStyle; BraceStyle braceStyle;
switch (typeDeclaration.ClassType) switch (typeDeclaration.ClassType)
{ {
@ -2250,7 +2253,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
public virtual void VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement) public virtual void VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement)
{ {
StartNode(variableDeclarationStatement); StartNode(variableDeclarationStatement);
WriteModifiers(variableDeclarationStatement.GetChildrenByRole(VariableDeclarationStatement.ModifierRole)); WriteModifiers(variableDeclarationStatement.Modifiers);
variableDeclarationStatement.Type.AcceptVisitor(this); variableDeclarationStatement.Type.AcceptVisitor(this);
Space(); Space();
WriteCommaSeparatedList(variableDeclarationStatement.Variables); WriteCommaSeparatedList(variableDeclarationStatement.Variables);
@ -2306,7 +2309,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(accessor); StartNode(accessor);
WriteAttributes(accessor.Attributes); WriteAttributes(accessor.Attributes);
WriteModifiers(accessor.ModifierTokens); WriteModifiers(accessor.Modifiers);
BraceStyle style = policy.StatementBraceStyle; BraceStyle style = policy.StatementBraceStyle;
if (accessor.Role == PropertyDeclaration.GetterRole) if (accessor.Role == PropertyDeclaration.GetterRole)
{ {
@ -2343,7 +2346,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(constructorDeclaration); StartNode(constructorDeclaration);
WriteAttributes(constructorDeclaration.Attributes); WriteAttributes(constructorDeclaration.Attributes);
WriteModifiers(constructorDeclaration.ModifierTokens); WriteModifiers(constructorDeclaration.Modifiers);
TypeDeclaration type = constructorDeclaration.Parent as TypeDeclaration; TypeDeclaration type = constructorDeclaration.Parent as TypeDeclaration;
if (type != null && type.Name != constructorDeclaration.Name) if (type != null && type.Name != constructorDeclaration.Name)
WriteIdentifier((Identifier)type.NameToken.Clone()); WriteIdentifier((Identifier)type.NameToken.Clone());
@ -2384,8 +2387,8 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(destructorDeclaration); StartNode(destructorDeclaration);
WriteAttributes(destructorDeclaration.Attributes); WriteAttributes(destructorDeclaration.Attributes);
WriteModifiers(destructorDeclaration.ModifierTokens); WriteModifiers(destructorDeclaration.Modifiers);
if (destructorDeclaration.ModifierTokens.Any()) if (destructorDeclaration.Modifiers != Modifiers.None)
{ {
Space(); Space();
} }
@ -2406,7 +2409,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(enumMemberDeclaration); StartNode(enumMemberDeclaration);
WriteAttributes(enumMemberDeclaration.Attributes); WriteAttributes(enumMemberDeclaration.Attributes);
WriteModifiers(enumMemberDeclaration.ModifierTokens); WriteModifiers(enumMemberDeclaration.Modifiers);
WriteIdentifier(enumMemberDeclaration.NameToken); WriteIdentifier(enumMemberDeclaration.NameToken);
if (!enumMemberDeclaration.Initializer.IsNull) if (!enumMemberDeclaration.Initializer.IsNull)
{ {
@ -2422,7 +2425,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(extensionDeclaration); StartNode(extensionDeclaration);
WriteAttributes(extensionDeclaration.Attributes); WriteAttributes(extensionDeclaration.Attributes);
WriteModifiers(extensionDeclaration.ModifierTokens); WriteModifiers(extensionDeclaration.Modifiers);
WriteKeyword(ExtensionDeclaration.ExtensionKeywordRole); WriteKeyword(ExtensionDeclaration.ExtensionKeywordRole);
WriteTypeParameters(extensionDeclaration.TypeParameters); WriteTypeParameters(extensionDeclaration.TypeParameters);
Space(policy.SpaceBeforeMethodDeclarationParentheses); Space(policy.SpaceBeforeMethodDeclarationParentheses);
@ -2452,7 +2455,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(eventDeclaration); StartNode(eventDeclaration);
WriteAttributes(eventDeclaration.Attributes); WriteAttributes(eventDeclaration.Attributes);
WriteModifiers(eventDeclaration.ModifierTokens); WriteModifiers(eventDeclaration.Modifiers);
WriteKeyword(EventDeclaration.EventKeywordRole); WriteKeyword(EventDeclaration.EventKeywordRole);
eventDeclaration.ReturnType.AcceptVisitor(this); eventDeclaration.ReturnType.AcceptVisitor(this);
Space(); Space();
@ -2465,7 +2468,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(customEventDeclaration); StartNode(customEventDeclaration);
WriteAttributes(customEventDeclaration.Attributes); WriteAttributes(customEventDeclaration.Attributes);
WriteModifiers(customEventDeclaration.ModifierTokens); WriteModifiers(customEventDeclaration.Modifiers);
WriteKeyword(CustomEventDeclaration.EventKeywordRole); WriteKeyword(CustomEventDeclaration.EventKeywordRole);
customEventDeclaration.ReturnType.AcceptVisitor(this); customEventDeclaration.ReturnType.AcceptVisitor(this);
Space(); Space();
@ -2489,7 +2492,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(fieldDeclaration); StartNode(fieldDeclaration);
WriteAttributes(fieldDeclaration.Attributes); WriteAttributes(fieldDeclaration.Attributes);
WriteModifiers(fieldDeclaration.ModifierTokens); WriteModifiers(fieldDeclaration.Modifiers);
fieldDeclaration.ReturnType.AcceptVisitor(this); fieldDeclaration.ReturnType.AcceptVisitor(this);
Space(); Space();
WriteCommaSeparatedList(fieldDeclaration.Variables); WriteCommaSeparatedList(fieldDeclaration.Variables);
@ -2501,7 +2504,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(fixedFieldDeclaration); StartNode(fixedFieldDeclaration);
WriteAttributes(fixedFieldDeclaration.Attributes); WriteAttributes(fixedFieldDeclaration.Attributes);
WriteModifiers(fixedFieldDeclaration.ModifierTokens); WriteModifiers(fixedFieldDeclaration.Modifiers);
WriteKeyword(FixedFieldDeclaration.FixedKeywordRole); WriteKeyword(FixedFieldDeclaration.FixedKeywordRole);
Space(); Space();
fixedFieldDeclaration.ReturnType.AcceptVisitor(this); fixedFieldDeclaration.ReturnType.AcceptVisitor(this);
@ -2530,7 +2533,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(indexerDeclaration); StartNode(indexerDeclaration);
WriteAttributes(indexerDeclaration.Attributes); WriteAttributes(indexerDeclaration.Attributes);
WriteModifiers(indexerDeclaration.ModifierTokens); WriteModifiers(indexerDeclaration.Modifiers);
indexerDeclaration.ReturnType.AcceptVisitor(this); indexerDeclaration.ReturnType.AcceptVisitor(this);
Space(); Space();
WritePrivateImplementationType(indexerDeclaration.PrivateImplementationType); WritePrivateImplementationType(indexerDeclaration.PrivateImplementationType);
@ -2575,7 +2578,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(methodDeclaration); StartNode(methodDeclaration);
WriteAttributes(methodDeclaration.Attributes); WriteAttributes(methodDeclaration.Attributes);
WriteModifiers(methodDeclaration.ModifierTokens); WriteModifiers(methodDeclaration.Modifiers);
methodDeclaration.ReturnType.AcceptVisitor(this); methodDeclaration.ReturnType.AcceptVisitor(this);
Space(); Space();
WritePrivateImplementationType(methodDeclaration.PrivateImplementationType); WritePrivateImplementationType(methodDeclaration.PrivateImplementationType);
@ -2595,7 +2598,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(operatorDeclaration); StartNode(operatorDeclaration);
WriteAttributes(operatorDeclaration.Attributes); WriteAttributes(operatorDeclaration.Attributes);
WriteModifiers(operatorDeclaration.ModifierTokens); WriteModifiers(operatorDeclaration.Modifiers);
if (operatorDeclaration.OperatorType == OperatorType.Explicit || operatorDeclaration.OperatorType == OperatorType.CheckedExplicit) if (operatorDeclaration.OperatorType == OperatorType.Explicit || operatorDeclaration.OperatorType == OperatorType.CheckedExplicit)
{ {
WriteKeyword(OperatorDeclaration.ExplicitRole); WriteKeyword(OperatorDeclaration.ExplicitRole);
@ -2695,7 +2698,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(propertyDeclaration); StartNode(propertyDeclaration);
WriteAttributes(propertyDeclaration.Attributes); WriteAttributes(propertyDeclaration.Attributes);
WriteModifiers(propertyDeclaration.ModifierTokens); WriteModifiers(propertyDeclaration.Modifiers);
propertyDeclaration.ReturnType.AcceptVisitor(this); propertyDeclaration.ReturnType.AcceptVisitor(this);
Space(); Space();
WritePrivateImplementationType(propertyDeclaration.PrivateImplementationType); WritePrivateImplementationType(propertyDeclaration.PrivateImplementationType);
@ -2901,7 +2904,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
StartNode(arraySpecifier); StartNode(arraySpecifier);
WriteToken(Roles.LBracket); WriteToken(Roles.LBracket);
foreach (var comma in arraySpecifier.GetChildrenByRole(Roles.Comma)) for (int i = 0; i < arraySpecifier.Dimensions - 1; i++)
{ {
writer.WriteToken(Roles.Comma, ","); writer.WriteToken(Roles.Comma, ",");
} }

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

@ -50,40 +50,19 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// This is used for C# 7 ref locals/ref return. /// This is used for C# 7 ref locals/ref return.
/// Parameters use ParameterDeclaration.ParameterModifier instead. /// Parameters use ParameterDeclaration.ParameterModifier instead.
/// </summary> /// </summary>
public bool HasRefSpecifier { public bool HasRefSpecifier { get; set; }
get {
return !GetChildByRole(RefRole).IsNull;
}
set {
SetChildByRole(RefRole, value ? new CSharpTokenNode(TextLocation.Empty, null) : null);
}
}
/// <summary> /// <summary>
/// Gets/sets whether this type has a 'readonly' specifier. /// Gets/sets whether this type has a 'readonly' specifier.
/// This is used for C# 7.2 'ref readonly' locals/ref return. /// This is used for C# 7.2 'ref readonly' locals/ref return.
/// Parameters use ParameterDeclaration.ParameterModifier instead. /// Parameters use ParameterDeclaration.ParameterModifier instead.
/// </summary> /// </summary>
public bool HasReadOnlySpecifier { public bool HasReadOnlySpecifier { get; set; }
get {
return !GetChildByRole(ReadonlyRole).IsNull;
}
set {
SetChildByRole(ReadonlyRole, value ? new CSharpTokenNode(TextLocation.Empty, null) : null);
}
}
[Slot("Roles.Type")] [Slot("Roles.Type")]
public partial AstType BaseType { get; set; } public partial AstType BaseType { get; set; }
public bool HasNullableSpecifier { public bool HasNullableSpecifier { get; set; }
get {
return !GetChildByRole(NullableRole).IsNull;
}
set {
SetChildByRole(NullableRole, value ? new CSharpTokenNode(TextLocation.Empty, null) : null);
}
}
public bool HasOnlyNullableSpecifier { public bool HasOnlyNullableSpecifier {
get { get {
@ -91,39 +70,22 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
} }
} }
public CSharpTokenNode NullableSpecifierToken { int pointerRank;
get {
return GetChildByRole(NullableRole);
}
}
public int PointerRank { public int PointerRank {
get { get {
return GetChildrenByRole(PointerRole).Count; return pointerRank;
} }
set { set {
if (value < 0) if (value < 0)
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException(nameof(value));
int d = this.PointerRank; pointerRank = value;
while (d > value)
{
GetChildByRole(PointerRole).Remove();
d--;
}
while (d < value)
{
InsertChildBefore(GetChildByRole(PointerRole), new CSharpTokenNode(TextLocation.Empty, PointerRole), PointerRole);
d++;
}
} }
} }
[Slot("ArraySpecifierRole")] [Slot("ArraySpecifierRole")]
public partial AstNodeCollection<ArraySpecifier> ArraySpecifiers { get; } public partial AstNodeCollection<ArraySpecifier> ArraySpecifiers { get; }
[Slot("PointerRole")]
public partial AstNodeCollection<CSharpTokenNode> PointerTokens { get; }
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{ {
ComposedType o = other as ComposedType; ComposedType o = other as ComposedType;
@ -207,22 +169,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
get { return GetChildByRole(Roles.LBracket); } get { return GetChildByRole(Roles.LBracket); }
} }
public int Dimensions { public int Dimensions { get; set; } = 1;
get { return 1 + GetChildrenByRole(Roles.Comma).Count; }
set {
int d = this.Dimensions;
while (d > value)
{
GetChildByRole(Roles.Comma).Remove();
d--;
}
while (d < value)
{
InsertChildBefore(GetChildByRole(Roles.Comma), new CSharpTokenNode(TextLocation.Empty, Roles.Comma), Roles.Comma);
d++;
}
}
}
public CSharpTokenNode RBracketToken { public CSharpTokenNode RBracketToken {
get { return GetChildByRole(Roles.RBracket); } get { return GetChildByRole(Roles.RBracket); }

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

@ -41,10 +41,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
this.Variables.Add(new VariableInitializer(name, initializer)); this.Variables.Add(new VariableInitializer(name, initializer));
} }
public Modifiers Modifiers { public Modifiers Modifiers { get; set; }
get { return EntityDeclaration.GetModifiers(this); }
set { EntityDeclaration.SetModifiers(this, value); }
}
[Slot("Roles.Type")] [Slot("Roles.Type")]
public partial AstType Type { get; set; } public partial AstType Type { get; set; }

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

@ -39,20 +39,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
get { return base.GetChildrenByRole(AttributeRole); } get { return base.GetChildrenByRole(AttributeRole); }
} }
public Modifiers Modifiers { public Modifiers Modifiers { get; set; }
get { return GetModifiers(this); }
set { SetModifiers(this, value); }
}
public bool HasModifier(Modifiers mod) public bool HasModifier(Modifiers mod)
{ {
return (Modifiers & mod) == mod; return (Modifiers & mod) == mod;
} }
public IEnumerable<CSharpModifierToken> ModifierTokens {
get { return GetChildrenByRole(ModifierRole); }
}
public virtual string Name { public virtual string Name {
get { get {
return GetChildByRole(Roles.Identifier).Name; return GetChildByRole(Roles.Identifier).Name;
@ -76,48 +69,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
get { return GetChildByRole(Roles.Semicolon); } get { return GetChildByRole(Roles.Semicolon); }
} }
internal static Modifiers GetModifiers(AstNode node)
{
Modifiers m = 0;
foreach (CSharpModifierToken t in node.GetChildrenByRole(ModifierRole))
{
m |= t.Modifier;
}
return m;
}
internal static void SetModifiers(AstNode node, Modifiers newValue)
{
Modifiers oldValue = GetModifiers(node);
AstNode insertionPos = node.GetChildrenByRole(AttributeRole).LastOrDefault();
foreach (Modifiers m in CSharpModifierToken.AllModifiers)
{
if ((m & newValue) != 0)
{
if ((m & oldValue) == 0)
{
// Modifier was added
var newToken = new CSharpModifierToken(TextLocation.Empty, m);
node.InsertChildAfter(insertionPos, newToken, ModifierRole);
insertionPos = newToken;
}
else
{
// Modifier already exists
insertionPos = node.GetChildrenByRole(ModifierRole).First(t => t.Modifier == m);
}
}
else
{
if ((m & oldValue) != 0)
{
// Modifier was removed
node.GetChildrenByRole(ModifierRole).First(t => t.Modifier == m).Remove();
}
}
}
}
protected bool MatchAttributesAndModifiers(EntityDeclaration o, PatternMatching.Match match) protected bool MatchAttributesAndModifiers(EntityDeclaration o, PatternMatching.Match match)
{ {
return (this.Modifiers == Modifiers.Any || this.Modifiers == o.Modifiers) && this.Attributes.DoMatch(o.Attributes, match); return (this.Modifiers == Modifiers.Any || this.Modifiers == o.Modifiers) && this.Attributes.DoMatch(o.Attributes, match);

Loading…
Cancel
Save