File: Debugging\BreakpointResolver.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.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports Microsoft.CodeAnalysis.Debugging
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Debugging
 
    Friend Class BreakpointResolver
        Inherits AbstractBreakpointResolver
 
        Private Shared ReadOnly s_identifierComparer As IEqualityComparer(Of String) = CaseInsensitiveComparison.Comparer
 
        Public Sub New(solution As Solution, text As String)
            MyBase.New(solution, text, LanguageNames.VisualBasic, s_identifierComparer)
        End Sub
 
        Protected Overrides Function GetMembers(type As INamedTypeSymbol, name As String) As IEnumerable(Of ISymbol)
            Dim members = type.GetMembers(name)
 
            Return If(s_identifierComparer.Equals(name, SyntaxFacts.GetText(SyntaxKind.NewKeyword)),
                      members.Concat(type.Constructors),
                      members)
        End Function
 
        Protected Overrides Function HasMethodBody(method As IMethodSymbol, cancellationToken As CancellationToken) As Boolean
            Dim location = method.Locations.First(Function(loc) loc.IsInSource)
            Dim tree = location.SourceTree
            Dim token = tree.GetRoot(cancellationToken).FindToken(location.SourceSpan.Start)
            Dim methodBlock = token.GetAncestor(Of MethodBlockBaseSyntax)()
 
            ' If there is no syntactic body then, obviously, False...
            If methodBlock Is Nothing Then
                Return False
            End If
 
            ' In VB, Partial method definitions have a syntactic body, but for the purpose of setting breakpoints in code,
            ' they should not be considered to have a body (because there is no executable code associated with them).
            If methodBlock.BlockStatement.Modifiers.Any(Function(t) t.IsKind(SyntaxKind.PartialKeyword)) Then
                Return False
            End If
 
            Return True
        End Function
 
        Protected Overrides Sub ParseText(ByRef nameParts As IList(Of NameAndArity), ByRef parameterCount As Integer?)
            Dim text As String = Me.Text
 
            Debug.Assert(text IsNot Nothing)
 
            Dim name = SyntaxFactory.ParseName(Me.Text, consumeFullText:=False)
            Dim lengthOfParsedText = name.FullSpan.End
            Dim parameterList = ParseParameterList(Me.Text, lengthOfParsedText)
            Dim foundIncompleteParameterList = False
 
            parameterCount = Nothing
            If parameterList IsNot Nothing Then
                If (parameterList.OpenParenToken.IsMissing OrElse parameterList.CloseParenToken.IsMissing) Then
                    foundIncompleteParameterList = True
                Else
                    lengthOfParsedText += parameterList.FullSpan.End
                    parameterCount = parameterList.Parameters.Count
                End If
            End If
 
            ' It's not obvious, but this method can handle the case were name "IsMissing" (no suitable name was be parsed).
            Dim parts = name.GetNameParts()
 
            ' If we could not parse a valid parameter list or there was additional trailing text that could not be
            ' interpreted, don't return any names or parameters.
            ' Also, "Break at Function" doesn't seem to support names prefixed with "Global" with the old language service.
            ' Since it doesn't seem necessary to disambiguate symbols in this scenario (there's UI to do it), I'm going to
            ' explicitly ignore names with a Global namespace prefix.  If we want to correctly support Global, we'd need to
            ' also modify the logic in FindMembersAsync to support exact matches on type name.  "Global" prefixes on
            ' parameters will be accepted, but we still only validate parameter count (as the old implementation did).
            If Not foundIncompleteParameterList AndAlso (lengthOfParsedText = Me.Text.Length) AndAlso
               Not parts.Where(Function(p) p.IsKind(SyntaxKind.GlobalName)).Any() Then
                nameParts = parts.Cast(Of SimpleNameSyntax)().Select(Function(p) New NameAndArity(p.Identifier.ValueText, p.Arity)).ToList()
            Else
                nameParts = SpecializedCollections.EmptyList(Of NameAndArity)()
            End If
        End Sub
 
        ' TODO:  This method can go away once https://roslyn.codeplex.com/workitem/231 is fixed.
        Private Shared Function ParseParameterList(text As String, offset As Integer) As ParameterListSyntax
            Return If(SyntaxFactory.ParseToken(text, offset).IsKind(SyntaxKind.OpenParenToken),
                      SyntaxFactory.ParseParameterList(text, offset, consumeFullText:=False),
                      Nothing)
        End Function
 
    End Class
 
End Namespace