Skip to content

Commit

Permalink
Walk green tree in SyntaxFacts.HasYieldOperations to avoid excessive …
Browse files Browse the repository at this point in the history
…allocations in reported trace (#67221)

* Walk green tree to avoid excessive allocations in reported trace

* Make private

* Remove comment

* Free stack on return

* Include github link for attribute descriptions.
---------

Co-authored-by: Cyrus Najmabadi <[email protected]>
Co-authored-by: Rikki Gibson <[email protected]>
  • Loading branch information
3 people authored Mar 7, 2023
1 parent 93d3aa1 commit 8770fb6
Showing 1 changed file with 44 additions and 18 deletions.
62 changes: 44 additions & 18 deletions src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
using static Microsoft.CodeAnalysis.CSharp.SyntaxKind;

Expand Down Expand Up @@ -543,29 +544,54 @@ internal static bool HasAwaitOperations(SyntaxNode node)
});
}

internal static bool IsNestedFunction(SyntaxNode child)
private static bool IsNestedFunction(SyntaxNode child)
=> IsNestedFunction(child.Kind());

private static bool IsNestedFunction(SyntaxKind kind)
=> kind is SyntaxKind.LocalFunctionStatement
or SyntaxKind.AnonymousMethodExpression
or SyntaxKind.SimpleLambdaExpression
or SyntaxKind.ParenthesizedLambdaExpression;

[PerformanceSensitive("https://github.com/dotnet/roslyn/pull/66970", Constraint = "Use Green nodes for walking to avoid heavy allocations.")]
internal static bool HasYieldOperations(SyntaxNode? node)
{
switch (child.Kind())
if (node is null)
return false;

var stack = ArrayBuilder<GreenNode>.GetInstance();
stack.Push(node.Green);

while (stack.Count > 0)
{
case SyntaxKind.LocalFunctionStatement:
case SyntaxKind.AnonymousMethodExpression:
case SyntaxKind.SimpleLambdaExpression:
case SyntaxKind.ParenthesizedLambdaExpression:
var current = stack.Pop();
Debug.Assert(node.Green == current || current is not Syntax.InternalSyntax.MemberDeclarationSyntax and not Syntax.InternalSyntax.TypeDeclarationSyntax);

if (current is null)
continue;

// Do not descend into functions and expressions
if (IsNestedFunction((SyntaxKind)current.RawKind) ||
current is Syntax.InternalSyntax.ExpressionSyntax)
{
continue;
}

if (current is Syntax.InternalSyntax.YieldStatementSyntax)
{
stack.Free();
return true;
default:
return false;
}

foreach (var child in current.ChildNodesAndTokens())
{
if (!child.IsToken)
stack.Push(child);
}
}
}

internal static bool HasYieldOperations(SyntaxNode? node)
{
// Do not descend into functions and expressions
return node is object &&
node.DescendantNodesAndSelf(child =>
{
Debug.Assert(ReferenceEquals(node, child) || child is not (MemberDeclarationSyntax or TypeDeclarationSyntax));
return !IsNestedFunction(child) && !(node is ExpressionSyntax);
}).Any(n => n is YieldStatementSyntax);
stack.Free();
return false;
}

internal static bool HasReturnWithExpression(SyntaxNode? node)
Expand Down

0 comments on commit 8770fb6

Please sign in to comment.