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; } } } }
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; } } } }