Esempio n. 1
0
        private IEnumerable <SyntaxNodeOrToken> DescendantNodesAndTokensIntoTrivia(TextSpan span, Func <SyntaxNode, bool> descendIntoChildren, bool includeSelf)
        {
            if (includeSelf && IsInSpan(ref span, this.FullSpan))
            {
                yield return(this);
            }

            using (var stack = new ThreeEnumeratorListStack(this, descendIntoChildren))
            {
                while (stack.IsNotEmpty)
                {
                    switch (stack.PeekNext())
                    {
                    case ThreeEnumeratorListStack.Which.Node:
                        SyntaxNodeOrToken value;
                        if (stack.TryGetNextInSpan(ref span, out value))
                        {
                            // PERF: The following code has an unusual structure (note the 'break' out of
                            // the case statement from inside an if body) in order to convince the compiler
                            // that it can save a field in the iterator machinery.
                            if (value.IsNode)
                            {
                                // parent nodes come before children (prefix document order)
                                stack.PushChildren(value.AsNode(), descendIntoChildren);
                            }
                            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);
                                    }

                                    // Exit the case block without yielding (see PERF note above)
                                    break;
                                }

                                // no structure trivia, so just yield this token now
                            }

                            // PERF: Yield here (rather than inside the if bodies above) so that it's
                            // obvious to the compiler that 'value' is not used beyond this point and,
                            // therefore, doesn't need to be kept in a field.
                            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)

                                // PERF: Push before yield return so that "structureNode" is 'dead' after the yield
                                // and therefore doesn't need to be stored in the iterator state machine. This
                                // saves a field.
                                stack.PushChildren(structureNode, descendIntoChildren);

                                yield return(structureNode);
                            }
                        }
                        break;

                    case ThreeEnumeratorListStack.Which.Token:
                        yield return(stack.PopToken());

                        break;
                    }
                }
            }
        }
Esempio n. 2
0
        private IEnumerable<SyntaxNodeOrToken> DescendantNodesAndTokensIntoTrivia(TextSpan span, Func<SyntaxNode, bool> descendIntoChildren, bool includeSelf)
        {
            if (includeSelf && IsInSpan(ref span, this.FullSpan))
            {
                yield return this;
            }

            using (var stack = new ThreeEnumeratorListStack(this, descendIntoChildren))
            {
                while (stack.IsNotEmpty)
                {
                    switch (stack.PeekNext())
                    {
                        case ThreeEnumeratorListStack.Which.Node:
                            SyntaxNodeOrToken value;
                            if (stack.TryGetNextInSpan(ref span, out value))
                            {
                                // PERF: The following code has an unusual structure (note the 'break' out of
                                // the case statement from inside an if body) in order to convince the compiler
                                // that it can save a field in the iterator machinery.
                                if (value.IsNode)
                                {
                                    // parent nodes come before children (prefix document order)
                                    stack.PushChildren(value.AsNode(), descendIntoChildren);
                                }
                                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);
                                        }

                                        // Exit the case block without yielding (see PERF note above)
                                        break;
                                    }

                                    // no structure trivia, so just yield this token now
                                }

                                // PERF: Yield here (rather than inside the if bodies above) so that it's
                                // obvious to the compiler that 'value' is not used beyond this point and,
                                // therefore, doesn't need to be kept in a field.
                                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)

                                    // PERF: Push before yield return so that "structureNode" is 'dead' after the yield
                                    // and therefore doesn't need to be stored in the iterator state machine. This
                                    // saves a field.
                                    stack.PushChildren(structureNode, descendIntoChildren);

                                    yield return structureNode;
                                }
                            }
                            break;

                        case ThreeEnumeratorListStack.Which.Token:
                            yield return stack.PopToken();
                            break;
                    }
                }
            }
        }