Browse Source

Make AstNode freezable.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
f74bf908bc
  1. 87
      ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs
  2. 6
      ICSharpCode.NRefactory.CSharp/Ast/CSharpModifierToken.cs
  3. 1
      ICSharpCode.NRefactory.CSharp/Ast/CSharpTokenNode.cs
  4. 16
      ICSharpCode.NRefactory.CSharp/Ast/CompilationUnit.cs
  5. 30
      ICSharpCode.NRefactory.CSharp/Ast/DocumentationReference.cs
  6. 12
      ICSharpCode.NRefactory.CSharp/Ast/Expressions/AnonymousMethodExpression.cs
  7. 1
      ICSharpCode.NRefactory.CSharp/Ast/Expressions/EmptyExpression.cs
  8. 7
      ICSharpCode.NRefactory.CSharp/Ast/Expressions/LambdaExpression.cs
  9. 15
      ICSharpCode.NRefactory.CSharp/Ast/Expressions/PrimitiveExpression.cs
  10. 19
      ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Comment.cs
  11. 1
      ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/PreProcessorDirective.cs
  12. 14
      ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/TypeDeclaration.cs
  13. 5
      ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs
  14. 49
      ICSharpCode.NRefactory.CSharp/Ast/Identifier.cs
  15. 12
      ICSharpCode.NRefactory.CSharp/Ast/MemberType.cs
  16. 25
      ICSharpCode.NRefactory.CSharp/Ast/PrimitiveType.cs
  17. 5
      ICSharpCode.NRefactory.CSharp/Ast/Roles.cs
  18. 1
      ICSharpCode.NRefactory.CSharp/Ast/Statements/EmptyStatement.cs
  19. 9
      ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/OperatorDeclaration.cs
  20. 9
      ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/ParameterDeclaration.cs
  21. 1
      ICSharpCode.NRefactory.Tests/CSharp/ContextAction/TestRefactoringContext.cs
  22. 18
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs
  23. 31
      ICSharpCode.NRefactory/Role.cs

87
ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs

