241 lines
7.6 KiB
C#
241 lines
7.6 KiB
C#
using System;
|
|
using System.Collections.Immutable;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp.Symbols;
|
|
using Microsoft.CodeAnalysis.PooledObjects;
|
|
using Roslyn.Utilities;
|
|
|
|
namespace Microsoft.CodeAnalysis.CSharp;
|
|
|
|
internal static class BoundNodeExtensions
|
|
{
|
|
private class ContainsAwaitVisitor : BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator
|
|
{
|
|
public bool ContainsAwait;
|
|
|
|
public override BoundNode? Visit(BoundNode? node)
|
|
{
|
|
if (!ContainsAwait)
|
|
{
|
|
return base.Visit(node);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode? VisitAwaitExpression(BoundAwaitExpression node)
|
|
{
|
|
ContainsAwait = true;
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static bool HasErrors<T>(this ImmutableArray<T> nodeArray) where T : BoundNode
|
|
{
|
|
if (nodeArray.IsDefault)
|
|
{
|
|
return false;
|
|
}
|
|
int i = 0;
|
|
for (int length = nodeArray.Length; i < length; i++)
|
|
{
|
|
if (nodeArray[i].HasErrors)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool HasErrors([NotNullWhen(true)] this BoundNode? node)
|
|
{
|
|
return node?.HasErrors ?? false;
|
|
}
|
|
|
|
public static bool IsConstructorInitializer(this BoundStatement statement)
|
|
{
|
|
if (statement.Kind == BoundKind.ExpressionStatement)
|
|
{
|
|
BoundExpression boundExpression = ((BoundExpressionStatement)statement).Expression;
|
|
if (boundExpression.Kind == BoundKind.Sequence && ((BoundSequence)boundExpression).SideEffects.IsDefaultOrEmpty)
|
|
{
|
|
boundExpression = ((BoundSequence)boundExpression).Value;
|
|
}
|
|
if (boundExpression.Kind == BoundKind.Call)
|
|
{
|
|
return ((BoundCall)boundExpression).IsConstructorInitializer();
|
|
}
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool IsConstructorInitializer(this BoundCall call)
|
|
{
|
|
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0013: Invalid comparison between Unknown and I4
|
|
MethodSymbol method = call.Method;
|
|
BoundExpression receiverOpt = call.ReceiverOpt;
|
|
if ((int)method.MethodKind == 1 && receiverOpt != null)
|
|
{
|
|
if (receiverOpt.Kind != BoundKind.ThisReference)
|
|
{
|
|
return receiverOpt.Kind == BoundKind.BaseReference;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static T MakeCompilerGenerated<T>(this T node) where T : BoundNode
|
|
{
|
|
node.WasCompilerGenerated = true;
|
|
return node;
|
|
}
|
|
|
|
public static bool ContainsAwaitExpression(this ImmutableArray<BoundExpression> expressions)
|
|
{
|
|
ContainsAwaitVisitor containsAwaitVisitor = new ContainsAwaitVisitor();
|
|
ImmutableArray<BoundExpression>.Enumerator enumerator = expressions.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundExpression current = enumerator.Current;
|
|
containsAwaitVisitor.Visit(current);
|
|
if (containsAwaitVisitor.ContainsAwait)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool VisitBinaryOperatorInterpolatedString<TInterpolatedStringType, TArg>(this BoundBinaryOperator binary, TArg arg, Func<TInterpolatedStringType, TArg, bool> stringCallback, Action<BoundBinaryOperator, TArg>? binaryOperatorCallback = null) where TInterpolatedStringType : BoundInterpolatedStringBase
|
|
{
|
|
ArrayBuilder<BoundBinaryOperator> instance = ArrayBuilder<BoundBinaryOperator>.GetInstance();
|
|
pushLeftNodes(binary, instance, arg, binaryOperatorCallback);
|
|
BoundBinaryOperator boundBinaryOperator = default(BoundBinaryOperator);
|
|
while (ArrayBuilderExtensions.TryPop<BoundBinaryOperator>(instance, ref boundBinaryOperator))
|
|
{
|
|
BoundExpression left = boundBinaryOperator.Left;
|
|
if (!(left is BoundBinaryOperator))
|
|
{
|
|
if (!(left is TInterpolatedStringType arg2))
|
|
{
|
|
throw ExceptionUtilities.UnexpectedValue((object)boundBinaryOperator.Left.Kind);
|
|
}
|
|
if (!stringCallback(arg2, arg))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
left = boundBinaryOperator.Right;
|
|
if (!(left is BoundBinaryOperator binary2))
|
|
{
|
|
if (!(left is TInterpolatedStringType arg3))
|
|
{
|
|
throw ExceptionUtilities.UnexpectedValue((object)boundBinaryOperator.Right.Kind);
|
|
}
|
|
if (!stringCallback(arg3, arg))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pushLeftNodes(binary2, instance, arg, binaryOperatorCallback);
|
|
}
|
|
}
|
|
instance.Free();
|
|
return true;
|
|
static void pushLeftNodes(BoundBinaryOperator boundBinaryOperator3, ArrayBuilder<BoundBinaryOperator> stack, TArg arg4, Action<BoundBinaryOperator, TArg>? action)
|
|
{
|
|
for (BoundBinaryOperator boundBinaryOperator2 = boundBinaryOperator3; boundBinaryOperator2 != null; boundBinaryOperator2 = boundBinaryOperator2.Left as BoundBinaryOperator)
|
|
{
|
|
action?.Invoke(boundBinaryOperator2, arg4);
|
|
ArrayBuilderExtensions.Push<BoundBinaryOperator>(stack, boundBinaryOperator2);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static TResult RewriteInterpolatedStringAddition<TInterpolatedStringType, TArg, TResult>(this BoundBinaryOperator binary, TArg arg, Func<TInterpolatedStringType, int, TArg, TResult> interpolatedStringFactory, Func<BoundBinaryOperator, TResult, TResult, TArg, TResult> binaryOperatorFactory) where TInterpolatedStringType : BoundInterpolatedStringBase
|
|
{
|
|
int i = 0;
|
|
return doRewrite(binary, arg, interpolatedStringFactory, binaryOperatorFactory, ref i);
|
|
static TResult doRewrite(BoundBinaryOperator binary2, TArg val3, Func<TInterpolatedStringType, int, TArg, TResult> func, Func<BoundBinaryOperator, TResult, TResult, TArg, TResult> func2, ref int reference)
|
|
{
|
|
TResult val = default(TResult);
|
|
ArrayBuilder<BoundBinaryOperator> instance = ArrayBuilder<BoundBinaryOperator>.GetInstance();
|
|
pushLeftNodes(binary2, instance);
|
|
BoundBinaryOperator boundBinaryOperator = default(BoundBinaryOperator);
|
|
while (ArrayBuilderExtensions.TryPop<BoundBinaryOperator>(instance, ref boundBinaryOperator))
|
|
{
|
|
BoundExpression left = boundBinaryOperator.Left;
|
|
TResult val2;
|
|
if (!(left is TInterpolatedStringType arg2))
|
|
{
|
|
if (!(left is BoundBinaryOperator))
|
|
{
|
|
throw ExceptionUtilities.UnexpectedValue((object)boundBinaryOperator.Left.Kind);
|
|
}
|
|
val2 = val;
|
|
}
|
|
else
|
|
{
|
|
val2 = func(arg2, reference++, val3);
|
|
}
|
|
TResult arg3 = val2;
|
|
left = boundBinaryOperator.Right;
|
|
if (!(left is TInterpolatedStringType arg4))
|
|
{
|
|
if (!(left is BoundBinaryOperator binary3))
|
|
{
|
|
throw ExceptionUtilities.UnexpectedValue((object)boundBinaryOperator.Right.Kind);
|
|
}
|
|
val2 = doRewrite(binary3, val3, func, func2, ref reference);
|
|
}
|
|
else
|
|
{
|
|
val2 = func(arg4, reference++, val3);
|
|
}
|
|
TResult arg5 = val2;
|
|
val = func2(boundBinaryOperator, arg3, arg5, val3);
|
|
}
|
|
instance.Free();
|
|
return val;
|
|
}
|
|
static void pushLeftNodes(BoundBinaryOperator boundBinaryOperator2, ArrayBuilder<BoundBinaryOperator> stack)
|
|
{
|
|
for (BoundBinaryOperator boundBinaryOperator = boundBinaryOperator2; boundBinaryOperator != null; boundBinaryOperator = boundBinaryOperator.Left as BoundBinaryOperator)
|
|
{
|
|
ArrayBuilderExtensions.Push<BoundBinaryOperator>(stack, boundBinaryOperator);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static InterpolatedStringHandlerData GetInterpolatedStringHandlerData(this BoundExpression e, bool throwOnMissing = true)
|
|
{
|
|
if (e is BoundBinaryOperator { InterpolatedStringHandlerData: var interpolatedStringHandlerData })
|
|
{
|
|
if (interpolatedStringHandlerData.HasValue)
|
|
{
|
|
return interpolatedStringHandlerData.GetValueOrDefault();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(e is BoundInterpolatedString { InterpolationData: var interpolationData }))
|
|
{
|
|
throw ExceptionUtilities.UnexpectedValue((object)e.Kind);
|
|
}
|
|
if (interpolationData.HasValue)
|
|
{
|
|
return interpolationData.GetValueOrDefault();
|
|
}
|
|
}
|
|
if (!throwOnMissing)
|
|
{
|
|
return default(InterpolatedStringHandlerData);
|
|
}
|
|
throw ExceptionUtilities.Unreachable("/_/src/Compilers/CSharp/Portable/BoundTree/BoundNodeExtensions.cs", 255);
|
|
}
|
|
}
|