diff --git a/Src/Compilers/Core/Source/CodeAnalysis.csproj b/Src/Compilers/Core/Source/CodeAnalysis.csproj
index 3e47e4917386ca3c9dffd092b1a0a76802c50a53..b33778abd88c075d6ccf758da084ac760e4850a8 100644
--- a/Src/Compilers/Core/Source/CodeAnalysis.csproj
+++ b/Src/Compilers/Core/Source/CodeAnalysis.csproj
@@ -268,8 +268,6 @@
-
-
@@ -541,6 +539,7 @@
+
diff --git a/Src/Compilers/Core/Source/InternalUtilities/UnionStack`2.cs b/Src/Compilers/Core/Source/InternalUtilities/UnionStack`2.cs
deleted file mode 100644
index 38dba693ce234653ca9732ee756a9a263d7898ff..0000000000000000000000000000000000000000
--- a/Src/Compilers/Core/Source/InternalUtilities/UnionStack`2.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System;
-using System.Diagnostics;
-using Microsoft.CodeAnalysis;
-
-namespace Roslyn.Utilities
-{
- internal class UnionStack
- where T0 : struct
- where T1 : struct
- {
- private ArrayBuilder stack0 = ArrayBuilder.GetInstance();
- private ArrayBuilder stack1 = ArrayBuilder.GetInstance();
- private ArrayBuilder discriminatorStack = ArrayBuilder.GetInstance();
-
- public enum Discriminator
- {
- Invalid,
- Value0,
- Value1
- }
-
- public void Push(T0 value)
- {
- stack0.Push(value);
- discriminatorStack.Push(Discriminator.Value0);
- }
-
- public void Push(ref T0 value)
- {
- stack0.Push(value);
- discriminatorStack.Push(Discriminator.Value0);
- }
-
- public void Push(T1 value)
- {
- stack1.Push(value);
- discriminatorStack.Push(Discriminator.Value1);
- }
-
- public void Push(ref T1 value)
- {
- stack1.Push(value);
- discriminatorStack.Push(Discriminator.Value1);
- }
-
- public bool TryPeek(out Discriminator discriminator)
- {
- if (discriminatorStack.Count == 0)
- {
- discriminator = Discriminator.Invalid;
- return false;
- }
-
- discriminator = discriminatorStack.Peek();
- return true;
- }
-
- public T0 PopValue0()
- {
- var discriminator = discriminatorStack.Pop();
- Debug.Assert(discriminator == Discriminator.Value0);
- return stack0.Pop();
- }
-
- public T1 PopValue1()
- {
- var discriminator = discriminatorStack.Pop();
- Debug.Assert(discriminator == Discriminator.Value1);
- return stack1.Pop();
- }
-
- public void FreePooledObjects()
- {
- stack0.Free();
- stack1.Free();
- discriminatorStack.Free();
- }
- }
-}
\ No newline at end of file
diff --git a/Src/Compilers/Core/Source/InternalUtilities/UnionStack`3.cs b/Src/Compilers/Core/Source/InternalUtilities/UnionStack`3.cs
deleted file mode 100644
index 849269c2ea95e4e1bc05350f4bdd147550d4c290..0000000000000000000000000000000000000000
--- a/Src/Compilers/Core/Source/InternalUtilities/UnionStack`3.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-using System;
-using System.Diagnostics;
-using Microsoft.CodeAnalysis;
-
-namespace Roslyn.Utilities
-{
- internal class UnionStack
- where T0 : struct
- where T1 : struct
- where T2 : struct
- {
- private ArrayBuilder stack0 = ArrayBuilder.GetInstance();
- private ArrayBuilder stack1 = ArrayBuilder.GetInstance();
- private ArrayBuilder stack2 = ArrayBuilder.GetInstance();
-
- public enum Discriminator : byte
- {
- Invalid,
- Value0,
- Value1,
- Value2
- }
-
- private ArrayBuilder discriminatorStack = ArrayBuilder.GetInstance();
-
- public void Push(ref T0 value)
- {
- stack0.Push(value);
- discriminatorStack.Push(Discriminator.Value0);
- }
-
- public void Push(T0 value)
- {
- stack0.Push(value);
- discriminatorStack.Push(Discriminator.Value0);
- }
-
- public void Push(ref T1 value)
- {
- stack1.Push(value);
- discriminatorStack.Push(Discriminator.Value1);
- }
-
- public void Push(T1 value)
- {
- stack1.Push(value);
- discriminatorStack.Push(Discriminator.Value1);
- }
-
- public void Push(ref T2 value)
- {
- stack2.Push(value);
- discriminatorStack.Push(Discriminator.Value2);
- }
-
- public void Push(T2 value)
- {
- stack2.Push(value);
- discriminatorStack.Push(Discriminator.Value2);
- }
-
- public bool TryPeekDiscriminator(out Discriminator discriminator)
- {
- if (discriminatorStack.Count == 0)
- {
- discriminator = Discriminator.Invalid;
- return false;
- }
-
- discriminator = discriminatorStack.Peek();
- return true;
- }
-
- public T0 PopValue0()
- {
- var discriminator = discriminatorStack.Pop();
- Debug.Assert(discriminator == Discriminator.Value0);
- return stack0.Pop();
- }
-
- public T1 PopValue1()
- {
- var discriminator = discriminatorStack.Pop();
- Debug.Assert(discriminator == Discriminator.Value1);
- return stack1.Pop();
- }
-
- public T2 PopValue2()
- {
- var discriminator = discriminatorStack.Pop();
- Debug.Assert(discriminator == Discriminator.Value2);
- return stack2.Pop();
- }
-
- public void FreePooledObjects()
- {
- stack0.Free();
- stack1.Free();
- stack2.Free();
- discriminatorStack.Free();
- }
- }
-}
\ No newline at end of file
diff --git a/Src/Compilers/Core/Source/Syntax/ChildSyntaxList.Enumerator.cs b/Src/Compilers/Core/Source/Syntax/ChildSyntaxList.Enumerator.cs
index a2981151187f81b62f5c7ffdf44ccf0f6429d658..0d62ef189c80827ca565e5dbb00670f67f9caca6 100644
--- a/Src/Compilers/Core/Source/Syntax/ChildSyntaxList.Enumerator.cs
+++ b/Src/Compilers/Core/Source/Syntax/ChildSyntaxList.Enumerator.cs
@@ -52,6 +52,31 @@ public void Reset()
{
this.childIndex = -1;
}
+
+ internal bool TryMoveNextAndGetCurrent(ref SyntaxNodeOrToken current)
+ {
+ if (!MoveNext())
+ {
+ return false;
+ }
+
+ current = ItemInternal(node, this.childIndex);
+ return true;
+ }
+
+ internal SyntaxNode TryMoveNextAndGetCurrentAsNode()
+ {
+ while (MoveNext())
+ {
+ var nodeValue = ItemInternalAsNode(node, this.childIndex);
+ if (nodeValue != null)
+ {
+ return nodeValue;
+ }
+ }
+
+ return null;
+ }
}
private class EnumeratorImpl : IEnumerator
diff --git a/Src/Compilers/Core/Source/Syntax/ChildSyntaxList.cs b/Src/Compilers/Core/Source/Syntax/ChildSyntaxList.cs
index 25281565d66ea860d04e155a6b5fe664a3c9e8ee..bf6c8a585fa0dc19c506d23cce966ce9d8c28bc2 100644
--- a/Src/Compilers/Core/Source/Syntax/ChildSyntaxList.cs
+++ b/Src/Compilers/Core/Source/Syntax/ChildSyntaxList.cs
@@ -158,6 +158,54 @@ internal static SyntaxNodeOrToken ItemInternal(SyntaxNode node, int index)
return new SyntaxNodeOrToken(node, greenChild, position, index);
}
+ ///
+ /// internal indexer that does not verify index.
+ /// Used when caller has already ensured that index is within bounds.
+ ///
+ internal static SyntaxNode ItemInternalAsNode(SyntaxNode node, int index)
+ {
+ GreenNode greenChild;
+ var green = node.Green;
+ var idx = index;
+ var slotIndex = 0;
+
+ // find a slot that contains the node or its parent list (if node is in a list)
+ // we will be skipping whole slots here so we will not loop for long
+ // the max possible number of slots is 11 (TypeDeclarationSyntax)
+ // and typically much less than that
+ //
+ // at the end of this loop we will have
+ // 1) slot index - slotIdx
+ // 2) if the slot is a list, node index in the list - idx
+ while (true)
+ {
+ greenChild = green.GetSlot(slotIndex);
+ if (greenChild != null)
+ {
+ int currentOccupancy = Occupancy(greenChild);
+ if (idx < currentOccupancy)
+ {
+ break;
+ }
+
+ idx -= currentOccupancy;
+ }
+
+ slotIndex++;
+ }
+
+ // get node that represents this slot
+ var red = node.GetNodeSlot(slotIndex);
+ if (greenChild.IsList && red != null)
+ {
+ // it is a red list of nodes (separated or not), most common case
+ return red.GetNodeSlot(idx);
+ }
+
+ // this is a single node or token
+ return red;
+ }
+
// for debugging
private SyntaxNodeOrToken[] Nodes
{
diff --git a/Src/Compilers/Core/Source/Syntax/SyntaxNode.Iterators.cs b/Src/Compilers/Core/Source/Syntax/SyntaxNode.Iterators.cs
new file mode 100644
index 0000000000000000000000000000000000000000..293a8b0b21fca5588e8c3497656c4cac8f08194f
--- /dev/null
+++ b/Src/Compilers/Core/Source/Syntax/SyntaxNode.Iterators.cs
@@ -0,0 +1,608 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using Microsoft.CodeAnalysis.Text;
+using Roslyn.Utilities;
+
+namespace Microsoft.CodeAnalysis
+{
+ public abstract partial class SyntaxNode
+ {
+ private IEnumerable DescendantNodesImpl(TextSpan span, Func descendIntoChildren, bool descendIntoTrivia, bool includeSelf)
+ {
+ return descendIntoTrivia
+ ? DescendantNodesAndTokensImpl(span, descendIntoChildren, descendIntoTrivia, includeSelf).Where(e => e.IsNode).Select(e => e.AsNode())
+ : DescendantNodesOnly(span, descendIntoChildren, includeSelf);
+ }
+
+ private IEnumerable DescendantNodesAndTokensImpl(TextSpan span, Func descendIntoChildren, bool descendIntoTrivia, bool includeSelf)
+ {
+ return descendIntoTrivia
+ ? DescendantNodesAndTokensIntoTrivia(span, descendIntoChildren, includeSelf)
+ : DescendantNodesAndTokensOnly(span, descendIntoChildren, includeSelf);
+ }
+
+ private IEnumerable DescendantTriviaImpl(TextSpan span, Func descendIntoChildren = null, bool descendIntoTrivia = false)
+ {
+ return descendIntoTrivia
+ ? DescendantTriviaIntoTrivia(span, descendIntoChildren)
+ : DescendantTriviaOnly(span, descendIntoChildren);
+ }
+
+ private static bool IsInSpan(ref TextSpan span, TextSpan childSpan)
+ {
+ return span.OverlapsWith(childSpan)
+ // special case for zero-width tokens (OverlapsWith never returns true for these)
+ || (childSpan.Length == 0 && span.IntersectsWith(childSpan));
+ }
+
+ private struct ChildSyntaxListEnumeratorStack : IDisposable
+ {
+ private static readonly ObjectPool StackPool = new ObjectPool(() => new ChildSyntaxList.Enumerator[16]);
+
+ private ChildSyntaxList.Enumerator[] stack;
+ private int stackPtr;
+
+ public ChildSyntaxListEnumeratorStack(SyntaxNode startingNode)
+ {
+ this.stack = StackPool.Allocate();
+ this.stackPtr = 0;
+ this.stack[0] = startingNode.ChildNodesAndTokens().GetEnumerator();
+ }
+
+ public bool IsNotEmpty { get { return stackPtr >= 0; } }
+
+ public bool TryGetNextInSpan(ref /*readonly*/ TextSpan span, out SyntaxNodeOrToken value)
+ {
+ value = default(SyntaxNodeOrToken);
+
+ while (stack[stackPtr].TryMoveNextAndGetCurrent(ref value))
+ {
+ if (IsInSpan(ref span, value.FullSpan))
+ {
+ return true;
+ }
+ }
+
+ stackPtr--;
+ return false;
+ }
+
+ public SyntaxNode TryGetNextAsNodeInSpan(ref /*readonly*/ TextSpan span)
+ {
+ SyntaxNode nodeValue;
+ while ((nodeValue = stack[stackPtr].TryMoveNextAndGetCurrentAsNode()) != null)
+ {
+ if (IsInSpan(ref span, nodeValue.FullSpan))
+ {
+ return nodeValue;
+ }
+ }
+
+ stackPtr--;
+ return null;
+ }
+
+ public void PushChildren(SyntaxNode node)
+ {
+ if (++stackPtr >= stack.Length)
+ {
+ // Geometric growth
+ Array.Resize(ref stack, checked(stackPtr * 2));
+ }
+
+ stack[stackPtr] = node.ChildNodesAndTokens().GetEnumerator();
+ }
+
+ public void PushChildren(SyntaxNode node, Func descendIntoChildren)
+ {
+ if (descendIntoChildren == null || descendIntoChildren(node))
+ {
+ PushChildren(node);
+ }
+ }
+
+ public void Dispose()
+ {
+ // Return only reasonably-sized stacks to the pool.
+ if (stack.Length < 256)
+ {
+ StackPool.Free(stack);
+ }
+ }
+ }
+
+ private struct TriviaListEnumeratorStack : IDisposable
+ {
+ private static readonly ObjectPool StackPool = new ObjectPool(() => new SyntaxTriviaList.Enumerator[16]);
+
+ private SyntaxTriviaList.Enumerator[] stack;
+ private int stackPtr;
+
+ public static TriviaListEnumeratorStack Create()
+ {
+ return new TriviaListEnumeratorStack() { stack = StackPool.Allocate(), stackPtr = -1 };
+ }
+
+ public bool TryGetNext(out SyntaxTrivia value)
+ {
+ value = default(SyntaxTrivia);
+
+ if (stack[stackPtr].MoveNext())
+ {
+ value = stack[stackPtr].Current;
+ return true;
+ }
+
+ stackPtr--;
+ return false;
+ }
+
+ public void PushLeadingTrivia(ref SyntaxToken token)
+ {
+ if (++stackPtr >= stack.Length)
+ {
+ // Geometric growth
+ Array.Resize(ref stack, checked(stackPtr * 2));
+ }
+
+ stack[stackPtr] = token.LeadingTrivia.GetEnumerator();
+ }
+
+ public void PushTrailingTrivia(ref SyntaxToken token)
+ {
+ if (++stackPtr >= stack.Length)
+ {
+ // Geometric growth
+ Array.Resize(ref stack, checked(stackPtr * 2));
+ }
+
+ stack[stackPtr] = token.TrailingTrivia.GetEnumerator();
+ }
+
+ public void Dispose()
+ {
+ // Return only reasonably-sized stacks to the pool.
+ if (stack.Length < 256)
+ {
+ StackPool.Free(stack);
+ }
+ }
+ }
+
+ private struct TwoEnumeratorListStack : IDisposable
+ {
+ public enum Which : byte
+ {
+ Node,
+ Trivia
+ }
+
+ private ChildSyntaxListEnumeratorStack nodeStack;
+ private TriviaListEnumeratorStack triviaStack;
+ private readonly ArrayBuilder discriminatorStack;
+
+ public TwoEnumeratorListStack(SyntaxNode startingNode)
+ {
+ this.nodeStack = new ChildSyntaxListEnumeratorStack(startingNode);
+ this.triviaStack = TriviaListEnumeratorStack.Create();
+ this.discriminatorStack = ArrayBuilder.GetInstance();
+ this.discriminatorStack.Push(Which.Node);
+ }
+
+ public bool IsNotEmpty { get { return discriminatorStack.Count != 0; } }
+
+ public Which PeekNext()
+ {
+ return discriminatorStack.Peek();
+ }
+
+ public bool TryGetNextInSpan(ref TextSpan span, out SyntaxNodeOrToken value)
+ {
+ if (nodeStack.TryGetNextInSpan(ref span, out value))
+ {
+ return true;
+ }
+
+ discriminatorStack.Pop();
+ return false;
+ }
+
+ public bool TryGetNext(out SyntaxTrivia value)
+ {
+ if(triviaStack.TryGetNext(out value))
+ {
+ return true;
+ }
+
+ discriminatorStack.Pop();
+ return false;
+ }
+
+ public void PushChildren(SyntaxNode node)
+ {
+ nodeStack.PushChildren(node);
+ discriminatorStack.Push(Which.Node);
+ }
+
+ public void PushLeadingTrivia(ref SyntaxToken token)
+ {
+ triviaStack.PushLeadingTrivia(ref token);
+ discriminatorStack.Push(Which.Trivia);
+ }
+
+ public void PushTrailingTrivia(ref SyntaxToken token)
+ {
+ triviaStack.PushTrailingTrivia(ref token);
+ discriminatorStack.Push(Which.Trivia);
+ }
+
+ public void Dispose()
+ {
+ this.nodeStack.Dispose();
+ this.triviaStack.Dispose();
+ this.discriminatorStack.Free();
+ }
+ }
+
+ private struct ThreeEnumeratorListStack : IDisposable
+ {
+ public enum Which : byte
+ {
+ Node,
+ Trivia,
+ Token
+ }
+
+ private ChildSyntaxListEnumeratorStack nodeStack;
+ private TriviaListEnumeratorStack triviaStack;
+ private readonly ArrayBuilder tokenStack;
+ private readonly ArrayBuilder discriminatorStack;
+
+ public ThreeEnumeratorListStack(SyntaxNode startingNode)
+ {
+ this.nodeStack = new ChildSyntaxListEnumeratorStack(startingNode);
+ this.triviaStack = TriviaListEnumeratorStack.Create();
+ this.tokenStack = ArrayBuilder.GetInstance();
+ this.discriminatorStack = ArrayBuilder.GetInstance();
+ this.discriminatorStack.Push(Which.Node);
+ }
+
+ public bool IsNotEmpty { get { return discriminatorStack.Count > 0; } }
+
+ public Which PeekNext()
+ {
+ return discriminatorStack.Peek();
+ }
+
+ public bool TryGetNextInSpan(ref TextSpan span, out SyntaxNodeOrToken value)
+ {
+ if (nodeStack.TryGetNextInSpan(ref span, out value))
+ {
+ return true;
+ }
+
+ discriminatorStack.Pop();
+ return false;
+ }
+
+ public bool TryGetNext(out SyntaxTrivia value)
+ {
+ if (triviaStack.TryGetNext(out value))
+ {
+ return true;
+ }
+
+ discriminatorStack.Pop();
+ return false;
+ }
+
+ public SyntaxNodeOrToken PopToken()
+ {
+ discriminatorStack.Pop();
+ return tokenStack.Pop();
+ }
+
+ public void PushChildren(SyntaxNode node)
+ {
+ nodeStack.PushChildren(node);
+ discriminatorStack.Push(Which.Node);
+ }
+
+ public void PushLeadingTrivia(ref SyntaxToken token)
+ {
+ triviaStack.PushLeadingTrivia(ref token);
+ discriminatorStack.Push(Which.Trivia);
+ }
+
+ public void PushTrailingTrivia(ref SyntaxToken token)
+ {
+ triviaStack.PushTrailingTrivia(ref token);
+ discriminatorStack.Push(Which.Trivia);
+ }
+
+ public void PushToken(ref SyntaxNodeOrToken value)
+ {
+ tokenStack.Push(value);
+ discriminatorStack.Push(Which.Token);
+ }
+
+ public void Dispose()
+ {
+ this.nodeStack.Dispose();
+ this.triviaStack.Dispose();
+ this.tokenStack.Free();
+ this.discriminatorStack.Free();
+ }
+
+ }
+
+ private IEnumerable DescendantNodesOnly(TextSpan span, Func descendIntoChildren, bool includeSelf)
+ {
+ if (includeSelf && IsInSpan(ref span, this.FullSpan))
+ {
+ yield return this;
+ }
+
+ if (descendIntoChildren != null && !descendIntoChildren(this))
+ {
+ yield break;
+ }
+
+ using (var stack = new ChildSyntaxListEnumeratorStack(this))
+ {
+ while (stack.IsNotEmpty)
+ {
+ SyntaxNode nodeValue = stack.TryGetNextAsNodeInSpan(ref span);
+ if (nodeValue != null)
+ {
+ yield return nodeValue;
+
+ stack.PushChildren(nodeValue, descendIntoChildren);
+ }
+ }
+ }
+ }
+
+ private IEnumerable DescendantNodesAndTokensOnly(TextSpan span, Func descendIntoChildren, bool includeSelf)
+ {
+ if (includeSelf && IsInSpan(ref span, this.FullSpan))
+ {
+ yield return this;
+ }
+
+ if (descendIntoChildren != null && !descendIntoChildren(this))
+ {
+ yield break;
+ }
+
+ using (var stack = new ChildSyntaxListEnumeratorStack(this))
+ {
+ SyntaxNodeOrToken value;
+ while (stack.IsNotEmpty)
+ {
+ if (stack.TryGetNextInSpan(ref span, out value))
+ {
+ yield return value;
+
+ var nodeValue = value.AsNode();
+ if (nodeValue != null)
+ {
+ stack.PushChildren(nodeValue, descendIntoChildren);
+ }
+ }
+ }
+ }
+ }
+
+ private IEnumerable DescendantNodesAndTokensIntoTrivia(TextSpan span, Func descendIntoChildren, bool includeSelf)
+ {
+ if (includeSelf && IsInSpan(ref span, this.FullSpan))
+ {
+ yield return this;
+ }
+
+ if (descendIntoChildren != null && !descendIntoChildren(this))
+ {
+ yield break;
+ }
+
+ using (var stack = new ThreeEnumeratorListStack(this))
+ {
+ while (stack.IsNotEmpty)
+ {
+ switch (stack.PeekNext())
+ {
+ case ThreeEnumeratorListStack.Which.Node:
+ SyntaxNodeOrToken value;
+ if (stack.TryGetNextInSpan(ref span, out value))
+ {
+ if (value.IsNode)
+ {
+ // parent nodes come before children (prefix document order)
+ yield return value;
+
+ var nodeValue = value.AsNode();
+
+ if (descendIntoChildren == null || descendIntoChildren(nodeValue))
+ {
+ stack.PushChildren(nodeValue);
+ }
+ }
+ else if (value.IsToken)
+ {
+ var token = value.AsToken();
+
+ // only look through trivia if this node has structured trivia
+ if (token.HasStructuredTrivia)
+ {
+ // trailing trivia comes last
+ if (token.HasTrailingTrivia)
+ {
+ stack.PushTrailingTrivia(ref token);
+ }
+
+ // tokens come between leading and trailing trivia
+ stack.PushToken(ref value);
+
+ // leading trivia comes first
+ if (token.HasLeadingTrivia)
+ {
+ stack.PushLeadingTrivia(ref token);
+ }
+ }
+ else
+ {
+ // no structure trivia, so just yield this token now
+ yield return value;
+ }
+ }
+ }
+
+ break;
+
+ case ThreeEnumeratorListStack.Which.Trivia:
+ // yield structure nodes and enumerate their children
+ SyntaxTrivia trivia;
+ if (stack.TryGetNext(out trivia))
+ {
+ if (trivia.HasStructure && IsInSpan(ref span, trivia.FullSpan))
+ {
+ var structureNode = trivia.GetStructure();
+
+ // parent nodes come before children (prefix document order)
+ yield return structureNode;
+
+ if (descendIntoChildren == null || descendIntoChildren(structureNode))
+ {
+ stack.PushChildren(structureNode);
+ }
+ }
+ }
+ break;
+
+ case ThreeEnumeratorListStack.Which.Token:
+ yield return stack.PopToken();
+ break;
+ }
+ }
+ }
+ }
+
+ private IEnumerable DescendantTriviaOnly(TextSpan span, Func descendIntoChildren)
+ {
+ if (descendIntoChildren != null && !descendIntoChildren(this))
+ {
+ yield break;
+ }
+
+ using (var stack = new ChildSyntaxListEnumeratorStack(this))
+ {
+ SyntaxNodeOrToken value;
+ while (stack.IsNotEmpty)
+ {
+ if (stack.TryGetNextInSpan(ref span, out value))
+ {
+ if (value.IsNode)
+ {
+ var nodeValue = value.AsNode();
+
+ stack.PushChildren(nodeValue, descendIntoChildren);
+ }
+ else if (value.IsToken)
+ {
+ var token = value.AsToken();
+
+ foreach (var trivia in token.LeadingTrivia)
+ {
+ if (IsInSpan(ref span, trivia.FullSpan))
+ {
+ yield return trivia;
+ }
+ }
+
+ foreach (var trivia in token.TrailingTrivia)
+ {
+ if (IsInSpan(ref span, trivia.FullSpan))
+ {
+ yield return trivia;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private IEnumerable DescendantTriviaIntoTrivia(TextSpan span, Func descendIntoChildren)
+ {
+ if (descendIntoChildren != null && !descendIntoChildren(this))
+ {
+ yield break;
+ }
+
+ using (var stack = new TwoEnumeratorListStack(this))
+ {
+ while (stack.IsNotEmpty)
+ {
+ switch (stack.PeekNext())
+ {
+ case TwoEnumeratorListStack.Which.Node:
+ SyntaxNodeOrToken value;
+ if (stack.TryGetNextInSpan(ref span, out value))
+ {
+ if (value.IsNode)
+ {
+ var nodeValue = value.AsNode();
+ if (descendIntoChildren == null || descendIntoChildren(nodeValue))
+ {
+ stack.PushChildren(nodeValue);
+ }
+ }
+ else if (value.IsToken)
+ {
+ var token = value.AsToken();
+
+ if (token.HasTrailingTrivia)
+ {
+ stack.PushTrailingTrivia(ref token);
+ }
+
+ if (token.HasLeadingTrivia)
+ {
+ stack.PushLeadingTrivia(ref token);
+ }
+ }
+ }
+
+ break;
+
+ case TwoEnumeratorListStack.Which.Trivia:
+ // yield structure nodes and enumerate their children
+ SyntaxTrivia trivia;
+ if (stack.TryGetNext(out trivia))
+ {
+ if (IsInSpan(ref span, trivia.FullSpan))
+ {
+ yield return trivia;
+ }
+
+ if (trivia.HasStructure)
+ {
+ var structureNode = trivia.GetStructure();
+
+ if (descendIntoChildren == null || descendIntoChildren(structureNode))
+ {
+ stack.PushChildren(structureNode);
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Src/Compilers/Core/Source/Syntax/SyntaxNode.cs b/Src/Compilers/Core/Source/Syntax/SyntaxNode.cs
index c2643bddb6bd913b295bd01246ad10dd323cb13b..2b7f32f2493540fd36e69aba687a4f32ef3a9590 100644
--- a/Src/Compilers/Core/Source/Syntax/SyntaxNode.cs
+++ b/Src/Compilers/Core/Source/Syntax/SyntaxNode.cs
@@ -5,23 +5,18 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
-using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
- using BoxedEnumerator = StrongBox;
- using Stack2 = UnionStack;
- using Stack3 = UnionStack;
-
///
/// Represents a non-terminal node in the syntax tree. This is the language agnostic equivalent of and .
///
[DebuggerDisplay("{GetDebuggerDisplay(), nq}")]
- public abstract class SyntaxNode
+ public abstract partial class SyntaxNode
{
private readonly GreenNode green;
private readonly SyntaxNode parent;
@@ -766,244 +761,6 @@ public IEnumerable DescendantNodesAndTokensAndSelf(TextSpan s
return DescendantNodesAndTokensImpl(span, descendIntoChildren, descendIntoTrivia, includeSelf: true);
}
- private IEnumerable DescendantNodesImpl(TextSpan span, Func descendIntoChildren, bool descendIntoTrivia, bool includeSelf)
- {
- return descendIntoTrivia
- ? DescendantNodesAndTokensImpl(span, descendIntoChildren, descendIntoTrivia, includeSelf).Where(e => e.IsNode).Select(e => e.AsNode())
- : DescendantNodesOnly(span, descendIntoChildren, includeSelf);
- }
-
- private IEnumerable DescendantNodesAndTokensImpl(TextSpan span, Func descendIntoChildren, bool descendIntoTrivia, bool includeSelf)
- {
- return descendIntoTrivia
- ? DescendantNodesAndTokensIntoTrivia(span, descendIntoChildren, includeSelf)
- : DescendantNodesAndTokensOnly(span, descendIntoChildren, includeSelf);
- }
-
- private static bool IsInSpan(TextSpan span, TextSpan childSpan)
- {
- return childSpan.OverlapsWith(span)
- // special case for zero-width tokens (OverlapsWith never returns true for these)
- || (childSpan.Length == 0 && childSpan.IntersectsWith(span));
- }
-
- private IEnumerable DescendantNodesOnly(TextSpan span, Func descendIntoChildren, bool includeSelf)
- {
- if (includeSelf && IsInSpan(span, this.FullSpan))
- {
- yield return this;
- }
-
- if (descendIntoChildren != null && !descendIntoChildren(this))
- {
- yield break;
- }
-
- // Keep around the strongboxes we use so that don't have to allocate unnecessarily. Use
- // strong boxes so we can mutate the enumerators (which are structs) without having to
- // pop them off the stack and push them back on. This saves about 10% of the time when
- // enumerating the tokens in a tree.
- var boxes = new Queue();
- var stack = new Stack();
- stack.Push(new BoxedEnumerator(this.ChildNodesAndTokens().GetEnumerator()));
-
- while (stack.Count > 0)
- {
- var enumerator = stack.Peek();
- if (!enumerator.Value.MoveNext())
- {
- var box = stack.Pop();
- box.Value = default(ChildSyntaxList.Enumerator);
- boxes.Enqueue(box);
- }
- else
- {
- var nodeValue = enumerator.Value.Current.AsNode();
- if (nodeValue != null && IsInSpan(span, nodeValue.FullSpan))
- {
- yield return nodeValue;
-
- if (descendIntoChildren == null || descendIntoChildren(nodeValue))
- {
- var box = boxes.Count == 0
- ? new BoxedEnumerator()
- : boxes.Dequeue();
- box.Value = nodeValue.ChildNodesAndTokens().GetEnumerator();
- stack.Push(box);
- }
- }
- }
- }
- }
-
- private IEnumerable DescendantNodesAndTokensOnly(TextSpan span, Func descendIntoChildren, bool includeSelf)
- {
- if (includeSelf && IsInSpan(span, this.FullSpan))
- {
- yield return this;
- }
-
- if (descendIntoChildren != null && !descendIntoChildren(this))
- {
- yield break;
- }
-
- // Keep around the strongboxes we use so that don't have to allocate unnecessarily. Use
- // strong boxes so we can mutate the enumerators (which are structs) without having to
- // pop them off the stack and push them back on. This saves about 10% of the time when
- // enumerating the tokens in a tree.
- var boxes = new Queue();
- var stack = new Stack();
- stack.Push(new BoxedEnumerator(this.ChildNodesAndTokens().GetEnumerator()));
-
- while (stack.Count > 0)
- {
- var enumerator = stack.Peek();
- if (!enumerator.Value.MoveNext())
- {
- var box = stack.Pop();
- box.Value = default(ChildSyntaxList.Enumerator);
- boxes.Enqueue(box);
- }
- else
- {
- var value = enumerator.Value.Current;
-
- if (IsInSpan(span, value.FullSpan))
- {
- yield return value;
-
- var nodeValue = value.AsNode();
- if (nodeValue != null)
- {
- if (descendIntoChildren == null || descendIntoChildren(nodeValue))
- {
- var box = boxes.Count == 0
- ? new BoxedEnumerator()
- : boxes.Dequeue();
- box.Value = value.AsNode().ChildNodesAndTokens().GetEnumerator();
- stack.Push(box);
- }
- }
- }
- }
- }
- }
-
- private IEnumerable DescendantNodesAndTokensIntoTrivia(TextSpan span, Func descendIntoChildren, bool includeSelf)
- {
- if (includeSelf && IsInSpan(span, this.FullSpan))
- {
- yield return this;
- }
-
- if (descendIntoChildren != null && !descendIntoChildren(this))
- {
- yield break;
- }
-
- var stack = new Stack3();
- try
- {
- stack.Push(this.ChildNodesAndTokens().GetEnumerator());
-
- Stack3.Discriminator discriminator;
- while (stack.TryPeekDiscriminator(out discriminator))
- {
- switch (discriminator)
- {
- case Stack3.Discriminator.Value0: // child nodes & tokens
- {
- var enumerator = stack.PopValue0();
- if (enumerator.MoveNext())
- {
- var value = enumerator.Current;
- stack.Push(ref enumerator);
-
- if (IsInSpan(span, value.FullSpan))
- {
- if (value.IsNode)
- {
- // parent nodes come before children (prefix document order)
- yield return value;
-
- var nodeValue = value.AsNode();
-
- if (descendIntoChildren == null || descendIntoChildren(nodeValue))
- {
- stack.Push(value.AsNode().ChildNodesAndTokens().GetEnumerator());
- }
- }
- else if (value.IsToken)
- {
- var token = value.AsToken();
-
- // only look through trivia if this node has structured trivia
- if (token.HasStructuredTrivia)
- {
- // trailing trivia comes last
- if (token.HasTrailingTrivia)
- {
- stack.Push(token.TrailingTrivia.GetEnumerator());
- }
-
- // tokens come between leading and trailing trivia
- stack.Push(ref value);
-
- // leading trivia comes first
- if (token.HasLeadingTrivia)
- {
- stack.Push(token.LeadingTrivia.GetEnumerator());
- }
- }
- else
- {
- // no structure trivia, so just yield this token now
- yield return value;
- }
- }
- }
- }
- break;
- }
-
- case Stack3.Discriminator.Value1: // trivia
- {
- // yield structure nodes and enumerate their children
- var enumerator = stack.PopValue1();
- if (enumerator.MoveNext())
- {
- var trivia = enumerator.Current;
- stack.Push(ref enumerator);
-
- if (trivia.HasStructure && IsInSpan(span, trivia.FullSpan))
- {
- var structureNode = trivia.GetStructure();
-
- // parent nodes come before children (prefix document order)
- yield return structureNode;
-
- if (descendIntoChildren == null || descendIntoChildren(structureNode))
- {
- stack.Push(structureNode.ChildNodesAndTokens().GetEnumerator());
- }
- }
- }
- break;
- }
-
- case Stack3.Discriminator.Value2: // single node or token
- yield return stack.PopValue2();
- break;
- }
- }
- }
- finally
- {
- stack.FreePooledObjects();
- }
- }
-
///
/// Finds the node with the smallest that contains .
/// is used to determine the behavior in case of a tie (i.e. a node having the same span as its parent).
@@ -1143,7 +900,7 @@ public SyntaxTrivia FindTrivia(int position, bool findInsideTrivia = false)
///
public IEnumerable DescendantTrivia(Func descendIntoChildren = null, bool descendIntoTrivia = false)
{
- return DescendantTrivia(this.FullSpan, descendIntoChildren, descendIntoTrivia);
+ return DescendantTriviaImpl(this.FullSpan, descendIntoChildren, descendIntoTrivia);
}
///
@@ -1151,161 +908,9 @@ public IEnumerable DescendantTrivia(Func descend
///
public IEnumerable DescendantTrivia(TextSpan span, Func descendIntoChildren = null, bool descendIntoTrivia = false)
{
- if (descendIntoTrivia)
- {
- return DescendantTriviaIntoTrivia(span, descendIntoChildren);
- }
- else
- {
- return DescendantTriviaOnly(span, descendIntoChildren);
- }
+ return DescendantTriviaImpl(span, descendIntoChildren, descendIntoTrivia);
}
- private IEnumerable DescendantTriviaOnly(TextSpan span, Func descendIntoChildren)
- {
- if (descendIntoChildren != null && !descendIntoChildren(this))
- {
- yield break;
- }
-
- var stack = new Stack();
- stack.Push(this.ChildNodesAndTokens().GetEnumerator());
-
- while (stack.Count > 0)
- {
- var enumerator = stack.Pop();
- if (enumerator.MoveNext())
- {
- var value = enumerator.Current;
- stack.Push(enumerator);
-
- if (IsInSpan(span, value.FullSpan))
- {
- if (value.IsNode)
- {
- var nodeValue = value.AsNode();
-
- if (descendIntoChildren == null || descendIntoChildren(nodeValue))
- {
- stack.Push(value.AsNode().ChildNodesAndTokens().GetEnumerator());
- }
- }
- else if (value.IsToken)
- {
- var token = value.AsToken();
-
- foreach (var trivia in token.LeadingTrivia)
- {
- if (IsInSpan(span, trivia.FullSpan))
- {
- yield return trivia;
- }
- }
-
- foreach (var trivia in token.TrailingTrivia)
- {
- if (IsInSpan(span, trivia.FullSpan))
- {
- yield return trivia;
- }
- }
- }
- }
- }
- }
- }
-
- private IEnumerable DescendantTriviaIntoTrivia(TextSpan span, Func descendIntoChildren)
- {
- if (descendIntoChildren != null && !descendIntoChildren(this))
- {
- yield break;
- }
-
- var stack = new Stack2();
- try
- {
- stack.Push(this.ChildNodesAndTokens().GetEnumerator());
-
- Stack2.Discriminator discriminator;
- while (stack.TryPeek(out discriminator))
- {
- switch (discriminator)
- {
- case Stack2.Discriminator.Value0: // child nodes & tokens
- {
- var enumerator = stack.PopValue0();
- if (enumerator.MoveNext())
- {
- var value = enumerator.Current;
- stack.Push(ref enumerator);
-
- if (IsInSpan(span, value.FullSpan))
- {
- if (value.IsNode)
- {
- var nodeValue = value.AsNode();
-
- if (descendIntoChildren == null || descendIntoChildren(nodeValue))
- {
- stack.Push(value.AsNode().ChildNodesAndTokens().GetEnumerator());
- }
- }
- else if (value.IsToken)
- {
- var token = value.AsToken();
-
- if (token.HasTrailingTrivia)
- {
- stack.Push(token.TrailingTrivia.GetEnumerator());
- }
-
- if (token.HasLeadingTrivia)
- {
- stack.Push(token.LeadingTrivia.GetEnumerator());
- }
- }
- }
- }
- break;
- }
-
- case Stack2.Discriminator.Value1: // trivia
- {
- var enumerator = stack.PopValue1();
- // yield structure nodes and enumerate their children
- if (enumerator.MoveNext())
- {
- var trivia = enumerator.Current;
- stack.Push(ref enumerator);
-
- if (IsInSpan(span, trivia.FullSpan))
- {
- yield return trivia;
- }
-
- if (trivia.HasStructure)
- {
- var structureNode = trivia.GetStructure();
-
- if (descendIntoChildren == null || descendIntoChildren(structureNode))
- {
- stack.Push(structureNode.ChildNodesAndTokens().GetEnumerator());
- }
- }
- }
- break;
- }
- }
- }
- }
- finally
- {
- stack.FreePooledObjects();
- }
- }
-
-
#endregion
#region Annotations