/// <summary> /// Construct context /// </summary> public RegionAnalysisContext(CSharpCompilation compilation, Symbol member, BoundNode boundNode, BoundNode firstInRegion, BoundNode lastInRegion) { this.Compilation = compilation; this.Member = member; this.BoundNode = boundNode; this.FirstInRegion = firstInRegion; this.LastInRegion = lastInRegion; this.Failed = boundNode == null || firstInRegion == null || lastInRegion == null || firstInRegion.Syntax.SpanStart > lastInRegion.Syntax.Span.End; if (!this.Failed && ReferenceEquals(firstInRegion, lastInRegion)) { switch (firstInRegion.Kind) { case BoundKind.NamespaceExpression: case BoundKind.TypeExpression: // Some bound nodes are still considered to be invalid for flow analysis this.Failed = true; break; } } }
public override BoundNode Visit(BoundNode node) { IOperation operation = node as IOperation; if (operation != null) { this.nodes.Add(operation); // Following operations are not bound node, therefore have to be added explicitly: // 1. IArgument // 2. IMemberInitializer // 3. ICase switch (operation.Kind) { case OperationKind.InvocationExpression: nodes.AddRange(((IInvocationExpression)operation).ArgumentsInSourceOrder); break; case OperationKind.ObjectCreationExpression: var objCreationExp = (IObjectCreationExpression)operation; nodes.AddRange(objCreationExp.ConstructorArguments); nodes.AddRange(objCreationExp.MemberInitializers); break; case OperationKind.SwitchStatement: nodes.AddRange(((ISwitchStatement)operation).Cases); break; } } return base.Visit(node); }
public static MultiDictionary<Symbol, CSharpSyntaxNode> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node) { var emptyStructs = new CaptureWalkerEmptyStructTypeCache(); var initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node, emptyStructs); var walker = new IteratorAndAsyncCaptureWalker(compilation, method, node, emptyStructs, initiallyAssignedVariables); bool badRegion = false; walker.Analyze(ref badRegion); Debug.Assert(!badRegion); var result = walker.variablesCaptured; if (!method.IsStatic && method.ContainingType.TypeKind == TypeKind.Struct) { // It is possible that the enclosing method only *writes* to the enclosing struct, but in that // case it should be considered captured anyway so that we have a proxy for it to write to. result.Add(method.ThisParameter, node.Syntax); } foreach (var variable in result.Keys.ToArray()) // take a snapshot, as we are modifying the underlying multidictionary { var local = variable as LocalSymbol; if ((object)local != null && local.RefKind != RefKind.None) { walker.AddSpillsForRef(walker.refLocalInitializers[local], result[local]); } } walker.Free(); return result; }
internal static void Analyze( CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet<PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes, out IEnumerable<Symbol> readInside, out IEnumerable<Symbol> writtenInside, out IEnumerable<Symbol> readOutside, out IEnumerable<Symbol> writtenOutside, out IEnumerable<Symbol> captured, out IEnumerable<Symbol> unsafeAddressTaken) { var walker = new ReadWriteWalker(compilation, member, node, firstInRegion, lastInRegion, unassignedVariableAddressOfSyntaxes); try { bool badRegion = false; walker.Analyze(ref badRegion); if (badRegion) { readInside = writtenInside = readOutside = writtenOutside = captured = unsafeAddressTaken = Enumerable.Empty<Symbol>(); } else { readInside = walker._readInside; writtenInside = walker._writtenInside; readOutside = walker._readOutside; writtenOutside = walker._writtenOutside; captured = walker.GetCaptured(); unsafeAddressTaken = walker.GetUnsafeAddressTaken(); } } finally { walker.Free(); } }
public static void IssueDiagnostics(CSharpCompilation compilation, BoundNode node, DiagnosticBag diagnostics, MethodSymbol containingSymbol) { Debug.Assert(node != null); Debug.Assert((object)containingSymbol != null); var diagnosticPass = new DiagnosticsPass(compilation, diagnostics, containingSymbol); diagnosticPass.Visit(node); }
private void NoteUnsafe(BoundNode node) { if (_inExpressionLambda && !_reportedUnsafe) { Error(ErrorCode.ERR_ExpressionTreeContainsPointerOp, node); _reportedUnsafe = true; } }
private IteratorAndAsyncCaptureWalker(CSharpCompilation compilation, MethodSymbol method, BoundNode node, CaptureWalkerEmptyStructTypeCache emptyStructCache, HashSet<Symbol> initiallyAssignedVariables) : base(compilation, method, node, emptyStructCache, trackUnassignments: true, initiallyAssignedVariables: initiallyAssignedVariables) { }
internal AbstractRegionControlFlowPass( CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion) : base(compilation, member, node, firstInRegion, lastInRegion) { }
public override BoundNode Visit(BoundNode node) { IOperation operation = node as IOperation; if (operation != null) { this.nodes.Add(operation); } return base.Visit(node); }
internal AbstractRegionDataFlowPass( CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet<Symbol> initiallyAssignedVariables = null, HashSet<PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes = null, bool trackUnassignments = false) : base(compilation, member, node, firstInRegion, lastInRegion, initiallyAssignedVariables, unassignedVariableAddressOfSyntaxes, trackUnassignments) { }
public static HashSet<LabelSymbol> Find(BoundNode node, Dictionary<BoundNode, HashSet<LabelSymbol>> unmatchedLabelsCache) { UnmatchedGotoFinder finder = new UnmatchedGotoFinder(unmatchedLabelsCache); finder.Visit(node); HashSet<LabelSymbol> gotos = finder._gotos; HashSet<LabelSymbol> targets = finder._targets; if (gotos != null && targets != null) { gotos.RemoveAll(targets); } return gotos; }
protected override void NoteBranch( PendingBranch pending, BoundNode gotoStmt, BoundStatement targetStmt) { targetStmt.AssertIsLabeledStatement(); if (!gotoStmt.WasCompilerGenerated && !targetStmt.WasCompilerGenerated && !RegionContains(gotoStmt.Syntax.Span) && RegionContains(targetStmt.Syntax.Span)) { pending.State = ResetState(pending.State); } base.NoteBranch(pending, gotoStmt, targetStmt); }
// Returns deterministically ordered list of variables that ought to be hoisted. public static OrderedSet<Symbol> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node, DiagnosticBag diagnostics) { var initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node, convertInsufficientExecutionStackExceptionToCancelledByStackGuardException: true); var walker = new IteratorAndAsyncCaptureWalker(compilation, method, node, new NeverEmptyStructTypeCache(), initiallyAssignedVariables); walker._convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = true; bool badRegion = false; walker.Analyze(ref badRegion); Debug.Assert(!badRegion); if (!method.IsStatic && method.ContainingType.TypeKind == TypeKind.Struct) { // It is possible that the enclosing method only *writes* to the enclosing struct, but in that // case it should be considered captured anyway so that we have a proxy for it to write to. walker.CaptureVariable(method.ThisParameter, node.Syntax); } var variablesToHoist = walker._variablesToHoist; var lazyDisallowedCaptures = walker._lazyDisallowedCaptures; var allVariables = walker.variableBySlot; walker.Free(); if (lazyDisallowedCaptures != null) { foreach (var kvp in lazyDisallowedCaptures) { var variable = kvp.Key; var type = (variable.Kind == SymbolKind.Local) ? ((LocalSymbol)variable).Type : ((ParameterSymbol)variable).Type; foreach (CSharpSyntaxNode syntax in kvp.Value) { // CS4013: Instance of type '{0}' cannot be used inside an anonymous function, query expression, iterator block or async method diagnostics.Add(ErrorCode.ERR_SpecialByRefInLambda, syntax.Location, type); } } } if (compilation.Options.OptimizationLevel != OptimizationLevel.Release) { Debug.Assert(variablesToHoist.Count == 0); // In debug build we hoist all locals and parameters: variablesToHoist.AddRange(from v in allVariables where v.Symbol != null && HoistInDebugBuild(v.Symbol) select v.Symbol); } return variablesToHoist; }
internal static IEnumerable<Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion) { var walker = new VariablesDeclaredWalker(compilation, member, node, firstInRegion, lastInRegion); try { bool badRegion = false; walker.Analyze(ref badRegion); return badRegion ? SpecializedCollections.EmptyEnumerable<Symbol>() : walker._variablesDeclared; } finally { walker.Free(); } }
internal static IEnumerable<Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion) { var walker = new AlwaysAssignedWalker(compilation, member, node, firstInRegion, lastInRegion); bool badRegion = false; try { var result = walker.Analyze(ref badRegion); return badRegion ? SpecializedCollections.EmptyEnumerable<Symbol>() : result; } finally { walker.Free(); } }
internal static HashSet<Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, EmptyStructTypeCache emptyStructCache = null) { var walker = new UnassignedVariablesWalker(compilation, member, node, emptyStructCache); try { bool badRegion = false; var result = walker.Analyze(ref badRegion); return badRegion ? new HashSet<Symbol>() : result; } finally { walker.Free(); } }
internal static HashSet<PrefixUnaryExpressionSyntax> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node) { var walker = new UnassignedAddressTakenVariablesWalker(compilation, member, node); try { bool badRegion = false; var result = walker.Analyze(ref badRegion); Debug.Assert(!badRegion); return result; } finally { walker.Free(); } }
public static void IssueDiagnostics(CSharpCompilation compilation, BoundNode node, DiagnosticBag diagnostics, MethodSymbol containingSymbol) { Debug.Assert(node != null); Debug.Assert((object)containingSymbol != null); try { var diagnosticPass = new DiagnosticsPass(compilation, diagnostics, containingSymbol); diagnosticPass.Visit(node); } catch (CancelledByStackGuardException ex) { ex.AddAnError(diagnostics); } }
internal static IEnumerable<StatementSyntax> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion) { var walker = new ExitPointsWalker(compilation, member, node, firstInRegion, lastInRegion); try { bool badRegion = false; walker.Analyze(ref badRegion); var result = walker._branchesOutOf.ToImmutableAndFree(); walker._branchesOutOf = null; return badRegion ? SpecializedCollections.EmptyEnumerable<StatementSyntax>() : result; } finally { walker.Free(); } }
internal static IEnumerable<LabeledStatementSyntax> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, out bool? succeeded) { var walker = new EntryPointsWalker(compilation, member, node, firstInRegion, lastInRegion); bool badRegion = false; try { walker.Analyze(ref badRegion); var result = walker.entryPoints; succeeded = !badRegion; return badRegion ? SpecializedCollections.EmptyEnumerable<LabeledStatementSyntax>() : result; } finally { walker.Free(); } }
internal static HashSet<Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet<Symbol> unassignedVariables, HashSet<PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes, out bool? succeeded) { var walker = new DataFlowsInWalker(compilation, member, node, firstInRegion, lastInRegion, unassignedVariables, unassignedVariableAddressOfSyntaxes); try { bool badRegion = false; var result = walker.Analyze(ref badRegion); succeeded = !badRegion; return badRegion ? new HashSet<Symbol>() : result; } finally { walker.Free(); } }
internal static HashSet<Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet<Symbol> unassignedVariables, ImmutableArray<ISymbol> dataFlowsIn) { var walker = new DataFlowsOutWalker(compilation, member, node, firstInRegion, lastInRegion, unassignedVariables, dataFlowsIn); try { bool badRegion = false; var result = walker.Analyze(ref badRegion); #if DEBUG // Assert that DataFlowsOut only contains variables that were assigned to inside the region Debug.Assert(badRegion || !result.Any((variable) => !walker.assignedInside.Contains(variable))); #endif return badRegion ? new HashSet<Symbol>() : result; } finally { walker.Free(); } }
public override BoundNode Visit(BoundNode node) { HashSet<LabelSymbol> unmatched; if (node != null && _unmatchedLabelsCache.TryGetValue(node, out unmatched)) { if (unmatched != null) { foreach (LabelSymbol label in unmatched) { AddGoto(label); } } return null; // Don't visit children. } return base.Visit(node); }
internal static void Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, out bool startPointIsReachable, out bool endPointIsReachable) { var walker = new RegionReachableWalker(compilation, member, node, firstInRegion, lastInRegion); var diagnostics = DiagnosticBag.GetInstance(); bool badRegion = false; try { walker.Analyze(ref badRegion, diagnostics); startPointIsReachable = badRegion || walker._reginStartPointIsReachable.GetValueOrDefault(true); endPointIsReachable = badRegion || walker._reginEndPointIsReachable.GetValueOrDefault(walker.State.Alive); } finally { diagnostics.Free(); walker.Free(); } }
public override BoundNode Visit(BoundNode node) { var partiallyLowered = node as PartiallyLoweredLocalFunctionReference; if (partiallyLowered != null) { var underlying = partiallyLowered.UnderlyingNode; Debug.Assert(underlying.Kind == BoundKind.Call || underlying.Kind == BoundKind.DelegateCreationExpression || underlying.Kind == BoundKind.Conversion); var oldProxies = _lambdaRewriter.proxies; _lambdaRewriter.proxies = partiallyLowered.Proxies; var result = base.Visit(underlying); _lambdaRewriter.proxies = oldProxies; return result; } return base.Visit(node); }
public override BoundNode Visit(BoundNode node) { IOperation operation = node as IOperation; if (operation != null) { this.nodes.Add(operation); switch (operation.Kind) { case OperationKind.InvocationExpression: nodes.AddRange(((IInvocationExpression)operation).ArgumentsInSourceOrder); break; case OperationKind.ObjectCreationExpression: var objCreationExp = (IObjectCreationExpression)operation; nodes.AddRange(objCreationExp.ConstructorArguments); nodes.AddRange(objCreationExp.MemberInitializers); break; } } return base.Visit(node); }
internal static HashSet<Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, bool convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = false) { var walker = new UnassignedVariablesWalker(compilation, member, node); if (convertInsufficientExecutionStackExceptionToCancelledByStackGuardException) { walker._convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = true; } try { bool badRegion = false; var result = walker.Analyze(ref badRegion); return badRegion ? new HashSet<Symbol>() : result; } finally { walker.Free(); } }
public static MultiDictionary<Symbol, CSharpSyntaxNode> Analyze(CSharpCompilation compilation, MethodSymbol method, BoundNode node) { var emptyStructs = new CaptureWalkerEmptyStructTypeCache(); var initiallyAssignedVariables = UnassignedVariablesWalker.Analyze(compilation, method, node, emptyStructs); var walker = new IteratorAndAsyncCaptureWalker(compilation, method, node, emptyStructs, initiallyAssignedVariables); bool badRegion = false; walker.Analyze(ref badRegion); Debug.Assert(!badRegion); var result = walker.variablesCaptured; if (!method.IsStatic && method.ContainingType.TypeKind == TypeKind.Struct) { // It is possible that the enclosing method only *writes* to the enclosing struct, but in that // case it should be considered captured anyway so that we have a proxy for it to write to. result.Add(method.ThisParameter, node.Syntax); } walker.Free(); return result; }
internal static IEnumerable <Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion) { var walker = new AlwaysAssignedWalker(compilation, member, node, firstInRegion, lastInRegion); bool badRegion = false; try { var result = walker.Analyze(ref badRegion); return(badRegion ? SpecializedCollections.EmptyEnumerable <Symbol>() : result); } finally { walker.Free(); } }
public override BoundNode?VisitLocalFunctionStatement(BoundLocalFunctionStatement localFunc) { var oldSymbol = this.CurrentSymbol; var localFuncSymbol = localFunc.Symbol; this.CurrentSymbol = localFuncSymbol; var oldPending = SavePending(); // we do not support branches into a lambda // SPEC: The entry point to a local function is always reachable. // Captured variables are definitely assigned if they are definitely assigned on // all branches into the local function. var savedState = this.State; this.State = this.TopState(); Optional <TLocalState> savedNonMonotonicState = NonMonotonicState; if (_nonMonotonicTransfer) { NonMonotonicState = ReachableBottomState(); } if (!localFunc.WasCompilerGenerated) { EnterParameters(localFuncSymbol.Parameters); } // State changes to captured variables are recorded, as calls to local functions // transition the state of captured variables if the variables have state changes // across all branches leaving the local function var localFunctionState = GetOrCreateLocalFuncUsages(localFuncSymbol); var savedLocalFunctionState = LocalFunctionStart(localFunctionState); var oldPending2 = SavePending(); // If this is an iterator, there's an implicit branch before the first statement // of the function where the enumerable is returned. if (localFuncSymbol.IsIterator) { PendingBranches.Add(new PendingBranch(null, this.State, null)); } VisitAlways(localFunc.Body); RestorePending(oldPending2); // process any forward branches within the lambda body ImmutableArray <PendingBranch> pendingReturns = RemoveReturns(); RestorePending(oldPending); Location?location = null; if (!localFuncSymbol.Locations.IsDefaultOrEmpty) { location = localFuncSymbol.Locations[0]; } LeaveParameters(localFuncSymbol.Parameters, localFunc.Syntax, location); // Intersect the state of all branches out of the local function var stateAtReturn = this.State; foreach (PendingBranch pending in pendingReturns) { this.State = pending.State; BoundNode branch = pending.Branch; // Pass the local function identifier as a location if the branch // is null or compiler generated. LeaveParameters(localFuncSymbol.Parameters, branch?.Syntax, branch?.WasCompilerGenerated == false ? null : location); Join(ref stateAtReturn, ref this.State); } // Record any changes to the state of captured variables if (RecordStateChange( savedLocalFunctionState, localFunctionState, ref stateAtReturn) && localFunctionState.Visited) { // If the sets have changed and we already used the results // of this local function in another computation, the previous // calculations may be invalid. We need to analyze until we // reach a fixed-point. stateChangedAfterUse = true; localFunctionState.Visited = false; } this.State = savedState; NonMonotonicState = savedNonMonotonicState; this.CurrentSymbol = oldSymbol; return(null); }
private void CheckVacuousComparisons(BoundBinaryOperator tree, ConstantValue constantValue, BoundNode operand) { Debug.Assert(tree != null); Debug.Assert(constantValue != null); Debug.Assert(operand != null); // We wish to detect comparisons between integers and constants which are likely to be wrong // because we know at compile time whether they will be true or false. For example: // // const short s = 1000; // byte b = whatever; // if (b < s) // // We know that this will always be true because when b and s are both converted to int for // the comparison, the left side will always be less than the right side. // // We only give the warning if there is no explicit conversion involved on the operand. // For example, if we had: // // const uint s = 1000; // sbyte b = whatever; // if ((byte)b < s) // // Then we do not give a warning. // // Note that the native compiler has what looks to be some dead code. It checks to see // if the conversion on the operand is from an enum type. But this is unnecessary if // we are rejecting cases with explicit conversions. The only possible cases are: // // enum == enumConstant -- enum types must be the same, so it must be in range. // enum == integralConstant -- not legal unless the constant is zero, which is in range. // enum == (ENUM)anyConstant -- if the constant is out of range then this is not legal in the first place // unless we're in an unchecked context, in which case, the user probably does // not want the warning. // integral == enumConstant -- never legal in the first place // // Since it seems pointless to try to check enums, we simply look for vacuous comparisons of // integral types here. for (BoundConversion conversion = operand as BoundConversion; conversion != null; conversion = conversion.Operand as BoundConversion) { if (conversion.ConversionKind != ConversionKind.ImplicitNumeric && conversion.ConversionKind != ConversionKind.ImplicitConstant) { return; } // As in dev11, we don't dig through explicit casts (see ExpressionBinder::WarnAboutBadRelationals). if (conversion.ExplicitCastInCode) { return; } if (!conversion.Operand.Type.SpecialType.IsIntegralType() || !conversion.Type.SpecialType.IsIntegralType()) { return; } if (!Binder.CheckConstantBounds(conversion.Operand.Type.SpecialType, constantValue)) { Error(ErrorCode.WRN_VacuousIntegralComp, tree, conversion.Operand.Type); return; } } }
private Symbol GetNodeSymbol(BoundNode node) { while (node != null) { switch (node.Kind) { case BoundKind.DeclarationPattern: { return(((BoundDeclarationPattern)node).LocalSymbol); } case BoundKind.FieldAccess: { var fieldAccess = (BoundFieldAccess)node; if (MayRequireTracking(fieldAccess.ReceiverOpt, fieldAccess.FieldSymbol)) { node = fieldAccess.ReceiverOpt; continue; } return(null); } case BoundKind.LocalDeclaration: { return(((BoundLocalDeclaration)node).LocalSymbol); } case BoundKind.ThisReference: { return(MethodThisParameter); } case BoundKind.Local: { return(((BoundLocal)node).LocalSymbol); } case BoundKind.Parameter: { return(((BoundParameter)node).ParameterSymbol); } case BoundKind.CatchBlock: { var local = ((BoundCatchBlock)node).Locals.FirstOrDefault(); return(local?.DeclarationKind == LocalDeclarationKind.CatchVariable ? local : null); } case BoundKind.ForEachStatement: { return(((BoundForEachStatement)node).IterationVariableOpt); } case BoundKind.RangeVariable: { return(((BoundRangeVariable)node).RangeVariableSymbol); } case BoundKind.EventAccess: { var eventAccess = (BoundEventAccess)node; FieldSymbol associatedField = eventAccess.EventSymbol.AssociatedField; if ((object)associatedField != null) { if (MayRequireTracking(eventAccess.ReceiverOpt, associatedField)) { node = eventAccess.ReceiverOpt; continue; } } return(null); } case BoundKind.LocalFunctionStatement: { return(((BoundLocalFunctionStatement)node).Symbol); } default: { return(null); } } } return(null); }
public static void GetExpressionSymbols(this BoundExpression node, ArrayBuilder <Symbol> symbols, BoundNode parent, Binder binder) { switch (node.Kind) { case BoundKind.MethodGroup: // Special case: if we are looking for info on "M" in "new Action(M)" in the context of a parent // then we want to get the symbol that overload resolution chose for M, not on the whole method group M. var delegateCreation = parent as BoundDelegateCreationExpression; if (delegateCreation != null && (object)delegateCreation.MethodOpt != null) { symbols.Add(delegateCreation.MethodOpt); } else { symbols.AddRange(CSharpSemanticModel.GetReducedAndFilteredMethodGroupSymbols(binder, (BoundMethodGroup)node)); } break; case BoundKind.BadExpression: symbols.AddRange(((BoundBadExpression)node).Symbols); break; case BoundKind.DelegateCreationExpression: var expr = (BoundDelegateCreationExpression)node; var ctor = expr.Type.GetMembers(WellKnownMemberNames.InstanceConstructorName).FirstOrDefault(); if ((object)ctor != null) { symbols.Add(ctor); } break; case BoundKind.Call: // Either overload resolution succeeded for this call or it did not. If it did not // succeed then we've stashed the original method symbols from the method group, // and we should use those as the symbols displayed for the call. If it did succeed // then we did not stash any symbols; just fall through to the default case. var originalMethods = ((BoundCall)node).OriginalMethodsOpt; if (originalMethods.IsDefault) { goto default; } symbols.AddRange(originalMethods); break; case BoundKind.IndexerAccess: // Same behavior as for a BoundCall: if overload resolution failed, pull out stashed candidates; // otherwise use the default behavior. var originalIndexers = ((BoundIndexerAccess)node).OriginalIndexersOpt; if (originalIndexers.IsDefault) { goto default; } symbols.AddRange(originalIndexers); break; default: var symbol = node.ExpressionSymbol; if ((object)symbol != null) { symbols.Add(symbol); } break; } }
public static BoundNode Rewrite(PooledDictionary <LocalSymbol, LocalSymbol> tempSubstitution, BoundNode node) { if (tempSubstitution.Count == 0) { return(node); } var substituter = new LocalSubstituter(tempSubstitution); return(substituter.Visit(node)); }
private ReadWriteWalker(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet <PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes) : base(compilation, member, node, firstInRegion, lastInRegion, unassignedVariableAddressOfSyntaxes: unassignedVariableAddressOfSyntaxes) { }
internal static void Analyze( CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet <PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes, out IEnumerable <Symbol> readInside, out IEnumerable <Symbol> writtenInside, out IEnumerable <Symbol> readOutside, out IEnumerable <Symbol> writtenOutside, out IEnumerable <Symbol> captured, out IEnumerable <Symbol> unsafeAddressTaken, out IEnumerable <Symbol> capturedInside, out IEnumerable <Symbol> capturedOutside) { var walker = new ReadWriteWalker(compilation, member, node, firstInRegion, lastInRegion, unassignedVariableAddressOfSyntaxes); try { bool badRegion = false; walker.Analyze(ref badRegion); if (badRegion) { readInside = writtenInside = readOutside = writtenOutside = captured = unsafeAddressTaken = capturedInside = capturedOutside = Enumerable.Empty <Symbol>(); } else { readInside = walker._readInside; writtenInside = walker._writtenInside; readOutside = walker._readOutside; writtenOutside = walker._writtenOutside; captured = walker.GetCaptured(); capturedInside = walker.GetCapturedInside(); capturedOutside = walker.GetCapturedOutside(); unsafeAddressTaken = walker.GetUnsafeAddressTaken(); } } finally { walker.Free(); } }
public override BoundNode DefaultVisit(BoundNode node) { Debug.Assert(!(node is BoundStatement)); return(base.DefaultVisit(node)); }
private void Error(ErrorCode code, BoundNode node, params object[] args) { _diagnostics.Add(code, node.Syntax.Location, args); }
private T GetUpdatedSymbol <T>(BoundNode expr, T sym) where T : Symbol? { if (sym is null)
private UnassignedVariablesWalker(CSharpCompilation compilation, Symbol member, BoundNode node) : base(compilation, member, node, new NeverEmptyStructTypeCache()) { }
public override BoundNode Visit(BoundNode node) { VisitAlways(node); return(null); }
DataFlowsOutWalker(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet<Symbol> unassignedVariables, ImmutableArray<ISymbol> dataFlowsIn) : base(compilation, member, node, firstInRegion, lastInRegion, unassignedVariables, trackUnassignments: true) { this.dataFlowsIn = dataFlowsIn; }
protected override void AnalyzeBoundNodeNullability(BoundNode boundRoot, Binder binder, DiagnosticBag diagnostics, bool createSnapshots) { NullableWalker.AnalyzeWithoutRewrite(Compilation, symbol: null, boundRoot, binder, diagnostics, createSnapshots); }
private void EnterStatement(BoundNode boundStatement) { _tempSubstitution.Clear(); }
public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatement localFunc) { var oldSymbol = this.currentSymbol; var localFuncSymbol = localFunc.Symbol; this.currentSymbol = localFuncSymbol; var oldPending = SavePending(); // we do not support branches into a lambda // SPEC: The entry point to a local function is always reachable. // Captured variables are definitely assigned if they are definitely assigned on // all branches into the local function. var savedState = this.State; this.State = this.TopState(); if (!localFunc.WasCompilerGenerated) { EnterParameters(localFuncSymbol.Parameters); } // Captured variables are definitely assigned if they are assigned on // all branches into the local function, so we store all reads from // possibly unassigned captured variables and later report definite // assignment errors if any of the captured variables is not assigned // on a particular branch. // // Assignments to captured variables are also recorded, as calls to local functions // definitely assign captured variables if the variables are definitely assigned at // all branches out of the local function. var usages = GetOrCreateLocalFuncUsages(localFuncSymbol); var oldReads = usages.ReadVars.Clone(); usages.ReadVars.Clear(); var oldPending2 = SavePending(); // If this is an iterator, there's an implicit branch before the first statement // of the function where the enumerable is returned. if (localFuncSymbol.IsIterator) { PendingBranches.Add(new PendingBranch(null, this.State, null)); } VisitAlways(localFunc.Body); RestorePending(oldPending2); // process any forward branches within the lambda body ImmutableArray <PendingBranch> pendingReturns = RemoveReturns(); RestorePending(oldPending); Location location = null; if (!localFuncSymbol.Locations.IsDefaultOrEmpty) { location = localFuncSymbol.Locations[0]; } LeaveParameters(localFuncSymbol.Parameters, localFunc.Syntax, location); // Intersect the state of all branches out of the local function LocalState stateAtReturn = this.State; foreach (PendingBranch pending in pendingReturns) { this.State = pending.State; BoundNode branch = pending.Branch; // Pass the local function identifier as a location if the branch // is null or compiler generated. LeaveParameters(localFuncSymbol.Parameters, branch?.Syntax, branch?.WasCompilerGenerated == false ? null : location); Join(ref stateAtReturn, ref this.State); } // Check for changes to the possibly unassigned and assigned sets // of captured variables if (RecordChangedVars(ref usages.WrittenVars, ref stateAtReturn, ref oldReads, ref usages.ReadVars) && usages.LocalFuncVisited) { // If the sets have changed and we already used the results // of this local function in another computation, the previous // calculations may be invalid. We need to analyze until we // reach a fixed-point. The previous writes are always valid, // so they are stored in usages.WrittenVars, while the reads // may be invalidated by new writes, so we throw the results out. stateChangedAfterUse = true; usages.LocalFuncVisited = false; } this.State = savedState; this.currentSymbol = oldSymbol; return(null); }
private void PopBlock(BoundNode previousBlock) { _currentScope = previousBlock; }
internal static HashSet <Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet <Symbol> unassignedVariables, ImmutableArray <ISymbol> dataFlowsIn) { var walker = new DataFlowsOutWalker(compilation, member, node, firstInRegion, lastInRegion, unassignedVariables, dataFlowsIn); try { bool badRegion = false; var result = walker.Analyze(ref badRegion); #if DEBUG // Assert that DataFlowsOut only contains variables that were assigned to inside the region Debug.Assert(badRegion || !result.Any((variable) => !walker._assignedInside.Contains(variable))); #endif return(badRegion ? new HashSet <Symbol>() : result); } finally { walker.Free(); } }
/// <summary> /// Create the optimized plan for the location of lambda methods and whether scopes need access to parent scopes /// </summary> internal void ComputeLambdaScopesAndFrameCaptures() { LambdaScopes = new Dictionary <MethodSymbol, BoundNode>(ReferenceEqualityComparer.Instance); NeedsParentFrame = new HashSet <BoundNode>(); RemoveUnneededReferences(); foreach (var kvp in CapturedVariablesByLambda) { var lambda = kvp.Key; var capturedVars = kvp.Value; var allCapturedVars = ArrayBuilder <Symbol> .GetInstance(capturedVars.Count); allCapturedVars.AddRange(capturedVars); // If any of the captured variables are local functions we'll need // to add the captured variables of that local function to the current // set. This has the effect of ensuring that if the local function // captures anything "above" the current scope then parent frame // is itself captured (so that the current lambda can call that // local function). foreach (var captured in capturedVars) { var capturedLocalFunction = captured as LocalFunctionSymbol; if (capturedLocalFunction != null) { allCapturedVars.AddRange( CapturedVariablesByLambda[capturedLocalFunction]); } } // get innermost and outermost scopes from which a lambda captures int innermostScopeDepth = -1; BoundNode innermostScope = null; int outermostScopeDepth = int.MaxValue; BoundNode outermostScope = null; foreach (var captured in allCapturedVars) { BoundNode curBlock = null; int curBlockDepth; if (!VariableScope.TryGetValue(captured, out curBlock)) { // this is something that is not defined in a block, like "this" // Since it is defined outside of the method, the depth is -1 curBlockDepth = -1; } else { curBlockDepth = BlockDepth(curBlock); } if (curBlockDepth > innermostScopeDepth) { innermostScopeDepth = curBlockDepth; innermostScope = curBlock; } if (curBlockDepth < outermostScopeDepth) { outermostScopeDepth = curBlockDepth; outermostScope = curBlock; } } allCapturedVars.Free(); // 1) if there is innermost scope, lambda goes there as we cannot go any higher. // 2) scopes in [innermostScope, outermostScope) chain need to have access to the parent scope. // // Example: // if a lambda captures a method's parameter and `this`, // its innermost scope depth is 0 (method locals and parameters) // and outermost scope is -1 // Such lambda will be placed in a closure frame that corresponds to the method's outer block // and this frame will also lift original `this` as a field when created by its parent. // Note that it is completely irrelevant how deeply the lexical scope of the lambda was originally nested. if (innermostScope != null) { LambdaScopes.Add(lambda, innermostScope); // Disable struct closures on methods converted to delegates, as well as on async and iterator methods. var markAsNoStruct = MethodsConvertedToDelegates.Contains(lambda) || lambda.IsAsync || lambda.IsIterator; if (markAsNoStruct) { ScopesThatCantBeStructs.Add(innermostScope); } while (innermostScope != outermostScope) { NeedsParentFrame.Add(innermostScope); ScopeParent.TryGetValue(innermostScope, out innermostScope); if (markAsNoStruct) { ScopesThatCantBeStructs.Add(innermostScope); } } } } }
private DataFlowsOutWalker(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet <Symbol> unassignedVariables, ImmutableArray <ISymbol> dataFlowsIn) : base(compilation, member, node, firstInRegion, lastInRegion, unassignedVariables, trackUnassignments: true) { _dataFlowsIn = dataFlowsIn; }
internal VariablesDeclaredWalker(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion) : base(compilation, member, node, firstInRegion, lastInRegion) { }
public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatement localFunc) { var oldMethodOrLambda = this.currentMethodOrLambda; this.currentMethodOrLambda = localFunc.Symbol; var oldPending = SavePending(); // we do not support branches into a lambda // Local functions don't affect outer state and are analyzed // with everything unassigned and reachable var savedState = this.State; this.State = this.ReachableState(); var usages = GetOrCreateLocalFuncUsages(localFunc.Symbol); var oldReads = usages.ReadVars; usages.ReadVars = BitVector.Empty; if (!localFunc.WasCompilerGenerated) { EnterParameters(localFunc.Symbol.Parameters); } var oldPending2 = SavePending(); VisitAlways(localFunc.Body); RestorePending(oldPending2); // process any forward branches within the lambda body ImmutableArray <PendingBranch> pendingReturns = RemoveReturns(); RestorePending(oldPending); Location location = null; if (!localFunc.Symbol.Locations.IsDefaultOrEmpty) { location = localFunc.Symbol.Locations[0]; } LeaveParameters(localFunc.Symbol.Parameters, localFunc.Syntax, location); LocalState stateAtReturn = this.State; foreach (PendingBranch pending in pendingReturns) { this.State = pending.State; BoundNode branch = pending.Branch; if (branch.Kind == BoundKind.ReturnStatement) { // ensure out parameters are definitely assigned at each return LeaveParameters(localFunc.Symbol.Parameters, branch.Syntax, branch.WasCompilerGenerated ? location : null); IntersectWith(ref stateAtReturn, ref this.State); } else { // other ways of branching out of a lambda are errors, previously reported in control-flow analysis } } // Check for changes to the read and write sets if (RecordChangedVars(ref usages.WrittenVars, ref stateAtReturn.Assigned, ref oldReads, ref usages.ReadVars) && usages.LocalFuncVisited) { stateChangedAfterUse = true; usages.LocalFuncVisited = false; } this.State = savedState; this.currentMethodOrLambda = oldMethodOrLambda; return(null); }
internal static IEnumerable <Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion) { var walker = new VariablesDeclaredWalker(compilation, member, node, firstInRegion, lastInRegion); try { bool badRegion = false; walker.Analyze(ref badRegion); return(badRegion ? SpecializedCollections.EmptyEnumerable <Symbol>() : walker._variablesDeclared); } finally { walker.Free(); } }
internal static (HashSet <Symbol> entry, HashSet <Symbol> exit) Analyze( CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion) { var walker = new DefinitelyAssignedWalker(compilation, member, node, firstInRegion, lastInRegion); try { bool badRegion = false; walker.Analyze(ref badRegion, diagnostics: null); return(badRegion ? (new HashSet <Symbol>(), new HashSet <Symbol>()) : (walker._definitelyAssignedOnEntry, walker._definitelyAssignedOnExit)); } finally { walker.Free(); } }
private BoundNode RewriteLambdaConversion(BoundLambda node) { var wasInExpressionLambda = inExpressionLambda; inExpressionLambda = inExpressionLambda || node.Type.IsExpressionTree(); if (inExpressionLambda) { var newType = VisitType(node.Type); var newBody = (BoundBlock)Visit(node.Body); node = node.Update(node.Symbol, newBody, node.Diagnostics, node.Binder, newType); var result0 = wasInExpressionLambda ? node : ExpressionLambdaRewriter.RewriteLambda(node, CompilationState, Diagnostics); inExpressionLambda = wasInExpressionLambda; return(result0); } NamedTypeSymbol translatedLambdaContainer; BoundNode lambdaScope = null; if (analysis.lambdaScopes.TryGetValue(node.Symbol, out lambdaScope)) { translatedLambdaContainer = frames[lambdaScope]; } else { translatedLambdaContainer = topLevelMethod.ContainingType; } // Move the body of the lambda to a freshly generated synthetic method on its frame. bool lambdaIsStatic = analysis.captures[node.Symbol].IsEmpty(); SynthesizedLambdaMethod generatedMethod = new SynthesizedLambdaMethod(translatedLambdaContainer, topLevelMethod, node, lambdaIsStatic, CompilationState); if (CompilationState.Emitting) { CompilationState.ModuleBuilder.AddCompilerGeneratedDefinition(translatedLambdaContainer, generatedMethod); } for (int i = 0; i < node.Symbol.ParameterCount; i++) { parameterMap.Add(node.Symbol.Parameters[i], generatedMethod.Parameters[i]); } // rewrite the lambda body as the generated method's body var oldMethod = currentMethod; var oldFrameThis = currentFrameThis; var oldTypeParameters = currentTypeParameters; var oldInnermostFramePointer = innermostFramePointer; var oldTypeMap = currentLambdaBodyTypeMap; var oldAddedStatements = addedStatements; var oldAddedLocals = addedLocals; addedStatements = null; addedLocals = null; // switch to the generated method currentMethod = generatedMethod; if (lambdaIsStatic) { // no link from a static lambda to its container innermostFramePointer = currentFrameThis = null; } else { currentFrameThis = generatedMethod.ThisParameter; innermostFramePointer = null; framePointers.TryGetValue(translatedLambdaContainer, out innermostFramePointer); } if (translatedLambdaContainer.OriginalDefinition is LambdaFrame) { currentTypeParameters = translatedLambdaContainer.TypeParameters; currentLambdaBodyTypeMap = (translatedLambdaContainer as LambdaFrame).TypeMap; } else { currentTypeParameters = generatedMethod.TypeParameters; currentLambdaBodyTypeMap = new TypeMap(topLevelMethod.TypeParameters, currentTypeParameters); } var body = AddStatementsIfNeeded((BoundStatement)VisitBlock(node.Body)); CheckLocalsDefined(body); CompilationState.AddGeneratedMethod(generatedMethod, body); // return to the old method currentMethod = oldMethod; currentFrameThis = oldFrameThis; currentTypeParameters = oldTypeParameters; innermostFramePointer = oldInnermostFramePointer; currentLambdaBodyTypeMap = oldTypeMap; addedLocals = oldAddedLocals; addedStatements = oldAddedStatements; // Rewrite the lambda expression (and the enclosing anonymous method conversion) as a delegate creation expression NamedTypeSymbol constructedFrame = (translatedLambdaContainer is LambdaFrame) ? translatedLambdaContainer.ConstructIfGeneric(StaticCast <TypeSymbol> .From(currentTypeParameters)) : translatedLambdaContainer; BoundExpression receiver = lambdaIsStatic ? new BoundTypeExpression(node.Syntax, null, constructedFrame) : FrameOfType(node.Syntax, constructedFrame); MethodSymbol referencedMethod = generatedMethod.AsMember(constructedFrame); if (referencedMethod.IsGenericMethod) { referencedMethod = referencedMethod.Construct(StaticCast <TypeSymbol> .From(currentTypeParameters)); } TypeSymbol type = this.VisitType(node.Type); BoundExpression result = new BoundDelegateCreationExpression( node.Syntax, receiver, referencedMethod, isExtensionMethod: false, type: type); // if the block containing the lambda is not the innermost block, // or the lambda is static, then the lambda object should be cached in its frame. // NOTE: we are not caching static lambdas in static ctors - cannot reuse such cache. var shouldCacheForStaticMethod = lambdaIsStatic && currentMethod.MethodKind != MethodKind.StaticConstructor && !referencedMethod.IsGenericMethod; // NOTE: We require "lambdaScope != null". // We do not want to introduce a field into an actual user's class (not a synthetic frame). var shouldCacheInLoop = lambdaScope != null && lambdaScope != analysis.blockParent[node.Body] && InLoopOrLambda(node.Syntax, lambdaScope.Syntax); if (shouldCacheForStaticMethod || shouldCacheInLoop) { // replace the expression "new Delegate(frame.M)" with "(frame.cache == null) ? (frame.cache = new Delegate(frame.M)) : frame.cache" var F = new SyntheticBoundNodeFactory(currentMethod, node.Syntax, CompilationState, Diagnostics); try { var cacheVariableName = GeneratedNames.MakeLambdaCacheName(CompilationState.GenerateTempNumber()); BoundExpression cacheVariable; if (shouldCacheForStaticMethod || shouldCacheInLoop && translatedLambdaContainer is LambdaFrame) { var cacheVariableType = lambdaIsStatic ? type : (translatedLambdaContainer as LambdaFrame).TypeMap.SubstituteType(type); var cacheField = new SynthesizedFieldSymbol(translatedLambdaContainer, cacheVariableType, cacheVariableName, isPublic: !lambdaIsStatic, isStatic: lambdaIsStatic); CompilationState.ModuleBuilder.AddCompilerGeneratedDefinition(translatedLambdaContainer, cacheField); cacheVariable = F.Field(receiver, cacheField.AsMember(constructedFrame)); //NOTE: the field was added to the unconstructed frame type. } else { // the lambda captures at most the "this" of the enclosing method. We cache its delegate in a local variable. var cacheLocal = F.SynthesizedLocal(type, cacheVariableName); if (addedLocals == null) { addedLocals = ArrayBuilder <LocalSymbol> .GetInstance(); } addedLocals.Add(cacheLocal); if (addedStatements == null) { addedStatements = ArrayBuilder <BoundStatement> .GetInstance(); } cacheVariable = F.Local(cacheLocal); addedStatements.Add(F.Assignment(cacheVariable, F.Null(type))); } result = F.Coalesce(cacheVariable, F.AssignmentExpression(cacheVariable, result)); } catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex) { Diagnostics.Add(ex.Diagnostic); return(new BoundBadExpression(F.Syntax, LookupResultKind.Empty, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundNode>(node), node.Type)); } } return(result); }
/// <summary> /// Introduce a frame around the translation of the given node. /// </summary> /// <param name="node">The node whose translation should be translated to contain a frame</param> /// <param name="frame">The frame for the translated node</param> /// <param name="F">A function that computes the translation of the node. It receives lists of added statements and added symbols</param> /// <returns>The translated statement, as returned from F</returns> private T IntroduceFrame <T>(BoundNode node, LambdaFrame frame, Func <ArrayBuilder <BoundExpression>, ArrayBuilder <LocalSymbol>, T> F) { NamedTypeSymbol frameType = frame.ConstructIfGeneric(StaticCast <TypeSymbol> .From(currentTypeParameters)); LocalSymbol framePointer = new LambdaFrameLocalSymbol(this.topLevelMethod, frameType, CompilationState); CSharpSyntaxNode syntax = node.Syntax; // assign new frame to the frame variable CompilationState.AddGeneratedMethod(frame.Constructor, FlowAnalysisPass.AppendImplicitReturn(Compiler.BindMethodBody(frame.Constructor, null), frame.Constructor)); var prologue = ArrayBuilder <BoundExpression> .GetInstance(); MethodSymbol constructor = frame.Constructor.AsMember(frameType); Debug.Assert(frameType == constructor.ContainingType); var newFrame = new BoundObjectCreationExpression( syntax: syntax, constructor: constructor); prologue.Add(new BoundAssignmentOperator(syntax, new BoundLocal(syntax, framePointer, null, frameType), newFrame, frameType)); CapturedSymbolReplacement oldInnermostFrameProxy = null; if ((object)innermostFramePointer != null) { proxies.TryGetValue(innermostFramePointer, out oldInnermostFrameProxy); if (analysis.needsParentFrame.Contains(node)) { var capturedFrame = new LambdaCapturedVariable(frame, innermostFramePointer); FieldSymbol frameParent = capturedFrame.AsMember(frameType); BoundExpression left = new BoundFieldAccess(syntax, new BoundLocal(syntax, framePointer, null, frameType), frameParent, null); BoundExpression right = FrameOfType(syntax, frameParent.Type as NamedTypeSymbol); BoundExpression assignment = new BoundAssignmentOperator(syntax, left, right, left.Type); if (this.currentMethod.MethodKind == MethodKind.Constructor && capturedFrame.Type == this.currentMethod.ContainingType && !this.seenBaseCall) { // Containing method is a constructor // Initialization statement for the "this" proxy must be inserted // after the constructor initializer statement block // This insertion will be done by the delegate F Debug.Assert(thisProxyInitDeferred == null); thisProxyInitDeferred = assignment; } else { prologue.Add(assignment); } if (CompilationState.Emitting) { CompilationState.ModuleBuilder.AddCompilerGeneratedDefinition(frame, capturedFrame); } proxies[innermostFramePointer] = new CapturedToFrameSymbolReplacement(capturedFrame); } } // Capture any parameters of this block. This would typically occur // at the top level of a method or lambda with captured parameters, or in a catch block. // TODO: speed up the following by computing it in analysis. foreach (var p in analysis.variablesCaptured) { BoundNode varNode; if (!analysis.variableBlock.TryGetValue(p, out varNode) || varNode != node || analysis.declaredInsideExpressionLambda.Contains(p)) { continue; } if (p is ParameterSymbol) { InitParameterProxy(syntax, p, framePointer, prologue); continue; } } Symbol oldInnermostFramePointer = innermostFramePointer; innermostFramePointer = framePointer; var addedLocals = ArrayBuilder <LocalSymbol> .GetInstance(); addedLocals.Add(framePointer); framePointers.Add(frame, framePointer); var result = F(prologue, addedLocals); framePointers.Remove(frame); innermostFramePointer = oldInnermostFramePointer; if ((object)innermostFramePointer != null) { if (oldInnermostFrameProxy != null) { proxies[innermostFramePointer] = oldInnermostFrameProxy; } else { proxies.Remove(innermostFramePointer); } } return(result); }
/// <summary> /// Check that the top-level node is well-defined, in the sense that all /// locals that are used are defined in some enclosing scope. /// </summary> /// <param name="node"></param> static partial void CheckLocalsDefined(BoundNode node);
private ParameterSymbol Param(BoundNode node) { switch (node.Kind) { case BoundKind.Parameter: return ((BoundParameter)node).ParameterSymbol; case BoundKind.ThisReference: return this.MethodThisParameter; default: return null; } }
/// <summary> /// Ensure that local variables are always in scope where used in bound trees /// </summary> /// <param name="node"></param> static partial void CheckLocalsDefined(BoundNode node) { LocalsDefinedScanner.INSTANCE.Visit(node); }
internal static HashSet <Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, bool convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = false) { var walker = new UnassignedVariablesWalker(compilation, member, node); if (convertInsufficientExecutionStackExceptionToCancelledByStackGuardException) { walker._convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = true; } try { bool badRegion = false; var result = walker.Analyze(ref badRegion); return(badRegion ? new HashSet <Symbol>() : result); } finally { walker.Free(); } }
internal static HashSet <Symbol> Analyze(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet <Symbol> unassignedVariables, HashSet <PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes, out bool?succeeded) { var walker = new DataFlowsInWalker(compilation, member, node, firstInRegion, lastInRegion, unassignedVariables, unassignedVariableAddressOfSyntaxes); try { bool badRegion = false; var result = walker.Analyze(ref badRegion); succeeded = !badRegion; return(badRegion ? new HashSet <Symbol>() : result); } finally { walker.Free(); } }