2772 lines
92 KiB
C#
2772 lines
92 KiB
C#
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Microsoft.CodeAnalysis.CSharp.Symbols;
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
using Microsoft.CodeAnalysis.PooledObjects;
|
|
using Microsoft.CodeAnalysis.Text;
|
|
using Roslyn.Utilities;
|
|
|
|
namespace Microsoft.CodeAnalysis.CSharp;
|
|
|
|
internal class DefiniteAssignmentPass : LocalDataFlowPass<DefiniteAssignmentPass.LocalState, DefiniteAssignmentPass.LocalFunctionState>
|
|
{
|
|
private sealed class SameDiagnosticComparer : EqualityComparer<Diagnostic>
|
|
{
|
|
public static readonly SameDiagnosticComparer Instance = new SameDiagnosticComparer();
|
|
|
|
public override bool Equals(Diagnostic x, Diagnostic y)
|
|
{
|
|
return x.Equals(y);
|
|
}
|
|
|
|
public override int GetHashCode(Diagnostic obj)
|
|
{
|
|
return Hash.Combine(Hash.CombineValues<object>((IEnumerable<object>)obj.Arguments, int.MaxValue), Hash.Combine(((object)obj.Location).GetHashCode(), obj.Code));
|
|
}
|
|
}
|
|
|
|
internal struct LocalState : ILocalDataFlowState, ILocalState
|
|
{
|
|
internal BitVector Assigned;
|
|
|
|
public bool NormalizeToBottom { get; }
|
|
|
|
public bool Reachable
|
|
{
|
|
get
|
|
{
|
|
if (((BitVector)(ref Assigned)).Capacity > 0)
|
|
{
|
|
return !IsAssigned(0);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
internal LocalState(BitVector assigned, bool normalizeToBottom = false)
|
|
{
|
|
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
|
|
Assigned = assigned;
|
|
NormalizeToBottom = normalizeToBottom;
|
|
}
|
|
|
|
public LocalState Clone()
|
|
{
|
|
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
|
|
return new LocalState(((BitVector)(ref Assigned)).Clone());
|
|
}
|
|
|
|
public bool IsAssigned(int slot)
|
|
{
|
|
return ((BitVector)(ref Assigned))[slot];
|
|
}
|
|
|
|
public void Assign(int slot)
|
|
{
|
|
if (slot != -1)
|
|
{
|
|
((BitVector)(ref Assigned))[slot] = true;
|
|
}
|
|
}
|
|
|
|
public void Unassign(int slot)
|
|
{
|
|
if (slot != -1)
|
|
{
|
|
((BitVector)(ref Assigned))[slot] = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal sealed class LocalFunctionState(LocalState stateFromBottom, LocalState stateFromTop) : AbstractLocalFunctionState(stateFromBottom, stateFromTop)
|
|
{
|
|
public BitVector ReadVars = BitVector.Empty;
|
|
|
|
public BitVector CapturedMask = BitVector.Null;
|
|
|
|
public BitVector InvertedCapturedMask = BitVector.Null;
|
|
}
|
|
|
|
private readonly PooledDictionary<VariableIdentifier, int> _variableSlot = PooledDictionary<LocalDataFlowPass<LocalState, LocalFunctionState>.VariableIdentifier, int>.GetInstance();
|
|
|
|
protected readonly ArrayBuilder<VariableIdentifier> variableBySlot = ArrayBuilder<LocalDataFlowPass<LocalState, LocalFunctionState>.VariableIdentifier>.GetInstance(1, default(LocalDataFlowPass<LocalState, LocalFunctionState>.VariableIdentifier));
|
|
|
|
private readonly HashSet<Symbol>? initiallyAssignedVariables;
|
|
|
|
private readonly PooledHashSet<LocalSymbol> _usedVariables = PooledHashSet<LocalSymbol>.GetInstance();
|
|
|
|
private PooledHashSet<ParameterSymbol>? _readParameters;
|
|
|
|
private readonly PooledHashSet<LocalFunctionSymbol> _usedLocalFunctions = PooledHashSet<LocalFunctionSymbol>.GetInstance();
|
|
|
|
private readonly PooledHashSet<Symbol> _writtenVariables = PooledHashSet<Symbol>.GetInstance();
|
|
|
|
private PooledHashSet<FieldSymbol>? _implicitlyInitializedFieldsOpt;
|
|
|
|
private readonly PooledDictionary<Symbol, Location> _unsafeAddressTakenVariables = PooledDictionary<Symbol, Location>.GetInstance();
|
|
|
|
private readonly PooledHashSet<Symbol> _capturedVariables = PooledHashSet<Symbol>.GetInstance();
|
|
|
|
private readonly PooledHashSet<Symbol> _capturedInside = PooledHashSet<Symbol>.GetInstance();
|
|
|
|
private readonly PooledHashSet<Symbol> _capturedOutside = PooledHashSet<Symbol>.GetInstance();
|
|
|
|
private readonly SourceAssemblySymbol? _sourceAssembly;
|
|
|
|
private readonly HashSet<PrefixUnaryExpressionSyntax>? _unassignedVariableAddressOfSyntaxes;
|
|
|
|
private BitVector _alreadyReported;
|
|
|
|
private readonly bool _requireOutParamsAssigned;
|
|
|
|
private readonly bool _trackClassFields;
|
|
|
|
private readonly bool _trackStaticMembers;
|
|
|
|
protected MethodSymbol? topLevelMethod;
|
|
|
|
protected bool _convertInsufficientExecutionStackExceptionToCancelledByStackGuardException;
|
|
|
|
private readonly bool _shouldCheckConverted;
|
|
|
|
private bool TrackImplicitlyInitializedFields
|
|
{
|
|
get
|
|
{
|
|
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_002d: Invalid comparison between Unknown and I4
|
|
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0041: Invalid comparison between Unknown and I4
|
|
if (_requireOutParamsAssigned && !_emptyStructTypeCache._dev12CompilerCompatibility)
|
|
{
|
|
Symbol currentSymbol = CurrentSymbol;
|
|
if (currentSymbol is MethodSymbol methodSymbol && (int)methodSymbol.MethodKind == 1)
|
|
{
|
|
NamedTypeSymbol containingType = currentSymbol.ContainingType;
|
|
if ((object)containingType != null)
|
|
{
|
|
return (int)containingType.TypeKind == 10;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public sealed override bool AwaitUsingAndForeachAddsPendingBranch => true;
|
|
|
|
private void AddImplicitlyInitializedField(FieldSymbol field)
|
|
{
|
|
if (TrackImplicitlyInitializedFields)
|
|
{
|
|
((HashSet<FieldSymbol>)(object)(_implicitlyInitializedFieldsOpt ?? (_implicitlyInitializedFieldsOpt = PooledHashSet<FieldSymbol>.GetInstance()))).Add(field);
|
|
}
|
|
}
|
|
|
|
internal DefiniteAssignmentPass(CSharpCompilation compilation, Symbol member, BoundNode node, bool strictAnalysis, bool trackUnassignments = false, HashSet<PrefixUnaryExpressionSyntax>? unassignedVariableAddressOfSyntaxes = null, bool requireOutParamsAssigned = true, bool trackClassFields = false, bool trackStaticMembers = false)
|
|
: base(compilation, member, node, strictAnalysis ? EmptyStructTypeCache.CreatePrecise() : EmptyStructTypeCache.CreateForDev12Compatibility(compilation), trackUnassignments)
|
|
{
|
|
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
|
|
initiallyAssignedVariables = null;
|
|
_sourceAssembly = GetSourceAssembly(compilation, member, node);
|
|
_unassignedVariableAddressOfSyntaxes = unassignedVariableAddressOfSyntaxes;
|
|
_requireOutParamsAssigned = requireOutParamsAssigned;
|
|
_trackClassFields = trackClassFields;
|
|
_trackStaticMembers = trackStaticMembers;
|
|
topLevelMethod = member as MethodSymbol;
|
|
_shouldCheckConverted = GetType() == typeof(DefiniteAssignmentPass);
|
|
State = new LocalState(BitVector.Empty);
|
|
}
|
|
|
|
internal DefiniteAssignmentPass(CSharpCompilation compilation, Symbol member, BoundNode node, EmptyStructTypeCache emptyStructs, bool trackUnassignments = false, HashSet<Symbol>? initiallyAssignedVariables = null)
|
|
: base(compilation, member, node, emptyStructs, trackUnassignments)
|
|
{
|
|
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
|
|
this.initiallyAssignedVariables = initiallyAssignedVariables;
|
|
_sourceAssembly = GetSourceAssembly(compilation, member, node);
|
|
CurrentSymbol = member;
|
|
_unassignedVariableAddressOfSyntaxes = null;
|
|
_requireOutParamsAssigned = true;
|
|
topLevelMethod = member as MethodSymbol;
|
|
_shouldCheckConverted = GetType() == typeof(DefiniteAssignmentPass);
|
|
State = new LocalState(BitVector.Empty);
|
|
}
|
|
|
|
internal DefiniteAssignmentPass(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet<Symbol> initiallyAssignedVariables, HashSet<PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes, bool trackUnassignments)
|
|
: base(compilation, member, node, EmptyStructTypeCache.CreateNeverEmpty(), firstInRegion, lastInRegion, true, trackUnassignments)
|
|
{
|
|
//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
|
|
this.initiallyAssignedVariables = initiallyAssignedVariables;
|
|
_sourceAssembly = null;
|
|
CurrentSymbol = member;
|
|
_unassignedVariableAddressOfSyntaxes = unassignedVariableAddressOfSyntaxes;
|
|
_shouldCheckConverted = GetType() == typeof(DefiniteAssignmentPass);
|
|
State = new LocalState(BitVector.Empty);
|
|
}
|
|
|
|
private static SourceAssemblySymbol? GetSourceAssembly(CSharpCompilation compilation, Symbol member, BoundNode node)
|
|
{
|
|
if ((object)member == null)
|
|
{
|
|
return null;
|
|
}
|
|
if (node.Kind == BoundKind.Attribute)
|
|
{
|
|
return null;
|
|
}
|
|
return member.ContainingAssembly as SourceAssemblySymbol;
|
|
}
|
|
|
|
protected override void Free()
|
|
{
|
|
variableBySlot.Free();
|
|
_variableSlot.Free();
|
|
_usedVariables.Free();
|
|
_readParameters?.Free();
|
|
_implicitlyInitializedFieldsOpt?.Free();
|
|
_usedLocalFunctions.Free();
|
|
_writtenVariables.Free();
|
|
_capturedVariables.Free();
|
|
_capturedInside.Free();
|
|
_capturedOutside.Free();
|
|
_unsafeAddressTakenVariables.Free();
|
|
base.Free();
|
|
}
|
|
|
|
protected override bool TryGetVariable(VariableIdentifier identifier, out int slot)
|
|
{
|
|
return ((Dictionary<LocalDataFlowPass<LocalState, LocalFunctionState>.VariableIdentifier, int>)(object)_variableSlot).TryGetValue(identifier, out slot);
|
|
}
|
|
|
|
protected override int AddVariable(VariableIdentifier identifier)
|
|
{
|
|
int count = variableBySlot.Count;
|
|
((Dictionary<LocalDataFlowPass<LocalState, LocalFunctionState>.VariableIdentifier, int>)(object)_variableSlot).Add(identifier, count);
|
|
variableBySlot.Add(identifier);
|
|
return count;
|
|
}
|
|
|
|
protected Symbol GetNonMemberSymbol(int slot)
|
|
{
|
|
LocalDataFlowPass<LocalState, LocalFunctionState>.VariableIdentifier variableIdentifier = variableBySlot[slot];
|
|
while (variableIdentifier.ContainingSlot > 0)
|
|
{
|
|
variableIdentifier = variableBySlot[variableIdentifier.ContainingSlot];
|
|
}
|
|
return variableIdentifier.Symbol;
|
|
}
|
|
|
|
private int RootSlot(int slot)
|
|
{
|
|
while (true)
|
|
{
|
|
int containingSlot = variableBySlot[slot].ContainingSlot;
|
|
if (containingSlot == 0)
|
|
{
|
|
break;
|
|
}
|
|
slot = containingSlot;
|
|
}
|
|
return slot;
|
|
}
|
|
|
|
protected override bool ConvertInsufficientExecutionStackExceptionToCancelledByStackGuardException()
|
|
{
|
|
return _convertInsufficientExecutionStackExceptionToCancelledByStackGuardException;
|
|
}
|
|
|
|
protected override ImmutableArray<PendingBranch> Scan(ref bool badRegion)
|
|
{
|
|
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0130: Unknown result type (might be due to invalid IL or missing references)
|
|
base.Diagnostics.Clear();
|
|
ImmutableArray<ParameterSymbol> methodParameters = base.MethodParameters;
|
|
ParameterSymbol methodThisParameter = base.MethodThisParameter;
|
|
_alreadyReported = BitVector.Empty;
|
|
regionPlace = RegionPlace.Before;
|
|
EnterParameters(methodParameters);
|
|
Symbol symbol = _symbol;
|
|
if (symbol is MethodSymbol methodSymbol)
|
|
{
|
|
if (!symbol.IsStatic && symbol.ContainingSymbol is SourceMemberContainerTypeSymbol sourceMemberContainerTypeSymbol)
|
|
{
|
|
SynthesizedPrimaryConstructor primaryConstructor = sourceMemberContainerTypeSymbol.PrimaryConstructor;
|
|
if ((object)primaryConstructor != null && !(methodSymbol is SynthesizedPrimaryConstructor))
|
|
{
|
|
Symbol currentSymbol = CurrentSymbol;
|
|
CurrentSymbol = primaryConstructor;
|
|
ImmutableArray<ParameterSymbol>.Enumerator enumerator = primaryConstructor.Parameters.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
ParameterSymbol current = enumerator.Current;
|
|
NoteWrite(current, null, read: true);
|
|
}
|
|
CurrentSymbol = currentSymbol;
|
|
}
|
|
}
|
|
}
|
|
else if ((symbol is FieldSymbol || symbol is PropertySymbol) && !symbol.IsStatic && symbol.ContainingSymbol is SourceMemberContainerTypeSymbol sourceMemberContainerTypeSymbol2)
|
|
{
|
|
SynthesizedPrimaryConstructor primaryConstructor = sourceMemberContainerTypeSymbol2.PrimaryConstructor;
|
|
if ((object)primaryConstructor != null)
|
|
{
|
|
SynthesizedPrimaryConstructor synthesizedPrimaryConstructor = primaryConstructor;
|
|
EnterParameters(synthesizedPrimaryConstructor.Parameters);
|
|
}
|
|
}
|
|
if ((object)methodThisParameter != null)
|
|
{
|
|
EnterParameter(methodThisParameter);
|
|
if ((int)methodThisParameter.Type.SpecialType != 0)
|
|
{
|
|
int orCreateSlot = GetOrCreateSlot(methodThisParameter);
|
|
SetSlotState(orCreateSlot, assigned: true);
|
|
}
|
|
}
|
|
ImmutableArray<AbstractFlowPass<LocalState, LocalFunctionState>.PendingBranch> result = base.Scan(ref badRegion);
|
|
if (ShouldAnalyzeOutParameters(out var location))
|
|
{
|
|
LeaveParameters(methodParameters, null, location);
|
|
if ((object)methodThisParameter != null)
|
|
{
|
|
LeaveParameter(methodThisParameter, null, location);
|
|
}
|
|
LocalState self = State;
|
|
ImmutableArray<AbstractFlowPass<LocalState, LocalFunctionState>.PendingBranch>.Enumerator enumerator2 = result.GetEnumerator();
|
|
while (enumerator2.MoveNext())
|
|
{
|
|
AbstractFlowPass<LocalState, LocalFunctionState>.PendingBranch current2 = enumerator2.Current;
|
|
State = current2.State;
|
|
LeaveParameters(methodParameters, current2.Branch.Syntax, null);
|
|
if ((object)methodThisParameter != null)
|
|
{
|
|
LeaveParameter(methodThisParameter, current2.Branch.Syntax, null);
|
|
}
|
|
Join(ref self, ref State);
|
|
}
|
|
State = self;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
protected override ImmutableArray<PendingBranch> RemoveReturns()
|
|
{
|
|
ImmutableArray<AbstractFlowPass<LocalState, LocalFunctionState>.PendingBranch> immutableArray = base.RemoveReturns();
|
|
if (CurrentSymbol is MethodSymbol { IsAsync: not false, IsImplicitlyDeclared: false } && !immutableArray.Any((AbstractFlowPass<LocalState, LocalFunctionState>.PendingBranch pending) => HasAwait(pending)))
|
|
{
|
|
Location location = ((CurrentSymbol is LambdaSymbol lambdaSymbol) ? lambdaSymbol.DiagnosticLocation : CurrentSymbol.GetFirstLocationOrNone());
|
|
base.Diagnostics.Add(ErrorCode.WRN_AsyncLacksAwaits, location);
|
|
}
|
|
return immutableArray;
|
|
}
|
|
|
|
private static bool HasAwait(PendingBranch pending)
|
|
{
|
|
BoundNode branch = pending.Branch;
|
|
if (branch == null)
|
|
{
|
|
return false;
|
|
}
|
|
return branch.Kind switch
|
|
{
|
|
BoundKind.AwaitExpression => true,
|
|
BoundKind.UsingStatement => ((BoundUsingStatement)branch).AwaitOpt != null,
|
|
BoundKind.ForEachStatement => ((BoundForEachStatement)branch).AwaitOpt != null,
|
|
BoundKind.UsingLocalDeclarations => ((BoundUsingLocalDeclarations)branch).AwaitOpt != null,
|
|
_ => false,
|
|
};
|
|
}
|
|
|
|
protected virtual void ReportUnassignedOutParameter(ParameterSymbol parameter, SyntaxNode node, Location location)
|
|
{
|
|
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0043: Expected O, but got Unknown
|
|
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00ee: Invalid comparison between Unknown and I4
|
|
if ((!_requireOutParamsAssigned && (object)topLevelMethod == CurrentSymbol) || base.Diagnostics == null || !State.Reachable)
|
|
{
|
|
return;
|
|
}
|
|
if (location == (Location)null)
|
|
{
|
|
location = (Location)new SourceLocation(node);
|
|
}
|
|
bool flag = false;
|
|
if (parameter.IsThis)
|
|
{
|
|
int num = VariableSlot(parameter);
|
|
if (!State.IsAssigned(num))
|
|
{
|
|
TypeSymbol type = parameter.Type;
|
|
foreach (FieldSymbol structInstanceField in _emptyStructTypeCache.GetStructInstanceFields(type))
|
|
{
|
|
if (_emptyStructTypeCache.IsEmptyStructType(structInstanceField.Type) || LocalDataFlowPass<LocalState, LocalFunctionState>.HasInitializer(structInstanceField))
|
|
{
|
|
continue;
|
|
}
|
|
int num2 = VariableSlot(structInstanceField, num);
|
|
if (num2 == -1 || !State.IsAssigned(num2))
|
|
{
|
|
Symbol associatedSymbol = structInstanceField.AssociatedSymbol;
|
|
bool flag2 = (object)associatedSymbol != null && (int)associatedSymbol.Kind == 15;
|
|
if (compilation.IsFeatureEnabled(MessageID.IDS_FeatureAutoDefaultStructs))
|
|
{
|
|
base.Diagnostics.Add(flag2 ? ErrorCode.WRN_UnassignedThisAutoPropertySupportedVersion : ErrorCode.WRN_UnassignedThisSupportedVersion, location, flag2 ? associatedSymbol : structInstanceField);
|
|
}
|
|
else
|
|
{
|
|
base.Diagnostics.Add(flag2 ? ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion : ErrorCode.ERR_UnassignedThisUnsupportedVersion, location, flag2 ? associatedSymbol : structInstanceField, new CSharpRequiredLanguageVersion(MessageID.IDS_FeatureAutoDefaultStructs.RequiredVersion()));
|
|
}
|
|
AddImplicitlyInitializedField(structInstanceField);
|
|
flag = true;
|
|
}
|
|
}
|
|
if (!flag)
|
|
{
|
|
if (type.HasInlineArrayAttribute(out var length) && length > 1)
|
|
{
|
|
FieldSymbol fieldSymbol = type.TryGetPossiblyUnsupportedByLanguageInlineArrayElementField();
|
|
if ((object)fieldSymbol != null)
|
|
{
|
|
if (!compilation.IsFeatureEnabled(MessageID.IDS_FeatureAutoDefaultStructs))
|
|
{
|
|
base.Diagnostics.Add(ErrorCode.ERR_ParamUnassigned, location, parameter.Name);
|
|
}
|
|
AddImplicitlyInitializedField(fieldSymbol);
|
|
}
|
|
}
|
|
flag = true;
|
|
}
|
|
}
|
|
}
|
|
if (!flag)
|
|
{
|
|
base.Diagnostics.Add(ErrorCode.ERR_ParamUnassigned, location, parameter.Name);
|
|
}
|
|
}
|
|
|
|
public static void Analyze(CSharpCompilation compilation, MethodSymbol member, BoundNode node, DiagnosticBag diagnostics, out ImmutableArray<FieldSymbol> implicitlyInitializedFieldsOpt, bool requireOutParamsAssigned)
|
|
{
|
|
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0108: Invalid comparison between Unknown and I4
|
|
DiagnosticBag val;
|
|
(val, implicitlyInitializedFieldsOpt) = analyze(strictAnalysis: true);
|
|
if (!val.HasAnyErrors())
|
|
{
|
|
diagnostics.AddRangeAndFree(val);
|
|
return;
|
|
}
|
|
DiagnosticBag item = analyze(strictAnalysis: false).Item1;
|
|
if (item.AsEnumerable().Any((Diagnostic d) => d.Code == 8078))
|
|
{
|
|
diagnostics.AddRangeAndFree(item);
|
|
val.Free();
|
|
return;
|
|
}
|
|
if (val.Count == item.Count)
|
|
{
|
|
diagnostics.AddRangeAndFree(val);
|
|
item.Free();
|
|
return;
|
|
}
|
|
HashSet<Diagnostic> hashSet = new HashSet<Diagnostic>(item.AsEnumerable(), SameDiagnosticComparer.Instance);
|
|
item.Free();
|
|
foreach (Diagnostic item3 in val.AsEnumerable())
|
|
{
|
|
if ((int)item3.Severity != 3 || hashSet.Contains(item3))
|
|
{
|
|
diagnostics.Add(item3);
|
|
continue;
|
|
}
|
|
ErrorCode code = (ErrorCode)item3.Code;
|
|
ErrorCode code2 = code switch
|
|
{
|
|
ErrorCode.ERR_UnassignedThisAutoPropertyUnsupportedVersion => ErrorCode.WRN_UnassignedThisAutoPropertyUnsupportedVersion,
|
|
ErrorCode.ERR_UnassignedThisUnsupportedVersion => ErrorCode.WRN_UnassignedThisUnsupportedVersion,
|
|
ErrorCode.ERR_ParamUnassigned => ErrorCode.WRN_ParamUnassigned,
|
|
ErrorCode.ERR_UseDefViolationProperty => ErrorCode.WRN_UseDefViolationProperty,
|
|
ErrorCode.ERR_UseDefViolationField => ErrorCode.WRN_UseDefViolationField,
|
|
ErrorCode.ERR_UseDefViolationThisUnsupportedVersion => ErrorCode.WRN_UseDefViolationThisUnsupportedVersion,
|
|
ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion => ErrorCode.WRN_UseDefViolationPropertyUnsupportedVersion,
|
|
ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion => ErrorCode.WRN_UseDefViolationFieldUnsupportedVersion,
|
|
ErrorCode.ERR_UseDefViolationOut => ErrorCode.WRN_UseDefViolationOut,
|
|
ErrorCode.ERR_UseDefViolation => ErrorCode.WRN_UseDefViolation,
|
|
_ => code,
|
|
};
|
|
DiagnosticWithInfo val2 = (DiagnosticWithInfo)(object)((item3 is DiagnosticWithInfo) ? item3 : null);
|
|
object[] array;
|
|
if (val2 != null)
|
|
{
|
|
DiagnosticInfo info = val2.Info;
|
|
if (info != null)
|
|
{
|
|
object[] arguments = info.Arguments;
|
|
array = arguments;
|
|
goto IL_024f;
|
|
}
|
|
}
|
|
array = item3.Arguments.ToArray();
|
|
goto IL_024f;
|
|
IL_024f:
|
|
object[] args = array;
|
|
diagnostics.Add(code2, item3.Location, args);
|
|
}
|
|
val.Free();
|
|
(DiagnosticBag, ImmutableArray<FieldSymbol> implicitlyInitializedFieldsOpt) analyze(bool strictAnalysis)
|
|
{
|
|
DiagnosticBag instance = DiagnosticBag.GetInstance();
|
|
ImmutableArray<FieldSymbol> item2 = default(ImmutableArray<FieldSymbol>);
|
|
DefiniteAssignmentPass definiteAssignmentPass = new DefiniteAssignmentPass(compilation, member, node, strictAnalysis, trackUnassignments: false, null, requireOutParamsAssigned)
|
|
{
|
|
_convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = true
|
|
};
|
|
try
|
|
{
|
|
bool badRegion = false;
|
|
definiteAssignmentPass.Analyze(ref badRegion, instance);
|
|
PooledHashSet<FieldSymbol> implicitlyInitializedFieldsOpt2 = definiteAssignmentPass._implicitlyInitializedFieldsOpt;
|
|
if (implicitlyInitializedFieldsOpt2 != null)
|
|
{
|
|
ArrayBuilder<FieldSymbol> instance2 = ArrayBuilder<FieldSymbol>.GetInstance(((HashSet<FieldSymbol>)(object)implicitlyInitializedFieldsOpt2).Count);
|
|
foreach (FieldSymbol item4 in (HashSet<FieldSymbol>)(object)implicitlyInitializedFieldsOpt2)
|
|
{
|
|
instance2.Add(item4);
|
|
}
|
|
instance2.Sort((IComparer<FieldSymbol>)LexicalOrderSymbolComparer.Instance);
|
|
item2 = instance2.ToImmutableAndFree();
|
|
}
|
|
}
|
|
catch (CancelledByStackGuardException ex) when (diagnostics != null)
|
|
{
|
|
ex.AddAnError(instance);
|
|
}
|
|
finally
|
|
{
|
|
definiteAssignmentPass.Free();
|
|
}
|
|
return (instance, implicitlyInitializedFieldsOpt: item2);
|
|
}
|
|
}
|
|
|
|
protected void Analyze(ref bool badRegion, DiagnosticBag diagnostics)
|
|
{
|
|
//IL_0004: 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)
|
|
Analyze(ref badRegion);
|
|
if (diagnostics == null)
|
|
{
|
|
return;
|
|
}
|
|
foreach (Symbol item in (HashSet<Symbol>)(object)_capturedVariables)
|
|
{
|
|
if (((Dictionary<Symbol, Location>)(object)_unsafeAddressTakenVariables).TryGetValue(item, out Location value) && (!(item is ParameterSymbol key) || !(item.ContainingSymbol is SynthesizedPrimaryConstructor synthesizedPrimaryConstructor) || !synthesizedPrimaryConstructor.GetCapturedParameters().ContainsKey(key)))
|
|
{
|
|
diagnostics.Add(ErrorCode.ERR_LocalCantBeFixedAndHoisted, value, item.Name);
|
|
}
|
|
}
|
|
diagnostics.AddRange(base.Diagnostics);
|
|
}
|
|
|
|
private void CheckCaptured(Symbol variable, ParameterSymbol? rangeVariableUnderlyingParameter = null)
|
|
{
|
|
if (CurrentSymbol is SourceMethodSymbol containingSymbol && Symbol.IsCaptured(rangeVariableUnderlyingParameter ?? variable, containingSymbol))
|
|
{
|
|
NoteCaptured(variable);
|
|
}
|
|
}
|
|
|
|
private void NoteCaptured(Symbol variable)
|
|
{
|
|
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_002c: Invalid comparison between Unknown and I4
|
|
if (regionPlace == RegionPlace.Inside)
|
|
{
|
|
((HashSet<Symbol>)(object)_capturedInside).Add(variable);
|
|
((HashSet<Symbol>)(object)_capturedVariables).Add(variable);
|
|
}
|
|
else if ((int)variable.Kind != 16)
|
|
{
|
|
((HashSet<Symbol>)(object)_capturedOutside).Add(variable);
|
|
((HashSet<Symbol>)(object)_capturedVariables).Add(variable);
|
|
}
|
|
}
|
|
|
|
protected IEnumerable<Symbol> GetCapturedInside()
|
|
{
|
|
return ((IEnumerable<Symbol>)_capturedInside).ToArray();
|
|
}
|
|
|
|
protected IEnumerable<Symbol> GetCapturedOutside()
|
|
{
|
|
return ((IEnumerable<Symbol>)_capturedOutside).ToArray();
|
|
}
|
|
|
|
protected IEnumerable<Symbol> GetCaptured()
|
|
{
|
|
return ((IEnumerable<Symbol>)_capturedVariables).ToArray();
|
|
}
|
|
|
|
protected IEnumerable<Symbol> GetUnsafeAddressTaken()
|
|
{
|
|
return ((Dictionary<Symbol, Location>)(object)_unsafeAddressTakenVariables).Keys.ToArray();
|
|
}
|
|
|
|
protected IEnumerable<MethodSymbol> GetUsedLocalFunctions()
|
|
{
|
|
return ((IEnumerable<LocalFunctionSymbol>)_usedLocalFunctions).ToArray();
|
|
}
|
|
|
|
private void NotePrimaryConstructorParameterReadIfNeeded(Symbol symbol)
|
|
{
|
|
if (symbol is ParameterSymbol item && symbol.ContainingSymbol is SynthesizedPrimaryConstructor)
|
|
{
|
|
if (_readParameters == null)
|
|
{
|
|
_readParameters = PooledHashSet<ParameterSymbol>.GetInstance();
|
|
}
|
|
((HashSet<ParameterSymbol>)(object)_readParameters).Add(item);
|
|
}
|
|
}
|
|
|
|
protected virtual void NoteRead(Symbol variable, ParameterSymbol rangeVariableUnderlyingParameter = null)
|
|
{
|
|
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0047: Invalid comparison between Unknown and I4
|
|
if (variable is LocalSymbol item)
|
|
{
|
|
((HashSet<LocalSymbol>)(object)_usedVariables).Add(item);
|
|
}
|
|
NotePrimaryConstructorParameterReadIfNeeded(variable);
|
|
if (variable is LocalFunctionSymbol item2)
|
|
{
|
|
((HashSet<LocalFunctionSymbol>)(object)_usedLocalFunctions).Add(item2);
|
|
}
|
|
if ((object)variable != null)
|
|
{
|
|
if ((object)_sourceAssembly != null && (int)variable.Kind == 6)
|
|
{
|
|
_sourceAssembly.NoteFieldAccess((FieldSymbol)variable.OriginalDefinition, read: true, write: false);
|
|
}
|
|
CheckCaptured(variable, rangeVariableUnderlyingParameter);
|
|
}
|
|
}
|
|
|
|
private void NoteRead(BoundNode fieldOrEventAccess)
|
|
{
|
|
BoundNode boundNode = fieldOrEventAccess;
|
|
while (boundNode != null)
|
|
{
|
|
switch (boundNode.Kind)
|
|
{
|
|
default:
|
|
return;
|
|
case BoundKind.FieldAccess:
|
|
{
|
|
BoundFieldAccess boundFieldAccess = (BoundFieldAccess)boundNode;
|
|
NoteRead(boundFieldAccess.FieldSymbol);
|
|
if (MayRequireTracking(boundFieldAccess.ReceiverOpt, boundFieldAccess.FieldSymbol))
|
|
{
|
|
boundNode = boundFieldAccess.ReceiverOpt;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
case BoundKind.EventAccess:
|
|
{
|
|
BoundEventAccess boundEventAccess = (BoundEventAccess)boundNode;
|
|
FieldSymbol associatedField = boundEventAccess.EventSymbol.AssociatedField;
|
|
if ((object)associatedField != null)
|
|
{
|
|
NoteRead(associatedField);
|
|
if (MayRequireTracking(boundEventAccess.ReceiverOpt, associatedField))
|
|
{
|
|
boundNode = boundEventAccess.ReceiverOpt;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
case BoundKind.ThisReference:
|
|
NoteRead(base.MethodThisParameter);
|
|
return;
|
|
case BoundKind.Local:
|
|
NoteRead(((BoundLocal)boundNode).LocalSymbol);
|
|
return;
|
|
case BoundKind.Parameter:
|
|
NoteRead(((BoundParameter)boundNode).ParameterSymbol);
|
|
return;
|
|
case BoundKind.InlineArrayAccess:
|
|
boundNode = ((BoundInlineArrayAccess)boundNode).Expression;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void NoteWrite(Symbol variable, BoundExpression value, bool read)
|
|
{
|
|
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_001f: Invalid comparison between Unknown and I4
|
|
if ((object)variable != null)
|
|
{
|
|
((HashSet<Symbol>)(object)_writtenVariables).Add(variable);
|
|
if ((object)_sourceAssembly != null && (int)variable.Kind == 6)
|
|
{
|
|
FieldSymbol fieldSymbol = (FieldSymbol)variable.OriginalDefinition;
|
|
_sourceAssembly.NoteFieldAccess(fieldSymbol, read && WriteConsideredUse(fieldSymbol.Type, value), write: true);
|
|
}
|
|
LocalSymbol localSymbol = variable as LocalSymbol;
|
|
if ((object)localSymbol != null && read && WriteConsideredUse(localSymbol.Type, value))
|
|
{
|
|
((HashSet<LocalSymbol>)(object)_usedVariables).Add(localSymbol);
|
|
}
|
|
CheckCaptured(variable);
|
|
}
|
|
}
|
|
|
|
internal static bool WriteConsideredUse(TypeSymbol type, BoundExpression value)
|
|
{
|
|
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0020: Invalid comparison between Unknown and I4
|
|
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0046: Invalid comparison between Unknown and I4
|
|
if (value == null || value.HasAnyErrors)
|
|
{
|
|
return true;
|
|
}
|
|
if ((object)type != null && type.IsReferenceType && (int)type.SpecialType != 20)
|
|
{
|
|
if (type is ArrayTypeSymbol { IsSZArray: not false } arrayTypeSymbol)
|
|
{
|
|
TypeSymbol elementType = arrayTypeSymbol.ElementType;
|
|
if ((object)elementType != null && (int)elementType.SpecialType == 10)
|
|
{
|
|
goto IL_0059;
|
|
}
|
|
}
|
|
return value.ConstantValueOpt != ConstantValue.Null;
|
|
}
|
|
goto IL_0059;
|
|
IL_0059:
|
|
if ((object)type != null && type.IsPointerOrFunctionPointer())
|
|
{
|
|
return true;
|
|
}
|
|
if (value != null && value.ConstantValueOpt != null && value.Kind != BoundKind.InterpolatedString)
|
|
{
|
|
return false;
|
|
}
|
|
switch (value.Kind)
|
|
{
|
|
case BoundKind.Conversion:
|
|
{
|
|
BoundConversion boundConversion = (BoundConversion)value;
|
|
if (boundConversion.ConversionKind.IsUserDefinedConversion() || boundConversion.ConversionKind == ConversionKind.IntPtr)
|
|
{
|
|
return true;
|
|
}
|
|
return WriteConsideredUse(null, boundConversion.Operand);
|
|
}
|
|
case BoundKind.DefaultLiteral:
|
|
case BoundKind.DefaultExpression:
|
|
return false;
|
|
case BoundKind.ObjectCreationExpression:
|
|
{
|
|
BoundObjectCreationExpression boundObjectCreationExpression = (BoundObjectCreationExpression)value;
|
|
if (boundObjectCreationExpression.Constructor.IsImplicitlyDeclared)
|
|
{
|
|
return boundObjectCreationExpression.InitializerExpressionOpt != null;
|
|
}
|
|
return true;
|
|
}
|
|
case BoundKind.Utf8String:
|
|
case BoundKind.TupleLiteral:
|
|
case BoundKind.ConvertedTupleLiteral:
|
|
return false;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private void NoteWrite(BoundExpression n, BoundExpression value, bool read)
|
|
{
|
|
while (n != null)
|
|
{
|
|
switch (n.Kind)
|
|
{
|
|
case BoundKind.FieldAccess:
|
|
{
|
|
BoundFieldAccess boundFieldAccess = (BoundFieldAccess)n;
|
|
if ((object)_sourceAssembly != null)
|
|
{
|
|
FieldSymbol originalDefinition2 = boundFieldAccess.FieldSymbol.OriginalDefinition;
|
|
_sourceAssembly.NoteFieldAccess(originalDefinition2, value == null || WriteConsideredUse(boundFieldAccess.FieldSymbol.Type, value), write: true);
|
|
}
|
|
if (MayRequireTracking(boundFieldAccess.ReceiverOpt, boundFieldAccess.FieldSymbol))
|
|
{
|
|
n = boundFieldAccess.ReceiverOpt;
|
|
if (n.Kind == BoundKind.Local)
|
|
{
|
|
((HashSet<LocalSymbol>)(object)_usedVariables).Add(((BoundLocal)n).LocalSymbol);
|
|
}
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
case BoundKind.EventAccess:
|
|
{
|
|
BoundEventAccess boundEventAccess = (BoundEventAccess)n;
|
|
FieldSymbol associatedField = boundEventAccess.EventSymbol.AssociatedField;
|
|
if ((object)associatedField != null)
|
|
{
|
|
if ((object)_sourceAssembly != null)
|
|
{
|
|
FieldSymbol originalDefinition = associatedField.OriginalDefinition;
|
|
_sourceAssembly.NoteFieldAccess(originalDefinition, value == null || WriteConsideredUse(associatedField.Type, value), write: true);
|
|
}
|
|
if (MayRequireTracking(boundEventAccess.ReceiverOpt, associatedField))
|
|
{
|
|
n = boundEventAccess.ReceiverOpt;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
case BoundKind.ThisReference:
|
|
NoteWrite(base.MethodThisParameter, value, read);
|
|
return;
|
|
case BoundKind.Local:
|
|
NoteWrite(((BoundLocal)n).LocalSymbol, value, read);
|
|
return;
|
|
case BoundKind.Parameter:
|
|
NoteWrite(((BoundParameter)n).ParameterSymbol, value, read);
|
|
return;
|
|
case BoundKind.RangeVariable:
|
|
NoteWrite(((BoundRangeVariable)n).Value, value, read);
|
|
return;
|
|
case BoundKind.InlineArrayAccess:
|
|
n = ((BoundInlineArrayAccess)n).Expression;
|
|
value = null;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void Normalize(ref LocalState state)
|
|
{
|
|
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_006b: Invalid comparison between Unknown and I4
|
|
int capacity = ((BitVector)(ref state.Assigned)).Capacity;
|
|
int count = variableBySlot.Count;
|
|
((BitVector)(ref state.Assigned)).EnsureCapacity(count);
|
|
for (int i = capacity; i < count; i++)
|
|
{
|
|
int containingSlot = variableBySlot[i].ContainingSlot;
|
|
bool flag = containingSlot > 0 && ((BitVector)(ref state.Assigned))[containingSlot] && (int)variableBySlot[containingSlot].Symbol.GetTypeOrReturnType().TypeKind == 10;
|
|
if (state.NormalizeToBottom && containingSlot == 0)
|
|
{
|
|
flag = true;
|
|
}
|
|
((BitVector)(ref state.Assigned))[i] = flag;
|
|
}
|
|
}
|
|
|
|
protected override bool TryGetReceiverAndMember(BoundExpression expr, out BoundExpression receiver, out Symbol member)
|
|
{
|
|
receiver = null;
|
|
member = null;
|
|
switch (expr.Kind)
|
|
{
|
|
case BoundKind.FieldAccess:
|
|
{
|
|
BoundFieldAccess boundFieldAccess = (BoundFieldAccess)expr;
|
|
FieldSymbol fieldSymbol = (FieldSymbol)(member = boundFieldAccess.FieldSymbol);
|
|
if (fieldSymbol.IsFixedSizeBuffer)
|
|
{
|
|
return false;
|
|
}
|
|
if (fieldSymbol.IsStatic)
|
|
{
|
|
return _trackStaticMembers;
|
|
}
|
|
receiver = boundFieldAccess.ReceiverOpt;
|
|
break;
|
|
}
|
|
case BoundKind.EventAccess:
|
|
{
|
|
BoundEventAccess boundEventAccess = (BoundEventAccess)expr;
|
|
EventSymbol eventSymbol = boundEventAccess.EventSymbol;
|
|
member = eventSymbol.AssociatedField;
|
|
if (eventSymbol.IsStatic)
|
|
{
|
|
return _trackStaticMembers;
|
|
}
|
|
receiver = boundEventAccess.ReceiverOpt;
|
|
break;
|
|
}
|
|
case BoundKind.PropertyAccess:
|
|
{
|
|
BoundPropertyAccess boundPropertyAccess = (BoundPropertyAccess)expr;
|
|
if (Binder.AccessingAutoPropertyFromConstructor(boundPropertyAccess, CurrentSymbol))
|
|
{
|
|
PropertySymbol propertySymbol = boundPropertyAccess.PropertySymbol;
|
|
member = (propertySymbol as SourcePropertySymbolBase)?.BackingField;
|
|
if ((object)member == null)
|
|
{
|
|
return false;
|
|
}
|
|
if (propertySymbol.IsStatic)
|
|
{
|
|
return _trackStaticMembers;
|
|
}
|
|
receiver = boundPropertyAccess.ReceiverOpt;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if ((object)member != null && receiver != null && receiver.Kind != BoundKind.TypeExpression)
|
|
{
|
|
return MayRequireTrackingReceiverType(receiver.Type);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool MayRequireTrackingReceiverType(TypeSymbol type)
|
|
{
|
|
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0013: Invalid comparison between Unknown and I4
|
|
if ((object)type != null)
|
|
{
|
|
if (!_trackClassFields)
|
|
{
|
|
return (int)type.TypeKind == 10;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected bool MayRequireTracking(BoundExpression receiverOpt, FieldSymbol fieldSymbol)
|
|
{
|
|
if ((object)fieldSymbol != null && receiverOpt != null && !fieldSymbol.IsStatic && !fieldSymbol.IsFixedSizeBuffer && receiverOpt.Kind != BoundKind.TypeExpression && MayRequireTrackingReceiverType(receiverOpt.Type))
|
|
{
|
|
return !receiverOpt.Type.IsPrimitiveRecursiveStruct();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected void CheckAssigned(Symbol symbol, SyntaxNode node)
|
|
{
|
|
if ((object)symbol == null)
|
|
{
|
|
return;
|
|
}
|
|
NoteRead(symbol);
|
|
if (State.Reachable)
|
|
{
|
|
int num = VariableSlot(symbol);
|
|
if (num >= ((BitVector)(ref State.Assigned)).Capacity)
|
|
{
|
|
Normalize(ref State);
|
|
}
|
|
if (num > 0 && !State.IsAssigned(num))
|
|
{
|
|
ReportUnassignedIfNotCapturedInLocalFunction(symbol, node, num);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ReportUnassignedIfNotCapturedInLocalFunction(Symbol symbol, SyntaxNode node, int slot, bool skipIfUseBeforeDeclaration = true)
|
|
{
|
|
if (IsCapturedInLocalFunction(slot))
|
|
{
|
|
RecordReadInLocalFunction(slot);
|
|
}
|
|
else
|
|
{
|
|
ReportUnassigned(symbol, node, slot, skipIfUseBeforeDeclaration);
|
|
}
|
|
}
|
|
|
|
protected virtual void ReportUnassigned(Symbol symbol, SyntaxNode node, int slot, bool skipIfUseBeforeDeclaration)
|
|
{
|
|
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0057: Invalid comparison between Unknown and I4
|
|
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00c5: Invalid comparison between Unknown and I4
|
|
//IL_006c: 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_007a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00e3: Invalid comparison between Unknown and I4
|
|
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00f1: Invalid comparison between Unknown and I4
|
|
DefiniteAssignmentPass definiteAssignmentPass = this;
|
|
SyntaxNode node2 = node;
|
|
if (slot <= 0 || symbol is LocalSymbol { IsConst: not false })
|
|
{
|
|
return;
|
|
}
|
|
if (slot >= ((BitVector)(ref _alreadyReported)).Capacity)
|
|
{
|
|
((BitVector)(ref _alreadyReported)).EnsureCapacity(variableBySlot.Count);
|
|
}
|
|
if (!skipIfUseBeforeDeclaration || (int)symbol.Kind != 8)
|
|
{
|
|
goto IL_008c;
|
|
}
|
|
Location val = symbol.TryGetFirstLocation();
|
|
if (val != null)
|
|
{
|
|
TextSpan val2 = node2.Span;
|
|
int end = ((TextSpan)(ref val2)).End;
|
|
val2 = val.SourceSpan;
|
|
if (end >= ((TextSpan)(ref val2)).Start)
|
|
{
|
|
goto IL_008c;
|
|
}
|
|
}
|
|
goto IL_015c;
|
|
IL_008c:
|
|
if (!((BitVector)(ref _alreadyReported))[slot] && !symbol.GetTypeOrReturnType().Type.IsErrorType())
|
|
{
|
|
string name = symbol.Name;
|
|
if ((int)symbol.Kind == 6)
|
|
{
|
|
addDiagnosticForStructField(slot, (FieldSymbol)symbol);
|
|
}
|
|
else if ((int)symbol.Kind == 13 && (int)((ParameterSymbol)symbol).RefKind == 2)
|
|
{
|
|
if (((ParameterSymbol)symbol).IsThis)
|
|
{
|
|
addDiagnosticForStructThis(symbol, slot);
|
|
}
|
|
else
|
|
{
|
|
base.Diagnostics.Add(ErrorCode.ERR_UseDefViolationOut, node2.Location, name);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
base.Diagnostics.Add(ErrorCode.ERR_UseDefViolation, node2.Location, name);
|
|
}
|
|
}
|
|
goto IL_015c;
|
|
IL_015c:
|
|
((BitVector)(ref _alreadyReported))[slot] = true;
|
|
void addDiagnosticForStructField(int fieldSlot, FieldSymbol fieldSymbol)
|
|
{
|
|
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0015: Invalid comparison between Unknown and I4
|
|
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0047: Invalid comparison between Unknown and I4
|
|
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_005f: Invalid comparison between Unknown and I4
|
|
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
|
|
Symbol associatedSymbol = fieldSymbol.AssociatedSymbol;
|
|
bool flag = (object)associatedSymbol != null && (int)associatedSymbol.Kind == 15;
|
|
string text = (flag ? associatedSymbol.Name : fieldSymbol.Name);
|
|
Symbol currentSymbol = CurrentSymbol;
|
|
if (currentSymbol is MethodSymbol methodSymbol && (int)methodSymbol.MethodKind == 1)
|
|
{
|
|
NamedTypeSymbol containingType = currentSymbol.ContainingType;
|
|
if ((object)containingType != null && (int)containingType.TypeKind == 10)
|
|
{
|
|
int orCreateSlot = GetOrCreateSlot(CurrentSymbol.EnclosingThisSymbol());
|
|
LocalDataFlowPass<LocalState, LocalFunctionState>.VariableIdentifier variableIdentifier;
|
|
while (true)
|
|
{
|
|
if (fieldSlot == 0)
|
|
{
|
|
base.Diagnostics.Add(flag ? ErrorCode.ERR_UseDefViolationProperty : ErrorCode.ERR_UseDefViolationField, node2.Location, text);
|
|
return;
|
|
}
|
|
variableIdentifier = variableBySlot[fieldSlot];
|
|
int containingSlot = variableIdentifier.ContainingSlot;
|
|
if (containingSlot == orCreateSlot)
|
|
{
|
|
break;
|
|
}
|
|
fieldSlot = containingSlot;
|
|
}
|
|
AddImplicitlyInitializedField((FieldSymbol)variableIdentifier.Symbol);
|
|
if ((int)fieldSymbol.RefKind != 0)
|
|
{
|
|
if (!flag)
|
|
{
|
|
base.Diagnostics.Add(ErrorCode.WRN_UseDefViolationRefField, node2.Location, text);
|
|
}
|
|
}
|
|
else if (compilation.IsFeatureEnabled(MessageID.IDS_FeatureAutoDefaultStructs))
|
|
{
|
|
base.Diagnostics.Add(flag ? ErrorCode.WRN_UseDefViolationPropertySupportedVersion : ErrorCode.WRN_UseDefViolationFieldSupportedVersion, node2.Location, text);
|
|
}
|
|
else
|
|
{
|
|
base.Diagnostics.Add(flag ? ErrorCode.ERR_UseDefViolationPropertyUnsupportedVersion : ErrorCode.ERR_UseDefViolationFieldUnsupportedVersion, node2.Location, text, new CSharpRequiredLanguageVersion(MessageID.IDS_FeatureAutoDefaultStructs.RequiredVersion()));
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
base.Diagnostics.Add(flag ? ErrorCode.ERR_UseDefViolationProperty : ErrorCode.ERR_UseDefViolationField, node2.Location, text);
|
|
}
|
|
void addDiagnosticForStructThis(Symbol thisParameter, int thisSlot)
|
|
{
|
|
if (TrackImplicitlyInitializedFields)
|
|
{
|
|
bool flag = false;
|
|
NamedTypeSymbol containingType = thisParameter.ContainingType;
|
|
foreach (FieldSymbol structInstanceField in _emptyStructTypeCache.GetStructInstanceFields(containingType))
|
|
{
|
|
if (!_emptyStructTypeCache.IsEmptyStructType(structInstanceField.Type) && !(structInstanceField is TupleErrorFieldSymbol))
|
|
{
|
|
int num = VariableSlot(structInstanceField, thisSlot);
|
|
if (num == -1 || !State.IsAssigned(num))
|
|
{
|
|
AddImplicitlyInitializedField(structInstanceField);
|
|
flag = true;
|
|
}
|
|
}
|
|
}
|
|
if (!flag && containingType.HasInlineArrayAttribute(out var length) && length > 1)
|
|
{
|
|
FieldSymbol fieldSymbol = containingType.TryGetPossiblyUnsupportedByLanguageInlineArrayElementField();
|
|
if ((object)fieldSymbol != null)
|
|
{
|
|
AddImplicitlyInitializedField(fieldSymbol);
|
|
flag = true;
|
|
}
|
|
}
|
|
}
|
|
if (compilation.IsFeatureEnabled(MessageID.IDS_FeatureAutoDefaultStructs))
|
|
{
|
|
base.Diagnostics.Add(ErrorCode.WRN_UseDefViolationThisSupportedVersion, node2.Location);
|
|
}
|
|
else
|
|
{
|
|
base.Diagnostics.Add(ErrorCode.ERR_UseDefViolationThisUnsupportedVersion, node2.Location, new CSharpRequiredLanguageVersion(MessageID.IDS_FeatureAutoDefaultStructs.RequiredVersion()));
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void CheckAssigned(BoundExpression expr, FieldSymbol fieldSymbol, SyntaxNode node)
|
|
{
|
|
if (State.Reachable && !IsAssigned(expr, out var unassignedSlot))
|
|
{
|
|
ReportUnassignedIfNotCapturedInLocalFunction(fieldSymbol, node, unassignedSlot);
|
|
}
|
|
NoteRead(expr);
|
|
}
|
|
|
|
private bool IsAssigned(BoundExpression node, out int unassignedSlot)
|
|
{
|
|
unassignedSlot = -1;
|
|
if (_emptyStructTypeCache.IsEmptyStructType(node.Type))
|
|
{
|
|
return true;
|
|
}
|
|
switch (node.Kind)
|
|
{
|
|
case BoundKind.ThisReference:
|
|
if ((object)base.MethodThisParameter == null)
|
|
{
|
|
unassignedSlot = -1;
|
|
return true;
|
|
}
|
|
unassignedSlot = GetOrCreateSlot(base.MethodThisParameter);
|
|
break;
|
|
case BoundKind.Local:
|
|
unassignedSlot = GetOrCreateSlot(((BoundLocal)node).LocalSymbol);
|
|
break;
|
|
case BoundKind.FieldAccess:
|
|
{
|
|
BoundFieldAccess boundFieldAccess = (BoundFieldAccess)node;
|
|
if (!MayRequireTracking(boundFieldAccess.ReceiverOpt, boundFieldAccess.FieldSymbol) || IsAssigned(boundFieldAccess.ReceiverOpt, out unassignedSlot))
|
|
{
|
|
return true;
|
|
}
|
|
unassignedSlot = GetOrCreateSlot(boundFieldAccess.FieldSymbol, unassignedSlot);
|
|
break;
|
|
}
|
|
case BoundKind.EventAccess:
|
|
{
|
|
BoundEventAccess boundEventAccess = (BoundEventAccess)node;
|
|
if (!MayRequireTracking(boundEventAccess.ReceiverOpt, boundEventAccess.EventSymbol.AssociatedField) || IsAssigned(boundEventAccess.ReceiverOpt, out unassignedSlot))
|
|
{
|
|
return true;
|
|
}
|
|
unassignedSlot = GetOrCreateSlot(boundEventAccess.EventSymbol.AssociatedField, unassignedSlot);
|
|
break;
|
|
}
|
|
case BoundKind.InlineArrayAccess:
|
|
{
|
|
BoundInlineArrayAccess boundInlineArrayAccess = (BoundInlineArrayAccess)node;
|
|
return IsAssigned(boundInlineArrayAccess.Expression, out unassignedSlot);
|
|
}
|
|
case BoundKind.PropertyAccess:
|
|
{
|
|
BoundPropertyAccess boundPropertyAccess = (BoundPropertyAccess)node;
|
|
if (Binder.AccessingAutoPropertyFromConstructor(boundPropertyAccess, CurrentSymbol))
|
|
{
|
|
SynthesizedBackingFieldSymbol synthesizedBackingFieldSymbol = (boundPropertyAccess.PropertySymbol as SourcePropertySymbolBase)?.BackingField;
|
|
if (synthesizedBackingFieldSymbol != null)
|
|
{
|
|
if (!MayRequireTracking(boundPropertyAccess.ReceiverOpt, synthesizedBackingFieldSymbol) || IsAssigned(boundPropertyAccess.ReceiverOpt, out unassignedSlot))
|
|
{
|
|
return true;
|
|
}
|
|
unassignedSlot = GetOrCreateSlot(synthesizedBackingFieldSymbol, unassignedSlot);
|
|
break;
|
|
}
|
|
}
|
|
goto default;
|
|
}
|
|
case BoundKind.Parameter:
|
|
{
|
|
BoundParameter boundParameter = (BoundParameter)node;
|
|
unassignedSlot = GetOrCreateSlot(boundParameter.ParameterSymbol);
|
|
break;
|
|
}
|
|
default:
|
|
unassignedSlot = -1;
|
|
return true;
|
|
}
|
|
if (unassignedSlot > 0)
|
|
{
|
|
return State.IsAssigned(unassignedSlot);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private Symbol UseNonFieldSymbolUnsafely(BoundExpression expression)
|
|
{
|
|
while (expression != null)
|
|
{
|
|
BoundFieldAccess boundFieldAccess;
|
|
switch (expression.Kind)
|
|
{
|
|
case BoundKind.FieldAccess:
|
|
{
|
|
boundFieldAccess = (BoundFieldAccess)expression;
|
|
FieldSymbol fieldSymbol = boundFieldAccess.FieldSymbol;
|
|
if ((object)_sourceAssembly != null)
|
|
{
|
|
_sourceAssembly.NoteFieldAccess(fieldSymbol, read: true, write: true);
|
|
}
|
|
if (fieldSymbol.ContainingType.IsReferenceType || fieldSymbol.IsStatic)
|
|
{
|
|
return null;
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.Local:
|
|
{
|
|
LocalSymbol localSymbol = ((BoundLocal)expression).LocalSymbol;
|
|
((HashSet<LocalSymbol>)(object)_usedVariables).Add(localSymbol);
|
|
return localSymbol;
|
|
}
|
|
case BoundKind.RangeVariable:
|
|
return ((BoundRangeVariable)expression).RangeVariableSymbol;
|
|
case BoundKind.Parameter:
|
|
return ((BoundParameter)expression).ParameterSymbol;
|
|
case BoundKind.ThisReference:
|
|
return base.MethodThisParameter;
|
|
case BoundKind.BaseReference:
|
|
return base.MethodThisParameter;
|
|
default:
|
|
return null;
|
|
}
|
|
expression = boundFieldAccess.ReceiverOpt;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
protected void Assign(BoundNode node, BoundExpression value, bool isRef = false, bool read = true)
|
|
{
|
|
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_001e: Invalid comparison between Unknown and I4
|
|
if (!isRef && node is BoundFieldAccess boundFieldAccess)
|
|
{
|
|
FieldSymbol fieldSymbol = boundFieldAccess.FieldSymbol;
|
|
if ((object)fieldSymbol != null && (int)fieldSymbol.RefKind != 0)
|
|
{
|
|
CheckAssigned(boundFieldAccess, node.Syntax);
|
|
}
|
|
}
|
|
AssignImpl(node, value, isRef, written: true, read);
|
|
}
|
|
|
|
protected virtual void AssignImpl(BoundNode node, BoundExpression value, bool isRef, bool written, bool read)
|
|
{
|
|
//IL_0136: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0276: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_027c: Invalid comparison between Unknown and I4
|
|
//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_01c7: Invalid comparison between Unknown and I4
|
|
BoundInlineArrayAccess boundInlineArrayAccess;
|
|
switch (node.Kind)
|
|
{
|
|
case BoundKind.DeclarationPattern:
|
|
case BoundKind.RecursivePattern:
|
|
case BoundKind.ListPattern:
|
|
{
|
|
BoundObjectPattern boundObjectPattern = (BoundObjectPattern)node;
|
|
if (boundObjectPattern.Variable is LocalSymbol symbol)
|
|
{
|
|
int orCreateSlot = GetOrCreateSlot(symbol);
|
|
SetSlotState(orCreateSlot, written || !State.Reachable);
|
|
}
|
|
if (written)
|
|
{
|
|
NoteWrite(boundObjectPattern.VariableAccess, value, read);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.LocalDeclaration:
|
|
{
|
|
LocalSymbol localSymbol = ((BoundLocalDeclaration)node).LocalSymbol;
|
|
int orCreateSlot2 = GetOrCreateSlot(localSymbol);
|
|
SetSlotState(orCreateSlot2, written || !State.Reachable);
|
|
if (written)
|
|
{
|
|
NoteWrite(localSymbol, value, read);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.Local:
|
|
{
|
|
BoundLocal boundLocal = (BoundLocal)node;
|
|
if ((int)boundLocal.LocalSymbol.RefKind != 0 && !isRef)
|
|
{
|
|
if (written)
|
|
{
|
|
VisitRvalue(boundLocal, isKnownToBeAnLvalue: true);
|
|
}
|
|
break;
|
|
}
|
|
int slot = MakeSlot(boundLocal);
|
|
SetSlotState(slot, written);
|
|
if (written)
|
|
{
|
|
NoteWrite(boundLocal, value, read);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.InlineArrayAccess:
|
|
{
|
|
boundInlineArrayAccess = (BoundInlineArrayAccess)node;
|
|
if (written)
|
|
{
|
|
NoteWrite(boundInlineArrayAccess.Expression, null, read);
|
|
}
|
|
if (boundInlineArrayAccess.Expression.Type.HasInlineArrayAttribute(out var length))
|
|
{
|
|
ConstantValue constantValueOpt = boundInlineArrayAccess.Argument.ConstantValueOpt;
|
|
if (constantValueOpt == null || (int)constantValueOpt.SpecialType != 13 || constantValueOpt.Int32Value != 0)
|
|
{
|
|
SyntaxNode location;
|
|
int? num = Binder.InferConstantIndexFromSystemIndex(compilation, boundInlineArrayAccess.Argument, length, out location);
|
|
if ((num ?? 1) != 0)
|
|
{
|
|
goto IL_022c;
|
|
}
|
|
}
|
|
int num2 = MakeMemberSlot(boundInlineArrayAccess.Expression, boundInlineArrayAccess.Expression.Type.TryGetInlineArrayElementField());
|
|
if (num2 > 0)
|
|
{
|
|
SetSlotState(num2, written);
|
|
break;
|
|
}
|
|
}
|
|
goto IL_022c;
|
|
}
|
|
case BoundKind.Parameter:
|
|
{
|
|
BoundParameter boundParameter = (BoundParameter)node;
|
|
ParameterSymbol parameterSymbol = boundParameter.ParameterSymbol;
|
|
if (isRef && (int)parameterSymbol.RefKind == 2)
|
|
{
|
|
LeaveParameter(parameterSymbol, node.Syntax, boundParameter.Syntax.Location);
|
|
}
|
|
int slot4 = MakeSlot(boundParameter);
|
|
SetSlotState(slot4, written);
|
|
if (written)
|
|
{
|
|
NoteWrite(boundParameter, value, read);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.ThisReference:
|
|
case BoundKind.FieldAccess:
|
|
case BoundKind.PropertyAccess:
|
|
case BoundKind.EventAccess:
|
|
{
|
|
BoundExpression boundExpression = (BoundExpression)node;
|
|
int slot3 = MakeSlot(boundExpression);
|
|
SetSlotState(slot3, written);
|
|
if (written)
|
|
{
|
|
NoteWrite(boundExpression, value, read);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.RangeVariable:
|
|
AssignImpl(((BoundRangeVariable)node).Value, value, isRef, written, read);
|
|
break;
|
|
case BoundKind.BadExpression:
|
|
{
|
|
BoundBadExpression boundBadExpression = (BoundBadExpression)node;
|
|
if (!boundBadExpression.ChildBoundNodes.IsDefault && boundBadExpression.ChildBoundNodes.Length == 1)
|
|
{
|
|
AssignImpl(boundBadExpression.ChildBoundNodes[0], value, isRef, written, read);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.TupleLiteral:
|
|
case BoundKind.ConvertedTupleLiteral:
|
|
{
|
|
((BoundTupleExpression)node).VisitAllElements(delegate(BoundExpression x, (DefiniteAssignmentPass self, bool isRef) arg)
|
|
{
|
|
arg.self.Assign(x, null, arg.isRef);
|
|
}, (this, isRef));
|
|
break;
|
|
}
|
|
IL_022c:
|
|
if (!written)
|
|
{
|
|
AssignImpl(boundInlineArrayAccess.Expression, null, isRef, written, read);
|
|
int slot2 = MakeSlot(boundInlineArrayAccess.Expression);
|
|
SetSlotState(slot2, written);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
private bool FieldsAllSet(int containingSlot, LocalState state)
|
|
{
|
|
TypeSymbol type = variableBySlot[containingSlot].Symbol.GetTypeOrReturnType().Type;
|
|
if (type.HasInlineArrayAttribute(out var length) && length > 1 && (object)type.TryGetPossiblyUnsupportedByLanguageInlineArrayElementField() != null)
|
|
{
|
|
return false;
|
|
}
|
|
foreach (FieldSymbol structInstanceField in _emptyStructTypeCache.GetStructInstanceFields(type))
|
|
{
|
|
if (!_emptyStructTypeCache.IsEmptyStructType(structInstanceField.Type) && !(structInstanceField is TupleErrorFieldSymbol))
|
|
{
|
|
int num = VariableSlot(structInstanceField, containingSlot);
|
|
if (num == -1 || !state.IsAssigned(num))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
protected void SetSlotState(int slot, bool assigned)
|
|
{
|
|
if (slot > 0)
|
|
{
|
|
if (assigned)
|
|
{
|
|
SetSlotAssigned(slot);
|
|
}
|
|
else
|
|
{
|
|
SetSlotUnassigned(slot);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void SetSlotAssigned(int slot, ref LocalState state)
|
|
{
|
|
if (slot < 0)
|
|
{
|
|
return;
|
|
}
|
|
LocalDataFlowPass<LocalState, LocalFunctionState>.VariableIdentifier variableIdentifier = variableBySlot[slot];
|
|
TypeSymbol type = variableIdentifier.Symbol.GetTypeOrReturnType().Type;
|
|
if (slot >= ((BitVector)(ref state.Assigned)).Capacity)
|
|
{
|
|
Normalize(ref state);
|
|
}
|
|
if (state.IsAssigned(slot))
|
|
{
|
|
return;
|
|
}
|
|
state.Assign(slot);
|
|
if (EmptyStructTypeCache.IsTrackableStructType(type))
|
|
{
|
|
foreach (FieldSymbol structInstanceField in _emptyStructTypeCache.GetStructInstanceFields(type))
|
|
{
|
|
int num = VariableSlot(structInstanceField, slot);
|
|
if (num > 0)
|
|
{
|
|
SetSlotAssigned(num, ref state);
|
|
}
|
|
}
|
|
}
|
|
while (variableIdentifier.ContainingSlot > 0)
|
|
{
|
|
slot = variableIdentifier.ContainingSlot;
|
|
if (!state.IsAssigned(slot) && FieldsAllSet(slot, state))
|
|
{
|
|
state.Assign(slot);
|
|
variableIdentifier = variableBySlot[slot];
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void SetSlotAssigned(int slot)
|
|
{
|
|
SetSlotAssigned(slot, ref State);
|
|
}
|
|
|
|
private void SetSlotUnassigned(int slot, ref LocalState state)
|
|
{
|
|
if (slot < 0)
|
|
{
|
|
return;
|
|
}
|
|
LocalDataFlowPass<LocalState, LocalFunctionState>.VariableIdentifier variableIdentifier = variableBySlot[slot];
|
|
TypeSymbol type = variableIdentifier.Symbol.GetTypeOrReturnType().Type;
|
|
if (!state.IsAssigned(slot))
|
|
{
|
|
return;
|
|
}
|
|
state.Unassign(slot);
|
|
if (EmptyStructTypeCache.IsTrackableStructType(type))
|
|
{
|
|
foreach (FieldSymbol structInstanceField in _emptyStructTypeCache.GetStructInstanceFields(type))
|
|
{
|
|
int num = VariableSlot(structInstanceField, slot);
|
|
if (num > 0)
|
|
{
|
|
SetSlotUnassigned(num, ref state);
|
|
}
|
|
}
|
|
}
|
|
while (variableIdentifier.ContainingSlot > 0)
|
|
{
|
|
slot = variableIdentifier.ContainingSlot;
|
|
state.Unassign(slot);
|
|
variableIdentifier = variableBySlot[slot];
|
|
}
|
|
}
|
|
|
|
private void SetSlotUnassigned(int slot)
|
|
{
|
|
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
|
|
if (NonMonotonicState.HasValue)
|
|
{
|
|
LocalState state = NonMonotonicState.Value;
|
|
SetSlotUnassigned(slot, ref state);
|
|
NonMonotonicState = Optional<LocalState>.op_Implicit(state);
|
|
}
|
|
SetSlotUnassigned(slot, ref State);
|
|
}
|
|
|
|
protected override LocalState TopState()
|
|
{
|
|
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0152: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0157: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0159: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_015c: Invalid comparison between Unknown and I4
|
|
//IL_015e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0162: Invalid comparison between Unknown and I4
|
|
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0168: Invalid comparison between Unknown and I4
|
|
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0106: Invalid comparison between Unknown and I4
|
|
LocalState state = new LocalState(BitVector.Empty);
|
|
Symbol symbol = CurrentSymbol;
|
|
while (true)
|
|
{
|
|
SymbolKind? val = symbol?.Kind;
|
|
bool flag;
|
|
if (val.HasValue)
|
|
{
|
|
SymbolKind valueOrDefault = val.GetValueOrDefault();
|
|
if ((int)valueOrDefault == 6 || (int)valueOrDefault == 9 || (int)valueOrDefault == 15)
|
|
{
|
|
flag = true;
|
|
goto IL_0172;
|
|
}
|
|
}
|
|
flag = false;
|
|
goto IL_0172;
|
|
IL_0172:
|
|
if (!flag)
|
|
{
|
|
break;
|
|
}
|
|
if ((object)symbol != CurrentSymbol && symbol is MethodSymbol { Parameters: var parameters } methodSymbol)
|
|
{
|
|
ImmutableArray<ParameterSymbol>.Enumerator enumerator = parameters.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
ParameterSymbol current = enumerator.Current;
|
|
int orCreateSlot = GetOrCreateSlot(current);
|
|
if (orCreateSlot > 0)
|
|
{
|
|
SetSlotAssigned(orCreateSlot, ref state);
|
|
}
|
|
}
|
|
if (methodSymbol.TryGetThisParameter(out var thisParameter) && (object)thisParameter != null)
|
|
{
|
|
int orCreateSlot2 = GetOrCreateSlot(thisParameter);
|
|
if (orCreateSlot2 > 0)
|
|
{
|
|
SetSlotAssigned(orCreateSlot2, ref state);
|
|
}
|
|
}
|
|
}
|
|
Symbol containingSymbol = symbol.ContainingSymbol;
|
|
if (!symbol.IsStatic && containingSymbol is SourceMemberContainerTypeSymbol sourceMemberContainerTypeSymbol)
|
|
{
|
|
SynthesizedPrimaryConstructor primaryConstructor = sourceMemberContainerTypeSymbol.PrimaryConstructor;
|
|
if ((object)primaryConstructor != null && (object)symbol != primaryConstructor)
|
|
{
|
|
ImmutableArray<ParameterSymbol>.Enumerator enumerator = primaryConstructor.Parameters.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
ParameterSymbol current2 = enumerator.Current;
|
|
int orCreateSlot3 = GetOrCreateSlot(current2);
|
|
if (orCreateSlot3 > 0)
|
|
{
|
|
if (!(symbol is MethodSymbol) && (int)current2.RefKind == 2)
|
|
{
|
|
SetSlotUnassigned(orCreateSlot3, ref state);
|
|
}
|
|
else
|
|
{
|
|
SetSlotAssigned(orCreateSlot3, ref state);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
symbol = containingSymbol;
|
|
}
|
|
return state;
|
|
}
|
|
|
|
protected override LocalState ReachableBottomState()
|
|
{
|
|
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
|
|
LocalState result = new LocalState(BitVector.AllSet(variableBySlot.Count));
|
|
((BitVector)(ref result.Assigned))[0] = false;
|
|
return result;
|
|
}
|
|
|
|
protected override void EnterParameter(ParameterSymbol parameter)
|
|
{
|
|
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0012: Invalid comparison between Unknown and I4
|
|
int orCreateSlot = GetOrCreateSlot(parameter);
|
|
if ((int)parameter.RefKind == 2 && !(CurrentSymbol is MethodSymbol { IsAsync: not false }))
|
|
{
|
|
if (orCreateSlot > 0)
|
|
{
|
|
SetSlotState(orCreateSlot, initiallyAssignedVariables?.Contains(parameter) ?? false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (orCreateSlot > 0)
|
|
{
|
|
SetSlotState(orCreateSlot, assigned: true);
|
|
}
|
|
NoteWrite(parameter, null, read: true);
|
|
}
|
|
SourceComplexParameterSymbolBase sourceComplexParameterSymbolBase = parameter as SourceComplexParameterSymbolBase;
|
|
bool flag;
|
|
if ((object)sourceComplexParameterSymbolBase != null)
|
|
{
|
|
Symbol containingSymbol = sourceComplexParameterSymbolBase.ContainingSymbol;
|
|
if (containingSymbol is LocalFunctionSymbol || containingSymbol is LambdaSymbol)
|
|
{
|
|
flag = true;
|
|
goto IL_0089;
|
|
}
|
|
}
|
|
flag = false;
|
|
goto IL_0089;
|
|
IL_0089:
|
|
if (flag)
|
|
{
|
|
VisitAttributes(sourceComplexParameterSymbolBase.BindParameterAttributes());
|
|
BoundParameterEqualsValue boundParameterEqualsValue = sourceComplexParameterSymbolBase.BindParameterEqualsValue();
|
|
if (boundParameterEqualsValue != null)
|
|
{
|
|
VisitRvalue(boundParameterEqualsValue.Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void VisitAttributes(ImmutableArray<(CSharpAttributeData, BoundAttribute)> boundAttributes)
|
|
{
|
|
if (boundAttributes.IsDefaultOrEmpty)
|
|
{
|
|
return;
|
|
}
|
|
ImmutableArray<(CSharpAttributeData, BoundAttribute)>.Enumerator enumerator = boundAttributes.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
var (cSharpAttributeData, boundAttribute) = enumerator.Current;
|
|
if (!((AttributeData)cSharpAttributeData).HasErrors)
|
|
{
|
|
ImmutableArray<BoundExpression>.Enumerator enumerator2 = boundAttribute.ConstructorArguments.GetEnumerator();
|
|
while (enumerator2.MoveNext())
|
|
{
|
|
BoundExpression current = enumerator2.Current;
|
|
VisitRvalue(current);
|
|
}
|
|
ImmutableArray<BoundAssignmentOperator>.Enumerator enumerator3 = boundAttribute.NamedArguments.GetEnumerator();
|
|
while (enumerator3.MoveNext())
|
|
{
|
|
BoundAssignmentOperator current2 = enumerator3.Current;
|
|
VisitRvalue(current2.Right);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void LeaveParameters(ImmutableArray<ParameterSymbol> parameters, SyntaxNode syntax, Location location)
|
|
{
|
|
if (State.Reachable)
|
|
{
|
|
base.LeaveParameters(parameters, syntax, location);
|
|
}
|
|
}
|
|
|
|
protected override void LeaveParameter(ParameterSymbol parameter, SyntaxNode syntax, Location location)
|
|
{
|
|
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0012: Invalid comparison between Unknown and I4
|
|
if (!parameter.IsThis && (int)parameter.RefKind != 2 && parameter.ContainingSymbol is SynthesizedPrimaryConstructor synthesizedPrimaryConstructor)
|
|
{
|
|
PooledHashSet<ParameterSymbol>? readParameters = _readParameters;
|
|
if ((readParameters == null || !((HashSet<ParameterSymbol>)(object)readParameters).Contains(parameter)) && !synthesizedPrimaryConstructor.GetCapturedParameters().ContainsKey(parameter))
|
|
{
|
|
DiagnosticBag diagnostics = base.Diagnostics;
|
|
SourceMemberContainerTypeSymbol containingType = synthesizedPrimaryConstructor.ContainingType;
|
|
bool flag = (((object)containingType != null && (containingType.IsRecord || containingType.IsRecordStruct)) ? true : false);
|
|
diagnostics.Add(flag ? ErrorCode.WRN_UnreadRecordParameter : ErrorCode.WRN_UnreadPrimaryConstructorParameter, parameter.GetFirstLocationOrNone(), parameter.Name);
|
|
}
|
|
}
|
|
if ((int)parameter.RefKind != 0)
|
|
{
|
|
int num = VariableSlot(parameter);
|
|
if (num > 0 && !State.IsAssigned(num))
|
|
{
|
|
ReportUnassignedOutParameter(parameter, syntax, location);
|
|
}
|
|
NoteRead(parameter);
|
|
}
|
|
}
|
|
|
|
protected override LocalState UnreachableState()
|
|
{
|
|
LocalState result = State.Clone();
|
|
((BitVector)(ref result.Assigned)).EnsureCapacity(1);
|
|
result.Assign(0);
|
|
return result;
|
|
}
|
|
|
|
public override void VisitPattern(BoundPattern pattern)
|
|
{
|
|
base.VisitPattern(pattern);
|
|
LocalState stateWhenFalse = StateWhenFalse;
|
|
SetState(StateWhenTrue);
|
|
assignPatternVariablesAndMarkReadFields(pattern);
|
|
SetConditionalState(State, stateWhenFalse);
|
|
void assignPatternVariablesAndMarkReadFields(BoundPattern boundPattern, bool definitely = true)
|
|
{
|
|
switch (boundPattern.Kind)
|
|
{
|
|
case BoundKind.DeclarationPattern:
|
|
{
|
|
BoundDeclarationPattern node = (BoundDeclarationPattern)boundPattern;
|
|
if (definitely)
|
|
{
|
|
Assign(node, null, isRef: false, read: false);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.SlicePattern:
|
|
{
|
|
BoundSlicePattern boundSlicePattern = (BoundSlicePattern)boundPattern;
|
|
if (boundSlicePattern.Pattern != null)
|
|
{
|
|
assignPatternVariablesAndMarkReadFields(boundSlicePattern.Pattern, definitely);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.ConstantPattern:
|
|
{
|
|
BoundConstantPattern boundConstantPattern = (BoundConstantPattern)boundPattern;
|
|
VisitRvalue(boundConstantPattern.Value);
|
|
break;
|
|
}
|
|
case BoundKind.RecursivePattern:
|
|
{
|
|
BoundRecursivePattern boundRecursivePattern = (BoundRecursivePattern)boundPattern;
|
|
if (!boundRecursivePattern.Deconstruction.IsDefaultOrEmpty)
|
|
{
|
|
ImmutableArray<BoundPositionalSubpattern>.Enumerator enumerator = boundRecursivePattern.Deconstruction.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundPositionalSubpattern current3 = enumerator.Current;
|
|
assignPatternVariablesAndMarkReadFields(current3.Pattern, definitely);
|
|
}
|
|
}
|
|
if (!boundRecursivePattern.Properties.IsDefaultOrEmpty)
|
|
{
|
|
ImmutableArray<BoundPropertySubpattern>.Enumerator enumerator3 = boundRecursivePattern.Properties.GetEnumerator();
|
|
while (enumerator3.MoveNext())
|
|
{
|
|
BoundPropertySubpattern current4 = enumerator3.Current;
|
|
if ((object)_sourceAssembly != null)
|
|
{
|
|
for (BoundPropertySubpatternMember boundPropertySubpatternMember = current4.Member; boundPropertySubpatternMember != null; boundPropertySubpatternMember = boundPropertySubpatternMember.Receiver)
|
|
{
|
|
if (boundPropertySubpatternMember.Symbol is FieldSymbol field)
|
|
{
|
|
_sourceAssembly.NoteFieldAccess(field, read: true, write: false);
|
|
}
|
|
}
|
|
}
|
|
assignPatternVariablesAndMarkReadFields(current4.Pattern, definitely);
|
|
}
|
|
}
|
|
if (definitely)
|
|
{
|
|
Assign(boundRecursivePattern, null, isRef: false, read: false);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.ITuplePattern:
|
|
{
|
|
ImmutableArray<BoundPositionalSubpattern>.Enumerator enumerator = ((BoundITuplePattern)boundPattern).Subpatterns.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundPositionalSubpattern current = enumerator.Current;
|
|
assignPatternVariablesAndMarkReadFields(current.Pattern, definitely);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.ListPattern:
|
|
{
|
|
BoundListPattern boundListPattern = (BoundListPattern)boundPattern;
|
|
ImmutableArray<BoundPattern>.Enumerator enumerator2 = boundListPattern.Subpatterns.GetEnumerator();
|
|
while (enumerator2.MoveNext())
|
|
{
|
|
BoundPattern current2 = enumerator2.Current;
|
|
assignPatternVariablesAndMarkReadFields(current2, definitely);
|
|
}
|
|
if (definitely)
|
|
{
|
|
Assign(boundListPattern, null, isRef: false, read: false);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.RelationalPattern:
|
|
{
|
|
BoundRelationalPattern boundRelationalPattern = (BoundRelationalPattern)boundPattern;
|
|
VisitRvalue(boundRelationalPattern.Value);
|
|
break;
|
|
}
|
|
case BoundKind.NegatedPattern:
|
|
{
|
|
BoundNegatedPattern boundNegatedPattern = (BoundNegatedPattern)boundPattern;
|
|
assignPatternVariablesAndMarkReadFields(boundNegatedPattern.Negated, definitely: false);
|
|
break;
|
|
}
|
|
case BoundKind.BinaryPattern:
|
|
{
|
|
BoundBinaryPattern boundBinaryPattern = (BoundBinaryPattern)boundPattern;
|
|
bool definitely2 = definitely && !boundBinaryPattern.Disjunction;
|
|
assignPatternVariablesAndMarkReadFields(boundBinaryPattern.Left, definitely2);
|
|
assignPatternVariablesAndMarkReadFields(boundBinaryPattern.Right, definitely2);
|
|
break;
|
|
}
|
|
default:
|
|
throw ExceptionUtilities.UnexpectedValue((object)boundPattern.Kind);
|
|
case BoundKind.DiscardPattern:
|
|
case BoundKind.TypePattern:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public override BoundNode VisitBlock(BoundBlock node)
|
|
{
|
|
if (node.Instrumentation != null)
|
|
{
|
|
DeclareVariable(node.Instrumentation.Local);
|
|
Visit(node.Instrumentation.Prologue);
|
|
}
|
|
DeclareVariables(node.Locals);
|
|
VisitStatementsWithLocalFunctions(node);
|
|
ImmutableArray<LocalSymbol>.Enumerator enumerator = node.Locals.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalSymbol current = enumerator.Current;
|
|
if (current.IsUsing)
|
|
{
|
|
NoteRead(current);
|
|
}
|
|
}
|
|
ReportUnusedVariables(node.Locals);
|
|
ReportUnusedVariables(node.LocalFunctions);
|
|
if (node.Instrumentation != null)
|
|
{
|
|
Visit(node.Instrumentation.Epilogue);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void VisitStatementsWithLocalFunctions(BoundBlock block)
|
|
{
|
|
if (!TrackingRegions && !block.LocalFunctions.IsDefaultOrEmpty)
|
|
{
|
|
ImmutableArray<BoundStatement>.Enumerator enumerator = block.Statements.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundStatement current = enumerator.Current;
|
|
if (current is BoundLocalFunctionStatement boundLocalFunctionStatement)
|
|
{
|
|
VisitAttributes(boundLocalFunctionStatement.Symbol.BindMethodAttributes());
|
|
VisitAlways(current);
|
|
}
|
|
}
|
|
enumerator = block.Statements.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundStatement current2 = enumerator.Current;
|
|
if (current2.Kind != BoundKind.LocalFunctionStatement)
|
|
{
|
|
VisitStatement(current2);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ImmutableArray<BoundStatement>.Enumerator enumerator = block.Statements.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
BoundStatement current3 = enumerator.Current;
|
|
VisitStatement(current3);
|
|
}
|
|
}
|
|
}
|
|
|
|
public override BoundNode VisitSwitchStatement(BoundSwitchStatement node)
|
|
{
|
|
DeclareVariables(node.InnerLocals);
|
|
BoundNode result = base.VisitSwitchStatement(node);
|
|
ReportUnusedVariables(node.InnerLocals);
|
|
ReportUnusedVariables(node.InnerLocalFunctions);
|
|
return result;
|
|
}
|
|
|
|
protected override void VisitSwitchSection(BoundSwitchSection node, bool isLastSection)
|
|
{
|
|
DeclareVariables(node.Locals);
|
|
base.VisitSwitchSection(node, isLastSection);
|
|
}
|
|
|
|
public override BoundNode VisitForStatement(BoundForStatement node)
|
|
{
|
|
DeclareVariables(node.OuterLocals);
|
|
DeclareVariables(node.InnerLocals);
|
|
BoundNode result = base.VisitForStatement(node);
|
|
ReportUnusedVariables(node.InnerLocals);
|
|
ReportUnusedVariables(node.OuterLocals);
|
|
return result;
|
|
}
|
|
|
|
public override BoundNode VisitDoStatement(BoundDoStatement node)
|
|
{
|
|
DeclareVariables(node.Locals);
|
|
BoundNode result = base.VisitDoStatement(node);
|
|
ReportUnusedVariables(node.Locals);
|
|
return result;
|
|
}
|
|
|
|
public override BoundNode VisitWhileStatement(BoundWhileStatement node)
|
|
{
|
|
DeclareVariables(node.Locals);
|
|
BoundNode result = base.VisitWhileStatement(node);
|
|
ReportUnusedVariables(node.Locals);
|
|
return result;
|
|
}
|
|
|
|
public override BoundNode VisitUsingStatement(BoundUsingStatement node)
|
|
{
|
|
ImmutableArray<LocalSymbol> locals = node.Locals;
|
|
DeclareVariables(locals);
|
|
BoundNode result = base.VisitUsingStatement(node);
|
|
if (!locals.IsDefaultOrEmpty)
|
|
{
|
|
ImmutableArray<LocalSymbol>.Enumerator enumerator = locals.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalSymbol current = enumerator.Current;
|
|
if (current.DeclarationKind == LocalDeclarationKind.UsingVariable)
|
|
{
|
|
NoteRead(current);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public override BoundNode VisitFixedStatement(BoundFixedStatement node)
|
|
{
|
|
DeclareVariables(node.Locals);
|
|
return base.VisitFixedStatement(node);
|
|
}
|
|
|
|
public override BoundNode VisitSequence(BoundSequence node)
|
|
{
|
|
DeclareVariables(node.Locals);
|
|
BoundNode result = base.VisitSequence(node);
|
|
ReportUnusedVariables(node.Locals);
|
|
return result;
|
|
}
|
|
|
|
private void DeclareVariables(ImmutableArray<LocalSymbol> locals)
|
|
{
|
|
ImmutableArray<LocalSymbol>.Enumerator enumerator = locals.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalSymbol current = enumerator.Current;
|
|
DeclareVariable(current);
|
|
}
|
|
}
|
|
|
|
private void DeclareVariable(LocalSymbol symbol)
|
|
{
|
|
bool assigned = symbol.IsConst || (initiallyAssignedVariables?.Contains(symbol) ?? false);
|
|
SetSlotState(GetOrCreateSlot(symbol), assigned);
|
|
}
|
|
|
|
private void ReportUnusedVariables(ImmutableArray<LocalSymbol> locals)
|
|
{
|
|
ImmutableArray<LocalSymbol>.Enumerator enumerator = locals.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalSymbol current = enumerator.Current;
|
|
ReportIfUnused(current, assigned: true);
|
|
}
|
|
}
|
|
|
|
private void ReportIfUnused(LocalSymbol symbol, bool assigned)
|
|
{
|
|
if (!((HashSet<LocalSymbol>)(object)_usedVariables).Contains(symbol) && symbol.DeclarationKind != LocalDeclarationKind.PatternVariable && !string.IsNullOrEmpty(symbol.Name))
|
|
{
|
|
base.Diagnostics.Add((assigned && ((HashSet<Symbol>)(object)_writtenVariables).Contains((Symbol)symbol)) ? ErrorCode.WRN_UnreferencedVarAssg : ErrorCode.WRN_UnreferencedVar, symbol.GetFirstLocationOrNone(), symbol.Name);
|
|
}
|
|
}
|
|
|
|
private void ReportUnusedVariables(ImmutableArray<LocalFunctionSymbol> locals)
|
|
{
|
|
ImmutableArray<LocalFunctionSymbol>.Enumerator enumerator = locals.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalFunctionSymbol current = enumerator.Current;
|
|
ReportIfUnused(current);
|
|
}
|
|
}
|
|
|
|
private void ReportIfUnused(LocalFunctionSymbol symbol)
|
|
{
|
|
if (!((HashSet<LocalFunctionSymbol>)(object)_usedLocalFunctions).Contains(symbol) && !string.IsNullOrEmpty(symbol.Name))
|
|
{
|
|
base.Diagnostics.Add(ErrorCode.WRN_UnreferencedLocalFunction, symbol.GetFirstLocationOrNone(), symbol.Name);
|
|
}
|
|
}
|
|
|
|
public override BoundNode VisitLocal(BoundLocal node)
|
|
{
|
|
//IL_007b: 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_008a: Invalid comparison between Unknown and I4
|
|
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00bf: Expected O, but got Unknown
|
|
LocalSymbol localSymbol = node.LocalSymbol;
|
|
SourceLocalSymbol obj = localSymbol as SourceLocalSymbol;
|
|
if ((object)obj != null && obj.IsVar)
|
|
{
|
|
SyntaxNode forbiddenZone = localSymbol.ForbiddenZone;
|
|
if (forbiddenZone != null && forbiddenZone.Contains(node.Syntax))
|
|
{
|
|
int orCreateSlot = GetOrCreateSlot(node.LocalSymbol);
|
|
if (orCreateSlot > 0)
|
|
{
|
|
((BitVector)(ref _alreadyReported))[orCreateSlot] = true;
|
|
}
|
|
}
|
|
}
|
|
CheckAssigned(localSymbol, node.Syntax);
|
|
if (localSymbol.IsFixed && CurrentSymbol is MethodSymbol methodSymbol && ((int)methodSymbol.MethodKind == 0 || (int)methodSymbol.MethodKind == 17) && ((HashSet<Symbol>)(object)_capturedVariables).Contains((Symbol)localSymbol))
|
|
{
|
|
base.Diagnostics.Add(ErrorCode.ERR_FixedLocalInLambda, (Location)new SourceLocation(node.Syntax), localSymbol);
|
|
}
|
|
SplitIfBooleanConstant(node);
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode VisitLocalDeclaration(BoundLocalDeclaration node)
|
|
{
|
|
GetOrCreateSlot(node.LocalSymbol);
|
|
HashSet<Symbol>? hashSet = initiallyAssignedVariables;
|
|
if (hashSet != null && hashSet.Contains(node.LocalSymbol))
|
|
{
|
|
Assign(node, null);
|
|
}
|
|
BoundNode result = base.VisitLocalDeclaration(node);
|
|
if (node.InitializerOpt != null)
|
|
{
|
|
Assign(node, node.InitializerOpt);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public override BoundNode VisitLocalId(BoundLocalId node)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode VisitParameterId(BoundParameterId node)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode VisitStateMachineInstanceId(BoundStateMachineInstanceId node)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode VisitMethodGroup(BoundMethodGroup node)
|
|
{
|
|
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0021: Invalid comparison between Unknown and I4
|
|
ImmutableArray<MethodSymbol>.Enumerator enumerator = node.Methods.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
MethodSymbol current = enumerator.Current;
|
|
if ((int)current.MethodKind == 17)
|
|
{
|
|
((HashSet<LocalFunctionSymbol>)(object)_usedLocalFunctions).Add((LocalFunctionSymbol)current);
|
|
}
|
|
}
|
|
return base.VisitMethodGroup(node);
|
|
}
|
|
|
|
public override BoundNode VisitLambda(BoundLambda node)
|
|
{
|
|
Symbol currentSymbol = CurrentSymbol;
|
|
CurrentSymbol = node.Symbol;
|
|
VisitAttributes(node.Symbol.BindMethodAttributes());
|
|
AbstractFlowPass<LocalState, LocalFunctionState>.SavedPending oldPending = SavePending();
|
|
LocalState self = State;
|
|
State = (State.Reachable ? State.Clone() : ReachableBottomState());
|
|
if (!node.WasCompilerGenerated)
|
|
{
|
|
EnterParameters(node.Symbol.Parameters);
|
|
}
|
|
AbstractFlowPass<LocalState, LocalFunctionState>.SavedPending oldPending2 = SavePending();
|
|
VisitAlways(node.Body);
|
|
RestorePending(oldPending2);
|
|
ImmutableArray<AbstractFlowPass<LocalState, LocalFunctionState>.PendingBranch> immutableArray = RemoveReturns();
|
|
RestorePending(oldPending);
|
|
LeaveParameters(node.Symbol.Parameters, node.Syntax, null);
|
|
Join(ref self, ref State);
|
|
ImmutableArray<AbstractFlowPass<LocalState, LocalFunctionState>.PendingBranch>.Enumerator enumerator = immutableArray.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
AbstractFlowPass<LocalState, LocalFunctionState>.PendingBranch current = enumerator.Current;
|
|
State = current.State;
|
|
if (current.Branch.Kind == BoundKind.ReturnStatement)
|
|
{
|
|
LeaveParameters(node.Symbol.Parameters, current.Branch.Syntax, null);
|
|
}
|
|
Join(ref self, ref State);
|
|
}
|
|
State = self;
|
|
CurrentSymbol = currentSymbol;
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode VisitThisReference(BoundThisReference node)
|
|
{
|
|
CheckAssigned(base.MethodThisParameter, node.Syntax);
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode VisitParameter(BoundParameter node)
|
|
{
|
|
if (!node.WasCompilerGenerated)
|
|
{
|
|
CheckAssigned(node.ParameterSymbol, node.Syntax);
|
|
}
|
|
else
|
|
{
|
|
NotePrimaryConstructorParameterReadIfNeeded(node.ParameterSymbol);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
|
|
{
|
|
base.VisitAssignmentOperator(node);
|
|
Assign(node.Left, node.Right, node.IsRef);
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode VisitDeconstructionAssignmentOperator(BoundDeconstructionAssignmentOperator node)
|
|
{
|
|
base.VisitDeconstructionAssignmentOperator(node);
|
|
Assign(node.Left, node.Right);
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode VisitIncrementOperator(BoundIncrementOperator node)
|
|
{
|
|
base.VisitIncrementOperator(node);
|
|
Assign(node.Operand, node);
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node)
|
|
{
|
|
VisitCompoundAssignmentTarget(node);
|
|
VisitRvalue(node.Right);
|
|
AfterRightHasBeenVisited(node);
|
|
Assign(node.Left, node);
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode VisitFixedLocalCollectionInitializer(BoundFixedLocalCollectionInitializer node)
|
|
{
|
|
BoundExpression boundExpression = node.Expression;
|
|
if (boundExpression.Kind == BoundKind.AddressOfOperator)
|
|
{
|
|
boundExpression = ((BoundAddressOfOperator)boundExpression).Operand;
|
|
}
|
|
VisitAddressOfOperand(boundExpression, shouldReadOperand: false);
|
|
return null;
|
|
}
|
|
|
|
public override BoundNode VisitAddressOfOperator(BoundAddressOfOperator node)
|
|
{
|
|
BoundExpression operand = node.Operand;
|
|
bool shouldReadOperand = false;
|
|
Symbol symbol = UseNonFieldSymbolUnsafely(operand);
|
|
if ((object)symbol != null)
|
|
{
|
|
HashSet<PrefixUnaryExpressionSyntax>? unassignedVariableAddressOfSyntaxes = _unassignedVariableAddressOfSyntaxes;
|
|
if (unassignedVariableAddressOfSyntaxes != null && !unassignedVariableAddressOfSyntaxes.Contains(node.Syntax as PrefixUnaryExpressionSyntax))
|
|
{
|
|
shouldReadOperand = true;
|
|
}
|
|
if (!((Dictionary<Symbol, Location>)(object)_unsafeAddressTakenVariables).ContainsKey(symbol))
|
|
{
|
|
((Dictionary<Symbol, Location>)(object)_unsafeAddressTakenVariables).Add(symbol, node.Syntax.Location);
|
|
}
|
|
}
|
|
VisitAddressOfOperand(node.Operand, shouldReadOperand);
|
|
return null;
|
|
}
|
|
|
|
protected override void WriteArgument(BoundExpression arg, RefKind refKind, MethodSymbol method)
|
|
{
|
|
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0002: Invalid comparison between Unknown and I4
|
|
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
|
|
if ((int)refKind == 1)
|
|
{
|
|
CheckAssigned(arg, arg.Syntax);
|
|
}
|
|
Assign(arg, null);
|
|
if ((int)refKind != 0 && ((object)method == null || method.IsExtern))
|
|
{
|
|
TypeSymbol type = arg.Type;
|
|
if ((object)type != null)
|
|
{
|
|
MarkFieldsUsed(type);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void CheckAssigned(BoundExpression expr, SyntaxNode node)
|
|
{
|
|
if (!State.Reachable)
|
|
{
|
|
return;
|
|
}
|
|
MakeSlot(expr);
|
|
switch (expr.Kind)
|
|
{
|
|
case BoundKind.Local:
|
|
CheckAssigned(((BoundLocal)expr).LocalSymbol, node);
|
|
break;
|
|
case BoundKind.Parameter:
|
|
CheckAssigned(((BoundParameter)expr).ParameterSymbol, node);
|
|
break;
|
|
case BoundKind.FieldAccess:
|
|
{
|
|
BoundFieldAccess boundFieldAccess = (BoundFieldAccess)expr;
|
|
FieldSymbol fieldSymbol = boundFieldAccess.FieldSymbol;
|
|
if (!fieldSymbol.IsFixedSizeBuffer && MayRequireTracking(boundFieldAccess.ReceiverOpt, fieldSymbol))
|
|
{
|
|
CheckAssigned(expr, fieldSymbol, node);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.EventAccess:
|
|
{
|
|
BoundEventAccess boundEventAccess = (BoundEventAccess)expr;
|
|
FieldSymbol associatedField = boundEventAccess.EventSymbol.AssociatedField;
|
|
if ((object)associatedField != null && MayRequireTracking(boundEventAccess.ReceiverOpt, associatedField))
|
|
{
|
|
CheckAssigned(boundEventAccess, associatedField, node);
|
|
}
|
|
break;
|
|
}
|
|
case BoundKind.ThisReference:
|
|
case BoundKind.BaseReference:
|
|
CheckAssigned(base.MethodThisParameter, node);
|
|
break;
|
|
case BoundKind.InlineArrayAccess:
|
|
CheckAssigned(((BoundInlineArrayAccess)expr).Expression, node);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void MarkFieldsUsed(TypeSymbol type)
|
|
{
|
|
//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_0009: Invalid comparison between Unknown and I4
|
|
//IL_000b: 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_0012: Invalid comparison between Unknown and I4
|
|
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_007b: Invalid comparison between Unknown and I4
|
|
TypeKind typeKind = type.TypeKind;
|
|
if ((int)typeKind != 1)
|
|
{
|
|
if (((int)typeKind != 2 && (int)typeKind != 10) || !type.IsFromCompilation(compilation) || !(type.ContainingAssembly is SourceAssemblySymbol sourceAssemblySymbol) || !sourceAssemblySymbol.TypesReferencedInExternalMethods.Add(type))
|
|
{
|
|
return;
|
|
}
|
|
ImmutableArray<Symbol>.Enumerator enumerator = ((NamedTypeSymbol)type).GetMembersUnordered().GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
Symbol current = enumerator.Current;
|
|
if ((int)current.Kind == 6)
|
|
{
|
|
FieldSymbol fieldSymbol = (FieldSymbol)current;
|
|
sourceAssemblySymbol.NoteFieldAccess(fieldSymbol, read: true, write: true);
|
|
MarkFieldsUsed(fieldSymbol.Type);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MarkFieldsUsed(((ArrayTypeSymbol)type).ElementType);
|
|
}
|
|
}
|
|
|
|
public override BoundNode VisitBaseReference(BoundBaseReference node)
|
|
{
|
|
CheckAssigned(base.MethodThisParameter, node.Syntax);
|
|
return null;
|
|
}
|
|
|
|
protected override void VisitCatchBlock(BoundCatchBlock catchBlock, ref LocalState finallyState)
|
|
{
|
|
DeclareVariables(catchBlock.Locals);
|
|
BoundExpression exceptionSourceOpt = catchBlock.ExceptionSourceOpt;
|
|
if (exceptionSourceOpt != null)
|
|
{
|
|
Assign(exceptionSourceOpt, null, isRef: false, read: false);
|
|
}
|
|
base.VisitCatchBlock(catchBlock, ref finallyState);
|
|
ImmutableArray<LocalSymbol>.Enumerator enumerator = catchBlock.Locals.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalSymbol current = enumerator.Current;
|
|
ReportIfUnused(current, current.DeclarationKind != LocalDeclarationKind.CatchVariable);
|
|
}
|
|
}
|
|
|
|
public override BoundNode VisitFieldAccess(BoundFieldAccess node)
|
|
{
|
|
BoundNode result = base.VisitFieldAccess(node);
|
|
NoteRead(node.FieldSymbol);
|
|
if (node.FieldSymbol.IsFixedSizeBuffer && node.Syntax != null && !SyntaxFacts.IsFixedStatementExpression(node.Syntax))
|
|
{
|
|
Symbol symbol = UseNonFieldSymbolUnsafely(node.ReceiverOpt);
|
|
if ((object)symbol != null)
|
|
{
|
|
CheckCaptured(symbol);
|
|
if (!((Dictionary<Symbol, Location>)(object)_unsafeAddressTakenVariables).ContainsKey(symbol))
|
|
{
|
|
((Dictionary<Symbol, Location>)(object)_unsafeAddressTakenVariables).Add(symbol, node.Syntax.Location);
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
else if (MayRequireTracking(node.ReceiverOpt, node.FieldSymbol))
|
|
{
|
|
CheckAssigned(node, node.FieldSymbol, node.Syntax);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public override BoundNode VisitPropertyAccess(BoundPropertyAccess node)
|
|
{
|
|
BoundNode result = base.VisitPropertyAccess(node);
|
|
if (Binder.AccessingAutoPropertyFromConstructor(node, CurrentSymbol))
|
|
{
|
|
SynthesizedBackingFieldSymbol synthesizedBackingFieldSymbol = (node.PropertySymbol as SourcePropertySymbolBase)?.BackingField;
|
|
if (synthesizedBackingFieldSymbol != null && MayRequireTracking(node.ReceiverOpt, synthesizedBackingFieldSymbol) && State.Reachable && !IsAssigned(node, out var unassignedSlot))
|
|
{
|
|
ReportUnassignedIfNotCapturedInLocalFunction(synthesizedBackingFieldSymbol, node.Syntax, unassignedSlot);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public override BoundNode VisitEventAccess(BoundEventAccess node)
|
|
{
|
|
BoundNode result = base.VisitEventAccess(node);
|
|
FieldSymbol associatedField = node.EventSymbol.AssociatedField;
|
|
if ((object)associatedField != null)
|
|
{
|
|
NoteRead(associatedField);
|
|
if (MayRequireTracking(node.ReceiverOpt, associatedField))
|
|
{
|
|
CheckAssigned(node, associatedField, node.Syntax);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public override void VisitForEachIterationVariables(BoundForEachStatement node)
|
|
{
|
|
ImmutableArray<LocalSymbol>.Enumerator enumerator = node.IterationVariables.GetEnumerator();
|
|
while (enumerator.MoveNext())
|
|
{
|
|
LocalSymbol current = enumerator.Current;
|
|
int orCreateSlot = GetOrCreateSlot(current);
|
|
if (orCreateSlot > 0)
|
|
{
|
|
SetSlotAssigned(orCreateSlot);
|
|
}
|
|
NoteWrite(current, null, read: true);
|
|
}
|
|
}
|
|
|
|
public override BoundNode VisitObjectInitializerMember(BoundObjectInitializerMember node)
|
|
{
|
|
//IL_0023: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0029: Invalid comparison between Unknown and I4
|
|
BoundNode result = base.VisitObjectInitializerMember(node);
|
|
if ((object)_sourceAssembly != null && node.MemberSymbol != null && (int)node.MemberSymbol.Kind == 6)
|
|
{
|
|
_sourceAssembly.NoteFieldAccess((FieldSymbol)node.MemberSymbol.OriginalDefinition, read: false, write: true);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public override BoundNode VisitDynamicObjectInitializerMember(BoundDynamicObjectInitializerMember node)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
protected override void VisitAssignmentOfNullCoalescingAssignment(BoundNullCoalescingAssignmentOperator node, BoundPropertyAccess propertyAccessOpt)
|
|
{
|
|
base.VisitAssignmentOfNullCoalescingAssignment(node, propertyAccessOpt);
|
|
Assign(node.LeftOperand, node.RightOperand);
|
|
}
|
|
|
|
protected override void AdjustStateForNullCoalescingAssignmentNonNullCase(BoundNullCoalescingAssignmentOperator node)
|
|
{
|
|
Assign(node.LeftOperand, node.LeftOperand);
|
|
}
|
|
|
|
protected override void AfterVisitInlineArrayAccess(BoundInlineArrayAccess node)
|
|
{
|
|
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000b: Invalid comparison between Unknown and I4
|
|
if ((int)node.GetItemOrSliceHelper == 402)
|
|
{
|
|
NoteWrite(node.Expression, null, read: false);
|
|
}
|
|
}
|
|
|
|
protected override void AfterVisitConversion(BoundConversion node)
|
|
{
|
|
if (node.Conversion.IsInlineArray && node.Type.OriginalDefinition.Equals(compilation.GetWellKnownType((WellKnownType)275), (TypeCompareKind)63))
|
|
{
|
|
NoteWrite(node.Operand, null, read: false);
|
|
}
|
|
}
|
|
|
|
protected override string Dump(LocalState state)
|
|
{
|
|
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
stringBuilder.Append("[assigned ");
|
|
AppendBitNames(state.Assigned, stringBuilder);
|
|
stringBuilder.Append("]");
|
|
return stringBuilder.ToString();
|
|
}
|
|
|
|
protected void AppendBitNames(BitVector a, StringBuilder builder)
|
|
{
|
|
bool flag = false;
|
|
foreach (int item in ((BitVector)(ref a)).TrueBits())
|
|
{
|
|
if (flag)
|
|
{
|
|
builder.Append(", ");
|
|
}
|
|
flag = true;
|
|
AppendBitName(item, builder);
|
|
}
|
|
}
|
|
|
|
protected void AppendBitName(int bit, StringBuilder builder)
|
|
{
|
|
LocalDataFlowPass<LocalState, LocalFunctionState>.VariableIdentifier variableIdentifier = variableBySlot[bit];
|
|
if (variableIdentifier.ContainingSlot > 0)
|
|
{
|
|
AppendBitName(variableIdentifier.ContainingSlot, builder);
|
|
builder.Append(".");
|
|
}
|
|
builder.Append((bit == 0) ? "<unreachable>" : (string.IsNullOrEmpty(variableIdentifier.Symbol.Name) ? ("<anon>" + variableIdentifier.Symbol.GetHashCode()) : variableIdentifier.Symbol.Name));
|
|
}
|
|
|
|
protected override bool Meet(ref LocalState self, ref LocalState other)
|
|
{
|
|
if (((BitVector)(ref self.Assigned)).Capacity != ((BitVector)(ref other.Assigned)).Capacity)
|
|
{
|
|
Normalize(ref self);
|
|
Normalize(ref other);
|
|
}
|
|
if (!other.Reachable)
|
|
{
|
|
((BitVector)(ref self.Assigned))[0] = true;
|
|
return true;
|
|
}
|
|
bool result = false;
|
|
for (int i = 1; i < ((BitVector)(ref self.Assigned)).Capacity; i++)
|
|
{
|
|
if (((BitVector)(ref other.Assigned))[i] && !((BitVector)(ref self.Assigned))[i])
|
|
{
|
|
SetSlotAssigned(i, ref self);
|
|
result = true;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
protected override bool Join(ref LocalState self, ref LocalState other)
|
|
{
|
|
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
|
|
if (self.Reachable == other.Reachable)
|
|
{
|
|
if (((BitVector)(ref self.Assigned)).Capacity != ((BitVector)(ref other.Assigned)).Capacity)
|
|
{
|
|
Normalize(ref self);
|
|
Normalize(ref other);
|
|
}
|
|
return ((BitVector)(ref self.Assigned)).IntersectWith(ref other.Assigned);
|
|
}
|
|
if (!self.Reachable)
|
|
{
|
|
self.Assigned = ((BitVector)(ref other.Assigned)).Clone();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected override LocalFunctionState CreateLocalFunctionState(LocalFunctionSymbol symbol)
|
|
{
|
|
return CreateLocalFunctionState();
|
|
}
|
|
|
|
private LocalFunctionState CreateLocalFunctionState()
|
|
{
|
|
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
|
|
return new LocalFunctionState(new LocalState(BitVector.AllSet(variableBySlot.Count), normalizeToBottom: true), UnreachableState());
|
|
}
|
|
|
|
protected override void VisitLocalFunctionUse(LocalFunctionSymbol localFunc, LocalFunctionState localFunctionState, SyntaxNode syntax, bool isCall)
|
|
{
|
|
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
|
|
((HashSet<LocalFunctionSymbol>)(object)_usedLocalFunctions).Add(localFunc);
|
|
BitVector readVars = localFunctionState.ReadVars;
|
|
for (int i = 1; i < ((BitVector)(ref readVars)).Capacity; i++)
|
|
{
|
|
if (((BitVector)(ref readVars))[i])
|
|
{
|
|
Symbol symbol = variableBySlot[i].Symbol;
|
|
CheckIfAssignedDuringLocalFunctionReplay(symbol, syntax, i);
|
|
}
|
|
}
|
|
base.VisitLocalFunctionUse(localFunc, localFunctionState, syntax, isCall);
|
|
}
|
|
|
|
private void CheckIfAssignedDuringLocalFunctionReplay(Symbol symbol, SyntaxNode node, int slot)
|
|
{
|
|
if ((object)symbol == null)
|
|
{
|
|
return;
|
|
}
|
|
NoteRead(symbol);
|
|
if (State.Reachable)
|
|
{
|
|
if (slot >= ((BitVector)(ref State.Assigned)).Capacity)
|
|
{
|
|
Normalize(ref State);
|
|
}
|
|
if (slot > 0 && !State.IsAssigned(slot))
|
|
{
|
|
ReportUnassignedIfNotCapturedInLocalFunction(symbol, node, slot, skipIfUseBeforeDeclaration: false);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RecordReadInLocalFunction(int slot)
|
|
{
|
|
LocalFunctionSymbol nearestLocalFunctionOpt = GetNearestLocalFunctionOpt(CurrentSymbol);
|
|
LocalFunctionState orCreateLocalFuncUsages = GetOrCreateLocalFuncUsages(nearestLocalFunctionOpt);
|
|
TypeSymbol type = variableBySlot[slot].Symbol.GetTypeOrReturnType().Type;
|
|
if (EmptyStructTypeCache.IsTrackableStructType(type))
|
|
{
|
|
foreach (FieldSymbol structInstanceField in _emptyStructTypeCache.GetStructInstanceFields(type))
|
|
{
|
|
int orCreateSlot = GetOrCreateSlot(structInstanceField, slot);
|
|
if (orCreateSlot > 0 && !State.IsAssigned(orCreateSlot))
|
|
{
|
|
RecordReadInLocalFunction(orCreateSlot);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
((BitVector)(ref orCreateLocalFuncUsages.ReadVars))[slot] = true;
|
|
}
|
|
|
|
private BitVector GetCapturedBitmask()
|
|
{
|
|
//IL_000d: 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_002e: Unknown result type (might be due to invalid IL or missing references)
|
|
int count = variableBySlot.Count;
|
|
BitVector result = BitVector.AllSet(count);
|
|
for (int i = 1; i < count; i++)
|
|
{
|
|
((BitVector)(ref result))[i] = IsCapturedInLocalFunction(i);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private bool IsCapturedInLocalFunction(int slot)
|
|
{
|
|
if (slot <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
Symbol symbol = variableBySlot[RootSlot(slot)].Symbol;
|
|
LocalFunctionSymbol nearestLocalFunctionOpt = GetNearestLocalFunctionOpt(CurrentSymbol);
|
|
if ((object)nearestLocalFunctionOpt != null)
|
|
{
|
|
return Symbol.IsCaptured(symbol, nearestLocalFunctionOpt);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static LocalFunctionSymbol GetNearestLocalFunctionOpt(Symbol symbol)
|
|
{
|
|
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000a: Invalid comparison between Unknown and I4
|
|
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0019: Invalid comparison between Unknown and I4
|
|
while (symbol != null)
|
|
{
|
|
if ((int)symbol.Kind == 9 && (int)((MethodSymbol)symbol).MethodKind == 17)
|
|
{
|
|
return (LocalFunctionSymbol)symbol;
|
|
}
|
|
symbol = symbol.ContainingSymbol;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
protected override LocalFunctionState LocalFunctionStart(LocalFunctionState startState)
|
|
{
|
|
//IL_000d: 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)
|
|
LocalFunctionState localFunctionState = CreateLocalFunctionState();
|
|
localFunctionState.ReadVars = ((BitVector)(ref startState.ReadVars)).Clone();
|
|
((BitVector)(ref startState.ReadVars)).Clear();
|
|
return localFunctionState;
|
|
}
|
|
|
|
protected override bool LocalFunctionEnd(LocalFunctionState savedState, LocalFunctionState currentState, ref LocalState stateAtReturn)
|
|
{
|
|
//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)
|
|
//IL_0020: 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_0080: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0075: 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)
|
|
if (((BitVector)(ref currentState.CapturedMask)).IsNull)
|
|
{
|
|
currentState.CapturedMask = GetCapturedBitmask();
|
|
currentState.InvertedCapturedMask = ((BitVector)(ref currentState.CapturedMask)).Clone();
|
|
((BitVector)(ref currentState.InvertedCapturedMask)).Invert();
|
|
}
|
|
((BitVector)(ref stateAtReturn.Assigned)).IntersectWith(ref currentState.CapturedMask);
|
|
if (NonMonotonicState.HasValue)
|
|
{
|
|
LocalState value = NonMonotonicState.Value;
|
|
((BitVector)(ref value.Assigned)).UnionWith(ref currentState.InvertedCapturedMask);
|
|
NonMonotonicState = Optional<LocalState>.op_Implicit(value);
|
|
}
|
|
BitVector readVars = currentState.ReadVars;
|
|
((BitVector)(ref readVars)).IntersectWith(ref currentState.CapturedMask);
|
|
return ((BitVector)(ref savedState.ReadVars)).UnionWith(ref readVars);
|
|
}
|
|
}
|