File: Lowering\Instrumentation\DebugInfoInjector_SequencePoints.vb
Web Access
Project: src\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.Immutable
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic
    Partial Friend Class DebugInfoInjector
        Friend Shared Function AddConditionSequencePoint(condition As BoundExpression, containingCatchWithFilter As BoundCatchBlock, currentMethodOrLambda As MethodSymbol) As BoundExpression
            Debug.Assert(containingCatchWithFilter.ExceptionFilterOpt.Syntax.Parent.IsKind(SyntaxKind.CatchFilterClause))
            Dim local As LocalSymbol = Nothing
            Return AddConditionSequencePoint(condition, containingCatchWithFilter.ExceptionFilterOpt.Syntax.Parent, currentMethodOrLambda, local, shareLocal:=False)
        End Function
 
        Friend Shared Function AddConditionSequencePoint(condition As BoundExpression, containingStatement As BoundStatement, currentMethodOrLambda As MethodSymbol) As BoundExpression
            Dim local As LocalSymbol = Nothing
            Return AddConditionSequencePoint(condition, containingStatement.Syntax, currentMethodOrLambda, local, shareLocal:=False)
        End Function
 
        Friend Shared Function AddConditionSequencePoint(
            condition As BoundExpression,
            containingStatement As BoundStatement,
            currentMethodOrLambda As MethodSymbol,
            ByRef lazyConditionalBranchLocal As LocalSymbol
        ) As BoundExpression
            Return AddConditionSequencePoint(condition, containingStatement.Syntax, currentMethodOrLambda, lazyConditionalBranchLocal, shareLocal:=True)
        End Function
 
        Private Shared Function AddConditionSequencePoint(condition As BoundExpression,
                                                   synthesizedVariableSyntax As SyntaxNode,
                                                   currentMethodOrLambda As MethodSymbol,
                                                   ByRef lazyConditionalBranchLocal As LocalSymbol,
                                                   shareLocal As Boolean) As BoundExpression
            If Not currentMethodOrLambda.DeclaringCompilation.Options.EnableEditAndContinue Then
                Return condition
            End If
 
            Dim conditionSyntax = condition.Syntax
 
            ' The local has to be associated with the syntax of the statement containing the condition since 
            ' EnC source mapping only operates on statements.
            If lazyConditionalBranchLocal Is Nothing Then
                lazyConditionalBranchLocal = New SynthesizedLocal(currentMethodOrLambda, condition.Type, SynthesizedLocalKind.ConditionalBranchDiscriminator, synthesizedVariableSyntax)
            Else
                Debug.Assert(lazyConditionalBranchLocal.SynthesizedKind = SynthesizedLocalKind.ConditionalBranchDiscriminator)
                Debug.Assert(lazyConditionalBranchLocal.Type Is condition.Type)
            End If
 
            ' Add hidden sequence point unless the condition is a constant expression.
            ' Constant expression must stay a const to not invalidate results of control flow analysis.
            Dim valueExpression = If(condition.ConstantValueOpt Is Nothing,
                                     New BoundSequencePointExpression(Nothing, MakeLocalRead(conditionSyntax, lazyConditionalBranchLocal), condition.Type),
                                     condition)
 
            Return New BoundSequence(
                conditionSyntax,
                If(shareLocal, ImmutableArray(Of LocalSymbol).Empty, ImmutableArray.Create(lazyConditionalBranchLocal)),
                ImmutableArray.Create(MakeAssignmentExpression(conditionSyntax, MakeLocalWrite(conditionSyntax, lazyConditionalBranchLocal), condition)),
                valueExpression,
                condition.Type)
        End Function
 
        Private Shared Function MakeLocalRead(syntax As SyntaxNode, localSym As LocalSymbol) As BoundLocal
            Dim boundNode = New BoundLocal(syntax, localSym, isLValue:=False, type:=localSym.Type)
            boundNode.SetWasCompilerGenerated()
            Return boundNode
        End Function
 
        Private Shared Function MakeLocalWrite(syntax As SyntaxNode, localSym As LocalSymbol) As BoundLocal
            Dim boundNode = New BoundLocal(syntax, localSym, isLValue:=True, type:=localSym.Type)
            boundNode.SetWasCompilerGenerated()
            Return boundNode
        End Function
 
        Private Shared Function MakeAssignmentExpression(syntax As SyntaxNode, left As BoundExpression, right As BoundExpression) As BoundExpression
            Debug.Assert(TypeSymbol.Equals(left.Type, right.Type, TypeCompareKind.ConsiderEverything))
            Dim boundNode = New BoundAssignmentOperator(syntax, left, right, suppressObjectClone:=True)
            boundNode.SetWasCompilerGenerated()
            Return boundNode
        End Function
 
        Public Overloads Shared Function CreateBlockPrologue(node As BoundBlock, previousPrologue As BoundStatement) As BoundStatement
            ' method block needs to get a sequence point inside the method scope, 
            ' but before starting any statements
            Dim asMethod = TryCast(node.Syntax, MethodBlockBaseSyntax)
            If asMethod IsNot Nothing Then
                Dim methodStatement As MethodBaseSyntax = asMethod.BlockStatement
 
                ' For methods we want the span of the statement without any leading attributes.
                ' The span begins at the first modifier or the 'Sub'/'Function' keyword.
                ' There is no need to do this adjustment for lambdas because they cannot
                ' have attributes.
 
                Dim firstModifierOrKeyword As SyntaxToken
 
                If methodStatement.Modifiers.Count > 0 Then
                    firstModifierOrKeyword = methodStatement.Modifiers(0)
                Else
                    firstModifierOrKeyword = methodStatement.DeclarationKeyword
                End If
 
                Dim statementSpanWithoutAttributes = TextSpan.FromBounds(firstModifierOrKeyword.SpanStart, methodStatement.Span.End)
 
                previousPrologue = New BoundSequencePointWithSpan(methodStatement, previousPrologue, statementSpanWithoutAttributes)
            Else
                Dim asLambda = TryCast(node.Syntax, LambdaExpressionSyntax)
                If asLambda IsNot Nothing Then
                    previousPrologue = New BoundSequencePoint(asLambda.SubOrFunctionHeader, previousPrologue)
                End If
            End If
 
            Return previousPrologue
        End Function
 
        Private Shared Function MarkInitializerSequencePoint(rewrittenStatement As BoundStatement, syntax As SyntaxNode, nameIndex As Integer) As BoundStatement
            If syntax.Parent.IsKind(SyntaxKind.PropertyStatement) Then
                ' Property [|P As Integer = 1|] Implements I.P
                ' Property [|P As New Integer|] Implements I.P
                Dim propertyStatement = DirectCast(syntax.Parent, PropertyStatementSyntax)
 
                Dim span = TextSpan.FromBounds(propertyStatement.Identifier.SpanStart,
                                               If(propertyStatement.Initializer Is Nothing, propertyStatement.AsClause.Span.End, propertyStatement.Initializer.Span.End))
 
                Return New BoundSequencePointWithSpan(syntax, rewrittenStatement, span)
            End If
 
            If syntax.IsKind(SyntaxKind.AsNewClause) Then
                Dim declarator = DirectCast(syntax.Parent, VariableDeclaratorSyntax)
                If declarator.Names.Count > 1 Then
                    ' Dim [|a|], b As New C()
                    Return New BoundSequencePoint(declarator.Names(nameIndex), rewrittenStatement)
                Else
                    ' Dim [|a As New C()|]
                    Return New BoundSequencePoint(syntax.Parent, rewrittenStatement)
                End If
            End If
 
            If syntax.IsKind(SyntaxKind.ModifiedIdentifier) Then
                Debug.Assert(DirectCast(syntax, ModifiedIdentifierSyntax).ArrayBounds IsNot Nothing)
                ' Dim [|a(1)|] As Integer
                Return New BoundSequencePoint(syntax, rewrittenStatement)
            End If
 
            ' Dim [|a = 1|]
            Debug.Assert(syntax.IsKind(SyntaxKind.EqualsValue))
            Return New BoundSequencePoint(syntax.Parent, rewrittenStatement)
        End Function
 
        Private Shared Function MarkInitializerSequencePoint(rewrittenStatement As BoundStatement, syntax As SyntaxNode) As BoundStatement
            Debug.Assert(syntax.IsKind(SyntaxKind.ModifiedIdentifier))
            Debug.Assert(syntax.Parent.Kind = SyntaxKind.VariableDeclarator)
 
            Dim modifiedIdentifier = DirectCast(syntax, ModifiedIdentifierSyntax)
            If modifiedIdentifier.ArrayBounds IsNot Nothing Then
                ' Dim [|a(1)|], b(1) As Integer
                Return New BoundSequencePoint(syntax, rewrittenStatement)
            End If
 
            Dim declarator = DirectCast(syntax.Parent, VariableDeclaratorSyntax)
            If declarator.Names.Count > 1 Then
                Debug.Assert(declarator.AsClause.IsKind(SyntaxKind.AsNewClause))
 
                ' Dim [|a|], b As New C()
                Return New BoundSequencePoint(syntax, rewrittenStatement)
            End If
 
            ' Dim [|a = 1|]
            ' Dim [|a As New C()|]
            Return New BoundSequencePoint(declarator, rewrittenStatement)
        End Function
    End Class
End Namespace