| File: Analysis\FlowAnalysis\DataFlowsInWalker.vb | Web Access |
| Project: src\roslyn\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.VisualBasic) |
' 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. Imports System.Collections.Generic Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic ''' <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> Friend Class DataFlowsInWalker Inherits AbstractRegionDataFlowPass ' TODO: normalize the result by removing variables that are unassigned in an unmodified flow analysis. Private Sub New(info As FlowAnalysisInfo, region As FlowAnalysisRegionInfo, unassignedVariables As HashSet(Of Symbol)) MyBase.New(info, region, unassignedVariables, trackStructsWithIntrinsicTypedFields:=True) End Sub Friend Overloads Shared Function Analyze(info As FlowAnalysisInfo, region As FlowAnalysisRegionInfo, unassignedVariables As HashSet(Of Symbol), ByRef succeeded As Boolean?, ByRef invalidRegionDetected As Boolean) As HashSet(Of Symbol) ' remove static locals from unassigned, otherwise they will never reach ReportUnassigned(...) Dim unassignedWithoutStatic As New HashSet(Of Symbol) For Each var In unassignedVariables If var.Kind <> SymbolKind.Local OrElse Not DirectCast(var, LocalSymbol).IsStatic Then unassignedWithoutStatic.Add(var) End If Next Dim walker = New DataFlowsInWalker(info, region, unassignedWithoutStatic) Try succeeded = walker.Analyze() AndAlso Not walker.InvalidRegionDetected invalidRegionDetected = walker.InvalidRegionDetected Return If(succeeded, walker._dataFlowsIn, New HashSet(Of Symbol)()) Finally walker.Free() End Try End Function Private ReadOnly _dataFlowsIn As HashSet(Of Symbol) = New HashSet(Of Symbol)() Private Function ResetState(state As LocalState) As LocalState Dim unreachable As Boolean = Not state.Reachable state = ReachableState() If unreachable Then state.Assign(0) End If Return state End Function Protected Overrides Sub EnterRegion() Me.SetState(ResetState(Me.State)) Me._dataFlowsIn.Clear() MyBase.EnterRegion() End Sub Protected Overrides Sub NoteBranch(pending As PendingBranch, stmt As BoundStatement, labelStmt As BoundLabelStatement) If stmt.Syntax IsNot Nothing AndAlso labelStmt.Syntax IsNot Nothing AndAlso Not IsInsideRegion(stmt.Syntax.Span) AndAlso IsInsideRegion(labelStmt.Syntax.Span) Then pending.State = ResetState(pending.State) End If MyBase.NoteBranch(pending, stmt, labelStmt) End Sub Public Overrides Function VisitRangeVariable(node As BoundRangeVariable) As BoundNode ' Sometimes query expressions refer to query range variable just to ' copy its value to a new compound variable. There is no reference ' to the range variable in code and, from user point of view, there is ' no access to it. ' If and only if range variable is declared outside of the region and read inside, it flows in. If Not node.WasCompilerGenerated AndAlso IsInside AndAlso Not IsInsideRegion(node.RangeVariable.Syntax.Span) Then _dataFlowsIn.Add(node.RangeVariable) End If Return Nothing End Function Protected Overrides Sub VisitAmbiguousLocalSymbol(ambiguous As DataFlowPass.AmbiguousLocalsPseudoSymbol) MyBase.VisitAmbiguousLocalSymbol(ambiguous) ' Locals from ambiguous implicit receiver can only be unassigned in *REGION* flow analysis ' if a new region starts after they are declared and before the implicit receiver is referenced; ' region data flow analysis for such regions is prohibited and should return Succeeded = False. ' Check if the first local in the collection was 'unassigned' by entering a region, ' in which case set a flag that the region is not valid If IsInside Then Dim firstLocal As LocalSymbol = ambiguous.Locals(0) If Not Me.State.IsAssigned(VariableSlot(firstLocal)) Then Me.SetInvalidRegion() End If End If End Sub Protected Overrides Sub ReportUnassigned(local As Symbol, node As SyntaxNode, rwContext As ReadWriteContext, Optional slot As Integer = SlotKind.NotTracked, Optional boundFieldAccess As BoundFieldAccess = Nothing) Debug.Assert(local.Kind <> SymbolKind.Field OrElse boundFieldAccess IsNot Nothing) If IsInsideRegion(node.Span) Then Debug.Assert(local.Kind <> SymbolKind.RangeVariable) If local.Kind = SymbolKind.Field Then Dim sym As Symbol = GetNodeSymbol(boundFieldAccess) ' Unreachable for AmbiguousLocalsPseudoSymbol: ambiguous implicit ' receiver should not ever be considered unassigned Debug.Assert(Not TypeOf sym Is AmbiguousLocalsPseudoSymbol) If sym IsNot Nothing Then _dataFlowsIn.Add(sym) End If Else _dataFlowsIn.Add(local) End If End If MyBase.ReportUnassigned(local, node, rwContext, slot, boundFieldAccess) End Sub Friend Overrides Sub AssignLocalOnDeclaration(local As LocalSymbol, node As BoundLocalDeclaration) ' NOTE: static locals should not be considered assigned even in presence of initializer If Not local.IsStatic Then MyBase.AssignLocalOnDeclaration(local, node) End If End Sub End Class End Namespace