@ -38,10 +38,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public abstract class AstNode : AbstractAnnotatable , IFreezable , INode , ICloneable
public abstract 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
// 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" ) ;
internal static readonly Role < AstNode > RootRole = new Role < AstNode > ( "Root" ) ;
#region Null
#region Null
public static readonly AstNode Null = new NullAstNode ( ) ;
public static readonly AstNode Null = new NullAstNode ( ) ;
sealed class NullAstNode : AstNode
sealed class NullAstNode : AstNode
{
{
@ -57,22 +57,22 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
}
}
}
public override void AcceptVisitor ( IAstVisitor visitor )
public override void AcceptVisitor ( IAstVisitor visitor )
{
{
visitor . VisitNullNode ( this ) ;
visitor . VisitNullNode ( this ) ;
}
}
public override T AcceptVisitor < T > ( IAstVisitor < T > visitor )
public override T AcceptVisitor < T > ( IAstVisitor < T > visitor )
{
{
return visitor . VisitNullNode ( this ) ;
return visitor . VisitNullNode ( this ) ;
}
}
public override S AcceptVisitor < T , S > ( IAstVisitor < T , S > visitor , T data )
public override S AcceptVisitor < T , S > ( IAstVisitor < T , S > visitor , T data )
{
{
return visitor . VisitNullNode ( this , data ) ;
return visitor . VisitNullNode ( this , data ) ;
}
}
protected internal override bool DoMatch ( AstNode other , PatternMatching . Match match )
protected internal override bool DoMatch ( AstNode other , PatternMatching . Match match )
{
{
return other = = null | | other . IsNull ;
return other = = null | | other . IsNull ;
}
}
@ -80,16 +80,16 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
#endregion
#endregion
#region PatternPlaceholder
#region PatternPlaceholder
public static implicit operator AstNode ( PatternMatching . Pattern pattern )
public static implicit operator AstNode ( PatternMatching . Pattern pattern )
{
{
return pattern ! = null ? new PatternPlaceholder ( pattern ) : null ;
return pattern ! = null ? new PatternPlaceholder ( pattern ) : null ;
}
}
sealed class PatternPlaceholder : AstNode , INode
sealed class PatternPlaceholder : AstNode , INode
{
{
readonly PatternMatching . Pattern child ;
readonly PatternMatching . Pattern child ;
public PatternPlaceholder ( PatternMatching . Pattern child )
public PatternPlaceholder ( PatternMatching . Pattern child )
{
{
this . child = child ;
this . child = child ;
}
}
@ -98,29 +98,29 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
get { return NodeType . Pattern ; }
get { return NodeType . Pattern ; }
}
}
public override void AcceptVisitor ( IAstVisitor visitor )
public override void AcceptVisitor ( IAstVisitor visitor )
{
{
visitor . VisitPatternPlaceholder ( this , child ) ;
visitor . VisitPatternPlaceholder ( this , child ) ;
}
}
public override T AcceptVisitor < T > ( IAstVisitor < T > visitor )
public override T AcceptVisitor < T > ( IAstVisitor < T > visitor )
{
{
return visitor . VisitPatternPlaceholder ( this , child ) ;
return visitor . VisitPatternPlaceholder ( this , child ) ;
}
}
public override S AcceptVisitor < T , S > ( IAstVisitor < T , S > visitor , T data )
public override S AcceptVisitor < T , S > ( IAstVisitor < T , S > visitor , T data )
{
{
return visitor . VisitPatternPlaceholder ( this , child , data ) ;
return visitor . VisitPatternPlaceholder ( this , child , data ) ;
}
}
protected internal override bool DoMatch ( AstNode other , PatternMatching . Match match )
protected internal override bool DoMatch ( AstNode other , PatternMatching . Match match )
{
{
return child . DoMatch ( other , match ) ;
return child . DoMatch ( other , match ) ;
}
}
bool PatternMatching . INode . DoMatchCollection ( Role role , PatternMatching . INode pos , PatternMatching . Match match , PatternMatching . BacktrackingInfo backtrackingInfo )
bool PatternMatching . INode . DoMatchCollection ( Role role , PatternMatching . INode pos , PatternMatching . Match match , PatternMatching . BacktrackingInfo backtrackingInfo )
{
{
return child . DoMatchCollection ( role , pos , match , backtrackingInfo ) ;
return child . DoMatchCollection ( role , pos , match , backtrackingInfo ) ;
}
}
}
}
#endregion
#endregion
@ -205,7 +205,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
}
set {
set {
if ( value = = null )
if ( value = = null )
throw new ArgumentNullException ( "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 ( ) ;
ThrowIfFrozen ( ) ;
@ -248,7 +248,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
get {
get {
AstNode next ;
AstNode next ;
for ( AstNode cur = firstChild ; cur ! = null ; cur = next ) {
for ( AstNode cur = firstChild ; cur ! = null ; cur = next ) {
Debug . Assert ( cur . parent = = this ) ;
Debug . Assert ( cur . parent = = this ) ;
// Remember next before yielding cur.
// Remember next before yielding cur.
// This allows removing/replacing nodes while iterating through the list.
// This allows removing/replacing nodes while iterating through the list.
next = cur . nextSibling ;
next = cur . nextSibling ;
@ -293,12 +293,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
get { return GetDescendantsImpl ( true ) ; }
get { return GetDescendantsImpl ( true ) ; }
}
}
public IEnumerable < AstNode > DescendantNodes ( Func < AstNode , bool > descendIntoChildren = null )
public IEnumerable < AstNode > DescendantNodes ( Func < AstNode , bool > descendIntoChildren = null )
{
{
return GetDescendantsImpl ( false , descendIntoChildren ) ;
return GetDescendantsImpl ( false , descendIntoChildren ) ;
}
}
public IEnumerable < AstNode > DescendantNodesAndSelf ( Func < AstNode , bool > descendIntoChildren = null )
public IEnumerable < AstNode > DescendantNodesAndSelf ( Func < AstNode , bool > descendIntoChildren = null )
{
{
return GetDescendantsImpl ( true , descendIntoChildren ) ;
return GetDescendantsImpl ( true , descendIntoChildren ) ;
}
}
@ -335,7 +335,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public T GetChildByRole < T > ( Role < T > role ) where T : AstNode
public T GetChildByRole < T > ( Role < T > role ) where T : AstNode
{
{
if ( role = = null )
if ( role = = null )
throw new ArgumentNullException ( "role" ) ;
throw new ArgumentNullException ( nameof ( role ) ) ;
uint roleIndex = role . Index ;
uint roleIndex = role . Index ;
for ( var cur = firstChild ; cur ! = null ; cur = cur . nextSibling ) {
for ( var cur = firstChild ; cur ! = null ; cur = cur . nextSibling ) {
if ( ( cur . flags & roleIndexMask ) = = roleIndex )
if ( ( cur . flags & roleIndexMask ) = = roleIndex )
@ -354,54 +354,54 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return Ancestors . FirstOrDefault ( pred ) ;
return Ancestors . FirstOrDefault ( pred ) ;
}
}
public AstNodeCollection < T > GetChildrenByRole < T > ( Role < T > role ) where T : AstNode
public AstNodeCollection < T > GetChildrenByRole < T > ( Role < T > role ) where T : AstNode
{
{
return new AstNodeCollection < T > ( this , role ) ;
return new AstNodeCollection < T > ( this , role ) ;
}
}
protected void SetChildByRole < T > ( Role < T > role , T newChild ) where T : AstNode
protected void SetChildByRole < T > ( Role < T > role , T newChild ) where T : AstNode
{
{
AstNode oldChild = GetChildByRole ( role ) ;
AstNode oldChild = GetChildByRole ( role ) ;
if ( oldChild . IsNull )
if ( oldChild . IsNull )
AddChild ( newChild , role ) ;
AddChild ( newChild , role ) ;
else
else
oldChild . ReplaceWith ( newChild ) ;
oldChild . ReplaceWith ( newChild ) ;
}
}
public void AddChild < T > ( T child , Role < T > role ) where T : AstNode
public void AddChild < T > ( T child , Role < T > role ) where T : AstNode
{
{
if ( role = = null )
if ( role = = null )
throw new ArgumentNullException ( "role" ) ;
throw new ArgumentNullException ( nameof ( role ) ) ;
if ( child = = null | | child . IsNull )
if ( child = = null | | child . IsNull )
return ;
return ;
ThrowIfFrozen ( ) ;
ThrowIfFrozen ( ) ;
if ( child = = this )
if ( child = = this )
throw new ArgumentException ( "Cannot add a node to itself as a child." , "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." , "child" ) ;
throw new ArgumentException ( "Node is already used in another tree." , nameof ( child ) ) ;
if ( child . IsFrozen )
if ( child . IsFrozen )
throw new ArgumentException ( "Cannot add a frozen node." , "child" ) ;
throw new ArgumentException ( "Cannot add a frozen node." , nameof ( child ) ) ;
AddChildUnsafe ( child , role ) ;
AddChildUnsafe ( child , role ) ;
}
}
public void AddChildWithExistingRole ( AstNode child )
public void AddChildWithExistingRole ( AstNode child )
{
{
if ( child = = null | | child . IsNull )
if ( child = = null | | child . IsNull )
return ;
return ;
ThrowIfFrozen ( ) ;
ThrowIfFrozen ( ) ;
if ( child = = this )
if ( child = = this )
throw new ArgumentException ( "Cannot add a node to itself as a child." , "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." , "child" ) ;
throw new ArgumentException ( "Node is already used in another tree." , nameof ( child ) ) ;
if ( child . IsFrozen )
if ( child . IsFrozen )
throw new ArgumentException ( "Cannot add a frozen node." , "child" ) ;
throw new ArgumentException ( "Cannot add a frozen node." , nameof ( child ) ) ;
AddChildUnsafe ( child , child . Role ) ;
AddChildUnsafe ( child , child . Role ) ;
}
}
/// <summary>
/// <summary>
/// Adds a child without performing any safety checks.
/// Adds a child without performing any safety checks.
/// </summary>
/// </summary>
internal void AddChildUnsafe ( AstNode child , Role role )
internal void AddChildUnsafe ( AstNode child , Role role )
{
{
child . parent = this ;
child . parent = this ;
child . SetRole ( role ) ;
child . SetRole ( role ) ;
@ -414,12 +414,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
}
}
}
public void InsertChildBefore < T > ( AstNode nextSibling , T child , Role < T > role ) where T : AstNode
public void InsertChildBefore < T > ( AstNode nextSibling , T child , Role < T > role ) where T : AstNode
{
{
if ( role = = null )
if ( role = = null )
throw new ArgumentNullException ( "role" ) ;
throw new ArgumentNullException ( nameof ( role ) ) ;
if ( nextSibling = = null | | nextSibling . IsNull ) {
if ( nextSibling = = null | | nextSibling . IsNull ) {
AddChild ( child , role ) ;
AddChild ( child , role ) ;
return ;
return ;
}
}
@ -427,17 +427,17 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return ;
return ;
ThrowIfFrozen ( ) ;
ThrowIfFrozen ( ) ;
if ( child . parent ! = null )
if ( child . parent ! = null )
throw new ArgumentException ( "Node is already used in another tree." , "child" ) ;
throw new ArgumentException ( "Node is already used in another tree." , nameof ( child ) ) ;
if ( child . IsFrozen )
if ( child . IsFrozen )
throw new ArgumentException ( "Cannot add a frozen node." , "child" ) ;
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." , "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",
// as there isn't any valid nextSibling in null nodes.
// as there isn't any valid nextSibling in null nodes.
InsertChildBeforeUnsafe ( nextSibling , child , role ) ;
InsertChildBeforeUnsafe ( nextSibling , child , role ) ;
}
}
internal void InsertChildBeforeUnsafe ( AstNode nextSibling , AstNode child , Role role )
internal void InsertChildBeforeUnsafe ( AstNode nextSibling , AstNode child , Role role )
{
{
child . parent = this ;
child . parent = this ;
child . SetRole ( role ) ;
child . SetRole ( role ) ;
@ -445,39 +445,39 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
child . prevSibling = nextSibling . prevSibling ;
child . prevSibling = nextSibling . prevSibling ;
if ( nextSibling . prevSibling ! = null ) {
if ( nextSibling . prevSibling ! = null ) {
Debug . Assert ( nextSibling . prevSibling . nextSibling = = nextSibling ) ;
Debug . Assert ( nextSibling . prevSibling . nextSibling = = nextSibling ) ;
nextSibling . prevSibling . nextSibling = child ;
nextSibling . prevSibling . nextSibling = child ;
} else {
} else {
Debug . Assert ( firstChild = = nextSibling ) ;
Debug . Assert ( firstChild = = nextSibling ) ;
firstChild = child ;
firstChild = child ;
}
}
nextSibling . prevSibling = child ;
nextSibling . prevSibling = child ;
}
}
public void InsertChildAfter < T > ( AstNode prevSibling , T child , Role < T > role ) where T : AstNode
public void InsertChildAfter < T > ( AstNode prevSibling , T child , Role < T > role ) where T : AstNode
{
{
InsertChildBefore ( ( prevSibling = = null | | prevSibling . IsNull ) ? firstChild : prevSibling . nextSibling , child , role ) ;
InsertChildBefore ( ( prevSibling = = null | | prevSibling . IsNull ) ? firstChild : prevSibling . nextSibling , child , role ) ;
}
}
/// <summary>
/// <summary>
/// Removes this node from its parent.
/// Removes this node from its parent.
/// </summary>
/// </summary>
public void Remove ( )
public void Remove ( )
{
{
if ( parent ! = null ) {
if ( parent ! = null ) {
ThrowIfFrozen ( ) ;
ThrowIfFrozen ( ) ;
if ( prevSibling ! = null ) {
if ( prevSibling ! = null ) {
Debug . Assert ( prevSibling . nextSibling = = this ) ;
Debug . Assert ( prevSibling . nextSibling = = this ) ;
prevSibling . nextSibling = nextSibling ;
prevSibling . nextSibling = nextSibling ;
} else {
} else {
Debug . Assert ( parent . firstChild = = this ) ;
Debug . Assert ( parent . firstChild = = this ) ;
parent . firstChild = nextSibling ;
parent . firstChild = nextSibling ;
}
}
if ( nextSibling ! = null ) {
if ( nextSibling ! = null ) {
Debug . Assert ( nextSibling . prevSibling = = this ) ;
Debug . Assert ( nextSibling . prevSibling = = this ) ;
nextSibling . prevSibling = prevSibling ;
nextSibling . prevSibling = prevSibling ;
} else {
} else {
Debug . Assert ( parent . lastChild = = this ) ;
Debug . Assert ( parent . lastChild = = this ) ;
parent . lastChild = prevSibling ;
parent . lastChild = prevSibling ;
}
}
parent = null ;
parent = null ;
@ -489,35 +489,35 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// <summary>
/// <summary>
/// Replaces this node with the new node.
/// Replaces this node with the new node.
/// </summary>
/// </summary>
public void ReplaceWith ( AstNode newNode )
public void ReplaceWith ( AstNode newNode )
{
{
if ( newNode = = null | | newNode . IsNull ) {
if ( newNode = = null | | newNode . IsNull ) {
Remove ( ) ;
Remove ( ) ;
return ;
return ;
}
}
if ( newNode = = this )
if ( newNode = = this )
return ; // nothing to do...
return ; // nothing to do...
if ( parent = = null ) {
if ( parent = = null ) {
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 ( ) ;
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 ) ) {
throw new ArgumentException ( string . Format ( "The new node '{0}' is not valid in the role {1}" , newNode . GetType ( ) . Name , this . Role . ToString ( ) ) , "newNode" ) ;
throw new ArgumentException ( string . Format ( "The new node '{0}' is not valid in the role {1}" , newNode . GetType ( ) . Name , this . Role . ToString ( ) ) , nameof ( newNode ) ) ;
}
}
if ( newNode . parent ! = null ) {
if ( newNode . parent ! = null ) {
// newNode is used within this tree?
// newNode is used within this tree?
if ( newNode . Ancestors . Contains ( this ) ) {
if ( newNode . Ancestors . Contains ( this ) ) {
// e.g. "parenthesizedExpr.ReplaceWith(parenthesizedExpr.Expression);"
// e.g. "parenthesizedExpr.ReplaceWith(parenthesizedExpr.Expression);"
// enable automatic removal
// enable automatic removal
newNode . Remove ( ) ;
newNode . Remove ( ) ;
} else {
} else {
throw new ArgumentException ( "Node is already used in another tree." , "newNode" ) ;
throw new ArgumentException ( "Node is already used in another tree." , nameof ( newNode ) ) ;
}
}
}
}
if ( newNode . IsFrozen )
if ( newNode . IsFrozen )
throw new ArgumentException ( "Cannot add a frozen node." , "newNode" ) ;
throw new ArgumentException ( "Cannot add a frozen node." , nameof ( newNode ) ) ;
newNode . parent = parent ;
newNode . parent = parent ;
newNode . SetRole ( this . Role ) ;
newNode . SetRole ( this . Role ) ;
@ -525,17 +525,17 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
newNode . nextSibling = nextSibling ;
newNode . nextSibling = nextSibling ;
if ( prevSibling ! = null ) {
if ( prevSibling ! = null ) {
Debug . Assert ( prevSibling . nextSibling = = this ) ;
Debug . Assert ( prevSibling . nextSibling = = this ) ;
prevSibling . nextSibling = newNode ;
prevSibling . nextSibling = newNode ;
} else {
} else {
Debug . Assert ( parent . firstChild = = this ) ;
Debug . Assert ( parent . firstChild = = this ) ;
parent . firstChild = newNode ;
parent . firstChild = newNode ;
}
}
if ( nextSibling ! = null ) {
if ( nextSibling ! = null ) {
Debug . Assert ( nextSibling . prevSibling = = this ) ;
Debug . Assert ( nextSibling . prevSibling = = this ) ;
nextSibling . prevSibling = newNode ;
nextSibling . prevSibling = newNode ;
} else {
} else {
Debug . Assert ( parent . lastChild = = this ) ;
Debug . Assert ( parent . lastChild = = this ) ;
parent . lastChild = newNode ;
parent . lastChild = newNode ;
}
}
parent = null ;
parent = null ;
@ -543,31 +543,31 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
nextSibling = null ;
nextSibling = null ;
}
}
public AstNode ReplaceWith ( Func < AstNode , AstNode > replaceFunction )
public AstNode ReplaceWith ( Func < AstNode , AstNode > replaceFunction )
{
{
if ( replaceFunction = = null )
if ( replaceFunction = = null )
throw new ArgumentNullException ( "replaceFunction" ) ;
throw new ArgumentNullException ( nameof ( replaceFunction ) ) ;
if ( parent = = null ) {
if ( parent = = null ) {
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" ) ;
}
}
AstNode oldParent = parent ;
AstNode oldParent = parent ;
AstNode oldSuccessor = nextSibling ;
AstNode oldSuccessor = nextSibling ;
Role oldRole = this . Role ;
Role oldRole = this . Role ;
Remove ( ) ;
Remove ( ) ;
AstNode replacement = replaceFunction ( this ) ;
AstNode replacement = replaceFunction ( this ) ;
if ( oldSuccessor ! = null & & oldSuccessor . parent ! = oldParent )
if ( oldSuccessor ! = null & & oldSuccessor . parent ! = oldParent )
throw new InvalidOperationException ( "replace function changed nextSibling of node being replaced?" ) ;
throw new InvalidOperationException ( "replace function changed nextSibling of node being replaced?" ) ;
if ( ! ( replacement = = null | | replacement . IsNull ) ) {
if ( ! ( replacement = = null | | replacement . IsNull ) ) {
if ( replacement . parent ! = null )
if ( replacement . parent ! = null )
throw new InvalidOperationException ( "replace function must return the root of a tree" ) ;
throw new InvalidOperationException ( "replace function must return the root of a tree" ) ;
if ( ! oldRole . IsValid ( replacement ) ) {
if ( ! oldRole . IsValid ( 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 role {1}" , replacement . GetType ( ) . Name , oldRole . ToString ( ) ) ) ;
}
}
if ( oldSuccessor ! = null )
if ( oldSuccessor ! = null )
oldParent . InsertChildBeforeUnsafe ( oldSuccessor , replacement , oldRole ) ;
oldParent . InsertChildBeforeUnsafe ( oldSuccessor , replacement , oldRole ) ;
else
else
oldParent . AddChildUnsafe ( replacement , oldRole ) ;
oldParent . AddChildUnsafe ( replacement , oldRole ) ;
}
}
return replacement ;
return replacement ;
}
}
@ -576,9 +576,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// Clones the whole subtree starting at this AST node.
/// Clones the whole subtree starting at this AST node.
/// </summary>
/// </summary>
/// <remarks>Annotations are copied over to the new nodes; and any annotations implementing ICloneable will be cloned.</remarks>
/// <remarks>Annotations are copied over to the new nodes; and any annotations implementing ICloneable will be cloned.</remarks>
public AstNode Clone ( )
public AstNode Clone ( )
{
{
AstNode copy = ( AstNode ) MemberwiseClone ( ) ;
AstNode copy = ( AstNode ) MemberwiseClone ( ) ;
// First, reset the shallow pointer copies
// First, reset the shallow pointer copies
copy . parent = null ;
copy . parent = null ;
copy . firstChild = null ;
copy . firstChild = null ;
@ -589,7 +589,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
// 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 ) {
copy . AddChildUnsafe ( cur . Clone ( ) , cur . Role ) ;
copy . AddChildUnsafe ( cur . Clone ( ) , cur . Role ) ;
}
}
// Finally, clone the annotation, if necessary
// Finally, clone the annotation, if necessary
@ -603,31 +603,31 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return Clone ( ) ;
return Clone ( ) ;
}
}
public abstract void AcceptVisitor ( IAstVisitor visitor ) ;
public abstract void AcceptVisitor ( IAstVisitor visitor ) ;
public abstract T AcceptVisitor < T > ( IAstVisitor < T > visitor ) ;
public abstract T AcceptVisitor < T > ( IAstVisitor < T > visitor ) ;
public abstract S AcceptVisitor < T , S > ( IAstVisitor < T , S > visitor , T data ) ;
public abstract S AcceptVisitor < T , S > ( IAstVisitor < T , S > visitor , T data ) ;
#region Pattern Matching
#region Pattern Matching
protected static bool MatchString ( string pattern , string text )
protected static bool MatchString ( string pattern , string text )
{
{
return PatternMatching . Pattern . MatchString ( pattern , text ) ;
return PatternMatching . Pattern . MatchString ( pattern , text ) ;
}
}
protected internal abstract bool DoMatch ( AstNode other , PatternMatching . Match match ) ;
protected internal abstract bool DoMatch ( AstNode other , PatternMatching . Match match ) ;
bool PatternMatching . INode . DoMatch ( PatternMatching . INode other , PatternMatching . Match match )
bool PatternMatching . INode . DoMatch ( PatternMatching . INode other , PatternMatching . Match match )
{
{
AstNode o = other as AstNode ;
AstNode o = other as AstNode ;
// try matching if other is null, or if other is an AstNode
// try matching if other is null, or if other is an AstNode
return ( other = = null | | o ! = null ) & & DoMatch ( o , match ) ;
return ( other = = null | | o ! = null ) & & DoMatch ( o , match ) ;
}
}
bool PatternMatching . INode . DoMatchCollection ( Role role , PatternMatching . INode pos , PatternMatching . Match match , PatternMatching . BacktrackingInfo backtrackingInfo )
bool PatternMatching . INode . DoMatchCollection ( Role role , PatternMatching . INode pos , PatternMatching . Match match , PatternMatching . BacktrackingInfo backtrackingInfo )
{
{
AstNode o = pos as AstNode ;
AstNode o = pos as AstNode ;
return ( pos = = null | | o ! = null ) & & DoMatch ( o , match ) ;
return ( pos = = null | | o ! = null ) & & DoMatch ( o , match ) ;
}
}
PatternMatching . INode PatternMatching . INode . NextSibling {
PatternMatching . INode PatternMatching . INode . NextSibling {
@ -640,12 +640,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
#endregion
#endregion
public AstNode GetNextNode ( )
public AstNode GetNextNode ( )
{
{
if ( NextSibling ! = null )
if ( NextSibling ! = null )
return NextSibling ;
return NextSibling ;
if ( Parent ! = null )
if ( Parent ! = null )
return Parent . GetNextNode ( ) ;
return Parent . GetNextNode ( ) ;
return null ;
return null ;
}
}
@ -654,20 +654,20 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary>
/// </summary>
/// <returns>The next node.</returns>
/// <returns>The next node.</returns>
/// <param name="pred">The predicate.</param>
/// <param name="pred">The predicate.</param>
public AstNode GetNextNode ( Func < AstNode , bool > pred )
public AstNode GetNextNode ( Func < AstNode , bool > pred )
{
{
var next = GetNextNode ( ) ;
var next = GetNextNode ( ) ;
while ( next ! = null & & ! pred ( next ) )
while ( next ! = null & & ! pred ( next ) )
next = next . GetNextNode ( ) ;
next = next . GetNextNode ( ) ;
return next ;
return next ;
}
}
public AstNode GetPrevNode ( )
public AstNode GetPrevNode ( )
{
{
if ( PrevSibling ! = null )
if ( PrevSibling ! = null )
return PrevSibling ;
return PrevSibling ;
if ( Parent ! = null )
if ( Parent ! = null )
return Parent . GetPrevNode ( ) ;
return Parent . GetPrevNode ( ) ;
return null ;
return null ;
}
}
@ -676,21 +676,21 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary>
/// </summary>
/// <returns>The next node.</returns>
/// <returns>The next node.</returns>
/// <param name="pred">The predicate.</param>
/// <param name="pred">The predicate.</param>
public AstNode GetPrevNode ( Func < AstNode , bool > pred )
public AstNode GetPrevNode ( Func < AstNode , bool > pred )
{
{
var prev = GetPrevNode ( ) ;
var prev = GetPrevNode ( ) ;
while ( prev ! = null & & ! pred ( prev ) )
while ( prev ! = null & & ! pred ( prev ) )
prev = prev . GetPrevNode ( ) ;
prev = prev . GetPrevNode ( ) ;
return prev ;
return prev ;
}
}
// filters all non c# nodes (comments, white spaces or pre processor directives)
// filters all non c# nodes (comments, white spaces or pre processor directives)
public AstNode GetCSharpNodeBefore ( AstNode node )
public AstNode GetCSharpNodeBefore ( AstNode node )
{
{
var n = node . PrevSibling ;
var n = node . PrevSibling ;
while ( n ! = null ) {
while ( n ! = null ) {
if ( n . Role ! = Roles . Comment )
if ( n . Role ! = Roles . Comment )
return n ;
return n ;
n = n . GetPrevNode ( ) ;
n = n . GetPrevNode ( ) ;
}
}
return null ;
return null ;
}
}
@ -700,10 +700,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary>
/// </summary>
/// <returns>The next node.</returns>
/// <returns>The next node.</returns>
/// <param name="pred">The predicate.</param>
/// <param name="pred">The predicate.</param>
public AstNode GetNextSibling ( Func < AstNode , bool > pred )
public AstNode GetNextSibling ( Func < AstNode , bool > pred )
{
{
var next = NextSibling ;
var next = NextSibling ;
while ( next ! = null & & ! pred ( next ) )
while ( next ! = null & & ! pred ( next ) )
next = next . NextSibling ;
next = next . NextSibling ;
return next ;
return next ;
}
}
@ -713,10 +713,10 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary>
/// </summary>
/// <returns>The next node.</returns>
/// <returns>The next node.</returns>
/// <param name="pred">The predicate.</param>
/// <param name="pred">The predicate.</param>
public AstNode GetPrevSibling ( Func < AstNode , bool > pred )
public AstNode GetPrevSibling ( Func < AstNode , bool > pred )
{
{
var prev = PrevSibling ;
var prev = PrevSibling ;
while ( prev ! = null & & ! pred ( prev ) )
while ( prev ! = null & & ! pred ( prev ) )
prev = prev . PrevSibling ;
prev = prev . PrevSibling ;
return prev ;
return prev ;
}
}
@ -727,9 +727,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// the current method declaration.
/// the current method declaration.
/// (End exclusive)
/// (End exclusive)
/// </summary>
/// </summary>
public AstNode GetNodeAt ( int line , int column , Predicate < AstNode > pred = null )
public AstNode GetNodeAt ( int line , int column , Predicate < AstNode > pred = null )
{
{
return GetNodeAt ( new TextLocation ( line , column ) , pred ) ;
return GetNodeAt ( new TextLocation ( line , column ) , pred ) ;
}
}
/// <summary>
/// <summary>
@ -737,7 +737,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// the current method declaration.
/// the current method declaration.
/// (End exclusive)
/// (End exclusive)
/// </summary>
/// </summary>
public AstNode GetNodeAt ( TextLocation location , Predicate < AstNode > pred = null )
public AstNode GetNodeAt ( TextLocation location , Predicate < AstNode > pred = null )
{
{
AstNode result = null ;
AstNode result = null ;
AstNode node = this ;
AstNode node = this ;
@ -746,7 +746,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
while ( child ! = null & & child . StartLocation > location )
while ( child ! = null & & child . StartLocation > location )
child = child . prevSibling ;
child = child . prevSibling ;
if ( child ! = null & & location < child . EndLocation ) {
if ( child ! = null & & location < child . EndLocation ) {
if ( pred = = null | | pred ( child ) )
if ( pred = = null | | pred ( child ) )
result = child ;
result = child ;
node = child ;
node = child ;
} else {
} else {
@ -762,9 +762,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// the current method declaration.
/// the current method declaration.
/// (End exclusive)
/// (End exclusive)
/// </summary>
/// </summary>
public T GetNodeAt < T > ( int line , int column ) where T : AstNode
public T GetNodeAt < T > ( int line , int column ) where T : AstNode
{
{
return GetNodeAt < T > ( new TextLocation ( line , column ) ) ;
return GetNodeAt < T > ( new TextLocation ( line , column ) ) ;
}
}
/// <summary>
/// <summary>
@ -772,7 +772,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// the current method declaration.
/// the current method declaration.
/// (End exclusive)
/// (End exclusive)
/// </summary>
/// </summary>
public T GetNodeAt < T > ( TextLocation location ) where T : AstNode
public T GetNodeAt < T > ( TextLocation location ) where T : AstNode
{
{
T result = null ;
T result = null ;
AstNode node = this ;
AstNode node = this ;
@ -802,7 +802,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary>
/// </summary>
public AstNode GetAdjacentNodeAt ( int line , int column , Predicate < AstNode > pred = null )
public AstNode GetAdjacentNodeAt ( int line , int column , Predicate < AstNode > pred = null )
{
{
return GetAdjacentNodeAt ( new TextLocation ( line , column ) , pred ) ;
return GetAdjacentNodeAt ( new TextLocation ( line , column ) , pred ) ;
}
}
/// <summary>
/// <summary>
@ -810,7 +810,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// the current method declaration.
/// the current method declaration.
/// (End inclusive)
/// (End inclusive)
/// </summary>
/// </summary>
public AstNode GetAdjacentNodeAt ( TextLocation location , Predicate < AstNode > pred = null )
public AstNode GetAdjacentNodeAt ( TextLocation location , Predicate < AstNode > pred = null )
{
{
AstNode result = null ;
AstNode result = null ;
AstNode node = this ;
AstNode node = this ;
@ -819,7 +819,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
while ( child ! = null & & child . StartLocation > location )
while ( child ! = null & & child . StartLocation > location )
child = child . prevSibling ;
child = child . prevSibling ;
if ( child ! = null & & location < = child . EndLocation ) {
if ( child ! = null & & location < = child . EndLocation ) {
if ( pred = = null | | pred ( child ) )
if ( pred = = null | | pred ( child ) )
result = child ;
result = child ;
node = child ;
node = child ;
} else {
} else {
@ -837,7 +837,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary>
/// </summary>
public T GetAdjacentNodeAt < T > ( int line , int column ) where T : AstNode
public T GetAdjacentNodeAt < T > ( int line , int column ) where T : AstNode
{
{
return GetAdjacentNodeAt < T > ( new TextLocation ( line , column ) ) ;
return GetAdjacentNodeAt < T > ( new TextLocation ( line , column ) ) ;
}
}
/// <summary>
/// <summary>
@ -845,7 +845,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// the current method declaration.
/// the current method declaration.
/// (End inclusive)
/// (End inclusive)
/// </summary>
/// </summary>
public T GetAdjacentNodeAt < T > ( TextLocation location ) where T : AstNode
public T GetAdjacentNodeAt < T > ( TextLocation location ) where T : AstNode
{
{
T result = null ;
T result = null ;
AstNode node = this ;
AstNode node = this ;
@ -882,15 +882,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// <summary>
/// <summary>
/// Returns the root nodes of all subtrees that are fully contained in the specified region.
/// Returns the root nodes of all subtrees that are fully contained in the specified region.
/// </summary>
/// </summary>
public IEnumerable < AstNode > GetNodesBetween ( int startLine , int startColumn , int endLine , int endColumn )
public IEnumerable < AstNode > GetNodesBetween ( int startLine , int startColumn , int endLine , int endColumn )
{
{
return GetNodesBetween ( new TextLocation ( startLine , startColumn ) , new TextLocation ( endLine , endColumn ) ) ;
return GetNodesBetween ( new TextLocation ( startLine , startColumn ) , new TextLocation ( endLine , endColumn ) ) ;
}
}
/// <summary>
/// <summary>
/// Returns the root nodes of all subtrees that are fully contained between <paramref name="start"/> and <paramref name="end"/> (inclusive).
/// Returns the root nodes of all subtrees that are fully contained between <paramref name="start"/> and <paramref name="end"/> (inclusive).
/// </summary>
/// </summary>
public IEnumerable < AstNode > GetNodesBetween ( TextLocation start , TextLocation end )
public IEnumerable < AstNode > GetNodesBetween ( TextLocation start , TextLocation end )
{
{
AstNode node = this ;
AstNode node = this ;
while ( node ! = null ) {
while ( node ! = null ) {
@ -920,13 +920,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// <param name='formattingOptions'>
/// <param name='formattingOptions'>
/// Formatting options.
/// Formatting options.
/// </param>
/// </param>
public virtual string ToString ( CSharpFormattingOptions formattingOptions )
public virtual string ToString ( CSharpFormattingOptions formattingOptions )
{
{
if ( IsNull )
if ( IsNull )
return "" ;
return "" ;
var w = new StringWriter ( ) ;
var w = new StringWriter ( ) ;
AcceptVisitor ( new CSharpOutputVisitor ( w , formattingOptions ? ? FormattingOptionsFactory . CreateMono ( ) ) ) ;
AcceptVisitor ( new CSharpOutputVisitor ( w , formattingOptions ? ? FormattingOptionsFactory . CreateMono ( ) ) ) ;
return w . ToString ( ) ;
return w . ToString ( ) ;
}
}
public sealed override string ToString ( )
public sealed override string ToString ( )
@ -940,9 +940,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// <returns>
/// <returns>
/// True, if the given coordinates are between StartLocation and EndLocation (exclusive); otherwise, false.
/// True, if the given coordinates are between StartLocation and EndLocation (exclusive); otherwise, false.
/// </returns>
/// </returns>
public bool Contains ( int line , int column )
public bool Contains ( int line , int column )
{
{
return Contains ( new TextLocation ( line , column ) ) ;
return Contains ( new TextLocation ( line , column ) ) ;
}
}
/// <summary>
/// <summary>
@ -951,7 +951,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// <returns>
/// <returns>
/// True, if location is between StartLocation and EndLocation (exclusive); otherwise, false.
/// True, if location is between StartLocation and EndLocation (exclusive); otherwise, false.
/// </returns>
/// </returns>
public bool Contains ( TextLocation location )
public bool Contains ( TextLocation location )
{
{
return this . StartLocation < = location & & location < this . EndLocation ;
return this . StartLocation < = location & & location < this . EndLocation ;
}
}
@ -962,9 +962,9 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// <returns>
/// <returns>
/// True, if the given coordinates are between StartLocation and EndLocation (inclusive); otherwise, false.
/// True, if the given coordinates are between StartLocation and EndLocation (inclusive); otherwise, false.
/// </returns>
/// </returns>
public bool IsInside ( int line , int column )
public bool IsInside ( int line , int column )
{
{
return IsInside ( new TextLocation ( line , column ) ) ;
return IsInside ( new TextLocation ( line , column ) ) ;
}
}
/// <summary>
/// <summary>
@ -973,16 +973,16 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// <returns>
/// <returns>
/// True, if location is between StartLocation and EndLocation (inclusive); otherwise, false.
/// True, if location is between StartLocation and EndLocation (inclusive); otherwise, false.
/// </returns>
/// </returns>
public bool IsInside ( TextLocation location )
public bool IsInside ( TextLocation location )
{
{
return this . StartLocation < = location & & location < = this . EndLocation ;
return this . StartLocation < = location & & location < = this . EndLocation ;
}
}
public override void AddAnnotation ( object annotation )
public override void AddAnnotation ( object annotation )
{
{
if ( this . IsNull )
if ( this . IsNull )
throw new InvalidOperationException ( "Cannot add annotations to the null node" ) ;
throw new InvalidOperationException ( "Cannot add annotations to the null node" ) ;
base . AddAnnotation ( annotation ) ;
base . AddAnnotation ( annotation ) ;
}
}
internal string DebugToString ( )
internal string DebugToString ( )