382 lines
11 KiB
C#
382 lines
11 KiB
C#
using System.Collections.Immutable;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using Microsoft.CodeAnalysis.CSharp.Symbols;
|
|
using Microsoft.CodeAnalysis.PooledObjects;
|
|
using Roslyn.Utilities;
|
|
|
|
namespace Microsoft.CodeAnalysis.CSharp;
|
|
|
|
internal static class BoundExpressionExtensions
|
|
{
|
|
public static RefKind GetRefKind(this BoundExpression node)
|
|
{
|
|
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0140: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0145: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00ee: Invalid comparison between Unknown and I4
|
|
//IL_0180: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_014b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00f6: Invalid comparison between Unknown and I4
|
|
//IL_0155: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_016b: Unknown result type (might be due to invalid IL or missing references)
|
|
switch (node.Kind)
|
|
{
|
|
case BoundKind.Local:
|
|
return ((BoundLocal)node).LocalSymbol.RefKind;
|
|
case BoundKind.Parameter:
|
|
return ((BoundParameter)node).ParameterSymbol.RefKind;
|
|
case BoundKind.FieldAccess:
|
|
return ((BoundFieldAccess)node).FieldSymbol.RefKind;
|
|
case BoundKind.Call:
|
|
return ((BoundCall)node).Method.RefKind;
|
|
case BoundKind.PropertyAccess:
|
|
return ((BoundPropertyAccess)node).PropertySymbol.RefKind;
|
|
case BoundKind.IndexerAccess:
|
|
return ((BoundIndexerAccess)node).Indexer.RefKind;
|
|
case BoundKind.ImplicitIndexerAccess:
|
|
return ((BoundImplicitIndexerAccess)node).IndexerOrSliceAccess.GetRefKind();
|
|
case BoundKind.InlineArrayAccess:
|
|
{
|
|
BoundInlineArrayAccess boundInlineArrayAccess = (BoundInlineArrayAccess)node;
|
|
if (!boundInlineArrayAccess.IsValue)
|
|
{
|
|
WellKnownMember getItemOrSliceHelper = boundInlineArrayAccess.GetItemOrSliceHelper;
|
|
if ((int)getItemOrSliceHelper == 400)
|
|
{
|
|
return (RefKind)1;
|
|
}
|
|
if ((int)getItemOrSliceHelper == 406)
|
|
{
|
|
return (RefKind)3;
|
|
}
|
|
}
|
|
return (RefKind)0;
|
|
}
|
|
case BoundKind.ObjectInitializerMember:
|
|
{
|
|
BoundObjectInitializerMember boundObjectInitializerMember = (BoundObjectInitializerMember)node;
|
|
if (boundObjectInitializerMember.HasErrors)
|
|
{
|
|
return (RefKind)0;
|
|
}
|
|
Symbol memberSymbol = boundObjectInitializerMember.MemberSymbol;
|
|
if (!(memberSymbol is FieldSymbol { RefKind: var refKind }))
|
|
{
|
|
if (!(memberSymbol is PropertySymbol { RefKind: var refKind2 }))
|
|
{
|
|
if (memberSymbol is EventSymbol)
|
|
{
|
|
return (RefKind)0;
|
|
}
|
|
throw ExceptionUtilities.UnexpectedValue((object)memberSymbol?.Kind);
|
|
}
|
|
return refKind2;
|
|
}
|
|
return refKind;
|
|
}
|
|
default:
|
|
return (RefKind)0;
|
|
}
|
|
}
|
|
|
|
public static bool IsLiteralNull(this BoundExpression node)
|
|
{
|
|
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_001e: Invalid comparison between Unknown and I4
|
|
if (node != null && node.Kind == BoundKind.Literal)
|
|
{
|
|
ConstantValue constantValueOpt = node.ConstantValueOpt;
|
|
if (constantValueOpt != null)
|
|
{
|
|
return (int)constantValueOpt.Discriminator == 0;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool IsLiteralDefault(this BoundExpression node)
|
|
{
|
|
return node.Kind == BoundKind.DefaultLiteral;
|
|
}
|
|
|
|
public static bool IsImplicitObjectCreation(this BoundExpression node)
|
|
{
|
|
return node.Kind == BoundKind.UnconvertedObjectCreationExpression;
|
|
}
|
|
|
|
public static bool IsLiteralDefaultOrImplicitObjectCreation(this BoundExpression node)
|
|
{
|
|
if (!node.IsLiteralDefault())
|
|
{
|
|
return node.IsImplicitObjectCreation();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool IsDefaultValue(this BoundExpression node)
|
|
{
|
|
if (node.Kind == BoundKind.DefaultExpression || node.Kind == BoundKind.DefaultLiteral)
|
|
{
|
|
return true;
|
|
}
|
|
ConstantValue constantValueOpt = node.ConstantValueOpt;
|
|
if (constantValueOpt != (ConstantValue)null)
|
|
{
|
|
return constantValueOpt.IsDefaultValue;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool HasExpressionType(this BoundExpression node)
|
|
{
|
|
return (object)node.Type != null;
|
|
}
|
|
|
|
public static bool HasDynamicType(this BoundExpression node)
|
|
{
|
|
return node.Type?.IsDynamic() ?? false;
|
|
}
|
|
|
|
public static NamedTypeSymbol? GetInferredDelegateType(this BoundExpression expr, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
|
|
{
|
|
NamedTypeSymbol? obj = expr.GetFunctionType()?.GetInternalDelegateType();
|
|
if ((object)obj != null)
|
|
{
|
|
obj.AddUseSiteInfo(ref useSiteInfo);
|
|
return obj;
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
public static TypeSymbol? GetTypeOrFunctionType(this BoundExpression expr)
|
|
{
|
|
TypeSymbol type = expr.Type;
|
|
if ((object)type != null)
|
|
{
|
|
return type;
|
|
}
|
|
return expr.GetFunctionType();
|
|
}
|
|
|
|
public static FunctionTypeSymbol? GetFunctionType(this BoundExpression expr)
|
|
{
|
|
if (!(expr is BoundMethodGroup boundMethodGroup))
|
|
{
|
|
if (expr is UnboundLambda unboundLambda)
|
|
{
|
|
return unboundLambda.FunctionType;
|
|
}
|
|
return null;
|
|
}
|
|
return boundMethodGroup.FunctionType;
|
|
}
|
|
|
|
public static bool MethodGroupReceiverIsDynamic(this BoundMethodGroup node)
|
|
{
|
|
if (node.InstanceOpt != null)
|
|
{
|
|
return node.InstanceOpt.HasDynamicType();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static void GetExpressionSymbols(this BoundExpression node, ArrayBuilder<Symbol> symbols, BoundNode parent, Binder binder)
|
|
{
|
|
switch (node.Kind)
|
|
{
|
|
case BoundKind.MethodGroup:
|
|
if (parent is BoundDelegateCreationExpression { MethodOpt: not null } boundDelegateCreationExpression)
|
|
{
|
|
symbols.Add((Symbol)boundDelegateCreationExpression.MethodOpt);
|
|
}
|
|
else
|
|
{
|
|
symbols.AddRange<MethodSymbol>(CSharpSemanticModel.GetReducedAndFilteredMethodGroupSymbols(binder, (BoundMethodGroup)node));
|
|
}
|
|
return;
|
|
case BoundKind.BadExpression:
|
|
{
|
|
ImmutableArray<Symbol>.Enumerator enumerator = ((BoundBadExpression)node).Symbols.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
Symbol current = enumerator.Current;
|
|
if ((object)current != null)
|
|
{
|
|
symbols.Add(current);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
case BoundKind.DelegateCreationExpression:
|
|
{
|
|
Symbol symbol = ((BoundDelegateCreationExpression)node).Type.GetMembers(".ctor").FirstOrDefault();
|
|
if ((object)symbol != null)
|
|
{
|
|
symbols.Add(symbol);
|
|
}
|
|
return;
|
|
}
|
|
case BoundKind.Call:
|
|
{
|
|
ImmutableArray<MethodSymbol> originalMethodsOpt = ((BoundCall)node).OriginalMethodsOpt;
|
|
if (!originalMethodsOpt.IsDefault)
|
|
{
|
|
symbols.AddRange<MethodSymbol>(originalMethodsOpt);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.IndexerAccess:
|
|
{
|
|
ImmutableArray<PropertySymbol> originalIndexersOpt = ((BoundIndexerAccess)node).OriginalIndexersOpt;
|
|
if (!originalIndexersOpt.IsDefault)
|
|
{
|
|
symbols.AddRange<PropertySymbol>(originalIndexersOpt);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
Symbol expressionSymbol = node.ExpressionSymbol;
|
|
if ((object)expressionSymbol != null)
|
|
{
|
|
symbols.Add(expressionSymbol);
|
|
}
|
|
}
|
|
|
|
public static Conversion GetConversion(this BoundExpression boundNode)
|
|
{
|
|
if (boundNode.Kind == BoundKind.Conversion)
|
|
{
|
|
return ((BoundConversion)boundNode).Conversion;
|
|
}
|
|
return Conversion.Identity;
|
|
}
|
|
|
|
internal static bool IsExpressionOfComImportType([NotNullWhen(true)] this BoundExpression? expressionOpt)
|
|
{
|
|
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_001c: Invalid comparison between Unknown and I4
|
|
if (expressionOpt == null)
|
|
{
|
|
return false;
|
|
}
|
|
if (expressionOpt.Type is NamedTypeSymbol namedTypeSymbol && (int)namedTypeSymbol.Kind == 11)
|
|
{
|
|
return namedTypeSymbol.IsComImport;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal static bool IsDiscardExpression(this BoundExpression expr)
|
|
{
|
|
if (!(expr is BoundDiscardExpression))
|
|
{
|
|
if (expr is OutDeconstructVarPendingInference outDeconstructVarPendingInference)
|
|
{
|
|
if (outDeconstructVarPendingInference.IsDiscardExpression)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else if (expr is BoundDeconstructValuePlaceholder { IsDiscardExpression: not false })
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static bool NullableAlwaysHasValue(this BoundExpression expr)
|
|
{
|
|
if ((object)expr.Type == null)
|
|
{
|
|
return false;
|
|
}
|
|
if (expr.Type.IsDynamic())
|
|
{
|
|
return false;
|
|
}
|
|
if (!expr.Type.IsNullableType())
|
|
{
|
|
return true;
|
|
}
|
|
if (expr.Kind == BoundKind.ObjectCreationExpression)
|
|
{
|
|
return ((BoundObjectCreationExpression)expr).Constructor.ParameterCount != 0;
|
|
}
|
|
if (expr.Kind == BoundKind.Conversion)
|
|
{
|
|
BoundConversion boundConversion = (BoundConversion)expr;
|
|
switch (boundConversion.ConversionKind)
|
|
{
|
|
case ConversionKind.ImplicitNullable:
|
|
case ConversionKind.ExplicitNullable:
|
|
return boundConversion.Operand.NullableAlwaysHasValue();
|
|
case ConversionKind.ImplicitEnumeration:
|
|
return boundConversion.Operand.NullableAlwaysHasValue();
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool NullableNeverHasValue(this BoundExpression expr)
|
|
{
|
|
if ((object)expr.Type == null && expr.ConstantValueOpt == ConstantValue.Null)
|
|
{
|
|
return true;
|
|
}
|
|
if ((object)expr.Type == null || !expr.Type.IsNullableType())
|
|
{
|
|
return false;
|
|
}
|
|
if (expr is BoundDefaultLiteral || expr is BoundDefaultExpression)
|
|
{
|
|
return true;
|
|
}
|
|
if (expr.Kind == BoundKind.ObjectCreationExpression)
|
|
{
|
|
return ((BoundObjectCreationExpression)expr).Constructor.ParameterCount == 0;
|
|
}
|
|
if (expr.Kind == BoundKind.Conversion)
|
|
{
|
|
BoundConversion boundConversion = (BoundConversion)expr;
|
|
switch (boundConversion.ConversionKind)
|
|
{
|
|
case ConversionKind.NullLiteral:
|
|
return true;
|
|
case ConversionKind.DefaultLiteral:
|
|
return true;
|
|
case ConversionKind.ImplicitNullable:
|
|
case ConversionKind.ExplicitNullable:
|
|
return boundConversion.Operand.NullableNeverHasValue();
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public static bool IsNullableNonBoolean(this BoundExpression expr)
|
|
{
|
|
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_001e: Invalid comparison between Unknown and I4
|
|
if (expr.Type.IsNullableType() && (int)expr.Type.GetNullableUnderlyingType().SpecialType != 7)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|