Browse Source

Add annotation support to AstNode.

newNRvisualizers
Daniel Grunwald 15 years ago
parent
commit
6d9cdacc80
  1. 183
      ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs

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

@ -28,6 +28,7 @@ using System; @@ -28,6 +28,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
namespace ICSharpCode.NRefactory.CSharp
{
@ -322,6 +323,10 @@ namespace ICSharpCode.NRefactory.CSharp @@ -322,6 +323,10 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
/// <summary>
/// Clones the whole subtree starting at this AST node.
/// </summary>
/// <remarks>Annotations are copied over to the new nodes; and any annotations implementating ICloneable will be cloned.</remarks>
public AstNode Clone()
{
AstNode copy = (AstNode)MemberwiseClone();
@ -338,9 +343,187 @@ namespace ICSharpCode.NRefactory.CSharp @@ -338,9 +343,187 @@ namespace ICSharpCode.NRefactory.CSharp
copy.AddChildUnsafe(cur.Clone(), cur.role);
}
// Finally, clone the annotation, if necessary
ICloneable annotations = copy.annotations as ICloneable; // read from copy (for thread-safety)
if (annotations != null)
copy.annotations = annotations.Clone();
return copy;
}
#region Annotation support
// Annotations: points either null (no annotations), to the single annotation,
// or to an AnnotationList.
// Once it is pointed at an AnnotationList, it will never change (this allows thread-safety support by locking the list)
object annotations;
sealed class AnnotationList : List<object>, ICloneable
{
// There are two uses for this custom list type:
// 1) it's private, and thus (unlike List<object>) cannot be confused with real annotations
// 2) It allows us to simplify the cloning logic by making the list behave the same as a clonable annotation.
public AnnotationList(int initialCapacity) : base(initialCapacity)
{
}
public object Clone()
{
AnnotationList copy = new AnnotationList(this.Count);
for (int i = 0; i < this.Count; i++) {
object obj = this[i];
ICloneable c = obj as ICloneable;
copy.Add(c != null ? c.Clone() : obj);
}
return copy;
}
}
public void AddAnnotation(object annotation)
{
if (annotation == null)
throw new ArgumentNullException("annotation");
retry: // Retry until successful
object oldAnnotation = Interlocked.CompareExchange(ref this.annotations, annotation, null);
if (oldAnnotation == null) {
return; // we successfully added a single annotation
}
AnnotationList list = oldAnnotation as AnnotationList;
if (list == null) {
// we need to transform the old annotation into a list
list = new AnnotationList(4);
list.Add(oldAnnotation);
list.Add(annotation);
if (Interlocked.CompareExchange(ref this.annotations, list, oldAnnotation) != oldAnnotation) {
// the transformation failed (some other thread wrote to this.annotations first)
goto retry;
}
} else {
// once there's a list, use simple locking
lock (list) {
list.Add(annotation);
}
}
}
public void RemoveAnnotations<T>() where T : class
{
retry: // Retry until successful
object oldAnnotations = this.annotations;
AnnotationList list = oldAnnotations as AnnotationList;
if (list != null) {
lock (list)
list.RemoveAll(obj => obj is T);
} else if (oldAnnotations is T) {
if (Interlocked.CompareExchange(ref this.annotations, null, oldAnnotations) != oldAnnotations) {
// Operation failed (some other thread wrote to this.annotations first)
goto retry;
}
}
}
public void RemoveAnnotations(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
retry: // Retry until successful
object oldAnnotations = this.annotations;
AnnotationList list = oldAnnotations as AnnotationList;
if (list != null) {
lock (list)
list.RemoveAll(obj => type.IsInstanceOfType(obj));
} else if (type.IsInstanceOfType(oldAnnotations)) {
if (Interlocked.CompareExchange(ref this.annotations, null, oldAnnotations) != oldAnnotations) {
// Operation failed (some other thread wrote to this.annotations first)
goto retry;
}
}
}
public T Annotation<T>() where T: class
{
object annotations = this.annotations;
AnnotationList list = annotations as AnnotationList;
if (list != null) {
lock (list) {
foreach (object obj in list) {
T t = obj as T;
if (t != null)
return t;
}
return null;
}
} else {
return annotations as T;
}
}
public object Annotation(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
object annotations = this.annotations;
AnnotationList list = annotations as AnnotationList;
if (list != null) {
lock (list) {
foreach (object obj in list) {
if (type.IsInstanceOfType(obj))
return obj;
}
}
} else {
if (type.IsInstanceOfType(annotations))
return annotations;
}
return null;
}
public IEnumerable<T> Annotations<T>() where T: class
{
object annotations = this.annotations;
AnnotationList list = annotations as AnnotationList;
if (list != null) {
List<T> result = new List<T>();
lock (list) {
foreach (object obj in list) {
T t = obj as T;
if (t != null)
result.Add(t);
}
}
return result;
} else {
T t = annotations as T;
if (t != null)
return new T[] { t };
else
return Enumerable.Empty<T>();
}
}
public IEnumerable<object> Annotations(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
object annotations = this.annotations;
AnnotationList list = annotations as AnnotationList;
if (list != null) {
List<object> result = new List<object>();
lock (list) {
foreach (object obj in list) {
if (type.IsInstanceOfType(obj))
result.Add(obj);
}
}
return result;
} else {
if (type.IsInstanceOfType(annotations))
return new object[] { annotations };
else
return Enumerable.Empty<object>();
}
}
#endregion
public abstract S AcceptVisitor<T, S> (AstVisitor<T, S> visitor, T data);
public static class Roles

Loading…
Cancel
Save