/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Lowering/LocalRewriter/LocalRewriter_UnstructuredExceptionHandling.vb
620 строк
37 KB
Julien Couvreur
Warn for multiple blank lines in source (#65451)
17 ноя 2022, 22:55
Не верифицирован
17 ноя 2022, 22:55
a8824e8
Код
Авторство
О чём код?
' 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.Immutable Imports System.Diagnostics Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports TypeKind = Microsoft.CodeAnalysis.TypeKind Namespace Microsoft.CodeAnalysis.VisualBasic Partial Friend Class LocalRewriter Private Const s_activeHandler_None As Integer = 0 Private Const s_activeHandler_ResumeNext As Integer = 1 Private Const s_activeHandler_FirstNonReservedOnErrorGotoIndex As Integer = 2 Private Const s_activeHandler_FirstOnErrorResumeNextIndex As Integer = -2 Private Structure UnstructuredExceptionHandlingState Public Context As BoundUnstructuredExceptionHandlingStatement Public ExceptionHandlers As ArrayBuilder(Of BoundGotoStatement) Public ResumeTargets As ArrayBuilder(Of BoundGotoStatement) Public OnErrorResumeNextCount As Integer Public ActiveHandlerTemporary As LocalSymbol Public ResumeTargetTemporary As LocalSymbol Public CurrentStatementTemporary As LocalSymbol Public ResumeNextLabel As LabelSymbol Public ResumeLabel As LabelSymbol End Structure Public Overrides Function VisitUnstructuredExceptionHandlingStatement(node As BoundUnstructuredExceptionHandlingStatement) As BoundNode Debug.Assert(_currentLineTemporary Is Nothing) If Not node.TrackLineNumber Then Return RewriteUnstructuredExceptionHandlingStatementIntoBlock(node) End If Dim nodeFactory As New SyntheticBoundNodeFactory(_topMethod, _currentMethodOrLambda, node.Syntax, _compilationState, _diagnostics) Dim int32 = nodeFactory.SpecialType(SpecialType.System_Int32) _currentLineTemporary = New SynthesizedLocal(_topMethod, int32, SynthesizedLocalKind.OnErrorCurrentLine, DirectCast(nodeFactory.Syntax, StatementSyntax)) Dim body As BoundBlock If node.ContainsOnError OrElse node.ContainsResume Then body = RewriteUnstructuredExceptionHandlingStatementIntoBlock(node) Else body = DirectCast(VisitBlock(node.Body), BoundBlock) End If body = body.Update(body.StatementListSyntax, If(body.Locals.IsEmpty, ImmutableArray.Create(Of LocalSymbol)(_currentLineTemporary), body.Locals.Add(_currentLineTemporary)), body.Statements) _currentLineTemporary = Nothing Return body End Function Private Function RewriteUnstructuredExceptionHandlingStatementIntoBlock(node As BoundUnstructuredExceptionHandlingStatement) As BoundBlock Debug.Assert(node.ContainsOnError OrElse node.ContainsResume) Debug.Assert(_unstructuredExceptionHandling.Context Is Nothing) Debug.Assert(_unstructuredExceptionHandling.ExceptionHandlers Is Nothing) Debug.Assert(_unstructuredExceptionHandling.ResumeTargets Is Nothing) Debug.Assert(_unstructuredExceptionHandling.OnErrorResumeNextCount = 0) Debug.Assert(_unstructuredExceptionHandling.ActiveHandlerTemporary Is Nothing) Debug.Assert(_unstructuredExceptionHandling.ResumeTargetTemporary Is Nothing) Debug.Assert(_unstructuredExceptionHandling.CurrentStatementTemporary Is Nothing) Debug.Assert(_unstructuredExceptionHandling.ResumeNextLabel Is Nothing) Debug.Assert(_unstructuredExceptionHandling.ResumeLabel Is Nothing) Debug.Assert(_currentMethodOrLambda Is _topMethod) ' We should emit code that is equivalent to the following: '----------------------------------------------------------------------- ' Dim VB$ActiveHandler As Integer ' Dim VB$ResumeTarget As Integer ' Dim VB$CurrentStatement As Integer ' ' Try ' <Body> ' Goto Done ' ' ResumeSwitch: ' Destination of ResumeNext and Resume jumps ' Select Case If(<Resume>, VB$ResumeTarget, VB$ResumeTarget + 1) ' Case 0: ' Goto ResumeSwitchFallThrough ' Case 1: ' Goto <resume target #1> ' ... ' End Select ' ' ResumeSwitchFallThrough: ' Goto OnErrorFailure ' ' OnError: ' VB$ResumeTarget = VB$CurrentStatement ' ' Select Case VB$ActiveHandler ' Case 0: ' Goto OnErrorSwitchFallThrough ' Case 1: ' Goto ResumeNext ' Case 2: ' Goto <OnError Handler #1> ' ... ' End Select ' ' OnErrorSwitchFallThrough: ' Goto OnErrorFailure ' ' Catch e As Exception When (VB$ActiveHandler <> 0) And (VB$ResumeTarget = 0) ' Microsoft.VisualBasic.CompilerServices.ProjectData.SetProjectError(e) ' Goto OnError ' End Try ' ' OnErrorFailure: ' Throw Microsoft.VisualBasic.CompilerServices.ProjectData.CreateProjectError(&H800A0033) ' ' Done: ' If VB$ResumeTarget <> 0 ' Microsoft.VisualBasic.CompilerServices.ProjectData.ClearProjectError() ' End If '----------------------------------------------------------------------- ' ' When a resumable statement is rewritten, code that changes VB$CurrentStatement local is ' injected before it and corresponding resume target is registered in unstructuredExceptionHandling.ResumeTargets. ' ' When [On Error] statement is rewritten, code that changes VB$ActiveHandler local is injected and corresponding ' handler is registered in unstructuredExceptionHandling.ExceptionHandlers. Dim locals = ArrayBuilder(Of LocalSymbol).GetInstance() _unstructuredExceptionHandling.Context = node _unstructuredExceptionHandling.ExceptionHandlers = ArrayBuilder(Of BoundGotoStatement).GetInstance() _unstructuredExceptionHandling.OnErrorResumeNextCount = 0 Dim nodeFactory As New SyntheticBoundNodeFactory(_topMethod, _currentMethodOrLambda, node.Syntax, _compilationState, _diagnostics) Dim int32 = nodeFactory.SpecialType(SpecialType.System_Int32) Dim bool = nodeFactory.SpecialType(SpecialType.System_Boolean) _unstructuredExceptionHandling.ActiveHandlerTemporary = New SynthesizedLocal(_topMethod, int32, SynthesizedLocalKind.OnErrorActiveHandler, DirectCast(nodeFactory.Syntax, StatementSyntax)) locals.Add(_unstructuredExceptionHandling.ActiveHandlerTemporary) _unstructuredExceptionHandling.ResumeTargetTemporary = New SynthesizedLocal(_topMethod, int32, SynthesizedLocalKind.OnErrorResumeTarget, DirectCast(nodeFactory.Syntax, StatementSyntax)) locals.Add(_unstructuredExceptionHandling.ResumeTargetTemporary) If node.ResumeWithoutLabelOpt IsNot Nothing Then _unstructuredExceptionHandling.CurrentStatementTemporary = New SynthesizedLocal(_topMethod, int32, SynthesizedLocalKind.OnErrorCurrentStatement, DirectCast(nodeFactory.Syntax, StatementSyntax)) locals.Add(_unstructuredExceptionHandling.CurrentStatementTemporary) _unstructuredExceptionHandling.ResumeNextLabel = New GeneratedLabelSymbol("$VB$UnstructuredExceptionHandling_ResumeNext") _unstructuredExceptionHandling.ResumeLabel = New GeneratedLabelSymbol("$VB$UnstructuredExceptionHandling_Resume") _unstructuredExceptionHandling.ResumeTargets = ArrayBuilder(Of BoundGotoStatement).GetInstance() End If Dim statements = ArrayBuilder(Of BoundStatement).GetInstance() ' Rewrite the body. statements.Add(DirectCast(Visit(node.Body), BoundBlock)) ' We reach this statement if there were no exceptions. If Instrument Then statements.Add(SyntheticBoundNodeFactory.HiddenSequencePoint()) End If If _unstructuredExceptionHandling.CurrentStatementTemporary IsNot Nothing Then RegisterUnstructuredExceptionHandlingResumeTarget(node.Syntax, False, statements) End If Dim doneLabel = New GeneratedLabelSymbol("$VB$UnstructuredExceptionHandling_Done") statements.Add(nodeFactory.Goto(doneLabel)) Dim onErrorFailureLabel = New GeneratedLabelSymbol("$VB$UnstructuredExceptionHandling_OnErrorFailure") If node.ResumeWithoutLabelOpt IsNot Nothing Then Dim resumeSwitchFallThroughLabel = New GeneratedLabelSymbol("$VB$UnstructuredExceptionHandling_ResumeSwitchFallThrough") Dim resumeSwitchJumps(1 + _unstructuredExceptionHandling.ResumeTargets.Count - 1) As BoundGotoStatement ' The 0th Resume table entry falls through and ' branches to failure because the ResumeTarget should never be 0. resumeSwitchJumps(s_activeHandler_None) = nodeFactory.Goto(resumeSwitchFallThroughLabel) For i As Integer = 0 To _unstructuredExceptionHandling.ResumeTargets.Count - 1 resumeSwitchJumps(i + 1) = _unstructuredExceptionHandling.ResumeTargets(i) Next statements.Add(New BoundUnstructuredExceptionResumeSwitch(node.Syntax, nodeFactory.Local(_unstructuredExceptionHandling.ResumeTargetTemporary, isLValue:=False), nodeFactory.Label(_unstructuredExceptionHandling.ResumeLabel), nodeFactory.Label(_unstructuredExceptionHandling.ResumeNextLabel), resumeSwitchJumps.AsImmutableOrNull())) ' The fall through case will branch to On Error Failure which throws an internal error exception. ' Should never get here at runtime unless something has gone wrong. statements.Add(nodeFactory.Label(resumeSwitchFallThroughLabel)) statements.Add(nodeFactory.Goto(onErrorFailureLabel)) End If Dim onErrorLabel = New GeneratedLabelSymbol("$VB$UnstructuredExceptionHandling_OnError") statements.Add(nodeFactory.Label(onErrorLabel)) ' Remember the current resume target. ' If we are not keeping track of the current line, then just ' store a non-zero into resumeTargetTemporary so we know we're in a ' handler. Otherwise, store the current line into the resume local ' so we know where to resume and to indicate that we're currently ' in a handler. ' statements.Add(nodeFactory.AssignmentExpression(nodeFactory.Local(_unstructuredExceptionHandling.ResumeTargetTemporary, isLValue:=True), If(_unstructuredExceptionHandling.CurrentStatementTemporary Is Nothing, DirectCast(nodeFactory.Literal(-1), BoundExpression), nodeFactory.Local(_unstructuredExceptionHandling.CurrentStatementTemporary, isLValue:=False))).ToStatement()) ' Generate switch that jumps to the active handler Dim onErrorSwitchFallThroughLabel = New GeneratedLabelSymbol("$VB$UnstructuredExceptionHandling_OnErrorSwitchFallThrough") Dim onErrorSwitchJumps(2 + _unstructuredExceptionHandling.ExceptionHandlers.Count - 1) As BoundGotoStatement onErrorSwitchJumps(s_activeHandler_None) = nodeFactory.Goto(onErrorSwitchFallThroughLabel) onErrorSwitchJumps(s_activeHandler_ResumeNext) = nodeFactory.Goto(If(node.ResumeWithoutLabelOpt IsNot Nothing, _unstructuredExceptionHandling.ResumeNextLabel, onErrorSwitchFallThroughLabel)) For i As Integer = 0 To _unstructuredExceptionHandling.ExceptionHandlers.Count - 1 onErrorSwitchJumps(s_activeHandler_FirstNonReservedOnErrorGotoIndex + i) = _unstructuredExceptionHandling.ExceptionHandlers(i) Next ' When resume is present and we are not optimizing: ' Determine if the handler index is less than or equal to -2 (ActiveHandler_FirstOnErrorResumeNextIndex): ' If so, replace it with ActiveHandler_ResumeNext and jump to the switch. statements.Add(New BoundUnstructuredExceptionOnErrorSwitch(node.Syntax, If(node.ResumeWithoutLabelOpt IsNot Nothing AndAlso OptimizationLevelIsDebug, nodeFactory.Conditional(nodeFactory.Binary(BinaryOperatorKind.GreaterThan, bool, nodeFactory.Local(_unstructuredExceptionHandling.ActiveHandlerTemporary, isLValue:=False), nodeFactory.Literal(s_activeHandler_FirstOnErrorResumeNextIndex)), nodeFactory.Local(_unstructuredExceptionHandling.ActiveHandlerTemporary, isLValue:=False), nodeFactory.Literal(s_activeHandler_ResumeNext), int32), DirectCast(nodeFactory.Local(_unstructuredExceptionHandling.ActiveHandlerTemporary, isLValue:=False), BoundExpression)), onErrorSwitchJumps.AsImmutableOrNull())) ' Something has gone wrong with the On Error mechanism if execution ' makes it here. Branch to the Failure block which will throw an internal ' error exception. statements.Add(nodeFactory.Label(onErrorSwitchFallThroughLabel)) statements.Add(nodeFactory.Goto(onErrorFailureLabel)) ' Done with content of the try block. Dim tryBlock = nodeFactory.Block(statements.ToImmutable()) statements.Clear() statements.Add(RewriteTryStatement( node.Syntax, tryBlock, ImmutableArray.Create(New BoundCatchBlock( node.Syntax, Nothing, Nothing, If(_currentLineTemporary IsNot Nothing, New BoundLocal(node.Syntax, _currentLineTemporary, isLValue:=False, type:=_currentLineTemporary.Type), Nothing), New BoundUnstructuredExceptionHandlingCatchFilter(node.Syntax, nodeFactory.Local(_unstructuredExceptionHandling.ActiveHandlerTemporary, isLValue:=False), nodeFactory.Local(_unstructuredExceptionHandling.ResumeTargetTemporary, isLValue:=False), bool), nodeFactory.Block(ImmutableArray.Create(Of BoundStatement)(nodeFactory.Goto(onErrorLabel))), isSynthesizedAsyncCatchAll:=False)), Nothing, Nothing)) ' Something has gone wrong with the On Error mechanism if execution ' makes it here. statements.Add(nodeFactory.Label(onErrorFailureLabel)) Dim createProjectError As MethodSymbol = nodeFactory.WellKnownMember(Of MethodSymbol)(WellKnownMember.Microsoft_VisualBasic_CompilerServices_ProjectData__CreateProjectError) If createProjectError IsNot Nothing Then Const E_INTERNALERROR As Integer = &H800A0033 ' 51 statements.Add(nodeFactory.Throw(New BoundCall(node.Syntax, createProjectError, Nothing, Nothing, ImmutableArray.Create(Of BoundExpression)(nodeFactory.Literal(E_INTERNALERROR)), Nothing, createProjectError.ReturnType))) End If statements.Add(nodeFactory.Label(doneLabel)) ' Upon exiting the method, the Err object is cleared, but only if an error has occurred and it ' has not been "handled" (i.e., a resume, resume next, or On Error Goto -1 has not been encountered). ' Generate a check of the resume local; if it's non-zero, then clear the Err object. Dim clearProjectError As MethodSymbol = nodeFactory.WellKnownMember(Of MethodSymbol)(WellKnownMember.Microsoft_VisualBasic_CompilerServices_ProjectData__ClearProjectError) If clearProjectError IsNot Nothing Then statements.Add(RewriteIfStatement(node.Syntax, nodeFactory.Binary(BinaryOperatorKind.NotEquals, bool, nodeFactory.Local(_unstructuredExceptionHandling.ResumeTargetTemporary, isLValue:=False), nodeFactory.Literal(0)), New BoundCall(node.Syntax, clearProjectError, Nothing, Nothing, ImmutableArray(Of BoundExpression).Empty, Nothing, clearProjectError.ReturnType).ToStatement(), Nothing, instrumentationTargetOpt:=Nothing)) End If _unstructuredExceptionHandling.Context = Nothing _unstructuredExceptionHandling.ExceptionHandlers.Free() _unstructuredExceptionHandling.ExceptionHandlers = Nothing If _unstructuredExceptionHandling.ResumeTargets IsNot Nothing Then _unstructuredExceptionHandling.ResumeTargets.Free() _unstructuredExceptionHandling.ResumeTargets = Nothing End If _unstructuredExceptionHandling.ActiveHandlerTemporary = Nothing _unstructuredExceptionHandling.ResumeTargetTemporary = Nothing _unstructuredExceptionHandling.CurrentStatementTemporary = Nothing _unstructuredExceptionHandling.ResumeNextLabel = Nothing _unstructuredExceptionHandling.ResumeLabel = Nothing _unstructuredExceptionHandling.OnErrorResumeNextCount = 0 Return nodeFactory.Block(locals.ToImmutableAndFree(), statements.ToImmutableAndFree()) End Function Public Overrides Function VisitOnErrorStatement(node As BoundOnErrorStatement) As BoundNode Dim nodeFactory As New SyntheticBoundNodeFactory(_topMethod, _currentMethodOrLambda, node.Syntax, _compilationState, _diagnostics) Dim statements = ArrayBuilder(Of BoundStatement).GetInstance() If ShouldGenerateUnstructuredExceptionHandlingResumeCode(node) Then RegisterUnstructuredExceptionHandlingResumeTarget(node.Syntax, False, statements) End If ' Reset the error object Dim clearProjectError As MethodSymbol = nodeFactory.WellKnownMember(Of MethodSymbol)(WellKnownMember.Microsoft_VisualBasic_CompilerServices_ProjectData__ClearProjectError) If clearProjectError IsNot Nothing Then statements.Add(New BoundCall(node.Syntax, clearProjectError, Nothing, Nothing, ImmutableArray(Of BoundExpression).Empty, Nothing, clearProjectError.ReturnType).ToStatement) End If Dim newErrorHandlerIndex As Integer Select Case node.OnErrorKind Case OnErrorStatementKind.GoToMinusOne ' Undocumented feature. -1 means to reset the handler. So, if ' we're currently in a handler, this instruction resets state ' to normal. statements.Add(nodeFactory.AssignmentExpression(nodeFactory.Local(_unstructuredExceptionHandling.ResumeTargetTemporary, isLValue:=True), nodeFactory.Literal(0)).ToStatement()) GoTo Done Case OnErrorStatementKind.GoToLabel newErrorHandlerIndex = s_activeHandler_FirstNonReservedOnErrorGotoIndex + _unstructuredExceptionHandling.ExceptionHandlers.Count _unstructuredExceptionHandling.ExceptionHandlers.Add(nodeFactory.Goto(node.LabelOpt, setWasCompilerGenerated:=False)) Case OnErrorStatementKind.ResumeNext If OptimizationLevelIsDebug Then newErrorHandlerIndex = s_activeHandler_FirstOnErrorResumeNextIndex - _unstructuredExceptionHandling.OnErrorResumeNextCount Else newErrorHandlerIndex = s_activeHandler_ResumeNext End If _unstructuredExceptionHandling.OnErrorResumeNextCount += 1 Case Else Debug.Assert(node.OnErrorKind = OnErrorStatementKind.GoToZero) newErrorHandlerIndex = s_activeHandler_None End Select statements.Add(nodeFactory.AssignmentExpression(nodeFactory.Local(_unstructuredExceptionHandling.ActiveHandlerTemporary, isLValue:=True), nodeFactory.Literal(newErrorHandlerIndex)).ToStatement()) Done: Debug.Assert(Not node.WasCompilerGenerated) Dim rewritten As BoundStatement = New BoundStatementList(node.Syntax, statements.ToImmutableAndFree()) If Instrument(node, rewritten) Then rewritten = _instrumenterOpt.InstrumentOnErrorStatement(node, rewritten) End If Return rewritten End Function Public Overrides Function VisitResumeStatement(node As BoundResumeStatement) As BoundNode Dim nodeFactory As New SyntheticBoundNodeFactory(_topMethod, _currentMethodOrLambda, node.Syntax, _compilationState, _diagnostics) Dim statements = ArrayBuilder(Of BoundStatement).GetInstance() Dim generateUnstructuredExceptionHandlingResumeCode As Boolean = ShouldGenerateUnstructuredExceptionHandlingResumeCode(node) If generateUnstructuredExceptionHandlingResumeCode Then RegisterUnstructuredExceptionHandlingResumeTarget(node.Syntax, True, statements) End If ' Reset the error object Dim clearProjectError As MethodSymbol = nodeFactory.WellKnownMember(Of MethodSymbol)(WellKnownMember.Microsoft_VisualBasic_CompilerServices_ProjectData__ClearProjectError) If clearProjectError IsNot Nothing Then statements.Add(New BoundCall(node.Syntax, clearProjectError, Nothing, Nothing, ImmutableArray(Of BoundExpression).Empty, Nothing, clearProjectError.ReturnType).ToStatement) End If ' Emit code to check to see if we're in a handler. Compare resumeTargetTemporary against 0. Dim createProjectError As MethodSymbol = nodeFactory.WellKnownMember(Of MethodSymbol)(WellKnownMember.Microsoft_VisualBasic_CompilerServices_ProjectData__CreateProjectError) If createProjectError IsNot Nothing Then Const E_RESUMEWITHOUTERROR As Integer = &H800A0014 ' 20 statements.Add(RewriteIfStatement(node.Syntax, nodeFactory.Binary(BinaryOperatorKind.Equals, nodeFactory.SpecialType(SpecialType.System_Boolean), nodeFactory.Local(_unstructuredExceptionHandling.ResumeTargetTemporary, isLValue:=False), nodeFactory.Literal(0)), nodeFactory.Throw(New BoundCall(node.Syntax, createProjectError, Nothing, Nothing, ImmutableArray.Create(Of BoundExpression)(nodeFactory.Literal(E_RESUMEWITHOUTERROR)), Nothing, createProjectError.ReturnType)), Nothing, instrumentationTargetOpt:=Nothing)) End If ' Now generate code based on what kind of Resume we have Select Case node.ResumeKind Case ResumeStatementKind.Label ' Resume label. Reset resume local statements.Add(nodeFactory.AssignmentExpression(nodeFactory.Local(_unstructuredExceptionHandling.ResumeTargetTemporary, isLValue:=True), nodeFactory.Literal(0)).ToStatement()) If generateUnstructuredExceptionHandlingResumeCode Then RegisterUnstructuredExceptionHandlingResumeTarget(node.Syntax, False, statements) End If statements.Add(nodeFactory.Goto(node.LabelOpt, setWasCompilerGenerated:=False)) Case ResumeStatementKind.Next statements.Add(nodeFactory.Goto(_unstructuredExceptionHandling.ResumeNextLabel)) Case Else Debug.Assert(node.ResumeKind = ResumeStatementKind.Plain) statements.Add(nodeFactory.Goto(_unstructuredExceptionHandling.ResumeLabel)) End Select Debug.Assert(Not node.WasCompilerGenerated) Dim rewritten As BoundStatement = New BoundStatementList(node.Syntax, statements.ToImmutableAndFree()) If Instrument(node, rewritten) Then rewritten = _instrumenterOpt.InstrumentResumeStatement(node, rewritten) End If Return rewritten End Function Private Function AddResumeTargetLabel(syntax As SyntaxNode) As BoundLabelStatement Debug.Assert(InsideValidUnstructuredExceptionHandlingResumeContext()) Dim targetResumeLabel = New GeneratedUnstructuredExceptionHandlingResumeLabel(_unstructuredExceptionHandling.Context.ResumeWithoutLabelOpt) _unstructuredExceptionHandling.ResumeTargets.Add(New BoundGotoStatement(syntax, targetResumeLabel, Nothing)) Return New BoundLabelStatement(syntax, targetResumeLabel) End Function Private Sub AddResumeTargetLabelAndUpdateCurrentStatementTemporary(syntax As SyntaxNode, canThrow As Boolean, statements As ArrayBuilder(Of BoundStatement)) Debug.Assert(InsideValidUnstructuredExceptionHandlingResumeContext()) statements.Add(AddResumeTargetLabel(syntax)) If canThrow Then Dim nodeFactory As New SyntheticBoundNodeFactory(_topMethod, _currentMethodOrLambda, syntax, _compilationState, _diagnostics) statements.Add(nodeFactory.AssignmentExpression(nodeFactory.Local(_unstructuredExceptionHandling.CurrentStatementTemporary, isLValue:=True), nodeFactory.Literal(_unstructuredExceptionHandling.ResumeTargets.Count)).ToStatement()) End If End Sub Private Function ShouldGenerateUnstructuredExceptionHandlingResumeCode(statement As BoundStatement) As Boolean If statement.WasCompilerGenerated Then Return False End If #If Not DEBUG Then If Not InsideValidUnstructuredExceptionHandlingResumeContext() Then Return False End If #End If If Not (TypeOf statement.Syntax Is StatementSyntax) Then If statement.Syntax.Parent IsNot Nothing AndAlso statement.Syntax.Parent.Kind = SyntaxKind.EraseStatement Then Debug.Assert(TypeOf statement.Syntax Is ExpressionSyntax) Else Select Case statement.Syntax.Kind Case SyntaxKind.ElseIfBlock If statement.Kind <> BoundKind.IfStatement Then Return False End If Case SyntaxKind.CaseBlock, SyntaxKind.CaseElseBlock If statement.Kind <> BoundKind.CaseBlock Then Return False End If Case SyntaxKind.ModifiedIdentifier If statement.Kind <> BoundKind.LocalDeclaration OrElse statement.Syntax.Parent Is Nothing OrElse statement.Syntax.Parent.Kind <> SyntaxKind.VariableDeclarator OrElse statement.Syntax.Parent.Parent Is Nothing OrElse statement.Syntax.Parent.Parent.Kind <> SyntaxKind.LocalDeclarationStatement Then Return False End If Case SyntaxKind.RedimClause If statement.Kind <> BoundKind.ExpressionStatement OrElse Not (TypeOf statement.Syntax.Parent Is ReDimStatementSyntax) Then Return False End If Case Else Return False End Select End If End If If TypeOf statement.Syntax Is DeclarationStatementSyntax Then Return False End If #If DEBUG Then If _currentMethodOrLambda Is _topMethod Then If Not (TypeOf statement.Syntax Is ExecutableStatementSyntax) Then Select Case statement.Kind Case BoundKind.IfStatement Debug.Assert(statement.Syntax.Kind = SyntaxKind.ElseIfBlock AndAlso statement.Syntax.Parent IsNot Nothing AndAlso statement.Syntax.Parent.Kind = SyntaxKind.MultiLineIfBlock AndAlso _unstructuredExceptionHandlingResumableStatements.ContainsKey(statement.Syntax.Parent)) Case BoundKind.CaseBlock Debug.Assert((statement.Syntax.Kind = SyntaxKind.CaseBlock OrElse statement.Syntax.Kind = SyntaxKind.CaseElseBlock) AndAlso statement.Syntax.Parent IsNot Nothing AndAlso statement.Syntax.Parent.Kind = SyntaxKind.SelectBlock AndAlso _unstructuredExceptionHandlingResumableStatements.ContainsKey(statement.Syntax.Parent)) Case BoundKind.LocalDeclaration Debug.Assert(statement.Syntax.Kind = SyntaxKind.ModifiedIdentifier AndAlso statement.Syntax.Parent IsNot Nothing AndAlso statement.Syntax.Parent.Kind = SyntaxKind.VariableDeclarator AndAlso statement.Syntax.Parent.Parent IsNot Nothing AndAlso statement.Syntax.Parent.Parent.Kind = SyntaxKind.LocalDeclarationStatement) Case BoundKind.ExpressionStatement Debug.Assert((statement.Syntax.Kind = SyntaxKind.RedimClause AndAlso TypeOf statement.Syntax.Parent Is ReDimStatementSyntax) OrElse (TypeOf statement.Syntax Is ExpressionSyntax AndAlso TypeOf statement.Syntax.Parent Is EraseStatementSyntax)) Case Else Debug.Assert(TypeOf statement.Syntax Is ExecutableStatementSyntax) End Select End If ' We want to throw if this function has been called for this StatementSyntax earlier. ' BoundStatement statement is stored to help with debugging. _unstructuredExceptionHandlingResumableStatements.Add(statement.Syntax, statement) End If Return InsideValidUnstructuredExceptionHandlingResumeContext() #Else Return True #End If End Function Private Structure UnstructuredExceptionHandlingContext Public Context As BoundUnstructuredExceptionHandlingStatement End Structure Private Function LeaveUnstructuredExceptionHandlingContext(node As BoundNode) As UnstructuredExceptionHandlingContext #If DEBUG Then _leaveRestoreUnstructuredExceptionHandlingContextTracker.Push(node) #End If Dim result As UnstructuredExceptionHandlingContext result.Context = _unstructuredExceptionHandling.Context _unstructuredExceptionHandling.Context = Nothing Return result End Function Private Sub RestoreUnstructuredExceptionHandlingContext(node As BoundNode, saved As UnstructuredExceptionHandlingContext) #If DEBUG Then If _leaveRestoreUnstructuredExceptionHandlingContextTracker.Peek Is node Then _leaveRestoreUnstructuredExceptionHandlingContextTracker.Pop() Else Debug.Assert(_leaveRestoreUnstructuredExceptionHandlingContextTracker.Peek Is node) End If #End If _unstructuredExceptionHandling.Context = saved.Context End Sub Private Function InsideValidUnstructuredExceptionHandlingResumeContext() As Boolean Return _unstructuredExceptionHandling.Context IsNot Nothing AndAlso _unstructuredExceptionHandling.CurrentStatementTemporary IsNot Nothing AndAlso _currentMethodOrLambda Is _topMethod End Function Private Function InsideValidUnstructuredExceptionHandlingOnErrorContext() As Boolean Return _currentMethodOrLambda Is _topMethod AndAlso _unstructuredExceptionHandling.Context IsNot Nothing AndAlso _unstructuredExceptionHandling.Context.ContainsOnError End Function Private Sub RegisterUnstructuredExceptionHandlingResumeTarget(syntax As SyntaxNode, canThrow As Boolean, statements As ArrayBuilder(Of BoundStatement)) AddResumeTargetLabelAndUpdateCurrentStatementTemporary(syntax, canThrow, statements) End Sub Private Function RegisterUnstructuredExceptionHandlingResumeTarget(syntax As SyntaxNode, node As BoundStatement, canThrow As Boolean) As BoundStatement Dim statements = ArrayBuilder(Of BoundStatement).GetInstance() AddResumeTargetLabelAndUpdateCurrentStatementTemporary(syntax, canThrow, statements) statements.Add(node) Return New BoundStatementList(syntax, statements.ToImmutableAndFree()) End Function Private Function RegisterUnstructuredExceptionHandlingNonThrowingResumeTarget(syntax As SyntaxNode) As BoundLabelStatement Return AddResumeTargetLabel(syntax) End Function Private Function RegisterUnstructuredExceptionHandlingResumeTarget(syntax As SyntaxNode, canThrow As Boolean) As ImmutableArray(Of BoundStatement) Dim statements = ArrayBuilder(Of BoundStatement).GetInstance() AddResumeTargetLabelAndUpdateCurrentStatementTemporary(syntax, canThrow, statements) Return statements.ToImmutableAndFree() End Function End Class End Namespace