|
' 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.Globalization
Imports Microsoft.CodeAnalysis.CodeLens
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.VisualBasic.LanguageService
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Namespace Microsoft.CodeAnalysis.VisualBasic.CodeLens
<ExportLanguageService(GetType(ICodeLensDisplayInfoService), LanguageNames.VisualBasic), [Shared]>
Friend NotInheritable Class VisualBasicDisplayInfoService
Implements ICodeLensDisplayInfoService
Private Shared ReadOnly Format As SymbolDisplayFormat = New SymbolDisplayFormat(
SymbolDisplayGlobalNamespaceStyle.Omitted, ' Don't prepend VB namespaces with "Global."
SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces, ' Show fully qualified names
SymbolDisplayGenericsOptions.IncludeTypeParameters,
SymbolDisplayMemberOptions.IncludeContainingType Or SymbolDisplayMemberOptions.IncludeParameters,
SymbolDisplayDelegateStyle.NameOnly,
SymbolDisplayExtensionMethodStyle.StaticMethod,
SymbolDisplayParameterOptions.IncludeType,
SymbolDisplayPropertyStyle.ShowReadWriteDescriptor,
SymbolDisplayLocalOptions.IncludeType,
SymbolDisplayKindOptions.None,
SymbolDisplayMiscellaneousOptions.UseSpecialTypes)
<ImportingConstructor>
<Obsolete(MefConstruction.ImportingConstructorMessage, True)>
Public Sub New()
End Sub
''' <summary>
''' Returns the node that should be displayed
''' </summary>
Public Function GetDisplayNode(node As SyntaxNode) As SyntaxNode Implements ICodeLensDisplayInfoService.GetDisplayNode
Select Case node.Kind()
' A variable declarator can contain multiple symbols, for example "Private field2, field3 As Integer"
' In that case default to the first field name.
Case SyntaxKind.VariableDeclarator
Dim variableNode = CType(node, VariableDeclaratorSyntax)
Return GetDisplayNode(variableNode.Names.First())
' A field declaration (global variable) can contain multiple symbols, for example "Private field2, field3 As Integer"
' In that case default to the first field name.
Case SyntaxKind.FieldDeclaration
Dim fieldNode = CType(node, FieldDeclarationSyntax)
Return GetDisplayNode(fieldNode.Declarators.First())
Case SyntaxKind.PredefinedType
Return GetDisplayNode(node.Parent)
Case SyntaxKind.DocumentationCommentTrivia
If node.IsStructuredTrivia Then
Dim structuredTriviaSyntax = CType(node, StructuredTriviaSyntax)
Return GetDisplayNode(structuredTriviaSyntax.ParentTrivia.Token.Parent)
Else
Return node
End If
End Select
Return node
End Function
Private Shared Function SymbolToDisplayString(symbol As ISymbol) As String
Return If(symbol Is Nothing, FeaturesResources.paren_Unknown_paren, symbol.ToDisplayString(Format))
End Function
Private Shared Function FormatPropertyAccessor(node As SyntaxNode, symbolName As String) As String
Dim symbolNameWithNoParams As String = RemoveParameters(symbolName)
If node.IsKind(SyntaxKind.GetAccessorBlock) Then
symbolName = String.Format(CultureInfo.CurrentCulture, VBFeaturesResources.Property_getter_name, symbolNameWithNoParams)
Else
Debug.Assert(node.IsKind(SyntaxKind.SetAccessorBlock))
symbolName = String.Format(CultureInfo.CurrentCulture, VBFeaturesResources.Property_setter_name, symbolNameWithNoParams)
End If
Return symbolName
End Function
Private Shared Function FormatEventHandler(node As SyntaxNode, symbolName As String) As String
' symbol name looks Like this at this point : Namespace.Class.Event(EventHandler)
Dim symbolNameWithNoParams As String = RemoveParameters(symbolName)
If node.IsKind(SyntaxKind.AddHandlerAccessorBlock) Then
symbolName = String.Format(CultureInfo.CurrentCulture, VBFeaturesResources.Event_add_handler_name, symbolNameWithNoParams)
Else
Debug.Assert(node.IsKind(SyntaxKind.RemoveHandlerAccessorBlock))
symbolName = String.Format(CultureInfo.CurrentCulture, VBFeaturesResources.Event_remove_handler_name, symbolNameWithNoParams)
End If
Return symbolName
End Function
Private Shared Function IsAccessorForDefaultProperty(symbol As ISymbol) As Boolean
Dim methodSymbol = TryCast(symbol, IMethodSymbol) ' its really a SourcePropertyAccessorSymbol but it Is Not accessible
If methodSymbol IsNot Nothing Then
Dim propertySymbol = TryCast(methodSymbol.AssociatedSymbol, IPropertySymbol)
If propertySymbol IsNot Nothing Then
' Applying the default modifier to a property allows it to be used Like a C# indexer
Return propertySymbol.IsDefault()
End If
End If
Return False
End Function
Private Shared Function RemoveParameters(symbolName As String) As String
Dim openParenIndex As Integer = symbolName.IndexOf("("c)
Dim symbolNameWithNoParams As String = symbolName.Substring(0, openParenIndex)
Return symbolNameWithNoParams
End Function
''' <summary>
''' Gets the DisplayName for the given node.
''' </summary>
Public Function GetDisplayName(semanticModel As SemanticModel, node As SyntaxNode) As String Implements ICodeLensDisplayInfoService.GetDisplayName
If VisualBasicSyntaxFacts.Instance.IsGlobalAssemblyAttribute(node) Then
Return node.ToString()
End If
Dim symbol As ISymbol = semanticModel.GetDeclaredSymbol(node)
Dim symbolName As String
Select Case node.Kind()
Case SyntaxKind.GetAccessorBlock,
SyntaxKind.SetAccessorBlock
' Indexer properties should Not include get And set
symbol = semanticModel.GetDeclaredSymbol(node)
If IsAccessorForDefaultProperty(symbol) AndAlso node.Parent.IsKind(SyntaxKind.PropertyBlock) Then
Return GetDisplayName(semanticModel, node.Parent)
Else
' Append "get" Or "set" to property accessors
symbolName = SymbolToDisplayString(symbol)
symbolName = FormatPropertyAccessor(node, symbolName)
End If
Case SyntaxKind.AddHandlerAccessorBlock,
SyntaxKind.RemoveHandlerAccessorBlock
' Append "add" Or "remove" to event handlers
symbolName = SymbolToDisplayString(symbol)
symbolName = FormatEventHandler(node, symbolName)
Case SyntaxKind.ImportsStatement
symbolName = "Imports"
Case Else
symbolName = SymbolToDisplayString(symbol)
End Select
Return symbolName
End Function
End Class
End Namespace
|