Browse Source

Drop dead IFreezable/Freeze apparatus from the C# AST

The C# AST inherited NRefactory's freezable model (IFreezable, Freeze,
IsFrozen, a frozen flag bit, and ThrowIfFrozen guards on every mutator),
but the decompiler never uses it: nothing calls Freeze(), not even the
generated null-node singletons, so every IsFrozen guard only ever
evaluated false. The decompiler is single-threaded and never shares or
freezes nodes. Remove the whole apparatus as preparation for the
slot-based AST rewrite, which has no place for it. Roles are untouched
here, so the flags word keeps its role index; only the freed frozen bit
goes away.
pull/3807/head
Siegfried Pammer 2 weeks ago committed by Siegfried Pammer
parent
commit
1f738677c6
  1. 48
      ICSharpCode.Decompiler/CSharp/Syntax/AstNode.cs
  2. 1
      ICSharpCode.Decompiler/CSharp/Syntax/CSharpModifierToken.cs
  3. 3
      ICSharpCode.Decompiler/CSharp/Syntax/DocumentationReference.cs
  4. 4
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/AnonymousMethodExpression.cs
  5. 2
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/LambdaExpression.cs
  6. 1
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/NullReferenceExpression.cs
  7. 3
      ICSharpCode.Decompiler/CSharp/Syntax/Expressions/PrimitiveExpression.cs
  8. 8
      ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/Comment.cs
  9. 1
      ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/TypeDeclaration.cs
  10. 2
      ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/TypeParameterDeclaration.cs
  11. 3
      ICSharpCode.Decompiler/CSharp/Syntax/Identifier.cs
  12. 1
      ICSharpCode.Decompiler/CSharp/Syntax/MemberType.cs
  13. 2
      ICSharpCode.Decompiler/CSharp/Syntax/PrimitiveType.cs
  14. 1
      ICSharpCode.Decompiler/CSharp/Syntax/SyntaxTree.cs
  15. 1
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/OperatorDeclaration.cs
  16. 4
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/ParameterDeclaration.cs

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