@ -33,12 +33,10 @@ using System.Threading;
namespace ICSharpCode.NRefactory.CSharp namespace ICSharpCode.NRefactory.CSharp
{ {
public abstract class AstNode : AbstractAnnotatable, PatternMatching.INode public abstract class AstNode : AbstractAnnotatable, ICSharpCode.NRefactory.TypeSystem.IFreezable, PatternMatching.INode
{ {
/// <summary> // the Root role must be available when creating the null nodes, so we can't put it in the Roles class
/// Root of an abstract syntax tree. internal static readonly Role<AstNode> RootRole = new Role<AstNode> ("Root");
/// </summary>
public static readonly Role<AstNode> Root = new Role<AstNode> ("Root");
#region Null #region Null
public static readonly AstNode Null = new NullAstNode (); public static readonly AstNode Null = new NullAstNode ();
@ -129,7 +127,42 @@ namespace ICSharpCode.NRefactory.CSharp
AstNode nextSibling; AstNode nextSibling;
AstNode firstChild; AstNode firstChild;
AstNode lastChild; AstNode lastChild;
Role role = Root;
// Flags, from least significant to most significant bits:
// - Role.RoleIndexBits: role index
// - 1 bit: IsFrozen
protected uint flags = RootRole.Index;
// Derived classes may also use a few bits,
// for example Identifier uses 1 bit for IsVerbatim
const uint roleIndexMask = (1u << Role.RoleIndexBits) - 1;
const uint frozenBit = 1u << 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;
@ -176,16 +209,24 @@ namespace ICSharpCode.NRefactory.CSharp
} }
public Role Role { public Role Role {
get { return role; } get {
return Role.GetByIndex(flags & roleIndexMask);
}
set { set {
if (value == null) if (value == null)
throw new ArgumentNullException("value"); throw new ArgumentNullException("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.");
role = value; ThrowIfFrozen();
SetRole(value);
} }
} }
void SetRole(Role role)
{
flags = (flags & ~roleIndexMask) | role.Index;
}
public AstNode NextSibling { public AstNode NextSibling {
get { return nextSibling; } get { return nextSibling; }
} }
@ -258,8 +299,9 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
if (role == null) if (role == null)
throw new ArgumentNullException ("role"); throw new ArgumentNullException ("role");
uint roleIndex = role.Index;
for (var cur = firstChild; cur != null; cur = cur.nextSibling) { for (var cur = firstChild; cur != null; cur = cur.nextSibling) {
if (cur.role == role) if ((cur.flags & roleIndexMask) == roleIndex)
return (T)cur; return (T)cur;
} }
return role.NullObject; return role.NullObject;
@ -285,10 +327,11 @@ namespace ICSharpCode.NRefactory.CSharp
throw new ArgumentNullException ("role"); throw new ArgumentNullException ("role");
if (child == null || child.IsNull) if (child == null || child.IsNull)
return; return;
if (this.IsNull) ThrowIfFrozen();
throw new InvalidOperationException ("Cannot add children to null nodes");
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.", "child");
if (child.IsFrozen)
throw new ArgumentException ("Cannot add a frozen node.", "child");
AddChildUnsafe (child, role); AddChildUnsafe (child, role);
} }
@ -298,7 +341,7 @@ namespace ICSharpCode.NRefactory.CSharp
void AddChildUnsafe (AstNode child, Role role) void AddChildUnsafe (AstNode child, Role role)
{ {
child.parent = this; child.parent = this;
child.role = role; child.SetRole(role);
if (firstChild == null) { if (firstChild == null) {
lastChild = firstChild = child; lastChild = firstChild = child;
} else { } else {
@ -319,8 +362,11 @@ namespace ICSharpCode.NRefactory.CSharp
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.", "child"); throw new ArgumentException ("Node is already used in another tree.", "child");
if (child.IsFrozen)
throw new ArgumentException ("Cannot add a frozen node.", "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.", "nextSibling");
// No need to test for "Cannot add children to null nodes", // No need to test for "Cannot add children to null nodes",
@ -331,7 +377,7 @@ namespace ICSharpCode.NRefactory.CSharp
void InsertChildBeforeUnsafe (AstNode nextSibling, AstNode child, Role role) void InsertChildBeforeUnsafe (AstNode nextSibling, AstNode child, Role role)
{ {
child.parent = this; child.parent = this;
child.role = role; child.SetRole(role);
child.nextSibling = nextSibling; child.nextSibling = nextSibling;
child.prevSibling = nextSibling.prevSibling; child.prevSibling = nextSibling.prevSibling;
@ -356,6 +402,7 @@ namespace ICSharpCode.NRefactory.CSharp
public void Remove () public void Remove ()
{ {
if (parent != null) { if (parent != null) {
ThrowIfFrozen();
if (prevSibling != null) { if (prevSibling != null) {
Debug.Assert (prevSibling.nextSibling == this); Debug.Assert (prevSibling.nextSibling == this);
prevSibling.nextSibling = nextSibling; prevSibling.nextSibling = nextSibling;
@ -390,10 +437,11 @@ namespace ICSharpCode.NRefactory.CSharp
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();
// 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 (!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, 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 ()), "newNode");
} }
if (newNode.parent != null) { if (newNode.parent != null) {
// newNode is used within this tree? // newNode is used within this tree?
@ -405,9 +453,11 @@ namespace ICSharpCode.NRefactory.CSharp
throw new ArgumentException ("Node is already used in another tree.", "newNode"); throw new ArgumentException ("Node is already used in another tree.", "newNode");
} }
} }
if (newNode.IsFrozen)
throw new ArgumentException ("Cannot add a frozen node.", "newNode");
newNode.parent = parent; newNode.parent = parent;
newNode.role = role; newNode.SetRole(this.Role);
newNode.prevSibling = prevSibling; newNode.prevSibling = prevSibling;
newNode.nextSibling = nextSibling; newNode.nextSibling = nextSibling;
if (parent != null) { if (parent != null) {
@ -440,7 +490,7 @@ namespace ICSharpCode.NRefactory.CSharp
} }
AstNode oldParent = parent; AstNode oldParent = parent;
AstNode oldSuccessor = nextSibling; AstNode oldSuccessor = nextSibling;
Role oldRole = 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)
@ -473,10 +523,11 @@ namespace ICSharpCode.NRefactory.CSharp
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) {
copy.AddChildUnsafe (cur.Clone (), cur.role); copy.AddChildUnsafe (cur.Clone (), cur.Role);
} }
// Finally, clone the annotation, if necessary // Finally, clone the annotation, if necessary

6
ICSharpCode.NRefactory.CSharp/Ast/CSharpModifierToken.cs

@ -29,14 +29,16 @@ using System.Linq;
namespace ICSharpCode.NRefactory.CSharp namespace ICSharpCode.NRefactory.CSharp
{ {
public class CSharpModifierToken : CSharpTokenNode public class CSharpModifierToken : CSharpTokenNode
{ {
Modifiers modifier; Modifiers modifier;
public Modifiers Modifier { public Modifiers Modifier {
get { return modifier; } get { return modifier; }
set { this.modifier = value; } set {
ThrowIfFrozen();
this.modifier = value;
}
} }
protected override int TokenLength { protected override int TokenLength {

1
ICSharpCode.NRefactory.CSharp/Ast/CSharpTokenNode.cs

@ -103,6 +103,7 @@ namespace ICSharpCode.NRefactory.CSharp
#region IRelocationable implementation #region IRelocationable implementation
void IRelocatable.SetStartLocation (TextLocation startLocation) void IRelocatable.SetStartLocation (TextLocation startLocation)
{ {
ThrowIfFrozen();
this.startLocation = startLocation; this.startLocation = startLocation;
} }
#endregion #endregion

16
ICSharpCode.NRefactory.CSharp/Ast/CompilationUnit.cs

@ -1,4 +1,4 @@
// //
// CompilationUnit.cs // CompilationUnit.cs
// //
// Author: // Author:
@ -45,10 +45,18 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
string fileName;
/// <summary> /// <summary>
/// Gets/Sets the file name of this compilation unit. /// Gets/Sets the file name of this compilation unit.
/// </summary> /// </summary>
public string FileName { get; set; } public string FileName {
get { return fileName; }
set {
ThrowIfFrozen();
fileName = value;
}
}
List<Error> errors = new List<Error> (); List<Error> errors = new List<Error> ();
@ -83,7 +91,7 @@ namespace ICSharpCode.NRefactory.CSharp
} }
foreach (var child in curNode.Children) { foreach (var child in curNode.Children) {
if (!(child is Statement || child is Expression) && if (!(child is Statement || child is Expression) &&
(child.Role != Roles.TypeMemberRole || (child is TypeDeclaration && includeInnerTypes))) (child.Role != Roles.TypeMemberRole || (child is TypeDeclaration && includeInnerTypes)))
nodeStack.Push (child); nodeStack.Push (child);
} }
} }
@ -99,7 +107,7 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
visitor.VisitCompilationUnit (this); visitor.VisitCompilationUnit (this);
} }
public override T AcceptVisitor<T> (IAstVisitor<T> visitor) public override T AcceptVisitor<T> (IAstVisitor<T> visitor)
{ {
return visitor.VisitCompilationUnit (this); return visitor.VisitCompilationUnit (this);

30
ICSharpCode.NRefactory.CSharp/Ast/DocumentationReference.cs

@ -29,6 +29,10 @@ namespace ICSharpCode.NRefactory.CSharp
public static readonly Role<AstType> DeclaringTypeRole = new Role<AstType>("DeclaringType", AstType.Null); public static readonly Role<AstType> DeclaringTypeRole = new Role<AstType>("DeclaringType", AstType.Null);
public static readonly Role<AstType> ConversionOperatorReturnTypeRole = new Role<AstType>("ConversionOperatorReturnType", AstType.Null); public static readonly Role<AstType> ConversionOperatorReturnTypeRole = new Role<AstType>("ConversionOperatorReturnType", AstType.Null);
EntityType entityType;
OperatorType operatorType;
bool hasParameterList;
/// <summary> /// <summary>
/// Gets/Sets the entity type. /// Gets/Sets the entity type.
/// Possible values are: /// Possible values are:
@ -37,18 +41,36 @@ namespace ICSharpCode.NRefactory.CSharp
/// <c>EntityType.TypeDefinition</c> for references to primitive types, /// <c>EntityType.TypeDefinition</c> for references to primitive types,
/// and <c>EntityType.None</c> for everything else. /// and <c>EntityType.None</c> for everything else.
/// </summary> /// </summary>
public EntityType EntityType { get; set; } public EntityType EntityType {
get { return entityType; }
set {
ThrowIfFrozen();
entityType = value;
}
}
/// <summary> /// <summary>
/// Gets/Sets the operator type. /// Gets/Sets the operator type.
/// This property is only used when EntityType==Operator. /// This property is only used when EntityType==Operator.
/// </summary> /// </summary>
public OperatorType OperatorType { get; set; } public OperatorType OperatorType {
get { return operatorType; }
set {
ThrowIfFrozen();
operatorType = value;
}
}
/// <summary> /// <summary>
/// Gets/Sets whether a parameter list was provided. /// Gets/Sets whether a parameter list was provided.
/// </summary> /// </summary>
public bool HasParameterList { get; set; } public bool HasParameterList {
get { return hasParameterList; }
set {
ThrowIfFrozen();
hasParameterList = value;
}
}
public override NodeType NodeType { public override NodeType NodeType {
get { return NodeType.Unknown; } get { return NodeType.Unknown; }
@ -113,7 +135,7 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
visitor.VisitDocumentationReference (this); visitor.VisitDocumentationReference (this);
} }
public override T AcceptVisitor<T> (IAstVisitor<T> visitor) public override T AcceptVisitor<T> (IAstVisitor<T> visitor)
{ {
return visitor.VisitDocumentationReference (this); return visitor.VisitDocumentationReference (this);

12
ICSharpCode.NRefactory.CSharp/Ast/Expressions/AnonymousMethodExpression.cs

@ -37,11 +37,19 @@ namespace ICSharpCode.NRefactory.CSharp
public readonly static TokenRole DelegateKeywordRole = new TokenRole ("delegate"); public readonly static TokenRole DelegateKeywordRole = new TokenRole ("delegate");
public readonly static TokenRole AsyncModifierRole = LambdaExpression.AsyncModifierRole; public readonly static TokenRole AsyncModifierRole = LambdaExpression.AsyncModifierRole;
public bool IsAsync { get; set; } bool isAsync;
public bool IsAsync {
get { return isAsync; }
set { ThrowIfFrozen(); isAsync = value; }
}
// used to tell the difference between delegate {} and delegate () {} // used to tell the difference between delegate {} and delegate () {}
bool hasParameterList;
public bool HasParameterList { public bool HasParameterList {
get; set; get { return hasParameterList; }
set { ThrowIfFrozen(); hasParameterList = value; }
} }
public CSharpTokenNode DelegateToken { public CSharpTokenNode DelegateToken {

1
ICSharpCode.NRefactory.CSharp/Ast/Expressions/EmptyExpression.cs

@ -58,6 +58,7 @@ namespace ICSharpCode.NRefactory.CSharp
#region IRelocationable implementation #region IRelocationable implementation
void IRelocatable.SetStartLocation (TextLocation startLocation) void IRelocatable.SetStartLocation (TextLocation startLocation)
{ {
ThrowIfFrozen();
this.location = startLocation; this.location = startLocation;
} }
#endregion #endregion

7
ICSharpCode.NRefactory.CSharp/Ast/Expressions/LambdaExpression.cs

@ -37,7 +37,12 @@ namespace ICSharpCode.NRefactory.CSharp
public readonly static TokenRole ArrowRole = new TokenRole ("=>"); public readonly static TokenRole ArrowRole = new TokenRole ("=>");
public static readonly Role<AstNode> BodyRole = new Role<AstNode>("Body", AstNode.Null); public static readonly Role<AstNode> BodyRole = new Role<AstNode>("Body", AstNode.Null);
public bool IsAsync { get; set; } bool isAsync;
public bool IsAsync {
get { return isAsync; }
set { ThrowIfFrozen(); isAsync = value; }
}
public AstNodeCollection<ParameterDeclaration> Parameters { public AstNodeCollection<ParameterDeclaration> Parameters {
get { return GetChildrenByRole (Roles.Parameter); } get { return GetChildrenByRole (Roles.Parameter); }

15
ICSharpCode.NRefactory.CSharp/Ast/Expressions/PrimitiveExpression.cs

@ -47,14 +47,21 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
object value;
public object Value { public object Value {
get; get { return this.value; }
set; set {
ThrowIfFrozen();
this.value = value;
}
} }
public string LiteralValue { public string LiteralValue {
get { get { return literalValue; }
return literalValue; set {
ThrowIfFrozen();
literalValue = value;
} }
} }

19
ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/Comment.cs

@ -58,19 +58,25 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
CommentType commentType;
public CommentType CommentType { public CommentType CommentType {
get; get { return commentType; }
set; set { ThrowIfFrozen(); commentType = value; }
} }
bool startsLine;
public bool StartsLine { public bool StartsLine {
get; get { return startsLine; }
set; set { ThrowIfFrozen(); startsLine = value; }
} }
string content;
public string Content { public string Content {
get; get { return content; }
set; set { ThrowIfFrozen(); content = value; }
} }
TextLocation startLocation; TextLocation startLocation;
@ -103,6 +109,7 @@ namespace ICSharpCode.NRefactory.CSharp
#region IRelocationable implementation #region IRelocationable implementation
void IRelocatable.SetStartLocation (TextLocation startLocation) void IRelocatable.SetStartLocation (TextLocation startLocation)
{ {
ThrowIfFrozen();
int lineDelta = startLocation.Line - this.startLocation.Line; int lineDelta = startLocation.Line - this.startLocation.Line;
endLocation = new TextLocation (endLocation.Line + lineDelta, lineDelta != 0 ? endLocation.Column : endLocation.Column + startLocation.Column - this.startLocation.Column); endLocation = new TextLocation (endLocation.Line + lineDelta, lineDelta != 0 ? endLocation.Column : endLocation.Column + startLocation.Column - this.startLocation.Column);
this.startLocation = startLocation; this.startLocation = startLocation;

1
ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/PreProcessorDirective.cs

@ -96,6 +96,7 @@ namespace ICSharpCode.NRefactory.CSharp
#region IRelocationable implementation #region IRelocationable implementation
void IRelocatable.SetStartLocation (TextLocation startLocation) void IRelocatable.SetStartLocation (TextLocation startLocation)
{ {
ThrowIfFrozen();
int lineDelta = startLocation.Line - this.startLocation.Line; int lineDelta = startLocation.Line - this.startLocation.Line;
endLocation = new TextLocation (endLocation.Line + lineDelta, lineDelta != 0 ? endLocation.Column : endLocation.Column + startLocation.Column - this.startLocation.Column); endLocation = new TextLocation (endLocation.Line + lineDelta, lineDelta != 0 ? endLocation.Column : endLocation.Column + startLocation.Column - this.startLocation.Column);
this.startLocation = startLocation; this.startLocation = startLocation;

14
ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/TypeDeclaration.cs

@ -114,17 +114,17 @@ namespace ICSharpCode.NRefactory.CSharp
public static TypeDeclaration Create(ClassType type) public static TypeDeclaration Create(ClassType type)
{ {
switch (type) { switch (type) {
case ICSharpCode.NRefactory.CSharp.ClassType.Class: case ICSharpCode.NRefactory.CSharp.ClassType.Class:
return new Class (); return new Class ();
case ICSharpCode.NRefactory.CSharp.ClassType.Struct: case ICSharpCode.NRefactory.CSharp.ClassType.Struct:
return new Struct (); return new Struct ();
case ICSharpCode.NRefactory.CSharp.ClassType.Interface: case ICSharpCode.NRefactory.CSharp.ClassType.Interface:
return new Interface (); return new Interface ();
case ICSharpCode.NRefactory.CSharp.ClassType.Enum: case ICSharpCode.NRefactory.CSharp.ClassType.Enum:
return new Enum (); return new Enum ();
default: default:
throw new System.ArgumentOutOfRangeException(); throw new System.ArgumentOutOfRangeException();
} }
} }

5
ICSharpCode.NRefactory.CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs

@ -42,8 +42,11 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildrenByRole (AttributeRole); } get { return GetChildrenByRole (AttributeRole); }
} }
VarianceModifier variance;
public VarianceModifier Variance { public VarianceModifier Variance {
get; set; get { return variance; }
set { ThrowIfFrozen(); variance = value; }
} }
public CSharpTokenNode VarianceToken { public CSharpTokenNode VarianceToken {

49
ICSharpCode.NRefactory.CSharp/Ast/Identifier.cs

@ -1,6 +1,6 @@
// //
// Identifier.cs // Identifier.cs
// //
// Author: // Author:
// Mike Krüger <mkrueger@novell.com> // Mike Krüger <mkrueger@novell.com>
// //
@ -42,7 +42,7 @@ namespace ICSharpCode.NRefactory.CSharp
public override void AcceptVisitor (IAstVisitor visitor) public override void AcceptVisitor (IAstVisitor visitor)
{ {
} }
public override T AcceptVisitor<T> (IAstVisitor<T> visitor) public override T AcceptVisitor<T> (IAstVisitor<T> visitor)
{ {
return default (T); return default (T);
@ -68,9 +68,10 @@ namespace ICSharpCode.NRefactory.CSharp
string name; string name;
public string Name { public string Name {
get { return this.name; } get { return this.name; }
set { set {
if (value == null) if (value == null)
throw new ArgumentNullException("value"); throw new ArgumentNullException("value");
ThrowIfFrozen();
this.name = value; this.name = value;
} }
} }
@ -80,25 +81,34 @@ namespace ICSharpCode.NRefactory.CSharp
get { get {
return startLocation; return startLocation;
} }
} }
public virtual bool IsVerbatim { const uint verbatimBit = 1u << AstNodeFlagsUsedBits;
public bool IsVerbatim {
get { get {
return false; return (flags & verbatimBit) != 0;
}
set {
ThrowIfFrozen();
if (value)
flags |= verbatimBit;
else
flags &= ~verbatimBit;
} }
} }
#region IRelocationable implementation #region IRelocationable implementation
void IRelocatable.SetStartLocation (TextLocation startLocation) void IRelocatable.SetStartLocation (TextLocation startLocation)
{ {
ThrowIfFrozen();
this.startLocation = startLocation; this.startLocation = startLocation;
} }
#endregion #endregion
public override TextLocation EndLocation { public override TextLocation EndLocation {
get { get {
return new TextLocation (StartLocation.Line, StartLocation.Column + (Name ?? "").Length); return new TextLocation (StartLocation.Line, StartLocation.Column + (Name ?? "").Length + (IsVerbatim ? 1 : 0));
} }
} }
@ -125,7 +135,7 @@ namespace ICSharpCode.NRefactory.CSharp
if (string.IsNullOrEmpty(name)) if (string.IsNullOrEmpty(name))
return Identifier.Null; return Identifier.Null;
if (name[0] == '@') if (name[0] == '@')
return new VerbatimIdentifier(name.Substring (1), location); return new Identifier (name.Substring (1), location) { IsVerbatim = true };
else else
return new Identifier (name, location); return new Identifier (name, location);
} }
@ -136,7 +146,7 @@ namespace ICSharpCode.NRefactory.CSharp
return Identifier.Null; return Identifier.Null;
if (isVerbatim) if (isVerbatim)
return new VerbatimIdentifier (name, location); return new Identifier (name, location) { IsVerbatim = true };
return new Identifier (name, location); return new Identifier (name, location);
} }
@ -144,7 +154,7 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
visitor.VisitIdentifier (this); visitor.VisitIdentifier (this);
} }
public override T AcceptVisitor<T> (IAstVisitor<T> visitor) public override T AcceptVisitor<T> (IAstVisitor<T> visitor)
{ {
return visitor.VisitIdentifier (this); return visitor.VisitIdentifier (this);
@ -160,24 +170,5 @@ namespace ICSharpCode.NRefactory.CSharp
Identifier o = other as Identifier; Identifier o = other as Identifier;
return o != null && !o.IsNull && MatchString(this.Name, o.Name); return o != null && !o.IsNull && MatchString(this.Name, o.Name);
} }
class VerbatimIdentifier : Identifier
{
public override TextLocation EndLocation {
get {
return new TextLocation (StartLocation.Line, StartLocation.Column + (Name ?? "").Length + 1); // @"..."
}
}
public override bool IsVerbatim {
get {
return true;
}
}
public VerbatimIdentifier(string name, TextLocation location) : base (name, location)
{
}
}
} }
} }

12
ICSharpCode.NRefactory.CSharp/Ast/MemberType.cs

@ -37,7 +37,15 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
public static readonly Role<AstType> TargetRole = new Role<AstType>("Target", AstType.Null); public static readonly Role<AstType> TargetRole = new Role<AstType>("Target", AstType.Null);
public bool IsDoubleColon { get; set; } bool isDoubleColon;
public bool IsDoubleColon {
get { return isDoubleColon; }
set {
ThrowIfFrozen();
isDoubleColon = value;
}
}
public AstType Target { public AstType Target {
get { return GetChildByRole(TargetRole); } get { return GetChildByRole(TargetRole); }
@ -93,7 +101,7 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
visitor.VisitMemberType (this); visitor.VisitMemberType (this);
} }
public override T AcceptVisitor<T> (IAstVisitor<T> visitor) public override T AcceptVisitor<T> (IAstVisitor<T> visitor)
{ {
return visitor.VisitMemberType (this); return visitor.VisitMemberType (this);

25
ICSharpCode.NRefactory.CSharp/Ast/PrimitiveType.cs

@ -34,8 +34,18 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
public class PrimitiveType : AstType, IRelocatable public class PrimitiveType : AstType, IRelocatable
{ {
public string Keyword { get; set; } TextLocation location;
public TextLocation Location { get; set; } string keyword = string.Empty;
public string Keyword {
get { return keyword; }
set {
if (value == null)
throw new ArgumentNullException();
ThrowIfFrozen();
keyword = value;
}
}
public KnownTypeCode KnownTypeCode { public KnownTypeCode KnownTypeCode {
get { return GetTypeCodeForPrimitiveType(this.Keyword); } get { return GetTypeCodeForPrimitiveType(this.Keyword); }
@ -53,17 +63,17 @@ namespace ICSharpCode.NRefactory.CSharp
public PrimitiveType(string keyword, TextLocation location) public PrimitiveType(string keyword, TextLocation location)
{ {
this.Keyword = keyword; this.Keyword = keyword;
this.Location = location; this.location = location;
} }
public override TextLocation StartLocation { public override TextLocation StartLocation {
get { get {
return Location; return location;
} }
} }
public override TextLocation EndLocation { public override TextLocation EndLocation {
get { get {
return new TextLocation (Location.Line, Location.Column + (Keyword != null ? Keyword.Length : 0)); return new TextLocation (location.Line, location.Column + keyword.Length);
} }
} }
@ -71,7 +81,8 @@ namespace ICSharpCode.NRefactory.CSharp
#region IRelocationable implementation #region IRelocationable implementation
void IRelocatable.SetStartLocation (TextLocation startLocation) void IRelocatable.SetStartLocation (TextLocation startLocation)
{ {
this.Location = startLocation; ThrowIfFrozen();
this.location = startLocation;
} }
#endregion #endregion
@ -98,7 +109,7 @@ namespace ICSharpCode.NRefactory.CSharp
public override string ToString() public override string ToString()
{ {
return Keyword ?? base.ToString(); return Keyword;
} }
public override ITypeReference ToTypeReference(SimpleNameLookupMode lookupMode = SimpleNameLookupMode.Type) public override ITypeReference ToTypeReference(SimpleNameLookupMode lookupMode = SimpleNameLookupMode.Type)

5
ICSharpCode.NRefactory.CSharp/Ast/Roles.cs

@ -1,4 +1,4 @@
// //
// Roles.cs // Roles.cs
// //
// Author: // Author:
@ -30,7 +30,8 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
public static class Roles public static class Roles
{ {
public static readonly Role<AstNode> Root = AstNode.RootRole;
// some pre defined constants for common roles // some pre defined constants for common roles
public static readonly Role<Identifier> Identifier = new Role<Identifier> ("Identifier", CSharp.Identifier.Null); public static readonly Role<Identifier> Identifier = new Role<Identifier> ("Identifier", CSharp.Identifier.Null);
public static readonly Role<BlockStatement> Body = new Role<BlockStatement> ("Body", CSharp.BlockStatement.Null); public static readonly Role<BlockStatement> Body = new Role<BlockStatement> ("Body", CSharp.BlockStatement.Null);

1
ICSharpCode.NRefactory.CSharp/Ast/Statements/EmptyStatement.cs

@ -51,6 +51,7 @@ namespace ICSharpCode.NRefactory.CSharp
#region IRelocationable implementation #region IRelocationable implementation
void IRelocatable.SetStartLocation (TextLocation startLocation) void IRelocatable.SetStartLocation (TextLocation startLocation)
{ {
ThrowIfFrozen();
this.Location = startLocation; this.Location = startLocation;
} }
#endregion #endregion

9
ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/OperatorDeclaration.cs

@ -109,9 +109,14 @@ namespace ICSharpCode.NRefactory.CSharp
get { return EntityType.Operator; } get { return EntityType.Operator; }
} }
OperatorType operatorType;
public OperatorType OperatorType { public OperatorType OperatorType {
get; get { return operatorType; }
set; set {
ThrowIfFrozen();
operatorType = value;
}
} }
public CSharpTokenNode OperatorToken { public CSharpTokenNode OperatorToken {

9
ICSharpCode.NRefactory.CSharp/Ast/TypeMembers/ParameterDeclaration.cs

@ -56,9 +56,14 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildrenByRole (AttributeRole); } get { return GetChildrenByRole (AttributeRole); }
} }
ParameterModifier parameterModifier;
public ParameterModifier ParameterModifier { public ParameterModifier ParameterModifier {
get; get { return parameterModifier; }
set; set {
ThrowIfFrozen();
parameterModifier = value;
}
} }
public AstType Type { public AstType Type {

1
ICSharpCode.NRefactory.Tests/CSharp/ContextAction/TestRefactoringContext.cs

@ -137,6 +137,7 @@ namespace ICSharpCode.NRefactory.CSharp.ContextActions
if (parser.HasErrors) if (parser.HasErrors)
parser.ErrorPrinter.Errors.ForEach (e => Console.WriteLine (e.Message)); parser.ErrorPrinter.Errors.ForEach (e => Console.WriteLine (e.Message));
Assert.IsFalse (parser.HasErrors, "File contains parsing errors."); Assert.IsFalse (parser.HasErrors, "File contains parsing errors.");
unit.Freeze();
var parsedFile = unit.ToTypeSystem(); var parsedFile = unit.ToTypeSystem();
IProjectContent pc = new CSharpProjectContent(); IProjectContent pc = new CSharpProjectContent();

18
ICSharpCode.NRefactory.Tests/CSharp/Resolver/FindReferencesTest.cs

@ -129,5 +129,23 @@ class Test {
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 3 && r is MethodDeclaration)); Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 3 && r is MethodDeclaration));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 8 && r is ForeachStatement)); Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 8 && r is ForeachStatement));
} }
[Test]
public void FindReferencesForOpImplicitInLocalVariableInitialization()
{
Init(@"using System;
class Test {
static void T() {
int x = new Test();
}
public static implicit operator int(Test x) { return 0; }
}");
var test = compilation.MainAssembly.TopLevelTypeDefinitions.Single(t => t.Name == "Test");
var opImplicit = test.Methods.Single(m => m.Name == "op_Implicit");
var actual = FindReferences(opImplicit).ToList();
Assert.AreEqual(2, actual.Count);
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 4 && r is ObjectCreateExpression));
Assert.IsTrue(actual.Any(r => r.StartLocation.Line == 6 && r is OperatorDeclaration));
}
} }
} }

