| File: Analysis\FlowAnalysis\ControlFlowPass.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 Imports System.Collections.Generic Imports System.Linq Imports System.Text Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic Partial Friend Class ControlFlowPass Inherits AbstractFlowPass(Of LocalState) Protected _convertInsufficientExecutionStackExceptionToCancelledByStackGuardException As Boolean = False ' By default, just let the original exception to bubble up. Friend Sub New(info As FlowAnalysisInfo, suppressConstExpressionsSupport As Boolean) MyBase.New(info, suppressConstExpressionsSupport) End Sub Friend Sub New(info As FlowAnalysisInfo, region As FlowAnalysisRegionInfo, suppressConstantExpressionsSupport As Boolean) MyBase.New(info, region, suppressConstantExpressionsSupport, False) End Sub Protected Overrides Function ReachableState() As LocalState Return New LocalState(True, False) End Function Protected Overrides Function UnreachableState() As LocalState Return New LocalState(False, Me.State.Reported) End Function Protected Overrides Sub Visit(node As BoundNode, dontLeaveRegion As Boolean) ' Expressions must be visited if regions can be on expression boundaries. If Not (TypeOf node Is BoundExpression) Then MyBase.Visit(node, dontLeaveRegion) End If End Sub ''' <summary> ''' Perform control flow analysis, reporting all necessary diagnostics. Returns true if the end of ''' the body might be reachable.. ''' </summary> ''' <param name = "diagnostics"></param> ''' <returns></returns> Public Overloads Shared Function Analyze(info As FlowAnalysisInfo, diagnostics As DiagnosticBag, suppressConstantExpressionsSupport As Boolean) As Boolean Dim walker = New ControlFlowPass(info, suppressConstantExpressionsSupport) If diagnostics IsNot Nothing Then walker._convertInsufficientExecutionStackExceptionToCancelledByStackGuardException = True End If Try walker.Analyze() If diagnostics IsNot Nothing Then diagnostics.AddRange(walker.diagnostics) End If Return walker.State.Alive Catch ex As CancelledByStackGuardException When diagnostics IsNot Nothing ex.AddAnError(diagnostics) Return True Finally walker.Free() End Try End Function Protected Overrides Function ConvertInsufficientExecutionStackExceptionToCancelledByStackGuardException() As Boolean Return _convertInsufficientExecutionStackExceptionToCancelledByStackGuardException End Function Protected Overrides Sub VisitStatement(statement As BoundStatement) Select Case statement.Kind Case BoundKind.LabelStatement, BoundKind.NoOpStatement, BoundKind.Block Case Else If Not Me.State.Alive AndAlso Not Me.State.Reported Then Select Case statement.Kind Case BoundKind.LocalDeclaration ' Declarations by themselves are not executable. Only report one as unreachable if it has an initializer. Dim decl = TryCast(statement, BoundLocalDeclaration) If decl.InitializerOpt IsNot Nothing Then ' TODO: uncomment the following line 'Me.diagnostics.Add(ERRID.WRN_UnreachableCode, decl.InitializerOpt.Syntax.GetLocation()) Me.State.Reported = True End If Case BoundKind.ReturnStatement ' VB always adds a return at the end of all methods. It may end up being ' marked as unreachable if the code has an explicit return in it. The final return is ' always reachable because all returns jump to the final synthetic return. Dim returnStmt = TryCast(statement, BoundReturnStatement) If Not returnStmt.IsEndOfMethodReturn Then ' TODO: uncomment the following line 'Me.diagnostics.Add(ERRID.WRN_UnreachableCode, statement.Syntax.GetLocation()) Me.State.Reported = True End If Case BoundKind.DimStatement ' Don't report anything, warnings will be reported when ' declarations inside this Dim statement are processed Case Else ' TODO: uncomment the following line 'Me.diagnostics.Add(ERRID.WRN_UnreachableCode, statement.Syntax.GetLocation()) Me.State.Reported = True End Select End If End Select MyBase.VisitStatement(statement) End Sub Protected Overrides Sub VisitTryBlock(tryBlock As BoundStatement, node As BoundTryStatement, ByRef tryState As LocalState) If node.CatchBlocks.IsEmpty Then MyBase.VisitTryBlock(tryBlock, node, tryState) Else Dim oldPendings As SavedPending = Me.SavePending() MyBase.VisitTryBlock(tryBlock, node, tryState) ' NOTE: C# generates errors for 'yield return' inside try statement here; ' it is valid in VB though. Me.RestorePending(oldPendings, mergeLabelsSeen:=True) End If End Sub Protected Overrides Sub VisitCatchBlock(node As BoundCatchBlock, ByRef finallyState As LocalState) Dim oldPendings As SavedPending = Me.SavePending() MyBase.VisitCatchBlock(node, finallyState) For Each branch In Me.PendingBranches if branch.Branch.Kind = BoundKind.YieldStatement Me.diagnostics.Add(ERRID.ERR_BadYieldInTryHandler, branch.Branch.Syntax.GetLocation) End If Next ' NOTE: VB generates error ERR_GotoIntoTryHandler in binding, but ' we still want to 'nest' pendings' state for catch statements Me.RestorePending(oldPendings) End Sub Protected Overrides Sub VisitFinallyBlock(finallyBlock As BoundStatement, ByRef endState As LocalState) Dim oldPending1 As SavedPending = SavePending() ' we do not support branches into a finally block Dim oldPending2 As SavedPending = SavePending() ' track only the branches out of the finally block MyBase.VisitFinallyBlock(finallyBlock, endState) RestorePending(oldPending2) ' resolve branches that remain within the finally block For Each branch In Me.PendingBranches Dim syntax = branch.Branch.Syntax Dim errorLocation As SyntaxNodeOrToken Dim errId As ERRID If branch.Branch.Kind = BoundKind.YieldStatement errId = errId.ERR_BadYieldInTryHandler errorLocation = syntax else errId = errId.ERR_BranchOutOfFinally If syntax.Kind = SyntaxKind.GoToStatement Then errorLocation = DirectCast(syntax, GoToStatementSyntax).Label Else errorLocation = syntax End If End If Me.diagnostics.Add(errId, errorLocation.GetLocation()) Next RestorePending(oldPending1) End Sub End Class End Namespace