|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.PooledObjects;
namespace Microsoft.CodeAnalysis.CSharp
{
internal abstract partial class BoundTreeWalker : BoundTreeVisitor
{
protected BoundTreeWalker()
{
}
public void VisitList<T>(ImmutableArray<T> list) where T : BoundNode
{
if (!list.IsDefault)
{
for (int i = 0; i < list.Length; i++)
{
this.Visit(list[i]);
}
}
}
protected void VisitUnoptimizedForm(BoundQueryClause queryClause)
{
BoundExpression? unoptimizedForm = queryClause.UnoptimizedForm;
// The unoptimized form of a query has an additional argument in the call,
// which is typically the "trivial" expression x where x is the query
// variable. So that we can make sense of x in this
// context, we store the unoptimized form and visit this extra argument.
var qc = unoptimizedForm as BoundQueryClause;
if (qc != null) unoptimizedForm = qc.Value;
var call = unoptimizedForm as BoundCall;
if (call != null && (object)call.Method != null)
{
var arguments = call.Arguments;
if (call.Method.Name == "Select")
{
this.Visit(arguments[arguments.Length - 1]);
}
else if (call.Method.Name == "GroupBy")
{
this.Visit(arguments[arguments.Length - 2]);
}
}
}
}
/// <summary>
/// Note: do not use a static/singleton instance of this type, as it holds state.
/// </summary>
internal abstract class BoundTreeWalkerWithStackGuard : BoundTreeWalker
{
private int _recursionDepth;
protected BoundTreeWalkerWithStackGuard()
{ }
protected BoundTreeWalkerWithStackGuard(int recursionDepth)
{
_recursionDepth = recursionDepth;
}
protected int RecursionDepth => _recursionDepth;
public override BoundNode? Visit(BoundNode? node)
{
var expression = node as BoundExpression;
if (expression != null)
{
return VisitExpressionWithStackGuard(ref _recursionDepth, expression);
}
return base.Visit(node);
}
protected BoundExpression VisitExpressionWithStackGuard(BoundExpression node)
{
return VisitExpressionWithStackGuard(ref _recursionDepth, node);
}
protected sealed override BoundExpression VisitExpressionWithoutStackGuard(BoundExpression node)
{
return (BoundExpression)base.Visit(node);
}
}
/// <summary>
/// Note: do not use a static/singleton instance of this type, as it holds state.
/// </summary>
internal abstract class BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator : BoundTreeWalkerWithStackGuard
{
protected BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator()
{ }
protected BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator(int recursionDepth)
: base(recursionDepth)
{ }
public sealed override BoundNode? VisitBinaryOperator(BoundBinaryOperator node)
{
if (node.Left.Kind != BoundKind.BinaryOperator)
{
return base.VisitBinaryOperator(node);
}
var rightOperands = ArrayBuilder<BoundExpression>.GetInstance();
rightOperands.Push(node.Right);
var binary = (BoundBinaryOperator)node.Left;
rightOperands.Push(binary.Right);
BoundExpression current = binary.Left;
while (current.Kind == BoundKind.BinaryOperator)
{
binary = (BoundBinaryOperator)current;
rightOperands.Push(binary.Right);
current = binary.Left;
}
this.Visit(current);
while (rightOperands.Count > 0)
{
this.Visit(rightOperands.Pop());
}
rightOperands.Free();
return null;
}
}
}
|