| File: FlowAnalysis\DataFlowsInWalker.cs | Web Access |
| Project: src\roslyn\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using System.Collections.Generic; using System.Diagnostics; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.CSharp { /// <summary> /// A region analysis walker that computes the set of variables whose values flow into (are used /// in) the region. A variable assigned outside is used inside if an analysis that leaves the /// variable unassigned on entry to the region would cause the generation of "unassigned" errors /// within the region. /// </summary> internal class DataFlowsInWalker : AbstractRegionDataFlowPass { // TODO: normalize the result by removing variables that are unassigned in an unmodified // flow analysis. private readonly HashSet<Symbol> _dataFlowsIn = new HashSet<Symbol>(); private DataFlowsInWalker(CSharpCompilation compilation, Symbol member, BoundNode node, BoundNode firstInRegion, BoundNode lastInRegion, HashSet<Symbol> unassignedVariables, HashSet<PrefixUnaryExpressionSyntax> unassignedVariableAddressOfSyntaxes) : base(compilation, member, node, firstInRegion, lastInRegion, unassignedVariables, unassignedVariableAddressOfSyntaxes) { } 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(); } } private HashSet<Symbol> Analyze(ref bool badRegion) { base.Analyze(ref badRegion, null); return _dataFlowsIn; } protected override LocalState TopState() { return new LocalState(BitVector.Empty); } private LocalState ResetState(LocalState state) { bool unreachable = !state.Reachable; state = TopState(); if (unreachable) { state.Assign(0); } return state; } protected override void EnterRegion() { this.State = ResetState(this.State); _dataFlowsIn.Clear(); base.EnterRegion(); } 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); } public override BoundNode VisitRangeVariable(BoundRangeVariable node) { if (IsInside && !RegionContains(node.RangeVariableSymbol.GetFirstLocation().SourceSpan)) { _dataFlowsIn.Add(node.RangeVariableSymbol); } return null; } protected override void ReportUnassigned(Symbol symbol, SyntaxNode node, int slot, bool skipIfUseBeforeDeclaration) { // TODO: how to handle fields of structs? if (RegionContains(node.Span)) { // if the field access is reported as unassigned it should mean the original local // or parameter flows in, so we should get the symbol associated with the expression _dataFlowsIn.Add(symbol.Kind == SymbolKind.Field ? GetNonMemberSymbol(slot) : symbol); } base.ReportUnassigned(symbol, node, slot, skipIfUseBeforeDeclaration); } protected override void ReportUnassignedOutParameter( ParameterSymbol parameter, SyntaxNode node, Location location) { if (node != null && node is ReturnStatementSyntax && RegionContains(node.Span)) { _dataFlowsIn.Add(parameter); } base.ReportUnassignedOutParameter(parameter, node, location); } } }