31
ICSharpCode.NRefactory/Role.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Threading;
namespace ICSharpCode.NRefactory namespace ICSharpCode.NRefactory
{ {
@ -25,12 +26,40 @@ namespace ICSharpCode.NRefactory
/// </summary> /// </summary>
public abstract class Role public abstract class Role
{ {
internal Role() {} // don't allow NRefactory consumers to derive from Role public const int RoleIndexBits = 9;
static readonly Role[] roles = new Role[1 << RoleIndexBits];
static int nextRoleIndex = 0;
readonly uint index;
[CLSCompliant(false)]
public uint Index {
get { return index; }
}
// don't allow NRefactory consumers to derive from Role
internal Role()
{
this.index = (uint)Interlocked.Increment(ref nextRoleIndex);
if (this.index >= roles.Length)
throw new InvalidOperationException("");
roles[this.index] = this;
}
/// <summary> /// <summary>
/// Gets whether the specified node is valid in this role. /// Gets whether the specified node is valid in this role.
/// </summary> /// </summary>
public abstract bool IsValid(object node); public abstract bool IsValid(object node);
/// <summary>
/// Gets the role with the specified index.
/// </summary>
[CLSCompliant(false)]
public static Role GetByIndex(uint index)
{
return roles[index];
}
} }
/// <summary> /// <summary>

Loading…
Cancel
Save