File: Debugging\VisualBasicBreakpointService.vb
Web Access
Project: src\src\Features\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.Features.vbproj (Microsoft.CodeAnalysis.VisualBasic.Features)
' 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.Composition
Imports System.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Debugging
Imports Microsoft.CodeAnalysis.ErrorReporting
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.EditAndContinue
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Debugging
 
    <ExportLanguageService(GetType(IBreakpointResolutionService), LanguageNames.VisualBasic), [Shared]>
    Friend NotInheritable Class VisualBasicBreakpointResolutionService
        Implements IBreakpointResolutionService
 
        <ImportingConstructor>
        <Obsolete(MefConstruction.ImportingConstructorMessage, True)>
        Public Sub New()
        End Sub
 
        Friend Shared Async Function GetBreakpointAsync(document As Document, position As Integer, length As Integer, cancellationToken As CancellationToken) As Task(Of BreakpointResolutionResult)
            Try
                Dim tree = Await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(False)
                If tree Is Nothing Then
                    Return Nothing
                End If
 
                ' Non-zero length means that the span is passed by the debugger and we may need validate it.
                ' In a rare VB case, this span may contain multiple methods, e.g., 
                '
                '    [Sub Goo() Handles A
                '
                '     End Sub
                '
                '     Sub Bar() Handles B]
                '
                '     End Sub
                '
                ' It happens when IDE services (e.g., NavBar or CodeFix) inserts a new method at the beginning of the existing one
                ' which happens to have a breakpoint on its head. In this situation, we should attempt to validate the span of the existing method,
                ' not that of a newly-prepended method.
 
                If length > 0 Then
                    Dim root = Await tree.GetRootAsync(cancellationToken).ConfigureAwait(False)
 
                    Dim item = root.DescendantNodes(
                            span:=New TextSpan(position, length),
                            descendIntoChildren:=Function(n) Not n.IsKind(SyntaxKind.ConstructorBlock, SyntaxKind.SubBlock)).
                        OfType(Of MethodBlockSyntax).Skip(1).LastOrDefault()
 
                    If item IsNot Nothing Then
                        position = item.SpanStart
                    End If
                End If
 
                Dim span As TextSpan
                If Not BreakpointSpans.TryGetBreakpointSpan(tree, position, cancellationToken, span) Then
                    Return Nothing
                End If
 
                If span.Length = 0 Then
                    Return BreakpointResolutionResult.CreateLineResult(document)
                End If
 
                Return BreakpointResolutionResult.CreateSpanResult(document, span)
            Catch e As Exception When FatalError.ReportAndCatchUnlessCanceled(e, cancellationToken)
                Return Nothing
            End Try
        End Function
 
        Public Function ResolveBreakpointAsync(document As Document, textSpan As TextSpan, Optional cancellationToken As CancellationToken = Nothing) As Task(Of BreakpointResolutionResult) Implements IBreakpointResolutionService.ResolveBreakpointAsync
            Return GetBreakpointAsync(document, textSpan.Start, textSpan.Length, cancellationToken)
        End Function
 
        Public Function ResolveBreakpointsAsync(
            solution As Solution,
            name As String,
            Optional cancellationToken As CancellationToken = Nothing) As Task(Of IEnumerable(Of BreakpointResolutionResult)) Implements IBreakpointResolutionService.ResolveBreakpointsAsync
 
            Return New BreakpointResolver(solution, name).DoAsync(cancellationToken)
        End Function
    End Class
End Namespace