@ -37,7 +37,7 @@ using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Syntax namespace ICSharpCode.Decompiler.CSharp.Syntax
{ {
public abstract class AstNode : AbstractAnnotatable, IFreezable, INode, ICloneable public abstract partial class AstNode : AbstractAnnotatable, INode, ICloneable
{ {
// the Root role must be available when creating the null nodes, so we can't put it in the Roles class // 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); internal static readonly Role<AstNode?> RootRole = new Role<AstNode?>("Root", null);
@ -135,40 +135,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
// Flags, from least significant to most significant bits: // Flags, from least significant to most significant bits:
// - Role.RoleIndexBits: role index // - Role.RoleIndexBits: role index
// - 1 bit: IsFrozen
protected uint flags = RootRole.Index; protected uint flags = RootRole.Index;
// Derived classes may also use a few bits, // Derived classes may also use a few bits,
// for example Identifier uses 1 bit for IsVerbatim // for example Identifier uses 1 bit for IsVerbatim
const uint roleIndexMask = (1u << Role.RoleIndexBits) - 1; const uint roleIndexMask = (1u << Role.RoleIndexBits) - 1;
const uint frozenBit = 1u << Role.RoleIndexBits; protected const int AstNodeFlagsUsedBits = Role.RoleIndexBits;
protected const int AstNodeFlagsUsedBits = Role.RoleIndexBits + 1;
protected AstNode()
{
if (IsNull)
Freeze();
}
public bool IsFrozen {
get { return (flags & frozenBit) != 0; }
}
public void Freeze()
{
if (!IsFrozen)
{
for (AstNode? child = firstChild; child != null; child = child.nextSibling)
child.Freeze();
flags |= frozenBit;
}
}
protected void ThrowIfFrozen()
{
if (IsFrozen)
throw new InvalidOperationException("Cannot mutate frozen " + GetType().Name);
}
public abstract NodeType NodeType { public abstract NodeType NodeType {
get; get;
@ -211,7 +183,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
throw new ArgumentNullException(nameof(value)); throw new ArgumentNullException(nameof(value));
if (!value.IsValid(this)) if (!value.IsValid(this))
throw new ArgumentException("This node is not valid in the new role."); throw new ArgumentException("This node is not valid in the new role.");
ThrowIfFrozen();
SetRole(value); SetRole(value);
} }
} }
@ -382,13 +353,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
throw new ArgumentNullException(nameof(role)); throw new ArgumentNullException(nameof(role));
if (child == null || child.IsNull) if (child == null || child.IsNull)
return; return;
ThrowIfFrozen();
if (child == this) if (child == this)
throw new ArgumentException("Cannot add a node to itself as a child.", nameof(child)); throw new ArgumentException("Cannot add a node to itself as a child.", nameof(child));
if (child.parent != null) if (child.parent != null)
throw new ArgumentException("Node is already used in another tree.", nameof(child)); throw new ArgumentException("Node is already used in another tree.", nameof(child));
if (child.IsFrozen)
throw new ArgumentException("Cannot add a frozen node.", nameof(child));
AddChildUnsafe(child, role); AddChildUnsafe(child, role);
} }
@ -396,13 +364,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{ {
if (child == null || child.IsNull) if (child == null || child.IsNull)
return; return;
ThrowIfFrozen();
if (child == this) if (child == this)
throw new ArgumentException("Cannot add a node to itself as a child.", nameof(child)); throw new ArgumentException("Cannot add a node to itself as a child.", nameof(child));
if (child.parent != null) if (child.parent != null)
throw new ArgumentException("Node is already used in another tree.", nameof(child)); throw new ArgumentException("Node is already used in another tree.", nameof(child));
if (child.IsFrozen)
throw new ArgumentException("Cannot add a frozen node.", nameof(child));
AddChildUnsafe(child, child.Role); AddChildUnsafe(child, child.Role);
} }
@ -437,11 +402,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
if (child == null || child.IsNull) if (child == null || child.IsNull)
return; return;
ThrowIfFrozen();
if (child.parent != null) if (child.parent != null)
throw new ArgumentException("Node is already used in another tree.", nameof(child)); throw new ArgumentException("Node is already used in another tree.", nameof(child));
if (child.IsFrozen)
throw new ArgumentException("Cannot add a frozen node.", nameof(child));
if (nextSibling.parent != this) if (nextSibling.parent != this)
throw new ArgumentException("NextSibling is not a child of this node.", nameof(nextSibling)); throw new ArgumentException("NextSibling is not a child of this node.", nameof(nextSibling));
// No need to test for "Cannot add children to null nodes", // No need to test for "Cannot add children to null nodes",
@ -481,7 +443,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{ {
if (parent != null) if (parent != null)
{ {
ThrowIfFrozen();
if (prevSibling != null) if (prevSibling != null)
{ {
Debug.Assert(prevSibling.nextSibling == this); Debug.Assert(prevSibling.nextSibling == this);
@ -524,7 +485,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{ {
throw new InvalidOperationException(this.IsNull ? "Cannot replace the null nodes" : "Cannot replace the root node"); throw new InvalidOperationException(this.IsNull ? "Cannot replace the null nodes" : "Cannot replace the root node");
} }
ThrowIfFrozen();
// Because this method doesn't statically check the new node's type with the role, // Because this method doesn't statically check the new node's type with the role,
// we perform a runtime test: // we perform a runtime test:
if (!this.Role.IsValid(newNode)) if (!this.Role.IsValid(newNode))
@ -545,9 +505,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
throw new ArgumentException("Node is already used in another tree.", nameof(newNode)); throw new ArgumentException("Node is already used in another tree.", nameof(newNode));
} }
} }
if (newNode.IsFrozen)
throw new ArgumentException("Cannot add a frozen node.", nameof(newNode));
newNode.parent = parent; newNode.parent = parent;
newNode.SetRole(this.Role); newNode.SetRole(this.Role);
newNode.prevSibling = prevSibling; newNode.prevSibling = prevSibling;
@ -623,7 +580,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
copy.lastChild = null; copy.lastChild = null;
copy.prevSibling = null; copy.prevSibling = null;
copy.nextSibling = null; copy.nextSibling = null;
copy.flags &= ~frozenBit; // unfreeze the copy
// Then perform a deep copy: // Then perform a deep copy:
for (AstNode? cur = firstChild; cur != null; cur = cur.nextSibling) for (AstNode? cur = firstChild; cur != null; cur = cur.nextSibling)

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

@ -38,7 +38,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public Modifiers Modifier { public Modifiers Modifier {
get { return modifier; } get { return modifier; }
set { set {
ThrowIfFrozen();
this.modifier = value; this.modifier = value;
} }
} }

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

@ -43,7 +43,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public SymbolKind SymbolKind { public SymbolKind SymbolKind {
get { return symbolKind; } get { return symbolKind; }
set { set {
ThrowIfFrozen();
symbolKind = value; symbolKind = value;
} }
} }
@ -55,7 +54,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public OperatorType OperatorType { public OperatorType OperatorType {
get { return operatorType; } get { return operatorType; }
set { set {
ThrowIfFrozen();
operatorType = value; operatorType = value;
} }
} }
@ -66,7 +64,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public bool HasParameterList { public bool HasParameterList {
get { return hasParameterList; } get { return hasParameterList; }
set { set {
ThrowIfFrozen();
hasParameterList = value; hasParameterList = value;
} }
} }

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

@ -41,7 +41,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public bool IsAsync { public bool IsAsync {
get { return isAsync; } get { return isAsync; }
set { ThrowIfFrozen(); isAsync = value; } set { isAsync = value; }
} }
// used to tell the difference between delegate {} and delegate () {} // used to tell the difference between delegate {} and delegate () {}
@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public bool HasParameterList { public bool HasParameterList {
get { return hasParameterList || Parameters.Any(); } get { return hasParameterList || Parameters.Any(); }
set { ThrowIfFrozen(); hasParameterList = value; } set { hasParameterList = value; }
} }
public CSharpTokenNode DelegateToken { public CSharpTokenNode DelegateToken {

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

@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public bool IsAsync { public bool IsAsync {
get { return isAsync; } get { return isAsync; }
set { ThrowIfFrozen(); isAsync = value; } set { isAsync = value; }
} }
public CSharpTokenNode LParToken { public CSharpTokenNode LParToken {

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

@ -40,7 +40,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
internal void SetStartLocation(TextLocation value) internal void SetStartLocation(TextLocation value)
{ {
ThrowIfFrozen();
this.location = value; this.location = value;
} }

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

@ -57,7 +57,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
internal void SetLocation(TextLocation startLocation, TextLocation endLocation) internal void SetLocation(TextLocation startLocation, TextLocation endLocation)
{ {
ThrowIfFrozen();
this.startLocation = startLocation; this.startLocation = startLocation;
this.endLocation = endLocation; this.endLocation = endLocation;
} }
@ -68,7 +67,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public object Value { public object Value {
get { return this.value; } get { return this.value; }
set { set {
ThrowIfFrozen();
this.value = value; this.value = value;
} }
} }
@ -76,7 +74,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public LiteralFormat Format { public LiteralFormat Format {
get { return format; } get { return format; }
set { set {
ThrowIfFrozen();
format = value; format = value;
} }
} }

8
ICSharpCode.Decompiler/CSharp/Syntax/GeneralScope/Comment.cs

@ -62,7 +62,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public CommentType CommentType { public CommentType CommentType {
get { return commentType; } get { return commentType; }
set { ThrowIfFrozen(); commentType = value; } set { commentType = value; }
} }
/// <summary> /// <summary>
@ -78,14 +78,14 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public bool StartsLine { public bool StartsLine {
get { return startsLine; } get { return startsLine; }
set { ThrowIfFrozen(); startsLine = value; } set { startsLine = value; }
} }
string content; string content;
public string Content { public string Content {
get { return content; } get { return content; }
set { ThrowIfFrozen(); content = value; } set { content = value; }
} }
TextLocation startLocation; TextLocation startLocation;
@ -104,13 +104,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
internal void SetStartLocation(TextLocation value) internal void SetStartLocation(TextLocation value)
{ {
ThrowIfFrozen();
this.startLocation = value; this.startLocation = value;
} }
internal void SetEndLocation(TextLocation value) internal void SetEndLocation(TextLocation value)
{ {
ThrowIfFrozen();
this.endLocation = value; this.endLocation = value;
} }

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

@ -83,7 +83,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public ClassType ClassType { public ClassType ClassType {
get { return classType; } get { return classType; }
set { set {
ThrowIfFrozen();
classType = value; classType = value;
} }
} }

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

@ -45,7 +45,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public VarianceModifier Variance { public VarianceModifier Variance {
get { return variance; } get { return variance; }
set { ThrowIfFrozen(); variance = value; } set { variance = value; }
} }
public CSharpTokenNode VarianceToken { public CSharpTokenNode VarianceToken {

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

@ -72,7 +72,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
set { set {
if (value == null) if (value == null)
throw new ArgumentNullException(nameof(value)); throw new ArgumentNullException(nameof(value));
ThrowIfFrozen();
this.name = value; this.name = value;
} }
} }
@ -86,7 +85,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
internal void SetStartLocation(TextLocation value) internal void SetStartLocation(TextLocation value)
{ {
ThrowIfFrozen();
this.startLocation = value; this.startLocation = value;
} }
@ -97,7 +95,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return (flags & verbatimBit) != 0; return (flags & verbatimBit) != 0;
} }
set { set {
ThrowIfFrozen();
if (value) if (value)
flags |= verbatimBit; flags |= verbatimBit;
else else

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

@ -37,7 +37,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public bool IsDoubleColon { public bool IsDoubleColon {
get { return isDoubleColon; } get { return isDoubleColon; }
set { set {
ThrowIfFrozen();
isDoubleColon = value; isDoubleColon = value;
} }
} }

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

@ -41,7 +41,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
set { set {
if (value == null) if (value == null)
throw new ArgumentNullException(); throw new ArgumentNullException();
ThrowIfFrozen();
keyword = value; keyword = value;
} }
} }
@ -73,7 +72,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
internal void SetStartLocation(TextLocation value) internal void SetStartLocation(TextLocation value)
{ {
ThrowIfFrozen();
this.location = value; this.location = value;
} }

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

@ -49,7 +49,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public string FileName { public string FileName {
get { return fileName; } get { return fileName; }
set { set {
ThrowIfFrozen();
fileName = value; fileName = value;
} }
} }

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

@ -173,7 +173,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public OperatorType OperatorType { public OperatorType OperatorType {
get { return operatorType; } get { return operatorType; }
set { set {
ThrowIfFrozen();
operatorType = value; operatorType = value;
} }
} }

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

@ -110,7 +110,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public bool HasThisModifier { public bool HasThisModifier {
get { return hasThisModifier; } get { return hasThisModifier; }
set { set {
ThrowIfFrozen();
hasThisModifier = value; hasThisModifier = value;
} }
} }
@ -118,7 +117,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public bool IsParams { public bool IsParams {
get { return isParams; } get { return isParams; }
set { set {
ThrowIfFrozen();
isParams = value; isParams = value;
} }
} }
@ -126,7 +124,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public bool IsScopedRef { public bool IsScopedRef {
get { return isScopedRef; } get { return isScopedRef; }
set { set {
ThrowIfFrozen();
isScopedRef = value; isScopedRef = value;
} }
} }
@ -136,7 +133,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public ReferenceKind ParameterModifier { public ReferenceKind ParameterModifier {
get { return parameterModifier; } get { return parameterModifier; }
set { set {
ThrowIfFrozen();
parameterModifier = value; parameterModifier = value;
} }
} }

Loading…
Cancel
Save