3340 lines
139 KiB
C#
3340 lines
139 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using Microsoft.Cci;
|
|
using Microsoft.CodeAnalysis.CSharp.Symbols;
|
|
using Microsoft.CodeAnalysis.PooledObjects;
|
|
using Roslyn.Utilities;
|
|
|
|
namespace Microsoft.CodeAnalysis.CSharp;
|
|
|
|
internal sealed class RefSafetyAnalysis : BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator
|
|
{
|
|
private enum EscapeLevel : uint
|
|
{
|
|
CallingMethod,
|
|
ReturnOnly
|
|
}
|
|
|
|
private readonly struct MixableDestination
|
|
{
|
|
internal BoundExpression Argument { get; }
|
|
|
|
internal ParameterSymbol? Parameter { get; }
|
|
|
|
internal EscapeLevel EscapeLevel { get; }
|
|
|
|
internal MixableDestination(ParameterSymbol parameter, BoundExpression argument)
|
|
{
|
|
Argument = argument;
|
|
Parameter = parameter;
|
|
EscapeLevel = GetParameterValEscapeLevel(parameter).Value;
|
|
}
|
|
|
|
internal MixableDestination(BoundExpression argument, EscapeLevel escapeLevel)
|
|
{
|
|
Argument = argument;
|
|
Parameter = null;
|
|
EscapeLevel = escapeLevel;
|
|
}
|
|
|
|
internal bool IsAssignableFrom(EscapeLevel level)
|
|
{
|
|
return EscapeLevel switch
|
|
{
|
|
EscapeLevel.CallingMethod => level == EscapeLevel.CallingMethod,
|
|
EscapeLevel.ReturnOnly => true,
|
|
_ => throw ExceptionUtilities.UnexpectedValue((object)EscapeLevel),
|
|
};
|
|
}
|
|
|
|
public override string? ToString()
|
|
{
|
|
return (Parameter, Argument, EscapeLevel).ToString();
|
|
}
|
|
}
|
|
|
|
private readonly struct EscapeArgument
|
|
{
|
|
internal ParameterSymbol? Parameter { get; }
|
|
|
|
internal BoundExpression Argument { get; }
|
|
|
|
internal RefKind RefKind { get; }
|
|
|
|
internal EscapeArgument(ParameterSymbol? parameter, BoundExpression argument, RefKind refKind, bool isArgList = false)
|
|
{
|
|
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
|
|
Argument = argument;
|
|
Parameter = parameter;
|
|
RefKind = refKind;
|
|
}
|
|
|
|
public void Deconstruct(out ParameterSymbol? parameter, out BoundExpression argument, out RefKind refKind)
|
|
{
|
|
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0018: Expected I4, but got Unknown
|
|
parameter = Parameter;
|
|
argument = Argument;
|
|
refKind = (RefKind)(int)RefKind;
|
|
}
|
|
|
|
public override string? ToString()
|
|
{
|
|
ParameterSymbol parameter = Parameter;
|
|
if ((object)parameter == null)
|
|
{
|
|
return Argument.ToString();
|
|
}
|
|
return parameter.ToString();
|
|
}
|
|
}
|
|
|
|
private readonly struct EscapeValue
|
|
{
|
|
internal ParameterSymbol? Parameter { get; }
|
|
|
|
internal BoundExpression Argument { get; }
|
|
|
|
internal EscapeLevel EscapeLevel { get; }
|
|
|
|
internal bool IsRefEscape { get; }
|
|
|
|
internal EscapeValue(ParameterSymbol? parameter, BoundExpression argument, EscapeLevel escapeLevel, bool isRefEscape)
|
|
{
|
|
Argument = argument;
|
|
Parameter = parameter;
|
|
EscapeLevel = escapeLevel;
|
|
IsRefEscape = isRefEscape;
|
|
}
|
|
|
|
public void Deconstruct(out ParameterSymbol? parameter, out BoundExpression argument, out EscapeLevel escapeLevel, out bool isRefEscape)
|
|
{
|
|
parameter = Parameter;
|
|
argument = Argument;
|
|
escapeLevel = EscapeLevel;
|
|
isRefEscape = IsRefEscape;
|
|
}
|
|
|
|
public override string? ToString()
|
|
{
|
|
ParameterSymbol parameter = Parameter;
|
|
if ((object)parameter == null)
|
|
{
|
|
return Argument.ToString();
|
|
}
|
|
return parameter.ToString();
|
|
}
|
|
}
|
|
|
|
private ref struct LocalScope
|
|
{
|
|
private readonly RefSafetyAnalysis _analysis;
|
|
|
|
private readonly ImmutableArray<LocalSymbol> _locals;
|
|
|
|
public LocalScope(RefSafetyAnalysis analysis, ImmutableArray<LocalSymbol> locals)
|
|
{
|
|
_analysis = analysis;
|
|
_locals = locals;
|
|
_analysis._localScopeDepth++;
|
|
ImmutableArray<LocalSymbol>.Enumerator enumerator = locals.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalSymbol current = enumerator.Current;
|
|
_analysis.AddLocalScopes(current, _analysis._localScopeDepth, 0u);
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
ImmutableArray<LocalSymbol>.Enumerator enumerator = _locals.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalSymbol current = enumerator.Current;
|
|
_analysis.RemoveLocalScopes(current);
|
|
}
|
|
_analysis._localScopeDepth--;
|
|
}
|
|
}
|
|
|
|
private ref struct UnsafeRegion
|
|
{
|
|
private readonly RefSafetyAnalysis _analysis;
|
|
|
|
private readonly bool _previousRegion;
|
|
|
|
public UnsafeRegion(RefSafetyAnalysis analysis, bool inUnsafeRegion)
|
|
{
|
|
_analysis = analysis;
|
|
_previousRegion = analysis._inUnsafeRegion;
|
|
_analysis._inUnsafeRegion = inUnsafeRegion;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_analysis._inUnsafeRegion = _previousRegion;
|
|
}
|
|
}
|
|
|
|
private ref struct PatternInput
|
|
{
|
|
private readonly RefSafetyAnalysis _analysis;
|
|
|
|
private readonly uint _previousInputValEscape;
|
|
|
|
public PatternInput(RefSafetyAnalysis analysis, uint patternInputValEscape)
|
|
{
|
|
_analysis = analysis;
|
|
_previousInputValEscape = analysis._patternInputValEscape;
|
|
_analysis._patternInputValEscape = patternInputValEscape;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_analysis._patternInputValEscape = _previousInputValEscape;
|
|
}
|
|
}
|
|
|
|
private ref struct PlaceholderRegion
|
|
{
|
|
private readonly RefSafetyAnalysis _analysis;
|
|
|
|
private readonly ArrayBuilder<(BoundValuePlaceholderBase, uint)> _placeholders;
|
|
|
|
public PlaceholderRegion(RefSafetyAnalysis analysis, ArrayBuilder<(BoundValuePlaceholderBase, uint)> placeholders)
|
|
{
|
|
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
|
|
_analysis = analysis;
|
|
_placeholders = placeholders;
|
|
Enumerator<(BoundValuePlaceholderBase, uint)> enumerator = placeholders.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
var (placeholder, valEscapeScope) = enumerator.Current;
|
|
_analysis.AddPlaceholderScope(placeholder, valEscapeScope);
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
|
|
Enumerator<(BoundValuePlaceholderBase, uint)> enumerator = _placeholders.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundValuePlaceholderBase item = enumerator.Current.Item1;
|
|
_analysis.RemovePlaceholderScope(item);
|
|
}
|
|
_placeholders.Free();
|
|
}
|
|
}
|
|
|
|
private readonly struct DeconstructionVariable
|
|
{
|
|
internal readonly BoundExpression Expression;
|
|
|
|
internal readonly uint ValEscape;
|
|
|
|
internal readonly ArrayBuilder<DeconstructionVariable>? NestedVariables;
|
|
|
|
internal DeconstructionVariable(BoundExpression expression, uint valEscape, ArrayBuilder<DeconstructionVariable>? nestedVariables)
|
|
{
|
|
Expression = expression;
|
|
ValEscape = valEscape;
|
|
NestedVariables = nestedVariables;
|
|
}
|
|
}
|
|
|
|
private const uint CallingMethodScope = 0u;
|
|
|
|
private const uint ReturnOnlyScope = 1u;
|
|
|
|
private const uint CurrentMethodScope = 2u;
|
|
|
|
private readonly CSharpCompilation _compilation;
|
|
|
|
private readonly MethodSymbol _symbol;
|
|
|
|
private readonly bool _useUpdatedEscapeRules;
|
|
|
|
private readonly BindingDiagnosticBag _diagnostics;
|
|
|
|
private bool _inUnsafeRegion;
|
|
|
|
private uint _localScopeDepth;
|
|
|
|
private Dictionary<LocalSymbol, (uint RefEscapeScope, uint ValEscapeScope)>? _localEscapeScopes;
|
|
|
|
private Dictionary<BoundValuePlaceholderBase, uint>? _placeholderScopes;
|
|
|
|
private uint _patternInputValEscape;
|
|
|
|
private bool CheckLocalRefEscape(SyntaxNode node, BoundLocal local, uint escapeTo, bool checkingReceiver, BindingDiagnosticBag diagnostics)
|
|
{
|
|
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
|
|
LocalSymbol localSymbol = local.LocalSymbol;
|
|
if (GetLocalScopes(localSymbol).RefEscapeScope <= escapeTo)
|
|
{
|
|
return true;
|
|
}
|
|
bool inUnsafeRegion = _inUnsafeRegion;
|
|
if (escapeTo <= 1)
|
|
{
|
|
if ((int)localSymbol.RefKind == 0)
|
|
{
|
|
if (checkingReceiver)
|
|
{
|
|
Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_RefReturnLocal2 : ErrorCode.ERR_RefReturnLocal2, SyntaxNodeOrToken.op_Implicit(local.Syntax), localSymbol);
|
|
}
|
|
else
|
|
{
|
|
Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_RefReturnLocal : ErrorCode.ERR_RefReturnLocal, SyntaxNodeOrToken.op_Implicit(node), localSymbol);
|
|
}
|
|
return inUnsafeRegion;
|
|
}
|
|
if (checkingReceiver)
|
|
{
|
|
Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_RefReturnNonreturnableLocal2 : ErrorCode.ERR_RefReturnNonreturnableLocal2, SyntaxNodeOrToken.op_Implicit(local.Syntax), localSymbol);
|
|
}
|
|
else
|
|
{
|
|
Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_RefReturnNonreturnableLocal : ErrorCode.ERR_RefReturnNonreturnableLocal, SyntaxNodeOrToken.op_Implicit(node), localSymbol);
|
|
}
|
|
return inUnsafeRegion;
|
|
}
|
|
Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_EscapeVariable : ErrorCode.ERR_EscapeVariable, SyntaxNodeOrToken.op_Implicit(node), localSymbol);
|
|
return inUnsafeRegion;
|
|
}
|
|
|
|
private static EscapeLevel? EscapeLevelFromScope(uint scope)
|
|
{
|
|
return scope switch
|
|
{
|
|
1u => EscapeLevel.ReturnOnly,
|
|
0u => EscapeLevel.CallingMethod,
|
|
_ => null,
|
|
};
|
|
}
|
|
|
|
private static uint GetParameterValEscape(ParameterSymbol parameter)
|
|
{
|
|
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000a: Invalid comparison between Unknown and I4
|
|
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0013: Invalid comparison between Unknown and I4
|
|
if ((object)parameter != null)
|
|
{
|
|
if ((int)parameter.EffectiveScope == 2)
|
|
{
|
|
return 2u;
|
|
}
|
|
if ((int)parameter.RefKind == 2 && parameter.UseUpdatedEscapeRules)
|
|
{
|
|
return 1u;
|
|
}
|
|
}
|
|
return 0u;
|
|
}
|
|
|
|
private static EscapeLevel? GetParameterValEscapeLevel(ParameterSymbol parameter)
|
|
{
|
|
return EscapeLevelFromScope(GetParameterValEscape(parameter));
|
|
}
|
|
|
|
private static uint GetParameterRefEscape(ParameterSymbol parameter)
|
|
{
|
|
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000c: Invalid comparison between Unknown and I4
|
|
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0015: Invalid comparison between Unknown and I4
|
|
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0021: Invalid comparison between Unknown and I4
|
|
if ((object)parameter != null)
|
|
{
|
|
RefKind refKind = parameter.RefKind;
|
|
if ((int)refKind == 0)
|
|
{
|
|
return 2u;
|
|
}
|
|
if ((int)parameter.EffectiveScope == 1)
|
|
{
|
|
return 2u;
|
|
}
|
|
if (parameter.HasUnscopedRefAttribute)
|
|
{
|
|
if ((int)refKind == 2)
|
|
{
|
|
return 1u;
|
|
}
|
|
if (!parameter.IsThis)
|
|
{
|
|
return 0u;
|
|
}
|
|
}
|
|
}
|
|
return 1u;
|
|
}
|
|
|
|
private static EscapeLevel? GetParameterRefEscapeLevel(ParameterSymbol parameter)
|
|
{
|
|
return EscapeLevelFromScope(GetParameterRefEscape(parameter));
|
|
}
|
|
|
|
private bool CheckParameterValEscape(SyntaxNode node, ParameterSymbol parameter, uint escapeTo, BindingDiagnosticBag diagnostics)
|
|
{
|
|
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
|
|
if (_useUpdatedEscapeRules)
|
|
{
|
|
if (GetParameterValEscape(parameter) > escapeTo)
|
|
{
|
|
Error(diagnostics, _inUnsafeRegion ? ErrorCode.WRN_EscapeVariable : ErrorCode.ERR_EscapeVariable, SyntaxNodeOrToken.op_Implicit(node), parameter);
|
|
return _inUnsafeRegion;
|
|
}
|
|
return true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private bool CheckParameterRefEscape(SyntaxNode node, BoundExpression parameter, ParameterSymbol parameterSymbol, uint escapeTo, bool checkingReceiver, BindingDiagnosticBag diagnostics)
|
|
{
|
|
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0016: Invalid comparison between Unknown and I4
|
|
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0186: Unknown result type (might be due to invalid IL or missing references)
|
|
uint parameterRefEscape = GetParameterRefEscape(parameterSymbol);
|
|
if (parameterRefEscape > escapeTo)
|
|
{
|
|
bool flag = (int)parameterSymbol.EffectiveScope == 1;
|
|
bool inUnsafeRegion = _inUnsafeRegion;
|
|
if (parameter is BoundThisReference)
|
|
{
|
|
Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_RefReturnStructThis : ErrorCode.ERR_RefReturnStructThis, SyntaxNodeOrToken.op_Implicit(node));
|
|
return inUnsafeRegion;
|
|
}
|
|
var (code, val) = (checkingReceiver ? (flag ? (inUnsafeRegion ? (ErrorCode.WRN_RefReturnScopedParameter2, parameter.Syntax) : (ErrorCode.ERR_RefReturnScopedParameter2, parameter.Syntax)) : ((!inUnsafeRegion) ? ((parameterRefEscape != 1) ? (ErrorCode.ERR_RefReturnParameter2, parameter.Syntax) : (ErrorCode.ERR_RefReturnOnlyParameter2, parameter.Syntax)) : ((parameterRefEscape != 1) ? (ErrorCode.WRN_RefReturnParameter2, parameter.Syntax) : (ErrorCode.WRN_RefReturnOnlyParameter2, parameter.Syntax)))) : (flag ? (inUnsafeRegion ? (ErrorCode.WRN_RefReturnScopedParameter, node) : (ErrorCode.ERR_RefReturnScopedParameter, node)) : ((!inUnsafeRegion) ? ((parameterRefEscape != 1) ? (ErrorCode.ERR_RefReturnParameter, node) : (ErrorCode.ERR_RefReturnOnlyParameter, node)) : ((parameterRefEscape != 1) ? (ErrorCode.WRN_RefReturnParameter, node) : (ErrorCode.WRN_RefReturnOnlyParameter, node)))));
|
|
Error(diagnostics, code, SyntaxNodeOrToken.op_Implicit(val), parameterSymbol.Name);
|
|
return inUnsafeRegion;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private uint GetFieldRefEscape(BoundFieldAccess fieldAccess, uint scopeOfTheContainingExpression)
|
|
{
|
|
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
|
|
FieldSymbol fieldSymbol = fieldAccess.FieldSymbol;
|
|
if (fieldSymbol.IsStatic || fieldSymbol.ContainingType.IsReferenceType)
|
|
{
|
|
return 0u;
|
|
}
|
|
if (_useUpdatedEscapeRules && (int)fieldSymbol.RefKind != 0)
|
|
{
|
|
return GetValEscape(fieldAccess.ReceiverOpt, scopeOfTheContainingExpression);
|
|
}
|
|
return GetRefEscape(fieldAccess.ReceiverOpt, scopeOfTheContainingExpression);
|
|
}
|
|
|
|
private bool CheckFieldRefEscape(SyntaxNode node, BoundFieldAccess fieldAccess, uint escapeFrom, uint escapeTo, BindingDiagnosticBag diagnostics)
|
|
{
|
|
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
|
|
FieldSymbol fieldSymbol = fieldAccess.FieldSymbol;
|
|
if (fieldSymbol.IsStatic || fieldSymbol.ContainingType.IsReferenceType)
|
|
{
|
|
return true;
|
|
}
|
|
if (_useUpdatedEscapeRules && (int)fieldSymbol.RefKind != 0)
|
|
{
|
|
return CheckValEscape(node, fieldAccess.ReceiverOpt, escapeFrom, escapeTo, checkingReceiver: true, diagnostics);
|
|
}
|
|
return CheckRefEscape(node, fieldAccess.ReceiverOpt, escapeFrom, escapeTo, checkingReceiver: true, diagnostics);
|
|
}
|
|
|
|
private bool CheckFieldLikeEventRefEscape(SyntaxNode node, BoundEventAccess eventAccess, uint escapeFrom, uint escapeTo, BindingDiagnosticBag diagnostics)
|
|
{
|
|
EventSymbol eventSymbol = eventAccess.EventSymbol;
|
|
if (eventSymbol.IsStatic || eventSymbol.ContainingType.IsReferenceType)
|
|
{
|
|
return true;
|
|
}
|
|
return CheckRefEscape(node, eventAccess.ReceiverOpt, escapeFrom, escapeTo, checkingReceiver: true, diagnostics);
|
|
}
|
|
|
|
internal uint GetInterpolatedStringHandlerConversionEscapeScope(BoundExpression expression, uint scopeOfTheContainingExpression)
|
|
{
|
|
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
|
|
uint num = GetValEscape(expression.GetInterpolatedStringHandlerData().Construction, scopeOfTheContainingExpression);
|
|
ArrayBuilder<BoundExpression> instance = ArrayBuilder<BoundExpression>.GetInstance();
|
|
GetInterpolatedStringHandlerArgumentsForEscape(expression, instance);
|
|
Enumerator<BoundExpression> enumerator = instance.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundExpression current = enumerator.Current;
|
|
uint valEscape = GetValEscape(current, scopeOfTheContainingExpression);
|
|
num = Math.Max(num, valEscape);
|
|
}
|
|
instance.Free();
|
|
return num;
|
|
}
|
|
|
|
private uint GetInvocationEscapeScope(Symbol symbol, BoundExpression? receiver, ThreeState receiverIsSubjectToCloning, ImmutableArray<ParameterSymbol> parameters, ImmutableArray<BoundExpression> argsOpt, ImmutableArray<RefKind> argRefKindsOpt, ImmutableArray<int> argsToParamsOpt, uint scopeOfTheContainingExpression, bool isRefEscape)
|
|
{
|
|
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_006b: Invalid comparison between Unknown and I4
|
|
if (UseUpdatedEscapeRulesForInvocation(symbol))
|
|
{
|
|
return GetInvocationEscapeWithUpdatedRules(symbol, receiver, receiverIsSubjectToCloning, parameters, argsOpt, argRefKindsOpt, argsToParamsOpt, scopeOfTheContainingExpression, isRefEscape);
|
|
}
|
|
if (!symbol.RequiresInstanceReceiver())
|
|
{
|
|
receiver = null;
|
|
}
|
|
uint num = 0u;
|
|
ArrayBuilder<EscapeArgument> instance = ArrayBuilder<EscapeArgument>.GetInstance();
|
|
GetInvocationArgumentsForEscape(symbol, null, (ThreeState)0, parameters, argsOpt, argRefKindsOpt, argsToParamsOpt, ignoreArglistRefKinds: true, null, instance);
|
|
try
|
|
{
|
|
Enumerator<EscapeArgument> enumerator = instance.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
enumerator.Current.Deconstruct(out ParameterSymbol _, out BoundExpression argument, out RefKind refKind);
|
|
BoundExpression expr = argument;
|
|
uint val = (((int)refKind > 0 && isRefEscape) ? GetRefEscape(expr, scopeOfTheContainingExpression) : GetValEscape(expr, scopeOfTheContainingExpression));
|
|
num = Math.Max(num, val);
|
|
if (num >= scopeOfTheContainingExpression)
|
|
{
|
|
return num;
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
instance.Free();
|
|
}
|
|
if (receiver != null && receiver.Type?.IsRefLikeType == true)
|
|
{
|
|
num = Math.Max(num, GetValEscape(receiver, scopeOfTheContainingExpression));
|
|
}
|
|
return num;
|
|
}
|
|
|
|
private uint GetInvocationEscapeWithUpdatedRules(Symbol symbol, BoundExpression? receiver, ThreeState receiverIsSubjectToCloning, ImmutableArray<ParameterSymbol> parameters, ImmutableArray<BoundExpression> argsOpt, ImmutableArray<RefKind> argRefKindsOpt, ImmutableArray<int> argsToParamsOpt, uint scopeOfTheContainingExpression, bool isRefEscape)
|
|
{
|
|
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_006a: Invalid comparison between Unknown and I4
|
|
uint num = 0u;
|
|
ArrayBuilder<EscapeValue> instance = ArrayBuilder<EscapeValue>.GetInstance();
|
|
GetFilteredInvocationArgumentsForEscapeWithUpdatedRules(symbol, receiver, receiverIsSubjectToCloning, parameters, argsOpt, argRefKindsOpt, argsToParamsOpt, isRefEscape, ignoreArglistRefKinds: true, instance);
|
|
bool flag = ReturnsRefToRefStruct(symbol);
|
|
Enumerator<EscapeValue> enumerator = instance.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
enumerator.Current.Deconstruct(out ParameterSymbol parameter, out BoundExpression argument, out EscapeLevel _, out bool isRefEscape2);
|
|
ParameterSymbol parameterSymbol = parameter;
|
|
BoundExpression expr = argument;
|
|
bool flag2 = isRefEscape2;
|
|
isRefEscape2 = !flag;
|
|
bool flag3;
|
|
if (!isRefEscape2)
|
|
{
|
|
if ((object)parameterSymbol == null)
|
|
{
|
|
goto IL_0082;
|
|
}
|
|
if ((int)parameterSymbol.RefKind != 0)
|
|
{
|
|
TypeSymbol type = parameterSymbol.Type;
|
|
if ((object)type != null && type.IsRefLikeType)
|
|
{
|
|
goto IL_0082;
|
|
}
|
|
}
|
|
flag3 = false;
|
|
goto IL_008a;
|
|
}
|
|
goto IL_0099;
|
|
IL_008a:
|
|
isRefEscape2 = flag3 && flag2 == isRefEscape;
|
|
goto IL_0099;
|
|
IL_0099:
|
|
if (isRefEscape2)
|
|
{
|
|
uint val = (flag2 ? GetRefEscape(expr, scopeOfTheContainingExpression) : GetValEscape(expr, scopeOfTheContainingExpression));
|
|
num = Math.Max(num, val);
|
|
if (num >= scopeOfTheContainingExpression)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
continue;
|
|
IL_0082:
|
|
flag3 = true;
|
|
goto IL_008a;
|
|
}
|
|
instance.Free();
|
|
return num;
|
|
}
|
|
|
|
private static bool ReturnsRefToRefStruct(Symbol symbol)
|
|
{
|
|
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0031: Invalid comparison between Unknown and I4
|
|
MethodSymbol methodSymbol = ((symbol is MethodSymbol methodSymbol2) ? methodSymbol2 : ((!(symbol is PropertySymbol propertySymbol)) ? null : propertySymbol.GetMethod));
|
|
MethodSymbol methodSymbol3 = methodSymbol;
|
|
if ((object)methodSymbol3 != null && (int)methodSymbol3.RefKind != 0)
|
|
{
|
|
TypeSymbol returnType = methodSymbol3.ReturnType;
|
|
if ((object)returnType != null)
|
|
{
|
|
return returnType.IsRefLikeType;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool CheckInvocationEscape(SyntaxNode syntax, Symbol symbol, BoundExpression? receiver, ThreeState receiverIsSubjectToCloning, ImmutableArray<ParameterSymbol> parameters, ImmutableArray<BoundExpression> argsOpt, ImmutableArray<RefKind> argRefKindsOpt, ImmutableArray<int> argsToParamsOpt, bool checkingReceiver, uint escapeFrom, uint escapeTo, BindingDiagnosticBag diagnostics, bool isRefEscape)
|
|
{
|
|
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0074: Invalid comparison between Unknown and I4
|
|
if (UseUpdatedEscapeRulesForInvocation(symbol))
|
|
{
|
|
return CheckInvocationEscapeWithUpdatedRules(syntax, symbol, receiver, receiverIsSubjectToCloning, parameters, argsOpt, argRefKindsOpt, argsToParamsOpt, checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape);
|
|
}
|
|
if (!symbol.RequiresInstanceReceiver())
|
|
{
|
|
receiver = null;
|
|
}
|
|
ArrayBuilder<EscapeArgument> instance = ArrayBuilder<EscapeArgument>.GetInstance();
|
|
GetInvocationArgumentsForEscape(symbol, null, (ThreeState)0, parameters, argsOpt, argRefKindsOpt, argsToParamsOpt, ignoreArglistRefKinds: true, null, instance);
|
|
try
|
|
{
|
|
Enumerator<EscapeArgument> enumerator = instance.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
var (parameter, boundExpression2, val2) = (EscapeArgument)(ref enumerator.Current);
|
|
if (!(((int)val2 > 0 && isRefEscape) ? CheckRefEscape(boundExpression2.Syntax, boundExpression2, escapeFrom, escapeTo, checkingReceiver: false, diagnostics) : CheckValEscape(boundExpression2.Syntax, boundExpression2, escapeFrom, escapeTo, checkingReceiver: false, diagnostics)))
|
|
{
|
|
if (!(symbol is SignatureOnlyMethodSymbol))
|
|
{
|
|
ReportInvocationEscapeError(syntax, symbol, parameter, checkingReceiver, diagnostics);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
instance.Free();
|
|
}
|
|
if (receiver != null && receiver.Type?.IsRefLikeType == true)
|
|
{
|
|
return CheckValEscape(receiver.Syntax, receiver, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private bool CheckInvocationEscapeWithUpdatedRules(SyntaxNode syntax, Symbol symbol, BoundExpression? receiver, ThreeState receiverIsSubjectToCloning, ImmutableArray<ParameterSymbol> parameters, ImmutableArray<BoundExpression> argsOpt, ImmutableArray<RefKind> argRefKindsOpt, ImmutableArray<int> argsToParamsOpt, bool checkingReceiver, uint escapeFrom, uint escapeTo, BindingDiagnosticBag diagnostics, bool isRefEscape)
|
|
{
|
|
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_006b: Invalid comparison between Unknown and I4
|
|
bool result = true;
|
|
ArrayBuilder<EscapeValue> instance = ArrayBuilder<EscapeValue>.GetInstance();
|
|
GetFilteredInvocationArgumentsForEscapeWithUpdatedRules(symbol, receiver, receiverIsSubjectToCloning, parameters, argsOpt, argRefKindsOpt, argsToParamsOpt, isRefEscape, ignoreArglistRefKinds: true, instance);
|
|
bool flag = ReturnsRefToRefStruct(symbol);
|
|
Enumerator<EscapeValue> enumerator = instance.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
enumerator.Current.Deconstruct(out ParameterSymbol parameter, out BoundExpression argument, out EscapeLevel _, out bool isRefEscape2);
|
|
ParameterSymbol parameterSymbol = parameter;
|
|
BoundExpression boundExpression = argument;
|
|
bool flag2 = isRefEscape2;
|
|
isRefEscape2 = !flag;
|
|
bool flag3;
|
|
if (!isRefEscape2)
|
|
{
|
|
if ((object)parameterSymbol == null)
|
|
{
|
|
goto IL_0083;
|
|
}
|
|
if ((int)parameterSymbol.RefKind != 0)
|
|
{
|
|
TypeSymbol type = parameterSymbol.Type;
|
|
if ((object)type != null && type.IsRefLikeType)
|
|
{
|
|
goto IL_0083;
|
|
}
|
|
}
|
|
flag3 = false;
|
|
goto IL_008b;
|
|
}
|
|
goto IL_009a;
|
|
IL_008b:
|
|
isRefEscape2 = flag3 && flag2 == isRefEscape;
|
|
goto IL_009a;
|
|
IL_009a:
|
|
if (isRefEscape2 && !(flag2 ? CheckRefEscape(boundExpression.Syntax, boundExpression, escapeFrom, escapeTo, checkingReceiver: false, diagnostics) : CheckValEscape(boundExpression.Syntax, boundExpression, escapeFrom, escapeTo, checkingReceiver: false, diagnostics)))
|
|
{
|
|
if (((boundExpression as BoundCapturedReceiverPlaceholder)?.Receiver ?? boundExpression) != receiver && !(symbol is SignatureOnlyMethodSymbol))
|
|
{
|
|
ReportInvocationEscapeError(syntax, symbol, parameterSymbol, checkingReceiver, diagnostics);
|
|
}
|
|
result = false;
|
|
break;
|
|
}
|
|
continue;
|
|
IL_0083:
|
|
flag3 = true;
|
|
goto IL_008b;
|
|
}
|
|
instance.Free();
|
|
return result;
|
|
}
|
|
|
|
private void GetInvocationArgumentsForEscape(Symbol symbol, BoundExpression? receiver, ThreeState receiverIsSubjectToCloning, ImmutableArray<ParameterSymbol> parameters, ImmutableArray<BoundExpression> argsOpt, ImmutableArray<RefKind> argRefKindsOpt, ImmutableArray<int> argsToParamsOpt, bool ignoreArglistRefKinds, ArrayBuilder<MixableDestination>? mixableArguments, ArrayBuilder<EscapeArgument> escapeArguments)
|
|
{
|
|
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_003d: Invalid comparison between Unknown and I4
|
|
//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_0166: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0169: Invalid comparison between Unknown and I4
|
|
//IL_015f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_01ba: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0183: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_019a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_019f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_01a6: Invalid comparison between Unknown and I4
|
|
if (receiver != null)
|
|
{
|
|
MethodSymbol methodSymbol2;
|
|
if (!(symbol is MethodSymbol methodSymbol))
|
|
{
|
|
if (!(symbol is PropertySymbol propertySymbol))
|
|
{
|
|
throw ExceptionUtilities.UnexpectedValue((object)symbol);
|
|
}
|
|
methodSymbol2 = propertySymbol.GetMethod ?? propertySymbol.SetMethod;
|
|
}
|
|
else
|
|
{
|
|
methodSymbol2 = methodSymbol;
|
|
}
|
|
MethodSymbol method = methodSymbol2;
|
|
if ((int)receiverIsSubjectToCloning == 2)
|
|
{
|
|
receiver = new BoundCapturedReceiverPlaceholder(receiver.Syntax, receiver, _localScopeDepth, receiver.Type).MakeCompilerGenerated();
|
|
}
|
|
EscapeArgument escapeArgument = getReceiver(method, receiver);
|
|
escapeArguments.Add(escapeArgument);
|
|
if (mixableArguments != null && isMixableParameter(escapeArgument.Parameter))
|
|
{
|
|
mixableArguments.Add(new MixableDestination(escapeArgument.Parameter, receiver));
|
|
}
|
|
}
|
|
if (argsOpt.IsDefault)
|
|
{
|
|
return;
|
|
}
|
|
for (int num = 0; num < argsOpt.Length; num++)
|
|
{
|
|
BoundExpression boundExpression = argsOpt[num];
|
|
if (boundExpression.Kind == BoundKind.ArgListOperator)
|
|
{
|
|
BoundArgListOperator boundArgListOperator = (BoundArgListOperator)boundExpression;
|
|
getArgList(boundArgListOperator.Arguments, ignoreArglistRefKinds ? default(ImmutableArray<RefKind>) : boundArgListOperator.ArgumentRefKindsOpt, mixableArguments, escapeArguments);
|
|
break;
|
|
}
|
|
ParameterSymbol parameterSymbol = ((num < parameters.Length) ? parameters[argsToParamsOpt.IsDefault ? num : argsToParamsOpt[num]] : null);
|
|
if (mixableArguments != null && isMixableParameter(parameterSymbol) && isMixableArgument(boundExpression))
|
|
{
|
|
mixableArguments.Add(new MixableDestination(parameterSymbol, boundExpression));
|
|
}
|
|
RefKind val = (RefKind)(((object)parameterSymbol != null) ? ((int)parameterSymbol.RefKind) : 0);
|
|
if (!argRefKindsOpt.IsDefault)
|
|
{
|
|
val = argRefKindsOpt[num];
|
|
}
|
|
bool flag = (int)val == 0;
|
|
bool flag2;
|
|
if (flag)
|
|
{
|
|
RefKind? val2 = parameterSymbol?.RefKind;
|
|
if (val2.HasValue)
|
|
{
|
|
RefKind valueOrDefault = val2.GetValueOrDefault();
|
|
if (valueOrDefault - 3 <= 1)
|
|
{
|
|
flag2 = true;
|
|
goto IL_01b0;
|
|
}
|
|
}
|
|
flag2 = false;
|
|
goto IL_01b0;
|
|
}
|
|
goto IL_01b4;
|
|
IL_01b0:
|
|
flag = flag2;
|
|
goto IL_01b4;
|
|
IL_01b4:
|
|
if (flag)
|
|
{
|
|
val = parameterSymbol.RefKind;
|
|
}
|
|
escapeArguments.Add(new EscapeArgument(parameterSymbol, boundExpression, val));
|
|
}
|
|
static void getArgList(ImmutableArray<BoundExpression> immutableArray, ImmutableArray<RefKind> immutableArray2, ArrayBuilder<MixableDestination>? val5, ArrayBuilder<EscapeArgument> val4)
|
|
{
|
|
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0033: Invalid comparison between Unknown and I4
|
|
for (int i = 0; i < immutableArray.Length; i++)
|
|
{
|
|
BoundExpression argument = immutableArray[i];
|
|
RefKind val3 = (RefKind)((!immutableArray2.IsDefault) ? ((int)immutableArray2[i]) : 0);
|
|
val4.Add(new EscapeArgument(null, argument, val3, isArgList: true));
|
|
if ((int)val3 == 1)
|
|
{
|
|
val5?.Add(new MixableDestination(argument, EscapeLevel.CallingMethod));
|
|
}
|
|
}
|
|
}
|
|
static EscapeArgument getReceiver(MethodSymbol? methodSymbol3, BoundExpression argument)
|
|
{
|
|
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
|
|
if (methodSymbol3 is FunctionPointerMethodSymbol)
|
|
{
|
|
return new EscapeArgument(null, argument, (RefKind)0);
|
|
}
|
|
RefKind refKind = (RefKind)0;
|
|
ParameterSymbol thisParameter = null;
|
|
if ((object)methodSymbol3 != null && methodSymbol3.TryGetThisParameter(out thisParameter) && (object)thisParameter != null)
|
|
{
|
|
refKind = thisParameter.RefKind;
|
|
}
|
|
return new EscapeArgument(thisParameter, argument, refKind);
|
|
}
|
|
static bool isMixableArgument(BoundExpression argument)
|
|
{
|
|
if (argument is BoundDeconstructValuePlaceholder boundDeconstructValuePlaceholder)
|
|
{
|
|
if ((object)boundDeconstructValuePlaceholder.VariableSymbol != null)
|
|
{
|
|
goto IL_0026;
|
|
}
|
|
}
|
|
else if (argument is BoundLocal { DeclarationKind: not BoundLocalDeclarationKind.None })
|
|
{
|
|
goto IL_0026;
|
|
}
|
|
bool flag3 = false;
|
|
goto IL_002c;
|
|
IL_0026:
|
|
flag3 = true;
|
|
goto IL_002c;
|
|
IL_002c:
|
|
if (flag3)
|
|
{
|
|
return false;
|
|
}
|
|
if (argument.IsDiscardExpression())
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
static bool isMixableParameter([NotNullWhen(true)] ParameterSymbol? parameter)
|
|
{
|
|
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
|
|
if ((object)parameter != null && parameter.Type.IsRefLikeType)
|
|
{
|
|
return parameter.RefKind.IsWritableReference();
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private void GetFilteredInvocationArgumentsForEscapeWithUpdatedRules(Symbol symbol, BoundExpression? receiver, ThreeState receiverIsSubjectToCloning, ImmutableArray<ParameterSymbol> parameters, ImmutableArray<BoundExpression> argsOpt, ImmutableArray<RefKind> argRefKindsOpt, ImmutableArray<int> argsToParamsOpt, bool isInvokedWithRef, bool ignoreArglistRefKinds, ArrayBuilder<EscapeValue> escapeValues)
|
|
{
|
|
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
|
|
if (isInvokedWithRef || hasRefLikeReturn(symbol))
|
|
{
|
|
GetEscapeValuesForUpdatedRules(symbol, receiver, receiverIsSubjectToCloning, parameters, argsOpt, argRefKindsOpt, argsToParamsOpt, ignoreArglistRefKinds, null, escapeValues);
|
|
}
|
|
static bool hasRefLikeReturn(Symbol symbol2)
|
|
{
|
|
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_001d: Invalid comparison between Unknown and I4
|
|
if (symbol2 is MethodSymbol methodSymbol)
|
|
{
|
|
if ((int)methodSymbol.MethodKind == 1)
|
|
{
|
|
return methodSymbol.ContainingType.IsRefLikeType;
|
|
}
|
|
return methodSymbol.ReturnType.IsRefLikeType;
|
|
}
|
|
if (symbol2 is PropertySymbol propertySymbol)
|
|
{
|
|
return propertySymbol.Type.IsRefLikeType;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private void GetEscapeValuesForUpdatedRules(Symbol symbol, BoundExpression? receiver, ThreeState receiverIsSubjectToCloning, ImmutableArray<ParameterSymbol> parameters, ImmutableArray<BoundExpression> argsOpt, ImmutableArray<RefKind> argRefKindsOpt, ImmutableArray<int> argsToParamsOpt, bool ignoreArglistRefKinds, ArrayBuilder<MixableDestination>? mixableArguments, ArrayBuilder<EscapeValue> escapeValues)
|
|
{
|
|
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00a7: Invalid comparison between Unknown and I4
|
|
if (!symbol.RequiresInstanceReceiver())
|
|
{
|
|
receiver = null;
|
|
}
|
|
ArrayBuilder<EscapeArgument> instance = ArrayBuilder<EscapeArgument>.GetInstance();
|
|
GetInvocationArgumentsForEscape(symbol, receiver, receiverIsSubjectToCloning, parameters, argsOpt, argRefKindsOpt, argsToParamsOpt, ignoreArglistRefKinds, mixableArguments, instance);
|
|
Enumerator<EscapeArgument> enumerator = instance.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
var (parameterSymbol2, boundExpression2, val2) = (EscapeArgument)(ref enumerator.Current);
|
|
if ((object)parameterSymbol2 == null)
|
|
{
|
|
if ((int)val2 != 0)
|
|
{
|
|
escapeValues.Add(new EscapeValue(null, boundExpression2, EscapeLevel.ReturnOnly, isRefEscape: true));
|
|
}
|
|
TypeSymbol? type = boundExpression2.Type;
|
|
if ((object)type != null && type.IsRefLikeType)
|
|
{
|
|
escapeValues.Add(new EscapeValue(null, boundExpression2, EscapeLevel.CallingMethod, isRefEscape: false));
|
|
}
|
|
continue;
|
|
}
|
|
if (parameterSymbol2.Type.IsRefLikeType && (int)parameterSymbol2.RefKind != 2)
|
|
{
|
|
EscapeLevel? parameterValEscapeLevel = GetParameterValEscapeLevel(parameterSymbol2);
|
|
if (parameterValEscapeLevel.HasValue)
|
|
{
|
|
EscapeLevel valueOrDefault = parameterValEscapeLevel.GetValueOrDefault();
|
|
escapeValues.Add(new EscapeValue(parameterSymbol2, boundExpression2, valueOrDefault, isRefEscape: false));
|
|
}
|
|
}
|
|
if ((int)parameterSymbol2.RefKind != 0)
|
|
{
|
|
EscapeLevel? parameterValEscapeLevel = GetParameterRefEscapeLevel(parameterSymbol2);
|
|
if (parameterValEscapeLevel.HasValue)
|
|
{
|
|
EscapeLevel valueOrDefault2 = parameterValEscapeLevel.GetValueOrDefault();
|
|
escapeValues.Add(new EscapeValue(parameterSymbol2, boundExpression2, valueOrDefault2, isRefEscape: true));
|
|
}
|
|
}
|
|
}
|
|
instance.Free();
|
|
}
|
|
|
|
private static string GetInvocationParameterName(ParameterSymbol? parameter)
|
|
{
|
|
if ((object)parameter == null)
|
|
{
|
|
return "__arglist";
|
|
}
|
|
string text = parameter.Name;
|
|
if (string.IsNullOrEmpty(text))
|
|
{
|
|
text = parameter.Ordinal.ToString();
|
|
}
|
|
return text;
|
|
}
|
|
|
|
private static void ReportInvocationEscapeError(SyntaxNode syntax, Symbol symbol, ParameterSymbol? parameter, bool checkingReceiver, BindingDiagnosticBag diagnostics)
|
|
{
|
|
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
|
|
ErrorCode standardCallEscapeError = GetStandardCallEscapeError(checkingReceiver);
|
|
string invocationParameterName = GetInvocationParameterName(parameter);
|
|
Error(diagnostics, standardCallEscapeError, SyntaxNodeOrToken.op_Implicit(syntax), symbol, invocationParameterName);
|
|
}
|
|
|
|
private bool UseUpdatedEscapeRulesForInvocation(Symbol symbol)
|
|
{
|
|
MethodSymbol methodSymbol2;
|
|
if (!(symbol is MethodSymbol methodSymbol))
|
|
{
|
|
if (!(symbol is PropertySymbol propertySymbol))
|
|
{
|
|
throw ExceptionUtilities.UnexpectedValue((object)symbol);
|
|
}
|
|
methodSymbol2 = propertySymbol.GetMethod ?? propertySymbol.SetMethod;
|
|
}
|
|
else
|
|
{
|
|
methodSymbol2 = methodSymbol;
|
|
}
|
|
return methodSymbol2?.UseUpdatedEscapeRules ?? false;
|
|
}
|
|
|
|
private bool ShouldInferDeclarationExpressionValEscape(BoundExpression argument, [NotNullWhen(true)] out SourceLocalSymbol? localSymbol)
|
|
{
|
|
Symbol symbol = ((argument is BoundDeconstructValuePlaceholder boundDeconstructValuePlaceholder) ? boundDeconstructValuePlaceholder.VariableSymbol : ((!(argument is BoundLocal { DeclarationKind: not BoundLocalDeclarationKind.None } boundLocal)) ? null : boundLocal.LocalSymbol));
|
|
if (symbol is SourceLocalSymbol sourceLocalSymbol && GetLocalScopes(sourceLocalSymbol).ValEscapeScope == 0)
|
|
{
|
|
localSymbol = sourceLocalSymbol;
|
|
return true;
|
|
}
|
|
localSymbol = null;
|
|
return false;
|
|
}
|
|
|
|
private bool CheckInvocationArgMixing(SyntaxNode syntax, Symbol symbol, BoundExpression? receiverOpt, ThreeState receiverIsSubjectToCloning, ImmutableArray<ParameterSymbol> parameters, ImmutableArray<BoundExpression> argsOpt, ImmutableArray<RefKind> argRefKindsOpt, ImmutableArray<int> argsToParamsOpt, uint scopeOfTheContainingExpression, BindingDiagnosticBag diagnostics)
|
|
{
|
|
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0182: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0187: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_015d: Unknown result type (might be due to invalid IL or missing references)
|
|
if (UseUpdatedEscapeRulesForInvocation(symbol))
|
|
{
|
|
return CheckInvocationArgMixingWithUpdatedRules(syntax, symbol, receiverOpt, receiverIsSubjectToCloning, parameters, argsOpt, argRefKindsOpt, argsToParamsOpt, scopeOfTheContainingExpression, diagnostics);
|
|
}
|
|
if (!symbol.RequiresInstanceReceiver())
|
|
{
|
|
receiverOpt = null;
|
|
}
|
|
uint num = scopeOfTheContainingExpression;
|
|
TypeSymbol? obj = receiverOpt?.Type;
|
|
if ((object)obj != null && obj.IsRefLikeType && !IsReceiverRefReadOnly(symbol))
|
|
{
|
|
num = GetValEscape(receiverOpt, scopeOfTheContainingExpression);
|
|
}
|
|
ArrayBuilder<EscapeArgument> instance = ArrayBuilder<EscapeArgument>.GetInstance();
|
|
GetInvocationArgumentsForEscape(symbol, receiverOpt, receiverIsSubjectToCloning, parameters, argsOpt, default(ImmutableArray<RefKind>), argsToParamsOpt, ignoreArglistRefKinds: false, null, instance);
|
|
try
|
|
{
|
|
Enumerator<EscapeArgument> enumerator = instance.GetEnumerator();
|
|
ParameterSymbol parameter;
|
|
BoundExpression argument;
|
|
RefKind refKind;
|
|
while (enumerator.MoveNext())
|
|
{
|
|
enumerator.Current.Deconstruct(out parameter, out argument, out refKind);
|
|
BoundExpression boundExpression = argument;
|
|
RefKind refKind2 = refKind;
|
|
if (!ShouldInferDeclarationExpressionValEscape(boundExpression, out SourceLocalSymbol _) && refKind2.IsWritableReference() && !boundExpression.IsDiscardExpression())
|
|
{
|
|
TypeSymbol? type = boundExpression.Type;
|
|
if ((object)type != null && type.IsRefLikeType)
|
|
{
|
|
num = Math.Min(num, GetValEscape(boundExpression, scopeOfTheContainingExpression));
|
|
}
|
|
}
|
|
}
|
|
bool flag = false;
|
|
uint num2 = 0u;
|
|
enumerator = instance.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
enumerator.Current.Deconstruct(out parameter, out argument, out refKind);
|
|
ParameterSymbol parameter2 = parameter;
|
|
BoundExpression boundExpression2 = argument;
|
|
num2 = Math.Max(num2, GetValEscape(boundExpression2, scopeOfTheContainingExpression));
|
|
if (!flag && !CheckValEscape(boundExpression2.Syntax, boundExpression2, scopeOfTheContainingExpression, num, checkingReceiver: false, diagnostics))
|
|
{
|
|
string invocationParameterName = GetInvocationParameterName(parameter2);
|
|
Error(diagnostics, ErrorCode.ERR_CallArgMixing, SyntaxNodeOrToken.op_Implicit(syntax), symbol, invocationParameterName);
|
|
flag = true;
|
|
}
|
|
}
|
|
enumerator = instance.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
enumerator.Current.Deconstruct(out parameter, out argument, out refKind);
|
|
BoundExpression argument2 = argument;
|
|
if (ShouldInferDeclarationExpressionValEscape(argument2, out SourceLocalSymbol localSymbol2))
|
|
{
|
|
SetLocalScopes(localSymbol2, _localScopeDepth, num2);
|
|
}
|
|
}
|
|
return !flag;
|
|
}
|
|
finally
|
|
{
|
|
instance.Free();
|
|
}
|
|
}
|
|
|
|
private bool CheckInvocationArgMixingWithUpdatedRules(SyntaxNode syntax, Symbol symbol, BoundExpression? receiverOpt, ThreeState receiverIsSubjectToCloning, ImmutableArray<ParameterSymbol> parameters, ImmutableArray<BoundExpression> argsOpt, ImmutableArray<RefKind> argRefKindsOpt, ImmutableArray<int> argsToParamsOpt, uint scopeOfTheContainingExpression, BindingDiagnosticBag diagnostics)
|
|
{
|
|
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
|
|
ArrayBuilder<MixableDestination> instance = ArrayBuilder<MixableDestination>.GetInstance();
|
|
ArrayBuilder<EscapeValue> escapeValues = ArrayBuilder<EscapeValue>.GetInstance();
|
|
GetEscapeValuesForUpdatedRules(symbol, receiverOpt, receiverIsSubjectToCloning, parameters, argsOpt, argRefKindsOpt, argsToParamsOpt, ignoreArglistRefKinds: false, instance, escapeValues);
|
|
bool flag = true;
|
|
Enumerator<MixableDestination> enumerator = instance.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
MixableDestination current = enumerator.Current;
|
|
uint valEscape = GetValEscape(current.Argument, scopeOfTheContainingExpression);
|
|
Enumerator<EscapeValue> enumerator2 = escapeValues.GetEnumerator();
|
|
while (enumerator2.MoveNext())
|
|
{
|
|
var (parameterSymbol2, boundExpression2, level, flag3) = (EscapeValue)(ref enumerator2.Current);
|
|
if (((object)current.Parameter == null || (object)current.Parameter != parameterSymbol2) && current.IsAssignableFrom(level))
|
|
{
|
|
flag = (flag3 ? CheckRefEscape(boundExpression2.Syntax, boundExpression2, scopeOfTheContainingExpression, valEscape, checkingReceiver: false, diagnostics) : CheckValEscape(boundExpression2.Syntax, boundExpression2, scopeOfTheContainingExpression, valEscape, checkingReceiver: false, diagnostics));
|
|
if (!flag)
|
|
{
|
|
string invocationParameterName = GetInvocationParameterName(parameterSymbol2);
|
|
Error(diagnostics, ErrorCode.ERR_CallArgMixing, SyntaxNodeOrToken.op_Implicit(syntax), symbol, invocationParameterName);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!flag)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
inferDeclarationExpressionValEscape();
|
|
instance.Free();
|
|
escapeValues.Free();
|
|
return flag;
|
|
void inferDeclarationExpressionValEscape()
|
|
{
|
|
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
|
|
uint num = 0u;
|
|
Enumerator<EscapeValue> enumerator3 = escapeValues.GetEnumerator();
|
|
while (enumerator3.MoveNext())
|
|
{
|
|
enumerator3.Current.Deconstruct(out ParameterSymbol _, out BoundExpression argument, out EscapeLevel _, out bool isRefEscape);
|
|
BoundExpression expr = argument;
|
|
bool flag4 = isRefEscape;
|
|
num = Math.Max(num, flag4 ? GetRefEscape(expr, scopeOfTheContainingExpression) : GetValEscape(expr, scopeOfTheContainingExpression));
|
|
}
|
|
ImmutableArray<BoundExpression>.Enumerator enumerator4 = argsOpt.GetEnumerator();
|
|
while (enumerator4.MoveNext())
|
|
{
|
|
BoundExpression current2 = enumerator4.Current;
|
|
if (ShouldInferDeclarationExpressionValEscape(current2, out SourceLocalSymbol localSymbol))
|
|
{
|
|
SetLocalScopes(localSymbol, _localScopeDepth, num);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static bool IsReceiverRefReadOnly(Symbol methodOrPropertySymbol)
|
|
{
|
|
if (!(methodOrPropertySymbol is MethodSymbol { IsEffectivelyReadOnly: var isEffectivelyReadOnly }))
|
|
{
|
|
if (methodOrPropertySymbol is PropertySymbol propertySymbol)
|
|
{
|
|
MethodSymbol getMethod = propertySymbol.GetMethod;
|
|
return ((object)getMethod == null || getMethod.IsEffectivelyReadOnly) && (propertySymbol.SetMethod?.IsEffectivelyReadOnly ?? true);
|
|
}
|
|
throw ExceptionUtilities.UnexpectedValue((object)methodOrPropertySymbol);
|
|
}
|
|
return isEffectivelyReadOnly;
|
|
}
|
|
|
|
private static ErrorCode GetStandardCallEscapeError(bool checkingReceiver)
|
|
{
|
|
if (!checkingReceiver)
|
|
{
|
|
return ErrorCode.ERR_EscapeCall;
|
|
}
|
|
return ErrorCode.ERR_EscapeCall2;
|
|
}
|
|
|
|
private static ErrorCode GetStandardRValueRefEscapeError(uint escapeTo)
|
|
{
|
|
if (escapeTo <= 1)
|
|
{
|
|
return ErrorCode.ERR_RefReturnLvalueExpected;
|
|
}
|
|
return ErrorCode.ERR_EscapeOther;
|
|
}
|
|
|
|
internal void ValidateEscape(BoundExpression expr, uint escapeTo, bool isByRef, BindingDiagnosticBag diagnostics)
|
|
{
|
|
if (isByRef)
|
|
{
|
|
CheckRefEscape(expr.Syntax, expr, _localScopeDepth, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
else
|
|
{
|
|
CheckValEscape(expr.Syntax, expr, _localScopeDepth, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
}
|
|
|
|
internal uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainingExpression)
|
|
{
|
|
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_001d: Invalid comparison between Unknown and I4
|
|
//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0201: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_041f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0295: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_03a7: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_03a9: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_03b0: Invalid comparison between Unknown and I4
|
|
//IL_0242: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0309: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_03b2: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_03b9: Invalid comparison between Unknown and I4
|
|
//IL_033f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0359: Unknown result type (might be due to invalid IL or missing references)
|
|
if (expr.HasAnyErrors)
|
|
{
|
|
return 0u;
|
|
}
|
|
TypeSymbol? type = expr.Type;
|
|
if ((object)type != null && (int)type.GetSpecialTypeSafe() == 6)
|
|
{
|
|
return 0u;
|
|
}
|
|
if (expr.ConstantValueOpt != (ConstantValue)null)
|
|
{
|
|
return scopeOfTheContainingExpression;
|
|
}
|
|
switch (expr.Kind)
|
|
{
|
|
case BoundKind.PointerIndirectionOperator:
|
|
case BoundKind.PointerElementAccess:
|
|
case BoundKind.ArrayAccess:
|
|
return 0u;
|
|
case BoundKind.RefValueOperator:
|
|
return 2u;
|
|
case BoundKind.Parameter:
|
|
return GetParameterRefEscape(((BoundParameter)expr).ParameterSymbol);
|
|
case BoundKind.Local:
|
|
return GetLocalScopes(((BoundLocal)expr).LocalSymbol).RefEscapeScope;
|
|
case BoundKind.CapturedReceiverPlaceholder:
|
|
return ((BoundCapturedReceiverPlaceholder)expr).LocalScopeDepth;
|
|
case BoundKind.ThisReference:
|
|
return GetParameterRefEscape(_symbol.ThisParameter);
|
|
case BoundKind.ConditionalOperator:
|
|
{
|
|
BoundConditionalOperator boundConditionalOperator = (BoundConditionalOperator)expr;
|
|
if (boundConditionalOperator.IsRef)
|
|
{
|
|
return Math.Max(GetRefEscape(boundConditionalOperator.Consequence, scopeOfTheContainingExpression), GetRefEscape(boundConditionalOperator.Alternative, scopeOfTheContainingExpression));
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.FieldAccess:
|
|
return GetFieldRefEscape((BoundFieldAccess)expr, scopeOfTheContainingExpression);
|
|
case BoundKind.EventAccess:
|
|
{
|
|
BoundEventAccess boundEventAccess = (BoundEventAccess)expr;
|
|
if (boundEventAccess.IsUsableAsField)
|
|
{
|
|
EventSymbol eventSymbol = boundEventAccess.EventSymbol;
|
|
if (eventSymbol.IsStatic || eventSymbol.ContainingType.IsReferenceType)
|
|
{
|
|
return 0u;
|
|
}
|
|
return GetRefEscape(boundEventAccess.ReceiverOpt, scopeOfTheContainingExpression);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.Call:
|
|
{
|
|
BoundCall boundCall = (BoundCall)expr;
|
|
MethodSymbol method = boundCall.Method;
|
|
if ((int)method.RefKind != 0)
|
|
{
|
|
return GetInvocationEscapeScope(boundCall.Method, boundCall.ReceiverOpt, boundCall.InitialBindingReceiverIsSubjectToCloning, method.Parameters, boundCall.Arguments, boundCall.ArgumentRefKindsOpt, boundCall.ArgsToParamsOpt, scopeOfTheContainingExpression, isRefEscape: true);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.FunctionPointerInvocation:
|
|
{
|
|
BoundFunctionPointerInvocation boundFunctionPointerInvocation = (BoundFunctionPointerInvocation)expr;
|
|
FunctionPointerMethodSymbol signature = boundFunctionPointerInvocation.FunctionPointer.Signature;
|
|
if ((int)signature.RefKind != 0)
|
|
{
|
|
return GetInvocationEscapeScope(signature, null, (ThreeState)0, signature.Parameters, boundFunctionPointerInvocation.Arguments, boundFunctionPointerInvocation.ArgumentRefKindsOpt, default(ImmutableArray<int>), scopeOfTheContainingExpression, isRefEscape: true);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.IndexerAccess:
|
|
{
|
|
BoundIndexerAccess boundIndexerAccess = (BoundIndexerAccess)expr;
|
|
PropertySymbol indexer = boundIndexerAccess.Indexer;
|
|
return GetInvocationEscapeScope(indexer, boundIndexerAccess.ReceiverOpt, boundIndexerAccess.InitialBindingReceiverIsSubjectToCloning, indexer.Parameters, boundIndexerAccess.Arguments, boundIndexerAccess.ArgumentRefKindsOpt, boundIndexerAccess.ArgsToParamsOpt, scopeOfTheContainingExpression, isRefEscape: true);
|
|
}
|
|
case BoundKind.ImplicitIndexerAccess:
|
|
{
|
|
BoundImplicitIndexerAccess boundImplicitIndexerAccess = (BoundImplicitIndexerAccess)expr;
|
|
BoundExpression indexerOrSliceAccess = boundImplicitIndexerAccess.IndexerOrSliceAccess;
|
|
if (!(indexerOrSliceAccess is BoundIndexerAccess boundIndexerAccess2))
|
|
{
|
|
if (!(indexerOrSliceAccess is BoundArrayAccess))
|
|
{
|
|
if (indexerOrSliceAccess is BoundCall boundCall2)
|
|
{
|
|
MethodSymbol method2 = boundCall2.Method;
|
|
if ((int)method2.RefKind != 0)
|
|
{
|
|
return GetInvocationEscapeScope(boundCall2.Method, boundImplicitIndexerAccess.Receiver, boundCall2.InitialBindingReceiverIsSubjectToCloning, method2.Parameters, boundCall2.Arguments, boundCall2.ArgumentRefKindsOpt, boundCall2.ArgsToParamsOpt, scopeOfTheContainingExpression, isRefEscape: true);
|
|
}
|
|
break;
|
|
}
|
|
throw ExceptionUtilities.UnexpectedValue((object)boundImplicitIndexerAccess.IndexerOrSliceAccess.Kind);
|
|
}
|
|
return 0u;
|
|
}
|
|
PropertySymbol indexer2 = boundIndexerAccess2.Indexer;
|
|
return GetInvocationEscapeScope(indexer2, boundImplicitIndexerAccess.Receiver, boundIndexerAccess2.InitialBindingReceiverIsSubjectToCloning, indexer2.Parameters, boundIndexerAccess2.Arguments, boundIndexerAccess2.ArgumentRefKindsOpt, boundIndexerAccess2.ArgsToParamsOpt, scopeOfTheContainingExpression, isRefEscape: true);
|
|
}
|
|
case BoundKind.InlineArrayAccess:
|
|
{
|
|
BoundInlineArrayAccess boundInlineArrayAccess = (BoundInlineArrayAccess)expr;
|
|
WellKnownMember getItemOrSliceHelper = boundInlineArrayAccess.GetItemOrSliceHelper;
|
|
bool flag = (((int)getItemOrSliceHelper == 400 || (int)getItemOrSliceHelper == 406) ? true : false);
|
|
if (flag && !boundInlineArrayAccess.IsValue)
|
|
{
|
|
ImmutableArray<BoundExpression> arguments;
|
|
ImmutableArray<RefKind> refKinds;
|
|
SignatureOnlyMethodSymbol inlineArrayAccessEquivalentSignatureMethod = GetInlineArrayAccessEquivalentSignatureMethod(boundInlineArrayAccess, out arguments, out refKinds);
|
|
return GetInvocationEscapeScope(inlineArrayAccessEquivalentSignatureMethod, null, (ThreeState)0, inlineArrayAccessEquivalentSignatureMethod.Parameters, arguments, refKinds, default(ImmutableArray<int>), scopeOfTheContainingExpression, isRefEscape: true);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.PropertyAccess:
|
|
{
|
|
BoundPropertyAccess boundPropertyAccess = (BoundPropertyAccess)expr;
|
|
return GetInvocationEscapeScope(boundPropertyAccess.PropertySymbol, boundPropertyAccess.ReceiverOpt, boundPropertyAccess.InitialBindingReceiverIsSubjectToCloning, default(ImmutableArray<ParameterSymbol>), default(ImmutableArray<BoundExpression>), default(ImmutableArray<RefKind>), default(ImmutableArray<int>), scopeOfTheContainingExpression, isRefEscape: true);
|
|
}
|
|
case BoundKind.AssignmentOperator:
|
|
{
|
|
BoundAssignmentOperator boundAssignmentOperator = (BoundAssignmentOperator)expr;
|
|
if (boundAssignmentOperator.IsRef)
|
|
{
|
|
return GetRefEscape(boundAssignmentOperator.Left, scopeOfTheContainingExpression);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return scopeOfTheContainingExpression;
|
|
}
|
|
|
|
internal bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint escapeFrom, uint escapeTo, bool checkingReceiver, BindingDiagnosticBag diagnostics)
|
|
{
|
|
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0024: Invalid comparison between Unknown and I4
|
|
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_05d0: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_027b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_04b9: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0298: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0515: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_02da: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0430: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0435: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0437: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_043e: Invalid comparison between Unknown and I4
|
|
//IL_0532: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_036a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0440: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0447: Invalid comparison between Unknown and I4
|
|
//IL_0387: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_03c3: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_03e0: Unknown result type (might be due to invalid IL or missing references)
|
|
if (escapeTo >= escapeFrom)
|
|
{
|
|
return true;
|
|
}
|
|
if (expr.HasAnyErrors)
|
|
{
|
|
return true;
|
|
}
|
|
TypeSymbol? type = expr.Type;
|
|
if ((object)type != null && (int)type.GetSpecialTypeSafe() == 6)
|
|
{
|
|
return true;
|
|
}
|
|
if (expr.ConstantValueOpt != (ConstantValue)null)
|
|
{
|
|
Error(diagnostics, GetStandardRValueRefEscapeError(escapeTo), SyntaxNodeOrToken.op_Implicit(node));
|
|
return false;
|
|
}
|
|
switch (expr.Kind)
|
|
{
|
|
case BoundKind.PointerIndirectionOperator:
|
|
case BoundKind.PointerElementAccess:
|
|
case BoundKind.ArrayAccess:
|
|
return true;
|
|
case BoundKind.RefValueOperator:
|
|
if (escapeTo > 1)
|
|
{
|
|
return true;
|
|
}
|
|
break;
|
|
case BoundKind.Parameter:
|
|
{
|
|
BoundParameter boundParameter = (BoundParameter)expr;
|
|
return CheckParameterRefEscape(node, boundParameter, boundParameter.ParameterSymbol, escapeTo, checkingReceiver, diagnostics);
|
|
}
|
|
case BoundKind.Local:
|
|
{
|
|
BoundLocal local = (BoundLocal)expr;
|
|
return CheckLocalRefEscape(node, local, escapeTo, checkingReceiver, diagnostics);
|
|
}
|
|
case BoundKind.CapturedReceiverPlaceholder:
|
|
if (((BoundCapturedReceiverPlaceholder)expr).LocalScopeDepth <= escapeTo)
|
|
{
|
|
return true;
|
|
}
|
|
break;
|
|
case BoundKind.ThisReference:
|
|
{
|
|
ParameterSymbol thisParameter = _symbol.ThisParameter;
|
|
return CheckParameterRefEscape(node, expr, thisParameter, escapeTo, checkingReceiver, diagnostics);
|
|
}
|
|
case BoundKind.ConditionalOperator:
|
|
{
|
|
BoundConditionalOperator boundConditionalOperator = (BoundConditionalOperator)expr;
|
|
if (boundConditionalOperator.IsRef)
|
|
{
|
|
if (CheckRefEscape(boundConditionalOperator.Consequence.Syntax, boundConditionalOperator.Consequence, escapeFrom, escapeTo, checkingReceiver: false, diagnostics))
|
|
{
|
|
return CheckRefEscape(boundConditionalOperator.Alternative.Syntax, boundConditionalOperator.Alternative, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
return false;
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.FieldAccess:
|
|
{
|
|
BoundFieldAccess fieldAccess = (BoundFieldAccess)expr;
|
|
return CheckFieldRefEscape(node, fieldAccess, escapeFrom, escapeTo, diagnostics);
|
|
}
|
|
case BoundKind.EventAccess:
|
|
{
|
|
BoundEventAccess boundEventAccess = (BoundEventAccess)expr;
|
|
if (boundEventAccess.IsUsableAsField)
|
|
{
|
|
return CheckFieldLikeEventRefEscape(node, boundEventAccess, escapeFrom, escapeTo, diagnostics);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.Call:
|
|
{
|
|
BoundCall boundCall = (BoundCall)expr;
|
|
MethodSymbol method = boundCall.Method;
|
|
if ((int)method.RefKind != 0)
|
|
{
|
|
return CheckInvocationEscape(boundCall.Syntax, method, boundCall.ReceiverOpt, boundCall.InitialBindingReceiverIsSubjectToCloning, method.Parameters, boundCall.Arguments, boundCall.ArgumentRefKindsOpt, boundCall.ArgsToParamsOpt, checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: true);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.IndexerAccess:
|
|
{
|
|
BoundIndexerAccess boundIndexerAccess = (BoundIndexerAccess)expr;
|
|
PropertySymbol indexer = boundIndexerAccess.Indexer;
|
|
if ((int)indexer.RefKind != 0)
|
|
{
|
|
return CheckInvocationEscape(boundIndexerAccess.Syntax, indexer, boundIndexerAccess.ReceiverOpt, boundIndexerAccess.InitialBindingReceiverIsSubjectToCloning, indexer.Parameters, boundIndexerAccess.Arguments, boundIndexerAccess.ArgumentRefKindsOpt, boundIndexerAccess.ArgsToParamsOpt, checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: true);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.ImplicitIndexerAccess:
|
|
{
|
|
BoundImplicitIndexerAccess boundImplicitIndexerAccess = (BoundImplicitIndexerAccess)expr;
|
|
BoundExpression indexerOrSliceAccess = boundImplicitIndexerAccess.IndexerOrSliceAccess;
|
|
if (!(indexerOrSliceAccess is BoundIndexerAccess boundIndexerAccess2))
|
|
{
|
|
if (indexerOrSliceAccess is BoundArrayAccess)
|
|
{
|
|
return true;
|
|
}
|
|
if (!(indexerOrSliceAccess is BoundCall boundCall2))
|
|
{
|
|
throw ExceptionUtilities.UnexpectedValue((object)boundImplicitIndexerAccess.IndexerOrSliceAccess.Kind);
|
|
}
|
|
MethodSymbol method2 = boundCall2.Method;
|
|
if ((int)method2.RefKind != 0)
|
|
{
|
|
return CheckInvocationEscape(boundCall2.Syntax, method2, boundImplicitIndexerAccess.Receiver, boundCall2.InitialBindingReceiverIsSubjectToCloning, method2.Parameters, boundCall2.Arguments, boundCall2.ArgumentRefKindsOpt, boundCall2.ArgsToParamsOpt, checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PropertySymbol indexer2 = boundIndexerAccess2.Indexer;
|
|
if ((int)indexer2.RefKind != 0)
|
|
{
|
|
return CheckInvocationEscape(boundIndexerAccess2.Syntax, indexer2, boundImplicitIndexerAccess.Receiver, boundIndexerAccess2.InitialBindingReceiverIsSubjectToCloning, indexer2.Parameters, boundIndexerAccess2.Arguments, boundIndexerAccess2.ArgumentRefKindsOpt, boundIndexerAccess2.ArgsToParamsOpt, checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: true);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.InlineArrayAccess:
|
|
{
|
|
BoundInlineArrayAccess boundInlineArrayAccess = (BoundInlineArrayAccess)expr;
|
|
WellKnownMember getItemOrSliceHelper = boundInlineArrayAccess.GetItemOrSliceHelper;
|
|
bool flag = (((int)getItemOrSliceHelper == 400 || (int)getItemOrSliceHelper == 406) ? true : false);
|
|
if (flag && !boundInlineArrayAccess.IsValue)
|
|
{
|
|
ImmutableArray<BoundExpression> arguments;
|
|
ImmutableArray<RefKind> refKinds;
|
|
SignatureOnlyMethodSymbol inlineArrayAccessEquivalentSignatureMethod = GetInlineArrayAccessEquivalentSignatureMethod(boundInlineArrayAccess, out arguments, out refKinds);
|
|
return CheckInvocationEscape(boundInlineArrayAccess.Syntax, inlineArrayAccessEquivalentSignatureMethod, null, (ThreeState)0, inlineArrayAccessEquivalentSignatureMethod.Parameters, arguments, refKinds, default(ImmutableArray<int>), checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: true);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.FunctionPointerInvocation:
|
|
{
|
|
BoundFunctionPointerInvocation boundFunctionPointerInvocation = (BoundFunctionPointerInvocation)expr;
|
|
FunctionPointerMethodSymbol signature = boundFunctionPointerInvocation.FunctionPointer.Signature;
|
|
if ((int)signature.RefKind != 0)
|
|
{
|
|
return CheckInvocationEscape(boundFunctionPointerInvocation.Syntax, signature, boundFunctionPointerInvocation.InvokedExpression, (ThreeState)1, signature.Parameters, boundFunctionPointerInvocation.Arguments, boundFunctionPointerInvocation.ArgumentRefKindsOpt, default(ImmutableArray<int>), checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: true);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.PropertyAccess:
|
|
{
|
|
BoundPropertyAccess boundPropertyAccess = (BoundPropertyAccess)expr;
|
|
PropertySymbol propertySymbol = boundPropertyAccess.PropertySymbol;
|
|
if ((int)propertySymbol.RefKind != 0)
|
|
{
|
|
return CheckInvocationEscape(boundPropertyAccess.Syntax, propertySymbol, boundPropertyAccess.ReceiverOpt, boundPropertyAccess.InitialBindingReceiverIsSubjectToCloning, default(ImmutableArray<ParameterSymbol>), default(ImmutableArray<BoundExpression>), default(ImmutableArray<RefKind>), default(ImmutableArray<int>), checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: true);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.AssignmentOperator:
|
|
{
|
|
BoundAssignmentOperator boundAssignmentOperator = (BoundAssignmentOperator)expr;
|
|
if (boundAssignmentOperator.IsRef)
|
|
{
|
|
return CheckRefEscape(node, boundAssignmentOperator.Left, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.Conversion:
|
|
{
|
|
BoundConversion boundConversion = (BoundConversion)expr;
|
|
if (boundConversion.Conversion == Conversion.ImplicitThrow)
|
|
{
|
|
return CheckRefEscape(node, boundConversion.Operand, escapeFrom, escapeTo, checkingReceiver, diagnostics);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.ThrowExpression:
|
|
return true;
|
|
}
|
|
Error(diagnostics, GetStandardRValueRefEscapeError(escapeTo), SyntaxNodeOrToken.op_Implicit(node));
|
|
return false;
|
|
}
|
|
|
|
internal uint GetBroadestValEscape(BoundTupleExpression expr, uint scopeOfTheContainingExpression)
|
|
{
|
|
uint num = scopeOfTheContainingExpression;
|
|
ImmutableArray<BoundExpression>.Enumerator enumerator = expr.Arguments.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundExpression current = enumerator.Current;
|
|
uint val = ((!(current is BoundTupleExpression expr2)) ? GetValEscape(current, scopeOfTheContainingExpression) : GetBroadestValEscape(expr2, scopeOfTheContainingExpression));
|
|
num = Math.Min(num, val);
|
|
}
|
|
return num;
|
|
}
|
|
|
|
internal uint GetValEscape(BoundExpression expr, uint scopeOfTheContainingExpression)
|
|
{
|
|
//IL_0565: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_041f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0392: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0493: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_04cf: Unknown result type (might be due to invalid IL or missing references)
|
|
if (expr.HasAnyErrors)
|
|
{
|
|
return 0u;
|
|
}
|
|
if (expr.ConstantValueOpt != (ConstantValue)null)
|
|
{
|
|
return 0u;
|
|
}
|
|
TypeSymbol? type = expr.Type;
|
|
if ((object)type == null || !type.IsRefLikeType)
|
|
{
|
|
return 0u;
|
|
}
|
|
switch (expr.Kind)
|
|
{
|
|
case BoundKind.ThisReference:
|
|
return GetParameterValEscape(_symbol.ThisParameter);
|
|
case BoundKind.DefaultLiteral:
|
|
case BoundKind.DefaultExpression:
|
|
case BoundKind.Utf8String:
|
|
return 0u;
|
|
case BoundKind.Parameter:
|
|
return GetParameterValEscape(((BoundParameter)expr).ParameterSymbol);
|
|
case BoundKind.FromEndIndexExpression:
|
|
return 0u;
|
|
case BoundKind.TupleLiteral:
|
|
case BoundKind.ConvertedTupleLiteral:
|
|
{
|
|
BoundTupleExpression boundTupleExpression = (BoundTupleExpression)expr;
|
|
return GetTupleValEscape(boundTupleExpression.Arguments, scopeOfTheContainingExpression);
|
|
}
|
|
case BoundKind.MakeRefOperator:
|
|
case BoundKind.RefValueOperator:
|
|
return 0u;
|
|
case BoundKind.DiscardExpression:
|
|
return 0u;
|
|
case BoundKind.DeconstructValuePlaceholder:
|
|
case BoundKind.AwaitableValuePlaceholder:
|
|
case BoundKind.InterpolatedStringArgumentPlaceholder:
|
|
return GetPlaceholderScope((BoundValuePlaceholderBase)expr);
|
|
case BoundKind.Local:
|
|
return GetLocalScopes(((BoundLocal)expr).LocalSymbol).ValEscapeScope;
|
|
case BoundKind.CapturedReceiverPlaceholder:
|
|
{
|
|
BoundCapturedReceiverPlaceholder boundCapturedReceiverPlaceholder = (BoundCapturedReceiverPlaceholder)expr;
|
|
return GetValEscape(boundCapturedReceiverPlaceholder.Receiver, boundCapturedReceiverPlaceholder.LocalScopeDepth);
|
|
}
|
|
case BoundKind.StackAllocArrayCreation:
|
|
case BoundKind.ConvertedStackAllocExpression:
|
|
return 2u;
|
|
case BoundKind.ConditionalOperator:
|
|
{
|
|
BoundConditionalOperator boundConditionalOperator = (BoundConditionalOperator)expr;
|
|
uint valEscape = GetValEscape(boundConditionalOperator.Consequence, scopeOfTheContainingExpression);
|
|
if (boundConditionalOperator.IsRef)
|
|
{
|
|
return valEscape;
|
|
}
|
|
return Math.Max(valEscape, GetValEscape(boundConditionalOperator.Alternative, scopeOfTheContainingExpression));
|
|
}
|
|
case BoundKind.NullCoalescingOperator:
|
|
{
|
|
BoundNullCoalescingOperator boundNullCoalescingOperator = (BoundNullCoalescingOperator)expr;
|
|
return Math.Max(GetValEscape(boundNullCoalescingOperator.LeftOperand, scopeOfTheContainingExpression), GetValEscape(boundNullCoalescingOperator.RightOperand, scopeOfTheContainingExpression));
|
|
}
|
|
case BoundKind.FieldAccess:
|
|
{
|
|
BoundFieldAccess boundFieldAccess = (BoundFieldAccess)expr;
|
|
FieldSymbol fieldSymbol = boundFieldAccess.FieldSymbol;
|
|
if (fieldSymbol.IsStatic || !fieldSymbol.ContainingType.IsRefLikeType)
|
|
{
|
|
return 0u;
|
|
}
|
|
return GetValEscape(boundFieldAccess.ReceiverOpt, scopeOfTheContainingExpression);
|
|
}
|
|
case BoundKind.Call:
|
|
{
|
|
BoundCall boundCall2 = (BoundCall)expr;
|
|
return GetInvocationEscapeScope(boundCall2.Method, boundCall2.ReceiverOpt, boundCall2.InitialBindingReceiverIsSubjectToCloning, boundCall2.Method.Parameters, boundCall2.Arguments, boundCall2.ArgumentRefKindsOpt, boundCall2.ArgsToParamsOpt, scopeOfTheContainingExpression, isRefEscape: false);
|
|
}
|
|
case BoundKind.FunctionPointerInvocation:
|
|
{
|
|
BoundFunctionPointerInvocation boundFunctionPointerInvocation = (BoundFunctionPointerInvocation)expr;
|
|
FunctionPointerMethodSymbol signature = boundFunctionPointerInvocation.FunctionPointer.Signature;
|
|
return GetInvocationEscapeScope(signature, null, (ThreeState)0, signature.Parameters, boundFunctionPointerInvocation.Arguments, boundFunctionPointerInvocation.ArgumentRefKindsOpt, default(ImmutableArray<int>), scopeOfTheContainingExpression, isRefEscape: false);
|
|
}
|
|
case BoundKind.IndexerAccess:
|
|
{
|
|
BoundIndexerAccess boundIndexerAccess2 = (BoundIndexerAccess)expr;
|
|
PropertySymbol indexer2 = boundIndexerAccess2.Indexer;
|
|
return GetInvocationEscapeScope(indexer2, boundIndexerAccess2.ReceiverOpt, boundIndexerAccess2.InitialBindingReceiverIsSubjectToCloning, indexer2.Parameters, boundIndexerAccess2.Arguments, boundIndexerAccess2.ArgumentRefKindsOpt, boundIndexerAccess2.ArgsToParamsOpt, scopeOfTheContainingExpression, isRefEscape: false);
|
|
}
|
|
case BoundKind.ImplicitIndexerAccess:
|
|
{
|
|
BoundImplicitIndexerAccess boundImplicitIndexerAccess = (BoundImplicitIndexerAccess)expr;
|
|
BoundExpression indexerOrSliceAccess = boundImplicitIndexerAccess.IndexerOrSliceAccess;
|
|
if (!(indexerOrSliceAccess is BoundIndexerAccess boundIndexerAccess))
|
|
{
|
|
if (!(indexerOrSliceAccess is BoundArrayAccess))
|
|
{
|
|
if (indexerOrSliceAccess is BoundCall boundCall)
|
|
{
|
|
return GetInvocationEscapeScope(boundCall.Method, boundImplicitIndexerAccess.Receiver, boundCall.InitialBindingReceiverIsSubjectToCloning, boundCall.Method.Parameters, boundCall.Arguments, boundCall.ArgumentRefKindsOpt, boundCall.ArgsToParamsOpt, scopeOfTheContainingExpression, isRefEscape: false);
|
|
}
|
|
throw ExceptionUtilities.UnexpectedValue((object)boundImplicitIndexerAccess.IndexerOrSliceAccess.Kind);
|
|
}
|
|
return scopeOfTheContainingExpression;
|
|
}
|
|
PropertySymbol indexer = boundIndexerAccess.Indexer;
|
|
return GetInvocationEscapeScope(indexer, boundImplicitIndexerAccess.Receiver, boundIndexerAccess.InitialBindingReceiverIsSubjectToCloning, indexer.Parameters, boundIndexerAccess.Arguments, boundIndexerAccess.ArgumentRefKindsOpt, boundIndexerAccess.ArgsToParamsOpt, scopeOfTheContainingExpression, isRefEscape: false);
|
|
}
|
|
case BoundKind.InlineArrayAccess:
|
|
{
|
|
BoundInlineArrayAccess elementAccess = (BoundInlineArrayAccess)expr;
|
|
ImmutableArray<BoundExpression> arguments2;
|
|
ImmutableArray<RefKind> refKinds2;
|
|
SignatureOnlyMethodSymbol inlineArrayAccessEquivalentSignatureMethod = GetInlineArrayAccessEquivalentSignatureMethod(elementAccess, out arguments2, out refKinds2);
|
|
return GetInvocationEscapeScope(inlineArrayAccessEquivalentSignatureMethod, null, (ThreeState)0, inlineArrayAccessEquivalentSignatureMethod.Parameters, arguments2, refKinds2, default(ImmutableArray<int>), scopeOfTheContainingExpression, isRefEscape: false);
|
|
}
|
|
case BoundKind.PropertyAccess:
|
|
{
|
|
BoundPropertyAccess boundPropertyAccess = (BoundPropertyAccess)expr;
|
|
return GetInvocationEscapeScope(boundPropertyAccess.PropertySymbol, boundPropertyAccess.ReceiverOpt, boundPropertyAccess.InitialBindingReceiverIsSubjectToCloning, default(ImmutableArray<ParameterSymbol>), default(ImmutableArray<BoundExpression>), default(ImmutableArray<RefKind>), default(ImmutableArray<int>), scopeOfTheContainingExpression, isRefEscape: false);
|
|
}
|
|
case BoundKind.ObjectCreationExpression:
|
|
{
|
|
BoundObjectCreationExpression boundObjectCreationExpression = (BoundObjectCreationExpression)expr;
|
|
MethodSymbol constructor = boundObjectCreationExpression.Constructor;
|
|
uint num = GetInvocationEscapeScope(constructor, null, (ThreeState)0, constructor.Parameters, boundObjectCreationExpression.Arguments, boundObjectCreationExpression.ArgumentRefKindsOpt, boundObjectCreationExpression.ArgsToParamsOpt, scopeOfTheContainingExpression, isRefEscape: false);
|
|
BoundObjectInitializerExpressionBase initializerExpressionOpt = boundObjectCreationExpression.InitializerExpressionOpt;
|
|
if (initializerExpressionOpt != null)
|
|
{
|
|
num = Math.Max(num, GetValEscape(initializerExpressionOpt, scopeOfTheContainingExpression));
|
|
}
|
|
return num;
|
|
}
|
|
case BoundKind.WithExpression:
|
|
{
|
|
BoundWithExpression boundWithExpression = (BoundWithExpression)expr;
|
|
return Math.Max(GetValEscape(boundWithExpression.Receiver, scopeOfTheContainingExpression), GetValEscape(boundWithExpression.InitializerExpression, scopeOfTheContainingExpression));
|
|
}
|
|
case BoundKind.UnaryOperator:
|
|
return GetValEscape(((BoundUnaryOperator)expr).Operand, scopeOfTheContainingExpression);
|
|
case BoundKind.Conversion:
|
|
{
|
|
BoundConversion boundConversion = (BoundConversion)expr;
|
|
if (boundConversion.ConversionKind == ConversionKind.InterpolatedStringHandler)
|
|
{
|
|
return GetInterpolatedStringHandlerConversionEscapeScope(boundConversion.Operand, scopeOfTheContainingExpression);
|
|
}
|
|
if (boundConversion.ConversionKind == ConversionKind.CollectionExpression)
|
|
{
|
|
if (!HasLocalScope((BoundCollectionExpression)boundConversion.Operand))
|
|
{
|
|
return 0u;
|
|
}
|
|
return 2u;
|
|
}
|
|
if (boundConversion.Conversion.IsInlineArray)
|
|
{
|
|
ImmutableArray<BoundExpression> arguments;
|
|
ImmutableArray<RefKind> refKinds;
|
|
SignatureOnlyMethodSymbol inlineArrayConversionEquivalentSignatureMethod = GetInlineArrayConversionEquivalentSignatureMethod(boundConversion, out arguments, out refKinds);
|
|
return GetInvocationEscapeScope(inlineArrayConversionEquivalentSignatureMethod, null, (ThreeState)0, inlineArrayConversionEquivalentSignatureMethod.Parameters, arguments, refKinds, default(ImmutableArray<int>), scopeOfTheContainingExpression, isRefEscape: false);
|
|
}
|
|
return GetValEscape(boundConversion.Operand, scopeOfTheContainingExpression);
|
|
}
|
|
case BoundKind.AssignmentOperator:
|
|
return GetValEscape(((BoundAssignmentOperator)expr).Right, scopeOfTheContainingExpression);
|
|
case BoundKind.IncrementOperator:
|
|
return GetValEscape(((BoundIncrementOperator)expr).Operand, scopeOfTheContainingExpression);
|
|
case BoundKind.CompoundAssignmentOperator:
|
|
{
|
|
BoundCompoundAssignmentOperator boundCompoundAssignmentOperator = (BoundCompoundAssignmentOperator)expr;
|
|
return Math.Max(GetValEscape(boundCompoundAssignmentOperator.Left, scopeOfTheContainingExpression), GetValEscape(boundCompoundAssignmentOperator.Right, scopeOfTheContainingExpression));
|
|
}
|
|
case BoundKind.BinaryOperator:
|
|
{
|
|
BoundBinaryOperator boundBinaryOperator = (BoundBinaryOperator)expr;
|
|
return Math.Max(GetValEscape(boundBinaryOperator.Left, scopeOfTheContainingExpression), GetValEscape(boundBinaryOperator.Right, scopeOfTheContainingExpression));
|
|
}
|
|
case BoundKind.RangeExpression:
|
|
{
|
|
BoundRangeExpression boundRangeExpression = (BoundRangeExpression)expr;
|
|
BoundExpression leftOperandOpt = boundRangeExpression.LeftOperandOpt;
|
|
uint val = ((leftOperandOpt != null) ? GetValEscape(leftOperandOpt, scopeOfTheContainingExpression) : 0);
|
|
BoundExpression rightOperandOpt = boundRangeExpression.RightOperandOpt;
|
|
return Math.Max(val, (rightOperandOpt != null) ? GetValEscape(rightOperandOpt, scopeOfTheContainingExpression) : 0u);
|
|
}
|
|
case BoundKind.UserDefinedConditionalLogicalOperator:
|
|
{
|
|
BoundUserDefinedConditionalLogicalOperator boundUserDefinedConditionalLogicalOperator = (BoundUserDefinedConditionalLogicalOperator)expr;
|
|
return Math.Max(GetValEscape(boundUserDefinedConditionalLogicalOperator.Left, scopeOfTheContainingExpression), GetValEscape(boundUserDefinedConditionalLogicalOperator.Right, scopeOfTheContainingExpression));
|
|
}
|
|
case BoundKind.QueryClause:
|
|
return GetValEscape(((BoundQueryClause)expr).Value, scopeOfTheContainingExpression);
|
|
case BoundKind.RangeVariable:
|
|
return GetValEscape(((BoundRangeVariable)expr).Value, scopeOfTheContainingExpression);
|
|
case BoundKind.ObjectInitializerExpression:
|
|
{
|
|
BoundObjectInitializerExpression initExpr = (BoundObjectInitializerExpression)expr;
|
|
return GetValEscapeOfObjectInitializer(initExpr, scopeOfTheContainingExpression);
|
|
}
|
|
case BoundKind.CollectionInitializerExpression:
|
|
{
|
|
BoundCollectionInitializerExpression boundCollectionInitializerExpression = (BoundCollectionInitializerExpression)expr;
|
|
return GetValEscape(boundCollectionInitializerExpression.Initializers, scopeOfTheContainingExpression);
|
|
}
|
|
case BoundKind.CollectionElementInitializer:
|
|
{
|
|
BoundCollectionElementInitializer boundCollectionElementInitializer = (BoundCollectionElementInitializer)expr;
|
|
return GetValEscape(boundCollectionElementInitializer.Arguments, scopeOfTheContainingExpression);
|
|
}
|
|
case BoundKind.ObjectInitializerMember:
|
|
return scopeOfTheContainingExpression;
|
|
case BoundKind.ObjectOrCollectionValuePlaceholder:
|
|
case BoundKind.ImplicitReceiver:
|
|
return scopeOfTheContainingExpression;
|
|
case BoundKind.InterpolatedStringHandlerPlaceholder:
|
|
return scopeOfTheContainingExpression;
|
|
case BoundKind.DisposableValuePlaceholder:
|
|
return scopeOfTheContainingExpression;
|
|
case BoundKind.PointerIndirectionOperator:
|
|
case BoundKind.PointerElementAccess:
|
|
return 0u;
|
|
case BoundKind.ArrayAccess:
|
|
case BoundKind.AwaitExpression:
|
|
case BoundKind.AsOperator:
|
|
case BoundKind.ConditionalAccess:
|
|
case BoundKind.ConditionalReceiver:
|
|
return scopeOfTheContainingExpression;
|
|
case BoundKind.UnconvertedSwitchExpression:
|
|
case BoundKind.ConvertedSwitchExpression:
|
|
{
|
|
BoundSwitchExpression boundSwitchExpression = (BoundSwitchExpression)expr;
|
|
return GetValEscape(ImmutableArrayExtensions.SelectAsArray<BoundSwitchExpressionArm, BoundExpression>(boundSwitchExpression.SwitchArms, (Func<BoundSwitchExpressionArm, BoundExpression>)((BoundSwitchExpressionArm a) => a.Value)), scopeOfTheContainingExpression);
|
|
}
|
|
default:
|
|
return scopeOfTheContainingExpression;
|
|
}
|
|
}
|
|
|
|
private bool HasLocalScope(BoundCollectionExpression expr)
|
|
{
|
|
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_009f: Invalid comparison between Unknown and I4
|
|
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00ab: Invalid comparison between Unknown and I4
|
|
TypeSymbol type = expr.Type;
|
|
if ((object)type == null || !type.IsRefLikeType || expr.Elements.Length == 0)
|
|
{
|
|
return false;
|
|
}
|
|
TypeWithAnnotations elementType;
|
|
CollectionExpressionTypeKind collectionExpressionTypeKind = ConversionsBase.GetCollectionExpressionTypeKind(_compilation, expr.Type, out elementType);
|
|
switch (collectionExpressionTypeKind)
|
|
{
|
|
case CollectionExpressionTypeKind.ReadOnlySpan:
|
|
return !LocalRewriter.ShouldUseRuntimeHelpersCreateSpan(expr, elementType.Type);
|
|
case CollectionExpressionTypeKind.Span:
|
|
return true;
|
|
case CollectionExpressionTypeKind.CollectionBuilder:
|
|
{
|
|
MethodSymbol collectionBuilderMethod = expr.CollectionBuilderMethod;
|
|
if ((object)collectionBuilderMethod != null)
|
|
{
|
|
ImmutableArray<ParameterSymbol> parameters = collectionBuilderMethod.Parameters;
|
|
if (parameters.Length == 1)
|
|
{
|
|
ParameterSymbol parameterSymbol = parameters[0];
|
|
if ((object)parameterSymbol != null && (int)parameterSymbol.RefKind == 0)
|
|
{
|
|
if ((int)parameterSymbol.EffectiveScope == 2)
|
|
{
|
|
return false;
|
|
}
|
|
if (LocalRewriter.ShouldUseRuntimeHelpersCreateSpan(expr, ((NamedTypeSymbol)parameterSymbol.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0].Type))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
default:
|
|
throw ExceptionUtilities.UnexpectedValue((object)collectionExpressionTypeKind);
|
|
}
|
|
}
|
|
|
|
private uint GetTupleValEscape(ImmutableArray<BoundExpression> elements, uint scopeOfTheContainingExpression)
|
|
{
|
|
uint num = scopeOfTheContainingExpression;
|
|
ImmutableArray<BoundExpression>.Enumerator enumerator = elements.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundExpression current = enumerator.Current;
|
|
num = Math.Max(num, GetValEscape(current, scopeOfTheContainingExpression));
|
|
}
|
|
return num;
|
|
}
|
|
|
|
private uint GetValEscapeOfObjectInitializer(BoundObjectInitializerExpression initExpr, uint scopeOfTheContainingExpression)
|
|
{
|
|
uint num = 0u;
|
|
ImmutableArray<BoundExpression>.Enumerator enumerator = initExpr.Initializers.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundExpression current = enumerator.Current;
|
|
if (current.Kind == BoundKind.AssignmentOperator)
|
|
{
|
|
BoundAssignmentOperator boundAssignmentOperator = (BoundAssignmentOperator)current;
|
|
uint val = (boundAssignmentOperator.IsRef ? GetRefEscape(boundAssignmentOperator.Right, scopeOfTheContainingExpression) : GetValEscape(boundAssignmentOperator.Right, scopeOfTheContainingExpression));
|
|
num = Math.Max(num, val);
|
|
BoundObjectInitializerMember boundObjectInitializerMember = (BoundObjectInitializerMember)boundAssignmentOperator.Left;
|
|
num = Math.Max(num, GetValEscape(boundObjectInitializerMember.Arguments, scopeOfTheContainingExpression));
|
|
}
|
|
else
|
|
{
|
|
num = Math.Max(num, GetValEscape(current, scopeOfTheContainingExpression));
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
private uint GetValEscape(ImmutableArray<BoundExpression> expressions, uint scopeOfTheContainingExpression)
|
|
{
|
|
uint num = 0u;
|
|
ImmutableArray<BoundExpression>.Enumerator enumerator = expressions.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundExpression current = enumerator.Current;
|
|
num = Math.Max(num, GetValEscape(current, scopeOfTheContainingExpression));
|
|
}
|
|
return num;
|
|
}
|
|
|
|
internal bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint escapeFrom, uint escapeTo, bool checkingReceiver, BindingDiagnosticBag diagnostics)
|
|
{
|
|
//IL_04a7: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_06c5: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0549: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_05cd: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_02e3: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0298: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0336: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_061a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0826: Unknown result type (might be due to invalid IL or missing references)
|
|
if (escapeTo >= escapeFrom)
|
|
{
|
|
return true;
|
|
}
|
|
if (expr.HasAnyErrors)
|
|
{
|
|
return true;
|
|
}
|
|
if (expr.ConstantValueOpt != (ConstantValue)null)
|
|
{
|
|
return true;
|
|
}
|
|
TypeSymbol? type = expr.Type;
|
|
if ((object)type == null || !type.IsRefLikeType)
|
|
{
|
|
return true;
|
|
}
|
|
bool inUnsafeRegion = _inUnsafeRegion;
|
|
switch (expr.Kind)
|
|
{
|
|
case BoundKind.ThisReference:
|
|
{
|
|
ParameterSymbol thisParameter = _symbol.ThisParameter;
|
|
return CheckParameterValEscape(node, thisParameter, escapeTo, diagnostics);
|
|
}
|
|
case BoundKind.DefaultLiteral:
|
|
case BoundKind.DefaultExpression:
|
|
case BoundKind.Utf8String:
|
|
return true;
|
|
case BoundKind.Parameter:
|
|
return CheckParameterValEscape(node, ((BoundParameter)expr).ParameterSymbol, escapeTo, diagnostics);
|
|
case BoundKind.TupleLiteral:
|
|
case BoundKind.ConvertedTupleLiteral:
|
|
{
|
|
BoundTupleExpression boundTupleExpression = (BoundTupleExpression)expr;
|
|
return CheckTupleValEscape(boundTupleExpression.Arguments, escapeFrom, escapeTo, diagnostics);
|
|
}
|
|
case BoundKind.MakeRefOperator:
|
|
case BoundKind.RefValueOperator:
|
|
return true;
|
|
case BoundKind.DiscardExpression:
|
|
return true;
|
|
case BoundKind.DeconstructValuePlaceholder:
|
|
case BoundKind.AwaitableValuePlaceholder:
|
|
case BoundKind.InterpolatedStringArgumentPlaceholder:
|
|
if (GetPlaceholderScope((BoundValuePlaceholderBase)expr) > escapeTo)
|
|
{
|
|
Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_EscapeVariable : ErrorCode.ERR_EscapeVariable, SyntaxNodeOrToken.op_Implicit(node), expr.Syntax);
|
|
return inUnsafeRegion;
|
|
}
|
|
return true;
|
|
case BoundKind.Local:
|
|
{
|
|
LocalSymbol localSymbol = ((BoundLocal)expr).LocalSymbol;
|
|
if (GetLocalScopes(localSymbol).ValEscapeScope > escapeTo)
|
|
{
|
|
Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_EscapeVariable : ErrorCode.ERR_EscapeVariable, SyntaxNodeOrToken.op_Implicit(node), localSymbol);
|
|
return inUnsafeRegion;
|
|
}
|
|
return true;
|
|
}
|
|
case BoundKind.CapturedReceiverPlaceholder:
|
|
{
|
|
BoundExpression receiver = ((BoundCapturedReceiverPlaceholder)expr).Receiver;
|
|
return CheckValEscape(receiver.Syntax, receiver, escapeFrom, escapeTo, checkingReceiver, diagnostics);
|
|
}
|
|
case BoundKind.StackAllocArrayCreation:
|
|
case BoundKind.ConvertedStackAllocExpression:
|
|
if (escapeTo < 2)
|
|
{
|
|
Error(diagnostics, inUnsafeRegion ? ErrorCode.WRN_EscapeStackAlloc : ErrorCode.ERR_EscapeStackAlloc, SyntaxNodeOrToken.op_Implicit(node), expr.Type);
|
|
return inUnsafeRegion;
|
|
}
|
|
return true;
|
|
case BoundKind.UnconvertedConditionalOperator:
|
|
{
|
|
BoundUnconvertedConditionalOperator boundUnconvertedConditionalOperator = (BoundUnconvertedConditionalOperator)expr;
|
|
if (CheckValEscape(boundUnconvertedConditionalOperator.Consequence.Syntax, boundUnconvertedConditionalOperator.Consequence, escapeFrom, escapeTo, checkingReceiver: false, diagnostics))
|
|
{
|
|
return CheckValEscape(boundUnconvertedConditionalOperator.Alternative.Syntax, boundUnconvertedConditionalOperator.Alternative, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
return false;
|
|
}
|
|
case BoundKind.ConditionalOperator:
|
|
{
|
|
BoundConditionalOperator boundConditionalOperator = (BoundConditionalOperator)expr;
|
|
bool flag2 = CheckValEscape(boundConditionalOperator.Consequence.Syntax, boundConditionalOperator.Consequence, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
if (!flag2 || boundConditionalOperator.IsRef)
|
|
{
|
|
return flag2;
|
|
}
|
|
return CheckValEscape(boundConditionalOperator.Alternative.Syntax, boundConditionalOperator.Alternative, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
case BoundKind.NullCoalescingOperator:
|
|
{
|
|
BoundNullCoalescingOperator boundNullCoalescingOperator = (BoundNullCoalescingOperator)expr;
|
|
if (CheckValEscape(boundNullCoalescingOperator.LeftOperand.Syntax, boundNullCoalescingOperator.LeftOperand, escapeFrom, escapeTo, checkingReceiver, diagnostics))
|
|
{
|
|
return CheckValEscape(boundNullCoalescingOperator.RightOperand.Syntax, boundNullCoalescingOperator.RightOperand, escapeFrom, escapeTo, checkingReceiver, diagnostics);
|
|
}
|
|
return false;
|
|
}
|
|
case BoundKind.FieldAccess:
|
|
{
|
|
BoundFieldAccess boundFieldAccess = (BoundFieldAccess)expr;
|
|
FieldSymbol fieldSymbol = boundFieldAccess.FieldSymbol;
|
|
if (fieldSymbol.IsStatic || !fieldSymbol.ContainingType.IsRefLikeType)
|
|
{
|
|
return true;
|
|
}
|
|
return CheckValEscape(node, boundFieldAccess.ReceiverOpt, escapeFrom, escapeTo, checkingReceiver: true, diagnostics);
|
|
}
|
|
case BoundKind.Call:
|
|
{
|
|
BoundCall boundCall2 = (BoundCall)expr;
|
|
MethodSymbol method2 = boundCall2.Method;
|
|
return CheckInvocationEscape(boundCall2.Syntax, method2, boundCall2.ReceiverOpt, boundCall2.InitialBindingReceiverIsSubjectToCloning, method2.Parameters, boundCall2.Arguments, boundCall2.ArgumentRefKindsOpt, boundCall2.ArgsToParamsOpt, checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: false);
|
|
}
|
|
case BoundKind.FunctionPointerInvocation:
|
|
{
|
|
BoundFunctionPointerInvocation boundFunctionPointerInvocation = (BoundFunctionPointerInvocation)expr;
|
|
FunctionPointerMethodSymbol signature = boundFunctionPointerInvocation.FunctionPointer.Signature;
|
|
return CheckInvocationEscape(boundFunctionPointerInvocation.Syntax, signature, null, (ThreeState)0, signature.Parameters, boundFunctionPointerInvocation.Arguments, boundFunctionPointerInvocation.ArgumentRefKindsOpt, default(ImmutableArray<int>), checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: false);
|
|
}
|
|
case BoundKind.IndexerAccess:
|
|
{
|
|
BoundIndexerAccess boundIndexerAccess2 = (BoundIndexerAccess)expr;
|
|
PropertySymbol indexer2 = boundIndexerAccess2.Indexer;
|
|
return CheckInvocationEscape(boundIndexerAccess2.Syntax, indexer2, boundIndexerAccess2.ReceiverOpt, boundIndexerAccess2.InitialBindingReceiverIsSubjectToCloning, indexer2.Parameters, boundIndexerAccess2.Arguments, boundIndexerAccess2.ArgumentRefKindsOpt, boundIndexerAccess2.ArgsToParamsOpt, checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: false);
|
|
}
|
|
case BoundKind.ImplicitIndexerAccess:
|
|
{
|
|
BoundImplicitIndexerAccess boundImplicitIndexerAccess = (BoundImplicitIndexerAccess)expr;
|
|
BoundExpression indexerOrSliceAccess = boundImplicitIndexerAccess.IndexerOrSliceAccess;
|
|
if (!(indexerOrSliceAccess is BoundIndexerAccess boundIndexerAccess))
|
|
{
|
|
if (!(indexerOrSliceAccess is BoundArrayAccess))
|
|
{
|
|
if (indexerOrSliceAccess is BoundCall boundCall)
|
|
{
|
|
MethodSymbol method = boundCall.Method;
|
|
return CheckInvocationEscape(boundCall.Syntax, method, boundImplicitIndexerAccess.Receiver, boundCall.InitialBindingReceiverIsSubjectToCloning, method.Parameters, boundCall.Arguments, boundCall.ArgumentRefKindsOpt, boundCall.ArgsToParamsOpt, checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: false);
|
|
}
|
|
throw ExceptionUtilities.UnexpectedValue((object)boundImplicitIndexerAccess.IndexerOrSliceAccess.Kind);
|
|
}
|
|
return false;
|
|
}
|
|
PropertySymbol indexer = boundIndexerAccess.Indexer;
|
|
return CheckInvocationEscape(boundIndexerAccess.Syntax, indexer, boundImplicitIndexerAccess.Receiver, boundIndexerAccess.InitialBindingReceiverIsSubjectToCloning, indexer.Parameters, boundIndexerAccess.Arguments, boundIndexerAccess.ArgumentRefKindsOpt, boundIndexerAccess.ArgsToParamsOpt, checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: false);
|
|
}
|
|
case BoundKind.InlineArrayAccess:
|
|
{
|
|
BoundInlineArrayAccess boundInlineArrayAccess = (BoundInlineArrayAccess)expr;
|
|
ImmutableArray<BoundExpression> arguments;
|
|
ImmutableArray<RefKind> refKinds;
|
|
SignatureOnlyMethodSymbol inlineArrayAccessEquivalentSignatureMethod = GetInlineArrayAccessEquivalentSignatureMethod(boundInlineArrayAccess, out arguments, out refKinds);
|
|
return CheckInvocationEscape(boundInlineArrayAccess.Syntax, inlineArrayAccessEquivalentSignatureMethod, null, (ThreeState)0, inlineArrayAccessEquivalentSignatureMethod.Parameters, arguments, refKinds, default(ImmutableArray<int>), checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: false);
|
|
}
|
|
case BoundKind.PropertyAccess:
|
|
{
|
|
BoundPropertyAccess boundPropertyAccess = (BoundPropertyAccess)expr;
|
|
return CheckInvocationEscape(boundPropertyAccess.Syntax, boundPropertyAccess.PropertySymbol, boundPropertyAccess.ReceiverOpt, boundPropertyAccess.InitialBindingReceiverIsSubjectToCloning, default(ImmutableArray<ParameterSymbol>), default(ImmutableArray<BoundExpression>), default(ImmutableArray<RefKind>), default(ImmutableArray<int>), checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: false);
|
|
}
|
|
case BoundKind.ObjectCreationExpression:
|
|
{
|
|
BoundObjectCreationExpression boundObjectCreationExpression = (BoundObjectCreationExpression)expr;
|
|
MethodSymbol constructor = boundObjectCreationExpression.Constructor;
|
|
bool flag = CheckInvocationEscape(boundObjectCreationExpression.Syntax, constructor, null, (ThreeState)0, constructor.Parameters, boundObjectCreationExpression.Arguments, boundObjectCreationExpression.ArgumentRefKindsOpt, boundObjectCreationExpression.ArgsToParamsOpt, checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: false);
|
|
BoundObjectInitializerExpressionBase initializerExpressionOpt = boundObjectCreationExpression.InitializerExpressionOpt;
|
|
if (initializerExpressionOpt != null)
|
|
{
|
|
flag = flag && CheckValEscape(initializerExpressionOpt.Syntax, initializerExpressionOpt, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
return flag;
|
|
}
|
|
case BoundKind.WithExpression:
|
|
{
|
|
BoundWithExpression boundWithExpression = (BoundWithExpression)expr;
|
|
bool num = CheckValEscape(node, boundWithExpression.Receiver, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
BoundObjectInitializerExpressionBase initializerExpression = boundWithExpression.InitializerExpression;
|
|
if (num)
|
|
{
|
|
return CheckValEscape(initializerExpression.Syntax, initializerExpression, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
return false;
|
|
}
|
|
case BoundKind.UnaryOperator:
|
|
{
|
|
BoundUnaryOperator boundUnaryOperator = (BoundUnaryOperator)expr;
|
|
return CheckValEscape(node, boundUnaryOperator.Operand, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
case BoundKind.FromEndIndexExpression:
|
|
return true;
|
|
case BoundKind.Conversion:
|
|
{
|
|
BoundConversion boundConversion = (BoundConversion)expr;
|
|
if (boundConversion.ConversionKind == ConversionKind.InterpolatedStringHandler)
|
|
{
|
|
return CheckInterpolatedStringHandlerConversionEscape(boundConversion.Operand, escapeFrom, escapeTo, diagnostics);
|
|
}
|
|
if (boundConversion.ConversionKind == ConversionKind.CollectionExpression)
|
|
{
|
|
if (HasLocalScope((BoundCollectionExpression)boundConversion.Operand) && escapeTo < 2)
|
|
{
|
|
Error(diagnostics, ErrorCode.ERR_CollectionExpressionEscape, SyntaxNodeOrToken.op_Implicit(node), expr.Type);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
if (boundConversion.Conversion.IsInlineArray)
|
|
{
|
|
ImmutableArray<BoundExpression> arguments2;
|
|
ImmutableArray<RefKind> refKinds2;
|
|
SignatureOnlyMethodSymbol inlineArrayConversionEquivalentSignatureMethod = GetInlineArrayConversionEquivalentSignatureMethod(boundConversion, out arguments2, out refKinds2);
|
|
return CheckInvocationEscape(boundConversion.Syntax, inlineArrayConversionEquivalentSignatureMethod, null, (ThreeState)0, inlineArrayConversionEquivalentSignatureMethod.Parameters, arguments2, refKinds2, default(ImmutableArray<int>), checkingReceiver, escapeFrom, escapeTo, diagnostics, isRefEscape: false);
|
|
}
|
|
return CheckValEscape(node, boundConversion.Operand, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
case BoundKind.AssignmentOperator:
|
|
{
|
|
BoundAssignmentOperator boundAssignmentOperator = (BoundAssignmentOperator)expr;
|
|
return CheckValEscape(node, boundAssignmentOperator.Left, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
case BoundKind.IncrementOperator:
|
|
{
|
|
BoundIncrementOperator boundIncrementOperator = (BoundIncrementOperator)expr;
|
|
return CheckValEscape(node, boundIncrementOperator.Operand, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
case BoundKind.CompoundAssignmentOperator:
|
|
{
|
|
BoundCompoundAssignmentOperator boundCompoundAssignmentOperator = (BoundCompoundAssignmentOperator)expr;
|
|
if (CheckValEscape(boundCompoundAssignmentOperator.Left.Syntax, boundCompoundAssignmentOperator.Left, escapeFrom, escapeTo, checkingReceiver: false, diagnostics))
|
|
{
|
|
return CheckValEscape(boundCompoundAssignmentOperator.Right.Syntax, boundCompoundAssignmentOperator.Right, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
return false;
|
|
}
|
|
case BoundKind.BinaryOperator:
|
|
{
|
|
BoundBinaryOperator boundBinaryOperator = (BoundBinaryOperator)expr;
|
|
if (boundBinaryOperator.OperatorKind == BinaryOperatorKind.Utf8Addition)
|
|
{
|
|
return true;
|
|
}
|
|
if (CheckValEscape(boundBinaryOperator.Left.Syntax, boundBinaryOperator.Left, escapeFrom, escapeTo, checkingReceiver: false, diagnostics))
|
|
{
|
|
return CheckValEscape(boundBinaryOperator.Right.Syntax, boundBinaryOperator.Right, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
return false;
|
|
}
|
|
case BoundKind.RangeExpression:
|
|
{
|
|
BoundRangeExpression boundRangeExpression = (BoundRangeExpression)expr;
|
|
BoundExpression leftOperandOpt = boundRangeExpression.LeftOperandOpt;
|
|
if (leftOperandOpt != null && !CheckValEscape(leftOperandOpt.Syntax, leftOperandOpt, escapeFrom, escapeTo, checkingReceiver: false, diagnostics))
|
|
{
|
|
return false;
|
|
}
|
|
BoundExpression rightOperandOpt = boundRangeExpression.RightOperandOpt;
|
|
if (rightOperandOpt != null)
|
|
{
|
|
return CheckValEscape(rightOperandOpt.Syntax, rightOperandOpt, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
return true;
|
|
}
|
|
case BoundKind.UserDefinedConditionalLogicalOperator:
|
|
{
|
|
BoundUserDefinedConditionalLogicalOperator boundUserDefinedConditionalLogicalOperator = (BoundUserDefinedConditionalLogicalOperator)expr;
|
|
if (CheckValEscape(boundUserDefinedConditionalLogicalOperator.Left.Syntax, boundUserDefinedConditionalLogicalOperator.Left, escapeFrom, escapeTo, checkingReceiver: false, diagnostics))
|
|
{
|
|
return CheckValEscape(boundUserDefinedConditionalLogicalOperator.Right.Syntax, boundUserDefinedConditionalLogicalOperator.Right, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
return false;
|
|
}
|
|
case BoundKind.QueryClause:
|
|
{
|
|
BoundExpression value3 = ((BoundQueryClause)expr).Value;
|
|
return CheckValEscape(value3.Syntax, value3, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
case BoundKind.RangeVariable:
|
|
{
|
|
BoundExpression value2 = ((BoundRangeVariable)expr).Value;
|
|
return CheckValEscape(value2.Syntax, value2, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
}
|
|
case BoundKind.ObjectInitializerExpression:
|
|
{
|
|
BoundObjectInitializerExpression initExpr = (BoundObjectInitializerExpression)expr;
|
|
return CheckValEscapeOfObjectInitializer(initExpr, escapeFrom, escapeTo, diagnostics);
|
|
}
|
|
case BoundKind.CollectionInitializerExpression:
|
|
{
|
|
BoundCollectionInitializerExpression boundCollectionInitializerExpression = (BoundCollectionInitializerExpression)expr;
|
|
return CheckValEscape(boundCollectionInitializerExpression.Initializers, escapeFrom, escapeTo, diagnostics);
|
|
}
|
|
case BoundKind.CollectionElementInitializer:
|
|
{
|
|
BoundCollectionElementInitializer boundCollectionElementInitializer = (BoundCollectionElementInitializer)expr;
|
|
return CheckValEscape(boundCollectionElementInitializer.Arguments, escapeFrom, escapeTo, diagnostics);
|
|
}
|
|
case BoundKind.PointerElementAccess:
|
|
{
|
|
BoundExpression expression = ((BoundPointerElementAccess)expr).Expression;
|
|
return CheckValEscape(expression.Syntax, expression, escapeFrom, escapeTo, checkingReceiver, diagnostics);
|
|
}
|
|
case BoundKind.PointerIndirectionOperator:
|
|
{
|
|
BoundExpression operand = ((BoundPointerIndirectionOperator)expr).Operand;
|
|
return CheckValEscape(operand.Syntax, operand, escapeFrom, escapeTo, checkingReceiver, diagnostics);
|
|
}
|
|
case BoundKind.ArrayAccess:
|
|
case BoundKind.AwaitExpression:
|
|
case BoundKind.AsOperator:
|
|
case BoundKind.ConditionalAccess:
|
|
return false;
|
|
case BoundKind.UnconvertedSwitchExpression:
|
|
case BoundKind.ConvertedSwitchExpression:
|
|
{
|
|
ImmutableArray<BoundSwitchExpressionArm>.Enumerator enumerator = ((BoundSwitchExpression)expr).SwitchArms.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundExpression value = enumerator.Current.Value;
|
|
if (!CheckValEscape(value.Syntax, value, escapeFrom, escapeTo, checkingReceiver: false, diagnostics))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
default:
|
|
diagnostics.Add(ErrorCode.ERR_InternalError, node.Location);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private SignatureOnlyMethodSymbol GetInlineArrayAccessEquivalentSignatureMethod(BoundInlineArrayAccess elementAccess, out ImmutableArray<BoundExpression> arguments, out ImmutableArray<RefKind> refKinds)
|
|
{
|
|
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000d: Invalid comparison between Unknown and I4
|
|
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0015: Invalid comparison between Unknown and I4
|
|
//IL_0045: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0051: Invalid comparison between Unknown and I4
|
|
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0059: Invalid comparison between Unknown and I4
|
|
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0039: Invalid comparison between Unknown and I4
|
|
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0071: Invalid comparison between Unknown and I4
|
|
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0041: 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)
|
|
WellKnownMember getItemOrSliceHelper = elementAccess.GetItemOrSliceHelper;
|
|
RefKind val;
|
|
RefKind val2;
|
|
if (((int)getItemOrSliceHelper == 400 || (int)getItemOrSliceHelper == 406) ? true : false)
|
|
{
|
|
if (elementAccess.IsValue)
|
|
{
|
|
val = (RefKind)0;
|
|
val2 = (RefKind)0;
|
|
}
|
|
else
|
|
{
|
|
val = (RefKind)(((int)elementAccess.GetItemOrSliceHelper != 406) ? 1 : 3);
|
|
val2 = val;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
getItemOrSliceHelper = elementAccess.GetItemOrSliceHelper;
|
|
if (((int)getItemOrSliceHelper != 402 && (int)getItemOrSliceHelper != 408) || 1 == 0)
|
|
{
|
|
throw ExceptionUtilities.Unreachable("/_/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs", 4765);
|
|
}
|
|
val = (RefKind)0;
|
|
val2 = (RefKind)(((int)elementAccess.GetItemOrSliceHelper != 408) ? 1 : 3);
|
|
}
|
|
SignatureOnlyMethodSymbol result = new SignatureOnlyMethodSymbol("", _symbol.ContainingType, (MethodKind)10, (CallingConvention)0, ImmutableArray<TypeParameterSymbol>.Empty, ImmutableArray.Create((ParameterSymbol)new SignatureOnlyParameterSymbol(TypeWithAnnotations.Create(elementAccess.Expression.Type), ImmutableArray<CustomModifier>.Empty, isParams: false, val2)), val, isInitOnly: false, isStatic: true, TypeWithAnnotations.Create(elementAccess.Type), ImmutableArray<CustomModifier>.Empty, ImmutableArray<MethodSymbol>.Empty);
|
|
arguments = ImmutableArray.Create(elementAccess.Expression);
|
|
refKinds = ImmutableArray.Create<RefKind>(val2);
|
|
return result;
|
|
}
|
|
|
|
private SignatureOnlyMethodSymbol GetInlineArrayConversionEquivalentSignatureMethod(BoundConversion conversion, out ImmutableArray<BoundExpression> arguments, out ImmutableArray<RefKind> refKinds)
|
|
{
|
|
return GetInlineArrayConversionEquivalentSignatureMethod(conversion.Operand, conversion.Type, out arguments, out refKinds);
|
|
}
|
|
|
|
private SignatureOnlyMethodSymbol GetInlineArrayConversionEquivalentSignatureMethod(BoundExpression inlineArray, TypeSymbol resultType, out ImmutableArray<BoundExpression> arguments, out ImmutableArray<RefKind> refKinds)
|
|
{
|
|
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
|
|
RefKind val = (RefKind)((!resultType.OriginalDefinition.Equals(_compilation.GetWellKnownType((WellKnownType)276), (TypeCompareKind)63)) ? 1 : 3);
|
|
SignatureOnlyMethodSymbol result = new SignatureOnlyMethodSymbol("", _symbol.ContainingType, (MethodKind)10, (CallingConvention)0, ImmutableArray<TypeParameterSymbol>.Empty, ImmutableArray.Create((ParameterSymbol)new SignatureOnlyParameterSymbol(TypeWithAnnotations.Create(inlineArray.Type), ImmutableArray<CustomModifier>.Empty, isParams: false, val)), (RefKind)0, isInitOnly: false, isStatic: true, TypeWithAnnotations.Create(resultType), ImmutableArray<CustomModifier>.Empty, ImmutableArray<MethodSymbol>.Empty);
|
|
arguments = ImmutableArray.Create(inlineArray);
|
|
refKinds = ImmutableArray.Create<RefKind>(val);
|
|
return result;
|
|
}
|
|
|
|
private bool CheckTupleValEscape(ImmutableArray<BoundExpression> elements, uint escapeFrom, uint escapeTo, BindingDiagnosticBag diagnostics)
|
|
{
|
|
ImmutableArray<BoundExpression>.Enumerator enumerator = elements.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundExpression current = enumerator.Current;
|
|
if (!CheckValEscape(current.Syntax, current, escapeFrom, escapeTo, checkingReceiver: false, diagnostics))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private bool CheckValEscapeOfObjectInitializer(BoundObjectInitializerExpression initExpr, uint escapeFrom, uint escapeTo, BindingDiagnosticBag diagnostics)
|
|
{
|
|
ImmutableArray<BoundExpression>.Enumerator enumerator = initExpr.Initializers.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundExpression current = enumerator.Current;
|
|
if (current.Kind == BoundKind.AssignmentOperator)
|
|
{
|
|
BoundAssignmentOperator boundAssignmentOperator = (BoundAssignmentOperator)current;
|
|
if (!(boundAssignmentOperator.IsRef ? CheckRefEscape(current.Syntax, boundAssignmentOperator.Right, escapeFrom, escapeTo, checkingReceiver: false, diagnostics) : CheckValEscape(current.Syntax, boundAssignmentOperator.Right, escapeFrom, escapeTo, checkingReceiver: false, diagnostics)))
|
|
{
|
|
return false;
|
|
}
|
|
BoundObjectInitializerMember boundObjectInitializerMember = (BoundObjectInitializerMember)boundAssignmentOperator.Left;
|
|
if (!CheckValEscape(boundObjectInitializerMember.Arguments, escapeFrom, escapeTo, diagnostics))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else if (!CheckValEscape(current.Syntax, current, escapeFrom, escapeTo, checkingReceiver: false, diagnostics))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private bool CheckValEscape(ImmutableArray<BoundExpression> expressions, uint escapeFrom, uint escapeTo, BindingDiagnosticBag diagnostics)
|
|
{
|
|
ImmutableArray<BoundExpression>.Enumerator enumerator = expressions.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundExpression current = enumerator.Current;
|
|
if (!CheckValEscape(current.Syntax, current, escapeFrom, escapeTo, checkingReceiver: false, diagnostics))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private bool CheckInterpolatedStringHandlerConversionEscape(BoundExpression expression, uint escapeFrom, uint escapeTo, BindingDiagnosticBag diagnostics)
|
|
{
|
|
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
|
|
InterpolatedStringHandlerData interpolatedStringHandlerData = expression.GetInterpolatedStringHandlerData();
|
|
CheckValEscape(expression.Syntax, interpolatedStringHandlerData.Construction, escapeFrom, escapeTo, checkingReceiver: false, diagnostics);
|
|
ArrayBuilder<BoundExpression> instance = ArrayBuilder<BoundExpression>.GetInstance();
|
|
GetInterpolatedStringHandlerArgumentsForEscape(expression, instance);
|
|
bool result = true;
|
|
Enumerator<BoundExpression> enumerator = instance.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundExpression current = enumerator.Current;
|
|
if (!CheckValEscape(current.Syntax, current, escapeFrom, escapeTo, checkingReceiver: false, diagnostics))
|
|
{
|
|
result = false;
|
|
break;
|
|
}
|
|
}
|
|
instance.Free();
|
|
return result;
|
|
}
|
|
|
|
private void GetInterpolatedStringHandlerArgumentsForEscape(BoundExpression expression, ArrayBuilder<BoundExpression> arguments)
|
|
{
|
|
while (expression is BoundBinaryOperator boundBinaryOperator)
|
|
{
|
|
GetInterpolatedStringHandlerArgumentsForEscape(boundBinaryOperator.Right, arguments);
|
|
expression = boundBinaryOperator.Left;
|
|
}
|
|
if (expression is BoundInterpolatedString interpolatedString)
|
|
{
|
|
getParts(interpolatedString);
|
|
return;
|
|
}
|
|
throw ExceptionUtilities.UnexpectedValue((object)expression.Kind);
|
|
void getParts(BoundInterpolatedString boundInterpolatedString)
|
|
{
|
|
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0060: Invalid comparison between Unknown and I4
|
|
ImmutableArray<BoundExpression>.Enumerator enumerator = boundInterpolatedString.Parts.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
if (enumerator.Current is BoundCall boundCall)
|
|
{
|
|
MethodSymbol method = boundCall.Method;
|
|
if ((object)method != null && method.Name == "AppendFormatted" && (!_useUpdatedEscapeRules || (int)boundCall.Method.Parameters[0].EffectiveScope != 2))
|
|
{
|
|
arguments.Add(boundCall.Arguments[0]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ValidateRefConditionalOperator(SyntaxNode node, BoundExpression trueExpr, BoundExpression falseExpr, BindingDiagnosticBag diagnostics)
|
|
{
|
|
uint localScopeDepth = _localScopeDepth;
|
|
uint valEscape = GetValEscape(trueExpr, localScopeDepth);
|
|
uint valEscape2 = GetValEscape(falseExpr, localScopeDepth);
|
|
if (valEscape != valEscape2)
|
|
{
|
|
if (valEscape < valEscape2)
|
|
{
|
|
CheckValEscape(falseExpr.Syntax, falseExpr, localScopeDepth, valEscape, checkingReceiver: false, diagnostics);
|
|
}
|
|
else
|
|
{
|
|
CheckValEscape(trueExpr.Syntax, trueExpr, localScopeDepth, valEscape2, checkingReceiver: false, diagnostics);
|
|
}
|
|
diagnostics.Add(_inUnsafeRegion ? ErrorCode.WRN_MismatchedRefEscapeInTernary : ErrorCode.ERR_MismatchedRefEscapeInTernary, node.Location);
|
|
}
|
|
}
|
|
|
|
private void ValidateAssignment(SyntaxNode node, BoundExpression op1, BoundExpression op2, bool isRef, BindingDiagnosticBag diagnostics)
|
|
{
|
|
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
|
|
if (op1.HasAnyErrors)
|
|
{
|
|
return;
|
|
}
|
|
bool flag = false;
|
|
if (isRef)
|
|
{
|
|
uint refEscape = GetRefEscape(op1, _localScopeDepth);
|
|
uint refEscape2 = GetRefEscape(op2, _localScopeDepth);
|
|
if (refEscape < refEscape2)
|
|
{
|
|
bool inUnsafeRegion = _inUnsafeRegion;
|
|
ErrorCode errorCode = ((refEscape2 == 1) ? (inUnsafeRegion ? ErrorCode.WRN_RefAssignReturnOnly : ErrorCode.ERR_RefAssignReturnOnly) : (inUnsafeRegion ? ErrorCode.WRN_RefAssignNarrower : ErrorCode.ERR_RefAssignNarrower));
|
|
ErrorCode code = errorCode;
|
|
Error(diagnostics, code, SyntaxNodeOrToken.op_Implicit(node), getName(op1), op2.Syntax);
|
|
if (!_inUnsafeRegion)
|
|
{
|
|
flag = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BoundKind kind = op1.Kind;
|
|
if ((kind == BoundKind.Local || kind == BoundKind.Parameter) ? true : false)
|
|
{
|
|
uint valEscape = GetValEscape(op1, _localScopeDepth);
|
|
refEscape2 = GetValEscape(op2, _localScopeDepth);
|
|
if (valEscape > refEscape2)
|
|
{
|
|
ErrorCode code2 = (_inUnsafeRegion ? ErrorCode.WRN_RefAssignValEscapeWider : ErrorCode.ERR_RefAssignValEscapeWider);
|
|
Error(diagnostics, code2, SyntaxNodeOrToken.op_Implicit(node), getName(op1), op2.Syntax);
|
|
if (!_inUnsafeRegion)
|
|
{
|
|
flag = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!flag && op1.Type.IsRefLikeType)
|
|
{
|
|
uint valEscape2 = GetValEscape(op1, _localScopeDepth);
|
|
ValidateEscape(op2, valEscape2, isByRef: false, diagnostics);
|
|
}
|
|
static object getName(BoundExpression expr)
|
|
{
|
|
Symbol expressionSymbol = expr.ExpressionSymbol;
|
|
if ((object)expressionSymbol != null)
|
|
{
|
|
return expressionSymbol.Name;
|
|
}
|
|
if (expr is BoundArrayAccess)
|
|
{
|
|
return MessageID.IDS_ArrayAccess.Localize();
|
|
}
|
|
if (expr is BoundPointerElementAccess)
|
|
{
|
|
return MessageID.IDS_PointerElementAccess.Localize();
|
|
}
|
|
return "";
|
|
}
|
|
}
|
|
|
|
internal static void Analyze(CSharpCompilation compilation, MethodSymbol symbol, BoundNode node, BindingDiagnosticBag diagnostics)
|
|
{
|
|
RefSafetyAnalysis refSafetyAnalysis = new RefSafetyAnalysis(compilation, symbol, InUnsafeMethod(symbol), symbol.ContainingModule.UseUpdatedEscapeRules, diagnostics);
|
|
try
|
|
{
|
|
refSafetyAnalysis.Visit(node);
|
|
}
|
|
catch (CancelledByStackGuardException ex)
|
|
{
|
|
ex.AddAnError(diagnostics);
|
|
}
|
|
}
|
|
|
|
private static bool InUnsafeMethod(Symbol symbol)
|
|
{
|
|
if (symbol is SourceMemberMethodSymbol { IsUnsafe: not false })
|
|
{
|
|
return true;
|
|
}
|
|
NamedTypeSymbol containingType = symbol.ContainingType;
|
|
while ((object)containingType != null)
|
|
{
|
|
NamedTypeSymbol originalDefinition = containingType.OriginalDefinition;
|
|
if (originalDefinition is SourceMemberContainerTypeSymbol { IsUnsafe: not false })
|
|
{
|
|
return true;
|
|
}
|
|
containingType = originalDefinition.ContainingType;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private RefSafetyAnalysis(CSharpCompilation compilation, MethodSymbol symbol, bool inUnsafeRegion, bool useUpdatedEscapeRules, BindingDiagnosticBag diagnostics, Dictionary<LocalSymbol, (uint RefEscapeScope, uint ValEscapeScope)>? localEscapeScopes = null)
|
|
{
|
|
_compilation = compilation;
|
|
_symbol = symbol;
|
|
_useUpdatedEscapeRules = useUpdatedEscapeRules;
|
|
_diagnostics = diagnostics;
|
|
_inUnsafeRegion = inUnsafeRegion;
|
|
_localScopeDepth = 1u;
|
|
_localEscapeScopes = localEscapeScopes;
|
|
}
|
|
|
|
private (uint RefEscapeScope, uint ValEscapeScope) GetLocalScopes(LocalSymbol local)
|
|
{
|
|
Dictionary<LocalSymbol, (uint RefEscapeScope, uint ValEscapeScope)>? localEscapeScopes = _localEscapeScopes;
|
|
if (localEscapeScopes == null || !localEscapeScopes.TryGetValue(local, out (uint, uint) value))
|
|
{
|
|
return (RefEscapeScope: 0u, ValEscapeScope: 0u);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
private void SetLocalScopes(LocalSymbol local, uint refEscapeScope, uint valEscapeScope)
|
|
{
|
|
AddOrSetLocalScopes(local, refEscapeScope, valEscapeScope);
|
|
}
|
|
|
|
private void AddPlaceholderScope(BoundValuePlaceholderBase placeholder, uint valEscapeScope)
|
|
{
|
|
if (_placeholderScopes == null)
|
|
{
|
|
_placeholderScopes = new Dictionary<BoundValuePlaceholderBase, uint>();
|
|
}
|
|
_placeholderScopes[placeholder] = valEscapeScope;
|
|
}
|
|
|
|
private void RemovePlaceholderScope(BoundValuePlaceholderBase placeholder)
|
|
{
|
|
}
|
|
|
|
private uint GetPlaceholderScope(BoundValuePlaceholderBase placeholder)
|
|
{
|
|
Dictionary<BoundValuePlaceholderBase, uint>? placeholderScopes = _placeholderScopes;
|
|
if (placeholderScopes == null || !placeholderScopes.TryGetValue(placeholder, out var value))
|
|
{
|
|
return 0u;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
public override BoundNode? VisitBlock(BoundBlock node)
|
|
{
|
|
UnsafeRegion unsafeRegion = new UnsafeRegion(this, _inUnsafeRegion || node.HasUnsafeModifier);
|
|
try
|
|
{
|
|
using (new LocalScope(this, node.Locals))
|
|
{
|
|
return base.VisitBlock(node);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
unsafeRegion.Dispose();
|
|
}
|
|
}
|
|
|
|
public override BoundNode? Visit(BoundNode? node)
|
|
{
|
|
return base.Visit(node);
|
|
}
|
|
|
|
public override BoundNode? VisitFieldEqualsValue(BoundFieldEqualsValue node)
|
|
{
|
|
throw ExceptionUtilities.Unreachable("/_/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs", 293);
|
|
}
|
|
|
|
public override BoundNode? VisitLocalFunctionStatement(BoundLocalFunctionStatement node)
|
|
{
|
|
LocalFunctionSymbol symbol = node.Symbol;
|
|
RefSafetyAnalysis refSafetyAnalysis = new RefSafetyAnalysis(_compilation, symbol, _inUnsafeRegion || symbol.IsUnsafe, _useUpdatedEscapeRules, _diagnostics, _localEscapeScopes);
|
|
refSafetyAnalysis.Visit(node.BlockBody);
|
|
refSafetyAnalysis.Visit(node.ExpressionBody);
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode? VisitLambda(BoundLambda node)
|
|
{
|
|
LambdaSymbol symbol = node.Symbol;
|
|
new RefSafetyAnalysis(_compilation, symbol, _inUnsafeRegion, _useUpdatedEscapeRules, _diagnostics, _localEscapeScopes).Visit(node.Body);
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode? VisitConstructorMethodBody(BoundConstructorMethodBody node)
|
|
{
|
|
using (new LocalScope(this, node.Locals))
|
|
{
|
|
return base.VisitConstructorMethodBody(node);
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitForStatement(BoundForStatement node)
|
|
{
|
|
using (new LocalScope(this, node.OuterLocals))
|
|
{
|
|
using (new LocalScope(this, node.InnerLocals))
|
|
{
|
|
return base.VisitForStatement(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitUsingStatement(BoundUsingStatement node)
|
|
{
|
|
using (new LocalScope(this, node.Locals))
|
|
{
|
|
Visit(node.DeclarationsOpt);
|
|
Visit(node.ExpressionOpt);
|
|
ArrayBuilder<(BoundValuePlaceholderBase, uint)> instance = ArrayBuilder<(BoundValuePlaceholderBase, uint)>.GetInstance();
|
|
BoundAwaitableInfo awaitOpt = node.AwaitOpt;
|
|
if (awaitOpt != null)
|
|
{
|
|
BoundExpression expressionOpt = node.ExpressionOpt;
|
|
uint valEscapeScope = ((expressionOpt != null) ? GetValEscape(expressionOpt, _localScopeDepth) : _localScopeDepth);
|
|
GetAwaitableInstancePlaceholders(instance, awaitOpt, valEscapeScope);
|
|
}
|
|
using (new PlaceholderRegion(this, instance))
|
|
{
|
|
Visit(node.AwaitOpt);
|
|
Visit(node.Body);
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitUsingLocalDeclarations(BoundUsingLocalDeclarations node)
|
|
{
|
|
ArrayBuilder<(BoundValuePlaceholderBase, uint)> instance = ArrayBuilder<(BoundValuePlaceholderBase, uint)>.GetInstance();
|
|
BoundAwaitableInfo awaitOpt = node.AwaitOpt;
|
|
if (awaitOpt != null)
|
|
{
|
|
GetAwaitableInstancePlaceholders(instance, awaitOpt, _localScopeDepth);
|
|
}
|
|
using (new PlaceholderRegion(this, instance))
|
|
{
|
|
return base.VisitUsingLocalDeclarations(node);
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitFixedStatement(BoundFixedStatement node)
|
|
{
|
|
using (new LocalScope(this, node.Locals))
|
|
{
|
|
return base.VisitFixedStatement(node);
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitDoStatement(BoundDoStatement node)
|
|
{
|
|
using (new LocalScope(this, node.Locals))
|
|
{
|
|
return base.VisitDoStatement(node);
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitWhileStatement(BoundWhileStatement node)
|
|
{
|
|
using (new LocalScope(this, node.Locals))
|
|
{
|
|
return base.VisitWhileStatement(node);
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitSwitchStatement(BoundSwitchStatement node)
|
|
{
|
|
Visit(node.Expression);
|
|
using (new LocalScope(this, node.InnerLocals))
|
|
{
|
|
using (new PatternInput(this, GetValEscape(node.Expression, _localScopeDepth)))
|
|
{
|
|
VisitList(node.SwitchSections);
|
|
Visit(node.DefaultLabel);
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitConvertedSwitchExpression(BoundConvertedSwitchExpression node)
|
|
{
|
|
Visit(node.Expression);
|
|
using (new PatternInput(this, GetValEscape(node.Expression, _localScopeDepth)))
|
|
{
|
|
VisitList(node.SwitchArms);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitSwitchSection(BoundSwitchSection node)
|
|
{
|
|
using (new LocalScope(this, node.Locals))
|
|
{
|
|
return base.VisitSwitchSection(node);
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitSwitchExpressionArm(BoundSwitchExpressionArm node)
|
|
{
|
|
using (new LocalScope(this, node.Locals))
|
|
{
|
|
return base.VisitSwitchExpressionArm(node);
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitCatchBlock(BoundCatchBlock node)
|
|
{
|
|
using (new LocalScope(this, node.Locals))
|
|
{
|
|
return base.VisitCatchBlock(node);
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitLocal(BoundLocal node)
|
|
{
|
|
return base.VisitLocal(node);
|
|
}
|
|
|
|
private void AddLocalScopes(LocalSymbol local, uint refEscapeScope, uint valEscapeScope)
|
|
{
|
|
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0017: Invalid comparison between Unknown and I4
|
|
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0026: Invalid comparison between Unknown and I4
|
|
ScopedKind val = (ScopedKind)(_useUpdatedEscapeRules ? ((int)local.Scope) : 0);
|
|
if ((int)val != 0)
|
|
{
|
|
refEscapeScope = (((int)val == 1) ? _localScopeDepth : 2u);
|
|
valEscapeScope = (((int)val == 2) ? _localScopeDepth : 0u);
|
|
}
|
|
AddOrSetLocalScopes(local, refEscapeScope, valEscapeScope);
|
|
}
|
|
|
|
private void AddOrSetLocalScopes(LocalSymbol local, uint refEscapeScope, uint valEscapeScope)
|
|
{
|
|
if (_localEscapeScopes == null)
|
|
{
|
|
_localEscapeScopes = new Dictionary<LocalSymbol, (uint, uint)>();
|
|
}
|
|
_localEscapeScopes[local] = (refEscapeScope, valEscapeScope);
|
|
}
|
|
|
|
private void RemoveLocalScopes(LocalSymbol local)
|
|
{
|
|
}
|
|
|
|
public override BoundNode? VisitLocalDeclaration(BoundLocalDeclaration node)
|
|
{
|
|
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
|
|
base.VisitLocalDeclaration(node);
|
|
BoundExpression initializerOpt = node.InitializerOpt;
|
|
if (initializerOpt != null)
|
|
{
|
|
SourceLocalSymbol sourceLocalSymbol = (SourceLocalSymbol)node.LocalSymbol;
|
|
uint refEscapeScope;
|
|
uint escapeTo;
|
|
(refEscapeScope, escapeTo) = GetLocalScopes(sourceLocalSymbol);
|
|
if (_useUpdatedEscapeRules && (int)sourceLocalSymbol.Scope != 0)
|
|
{
|
|
BoundTypeExpression? declaredTypeOpt = node.DeclaredTypeOpt;
|
|
if (declaredTypeOpt != null && declaredTypeOpt.Type.IsRefLikeType)
|
|
{
|
|
ValidateEscape(initializerOpt, escapeTo, isByRef: false, _diagnostics);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetLocalScopes(sourceLocalSymbol, _localScopeDepth, _localScopeDepth);
|
|
escapeTo = GetValEscape(initializerOpt, _localScopeDepth);
|
|
if ((int)sourceLocalSymbol.RefKind != 0)
|
|
{
|
|
refEscapeScope = GetRefEscape(initializerOpt, _localScopeDepth);
|
|
}
|
|
SetLocalScopes(sourceLocalSymbol, refEscapeScope, escapeTo);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode? VisitReturnStatement(BoundReturnStatement node)
|
|
{
|
|
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0024: Invalid comparison between Unknown and I4
|
|
base.VisitReturnStatement(node);
|
|
BoundExpression expressionOpt = node.ExpressionOpt;
|
|
if (expressionOpt != null && (object)expressionOpt.Type != null)
|
|
{
|
|
ValidateEscape(expressionOpt, 1u, (int)node.RefKind > 0, _diagnostics);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode? VisitYieldReturnStatement(BoundYieldReturnStatement node)
|
|
{
|
|
base.VisitYieldReturnStatement(node);
|
|
BoundExpression expression = node.Expression;
|
|
if (expression != null && (object)expression.Type != null)
|
|
{
|
|
ValidateEscape(expression, 1u, isByRef: false, _diagnostics);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode? VisitAssignmentOperator(BoundAssignmentOperator node)
|
|
{
|
|
base.VisitAssignmentOperator(node);
|
|
if (node.Left.Kind != BoundKind.DiscardExpression)
|
|
{
|
|
ValidateAssignment(node.Syntax, node.Left, node.Right, node.IsRef, _diagnostics);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode? VisitIsPatternExpression(BoundIsPatternExpression node)
|
|
{
|
|
Visit(node.Expression);
|
|
using (new PatternInput(this, GetValEscape(node.Expression, _localScopeDepth)))
|
|
{
|
|
Visit(node.Pattern);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitDeclarationPattern(BoundDeclarationPattern node)
|
|
{
|
|
SetPatternLocalScopes(node);
|
|
using (new PatternInput(this, getDeclarationValEscape(node.DeclaredType, _patternInputValEscape)))
|
|
{
|
|
return base.VisitDeclarationPattern(node);
|
|
}
|
|
static uint getDeclarationValEscape(BoundTypeExpression typeExpression, uint valEscape)
|
|
{
|
|
if (!typeExpression.Type.IsRefLikeType)
|
|
{
|
|
return 0u;
|
|
}
|
|
return valEscape;
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitListPattern(BoundListPattern node)
|
|
{
|
|
SetPatternLocalScopes(node);
|
|
return base.VisitListPattern(node);
|
|
}
|
|
|
|
public override BoundNode? VisitRecursivePattern(BoundRecursivePattern node)
|
|
{
|
|
SetPatternLocalScopes(node);
|
|
return base.VisitRecursivePattern(node);
|
|
}
|
|
|
|
public override BoundNode? VisitPositionalSubpattern(BoundPositionalSubpattern node)
|
|
{
|
|
using (new PatternInput(this, getPositionalValEscape(node.Symbol, _patternInputValEscape)))
|
|
{
|
|
return base.VisitPositionalSubpattern(node);
|
|
}
|
|
static uint getPositionalValEscape(Symbol? symbol, uint valEscape)
|
|
{
|
|
if ((object)symbol != null)
|
|
{
|
|
if (!symbol.GetTypeOrReturnType().IsRefLikeType())
|
|
{
|
|
return 0u;
|
|
}
|
|
return valEscape;
|
|
}
|
|
return valEscape;
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitPropertySubpattern(BoundPropertySubpattern node)
|
|
{
|
|
using (new PatternInput(this, getMemberValEscape(node.Member, _patternInputValEscape)))
|
|
{
|
|
return base.VisitPropertySubpattern(node);
|
|
}
|
|
static uint getMemberValEscape(BoundPropertySubpatternMember? member, uint valEscape)
|
|
{
|
|
if (member == null)
|
|
{
|
|
return valEscape;
|
|
}
|
|
valEscape = getMemberValEscape(member.Receiver, valEscape);
|
|
if (!member.Type.IsRefLikeType)
|
|
{
|
|
return 0u;
|
|
}
|
|
return valEscape;
|
|
}
|
|
}
|
|
|
|
private void SetPatternLocalScopes(BoundObjectPattern pattern)
|
|
{
|
|
if (pattern.Variable is LocalSymbol local)
|
|
{
|
|
SetLocalScopes(local, _localScopeDepth, _patternInputValEscape);
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitConditionalOperator(BoundConditionalOperator node)
|
|
{
|
|
base.VisitConditionalOperator(node);
|
|
if (node.IsRef)
|
|
{
|
|
ValidateRefConditionalOperator(node.Syntax, node.Consequence, node.Alternative, _diagnostics);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void VisitArgumentsAndGetArgumentPlaceholders(BoundExpression? receiverOpt, ImmutableArray<BoundExpression> arguments)
|
|
{
|
|
for (int num = 0; num < arguments.Length; num++)
|
|
{
|
|
BoundExpression boundExpression = arguments[num];
|
|
BoundConversion boundConversion = boundExpression as BoundConversion;
|
|
bool flag;
|
|
if (boundConversion != null && boundConversion.ConversionKind == ConversionKind.InterpolatedStringHandler)
|
|
{
|
|
BoundExpression operand = boundConversion.Operand;
|
|
if (operand is BoundInterpolatedString || operand is BoundBinaryOperator)
|
|
{
|
|
flag = true;
|
|
goto IL_0040;
|
|
}
|
|
}
|
|
flag = false;
|
|
goto IL_0040;
|
|
IL_0040:
|
|
if (flag)
|
|
{
|
|
InterpolatedStringHandlerData interpolationData = boundConversion.Operand.GetInterpolatedStringHandlerData();
|
|
ArrayBuilder<(BoundValuePlaceholderBase, uint)> instance = ArrayBuilder<(BoundValuePlaceholderBase, uint)>.GetInstance();
|
|
GetInterpolatedStringPlaceholders(instance, in interpolationData, receiverOpt, num, arguments);
|
|
new PlaceholderRegion(this, instance);
|
|
}
|
|
Visit(boundExpression);
|
|
}
|
|
}
|
|
|
|
protected override void VisitArguments(BoundCall node)
|
|
{
|
|
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
|
|
VisitArgumentsAndGetArgumentPlaceholders(node.ReceiverOpt, node.Arguments);
|
|
if (!node.HasErrors)
|
|
{
|
|
MethodSymbol method = node.Method;
|
|
CheckInvocationArgMixing(node.Syntax, method, node.ReceiverOpt, node.InitialBindingReceiverIsSubjectToCloning, method.Parameters, node.Arguments, node.ArgumentRefKindsOpt, node.ArgsToParamsOpt, _localScopeDepth, _diagnostics);
|
|
}
|
|
}
|
|
|
|
private void GetInterpolatedStringPlaceholders(ArrayBuilder<(BoundValuePlaceholderBase, uint)> placeholders, in InterpolatedStringHandlerData interpolationData, BoundExpression? receiver, int nArgumentsVisited, ImmutableArray<BoundExpression> arguments)
|
|
{
|
|
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
|
|
placeholders.Add(((BoundValuePlaceholderBase)interpolationData.ReceiverPlaceholder, _localScopeDepth));
|
|
ImmutableArray<BoundInterpolatedStringArgumentPlaceholder>.Enumerator enumerator = interpolationData.ArgumentPlaceholders.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundInterpolatedStringArgumentPlaceholder current = enumerator.Current;
|
|
int argumentIndex = current.ArgumentIndex;
|
|
uint item;
|
|
if (argumentIndex >= 0)
|
|
{
|
|
item = ((argumentIndex < nArgumentsVisited) ? GetValEscape(arguments[argumentIndex], _localScopeDepth) : 0u);
|
|
}
|
|
else
|
|
{
|
|
switch (argumentIndex)
|
|
{
|
|
case -1:
|
|
break;
|
|
default:
|
|
throw ExceptionUtilities.UnexpectedValue((object)current.ArgumentIndex);
|
|
case -3:
|
|
case -2:
|
|
continue;
|
|
}
|
|
item = ((receiver != null) ? (receiver.GetRefKind().IsWritableReference() ? GetRefEscape(receiver, _localScopeDepth) : GetValEscape(receiver, _localScopeDepth)) : 0u);
|
|
}
|
|
placeholders.Add(((BoundValuePlaceholderBase)current, item));
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitObjectCreationExpression(BoundObjectCreationExpression node)
|
|
{
|
|
VisitObjectCreationExpressionBase(node);
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode? VisitDynamicObjectCreationExpression(BoundDynamicObjectCreationExpression node)
|
|
{
|
|
VisitObjectCreationExpressionBase(node);
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode? VisitNewT(BoundNewT node)
|
|
{
|
|
VisitObjectCreationExpressionBase(node);
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode? VisitNoPiaObjectCreationExpression(BoundNoPiaObjectCreationExpression node)
|
|
{
|
|
VisitObjectCreationExpressionBase(node);
|
|
return null;
|
|
}
|
|
|
|
private void VisitObjectCreationExpressionBase(BoundObjectCreationExpressionBase node)
|
|
{
|
|
VisitArgumentsAndGetArgumentPlaceholders(null, node.Arguments);
|
|
Visit(node.InitializerExpressionOpt);
|
|
if (!node.HasErrors)
|
|
{
|
|
MethodSymbol constructor = node.Constructor;
|
|
if ((object)constructor != null)
|
|
{
|
|
CheckInvocationArgMixing(node.Syntax, constructor, null, (ThreeState)0, constructor.Parameters, node.Arguments, node.ArgumentRefKindsOpt, node.ArgsToParamsOpt, _localScopeDepth, _diagnostics);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitPropertyAccess(BoundPropertyAccess node)
|
|
{
|
|
return base.VisitPropertyAccess(node);
|
|
}
|
|
|
|
public override BoundNode? VisitIndexerAccess(BoundIndexerAccess node)
|
|
{
|
|
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
|
|
Visit(node.ReceiverOpt);
|
|
VisitArgumentsAndGetArgumentPlaceholders(node.ReceiverOpt, node.Arguments);
|
|
if (!node.HasErrors)
|
|
{
|
|
PropertySymbol indexer = node.Indexer;
|
|
CheckInvocationArgMixing(node.Syntax, indexer, node.ReceiverOpt, node.InitialBindingReceiverIsSubjectToCloning, indexer.Parameters, node.Arguments, node.ArgumentRefKindsOpt, node.ArgsToParamsOpt, _localScopeDepth, _diagnostics);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode? VisitFunctionPointerInvocation(BoundFunctionPointerInvocation node)
|
|
{
|
|
VisitArgumentsAndGetArgumentPlaceholders(null, node.Arguments);
|
|
if (!node.HasErrors)
|
|
{
|
|
FunctionPointerMethodSymbol signature = node.FunctionPointer.Signature;
|
|
CheckInvocationArgMixing(node.Syntax, signature, null, (ThreeState)0, signature.Parameters, node.Arguments, node.ArgumentRefKindsOpt, default(ImmutableArray<int>), _localScopeDepth, _diagnostics);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode? VisitAwaitExpression(BoundAwaitExpression node)
|
|
{
|
|
Visit(node.Expression);
|
|
ArrayBuilder<(BoundValuePlaceholderBase, uint)> instance = ArrayBuilder<(BoundValuePlaceholderBase, uint)>.GetInstance();
|
|
GetAwaitableInstancePlaceholders(instance, node.AwaitableInfo, GetValEscape(node.Expression, _localScopeDepth));
|
|
using (new PlaceholderRegion(this, instance))
|
|
{
|
|
Visit(node.AwaitableInfo);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private void GetAwaitableInstancePlaceholders(ArrayBuilder<(BoundValuePlaceholderBase, uint)> placeholders, BoundAwaitableInfo awaitableInfo, uint valEscapeScope)
|
|
{
|
|
BoundAwaitableValuePlaceholder awaitableInstancePlaceholder = awaitableInfo.AwaitableInstancePlaceholder;
|
|
if (awaitableInstancePlaceholder != null)
|
|
{
|
|
placeholders.Add(((BoundValuePlaceholderBase)awaitableInstancePlaceholder, valEscapeScope));
|
|
}
|
|
}
|
|
|
|
public override BoundNode? VisitImplicitIndexerAccess(BoundImplicitIndexerAccess node)
|
|
{
|
|
base.VisitImplicitIndexerAccess(node);
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode? VisitDeconstructionAssignmentOperator(BoundDeconstructionAssignmentOperator node)
|
|
{
|
|
base.VisitDeconstructionAssignmentOperator(node);
|
|
BoundTupleExpression left = node.Left;
|
|
BoundConversion right = node.Right;
|
|
ArrayBuilder<DeconstructionVariable> deconstructionAssignmentVariables = GetDeconstructionAssignmentVariables(left);
|
|
VisitDeconstructionArguments(deconstructionAssignmentVariables, right.Syntax, right.Conversion, right.Operand);
|
|
ArrayBuilderExtensions.FreeAll<DeconstructionVariable>(deconstructionAssignmentVariables, (Func<DeconstructionVariable, ArrayBuilder<DeconstructionVariable>>)((DeconstructionVariable v) => v.NestedVariables));
|
|
return null;
|
|
}
|
|
|
|
private void VisitDeconstructionArguments(ArrayBuilder<DeconstructionVariable> variables, SyntaxNode syntax, Conversion conversion, BoundExpression right)
|
|
{
|
|
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
|
|
if (conversion.DeconstructionInfo.IsDefault || !(conversion.DeconstructionInfo.Invocation is BoundCall boundCall))
|
|
{
|
|
return;
|
|
}
|
|
MethodSymbol method = boundCall.Method;
|
|
if ((object)method == null)
|
|
{
|
|
return;
|
|
}
|
|
ArrayBuilder<(BoundValuePlaceholderBase, uint)> instance = ArrayBuilder<(BoundValuePlaceholderBase, uint)>.GetInstance();
|
|
instance.Add(((BoundValuePlaceholderBase)conversion.DeconstructionInfo.InputPlaceholder, GetValEscape(right, _localScopeDepth)));
|
|
ImmutableArray<ParameterSymbol> parameters = method.Parameters;
|
|
int count = variables.Count;
|
|
int num = (boundCall.InvokedAsExtensionMethod ? 1 : 0);
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
DeconstructionVariable deconstructionVariable = variables[i];
|
|
ArrayBuilder<DeconstructionVariable>? nestedVariables = deconstructionVariable.NestedVariables;
|
|
BoundDeconstructValuePlaceholder item = (BoundDeconstructValuePlaceholder)boundCall.Arguments[i + num];
|
|
uint item2 = ((nestedVariables == null) ? GetValEscape(deconstructionVariable.Expression, _localScopeDepth) : _localScopeDepth);
|
|
instance.Add(((BoundValuePlaceholderBase)item, item2));
|
|
}
|
|
using (new PlaceholderRegion(this, instance))
|
|
{
|
|
CheckInvocationArgMixing(syntax, method, boundCall.ReceiverOpt, boundCall.InitialBindingReceiverIsSubjectToCloning, parameters, boundCall.Arguments, boundCall.ArgumentRefKindsOpt, boundCall.ArgsToParamsOpt, _localScopeDepth, _diagnostics);
|
|
for (int j = 0; j < count; j++)
|
|
{
|
|
ArrayBuilder<DeconstructionVariable> nestedVariables2 = variables[j].NestedVariables;
|
|
if (nestedVariables2 != null)
|
|
{
|
|
(BoundValuePlaceholder? placeholder, BoundExpression? conversion) tuple = conversion.DeconstructConversionInfo[j];
|
|
Conversion conversion2 = BoundNode.GetConversion(placeholder: tuple.placeholder, conversion: tuple.conversion);
|
|
VisitDeconstructionArguments(nestedVariables2, syntax, conversion2, boundCall.Arguments[j + num]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private ArrayBuilder<DeconstructionVariable> GetDeconstructionAssignmentVariables(BoundTupleExpression tuple)
|
|
{
|
|
ImmutableArray<BoundExpression> arguments = tuple.Arguments;
|
|
ArrayBuilder<DeconstructionVariable> instance = ArrayBuilder<DeconstructionVariable>.GetInstance(arguments.Length);
|
|
ImmutableArray<BoundExpression>.Enumerator enumerator = arguments.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundExpression current = enumerator.Current;
|
|
instance.Add(getDeconstructionAssignmentVariable(current));
|
|
}
|
|
return instance;
|
|
DeconstructionVariable getDeconstructionAssignmentVariable(BoundExpression expr)
|
|
{
|
|
if (!(expr is BoundTupleExpression tuple2))
|
|
{
|
|
return new DeconstructionVariable(expr, GetValEscape(expr, _localScopeDepth), null);
|
|
}
|
|
return new DeconstructionVariable(expr, uint.MaxValue, GetDeconstructionAssignmentVariables(tuple2));
|
|
}
|
|
}
|
|
|
|
private static ImmutableArray<BoundExpression> GetDeconstructionRightParts(BoundExpression expr)
|
|
{
|
|
if (!(expr is BoundTupleExpression boundTupleExpression))
|
|
{
|
|
if (expr is BoundConversion { ConversionKind: var conversionKind } boundConversion && (conversionKind == ConversionKind.Identity || conversionKind == ConversionKind.ImplicitTupleLiteral))
|
|
{
|
|
return GetDeconstructionRightParts(boundConversion.Operand);
|
|
}
|
|
throw ExceptionUtilities.Unreachable("/_/src/Compilers/CSharp/Portable/Binder/RefSafetyAnalysis.cs", 976);
|
|
}
|
|
return boundTupleExpression.Arguments;
|
|
}
|
|
|
|
public override BoundNode? VisitForEachStatement(BoundForEachStatement node)
|
|
{
|
|
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
|
|
Visit(node.Expression);
|
|
ForEachEnumeratorInfo enumeratorInfoOpt = node.EnumeratorInfoOpt;
|
|
BoundExpression inlineArray;
|
|
if (enumeratorInfoOpt != null && (int)enumeratorInfoOpt.InlineArraySpanType != 0 && !enumeratorInfoOpt.InlineArrayUsedAsValue)
|
|
{
|
|
if (node.Expression is BoundConversion { Conversion: { IsIdentity: not false }, ExplicitCastInCode: false } boundConversion)
|
|
{
|
|
BoundExpression operand = boundConversion.Operand;
|
|
if (operand != null)
|
|
{
|
|
inlineArray = operand;
|
|
goto IL_0078;
|
|
}
|
|
}
|
|
inlineArray = node.Expression;
|
|
goto IL_0078;
|
|
}
|
|
uint num = GetValEscape(node.Expression, _localScopeDepth);
|
|
goto IL_00d4;
|
|
IL_00d4:
|
|
using (new LocalScope(this, ImmutableArray<LocalSymbol>.Empty))
|
|
{
|
|
ImmutableArray<LocalSymbol>.Enumerator enumerator = node.IterationVariables.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalSymbol current = enumerator.Current;
|
|
AddLocalScopes(current, ((int)current.RefKind == 0) ? _localScopeDepth : num, num);
|
|
}
|
|
ArrayBuilder<(BoundValuePlaceholderBase, uint)> instance = ArrayBuilder<(BoundValuePlaceholderBase, uint)>.GetInstance();
|
|
BoundDeconstructValuePlaceholder boundDeconstructValuePlaceholder = node.DeconstructionOpt?.TargetPlaceholder;
|
|
if (boundDeconstructValuePlaceholder != null)
|
|
{
|
|
instance.Add(((BoundValuePlaceholderBase)boundDeconstructValuePlaceholder, num));
|
|
}
|
|
BoundAwaitableInfo awaitOpt = node.AwaitOpt;
|
|
if (awaitOpt != null)
|
|
{
|
|
GetAwaitableInstancePlaceholders(instance, awaitOpt, num);
|
|
}
|
|
using (new PlaceholderRegion(this, instance))
|
|
{
|
|
Visit(node.IterationVariableType);
|
|
Visit(node.IterationErrorExpressionOpt);
|
|
Visit(node.DeconstructionOpt);
|
|
Visit(node.AwaitOpt);
|
|
Visit(node.Body);
|
|
enumerator = node.IterationVariables.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalSymbol current2 = enumerator.Current;
|
|
RemoveLocalScopes(current2);
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
IL_0078:
|
|
ImmutableArray<BoundExpression> arguments;
|
|
ImmutableArray<RefKind> refKinds;
|
|
SignatureOnlyMethodSymbol inlineArrayConversionEquivalentSignatureMethod = GetInlineArrayConversionEquivalentSignatureMethod(inlineArray, node.EnumeratorInfoOpt.GetEnumeratorInfo.Method.ContainingType, out arguments, out refKinds);
|
|
num = GetInvocationEscapeScope(inlineArrayConversionEquivalentSignatureMethod, null, (ThreeState)0, inlineArrayConversionEquivalentSignatureMethod.Parameters, arguments, refKinds, default(ImmutableArray<int>), _localScopeDepth, isRefEscape: false);
|
|
goto IL_00d4;
|
|
}
|
|
|
|
private static void Error(BindingDiagnosticBag diagnostics, ErrorCode code, SyntaxNodeOrToken syntax, params object[] args)
|
|
{
|
|
Location location = ((SyntaxNodeOrToken)(ref syntax)).GetLocation();
|
|
Error(diagnostics, code, location, args);
|
|
}
|
|
|
|
private static void Error(BindingDiagnosticBag diagnostics, ErrorCode code, Location location, params object[] args)
|
|
{
|
|
((BindingDiagnosticBag)diagnostics).Add((Diagnostic)(object)new CSDiagnostic((DiagnosticInfo)(object)new CSDiagnosticInfo(code, args), location));
|
|
}
|
|
}
|