|
' 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.Collections
Imports Microsoft.CodeAnalysis.Debugging
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
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
|