File: SymbolDisplay\SymbolDisplayVisitor_Minimal.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 Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic
    Partial Friend Class SymbolDisplayVisitor
        Protected Overrides Function ShouldRestrictMinimallyQualifyLookupToNamespacesAndTypes() As Boolean
            Dim token = SemanticModelOpt.SyntaxTree.GetRoot().FindToken(PositionOpt)
            Dim startNode = token.Parent
 
            Return SyntaxFacts.IsInNamespaceOrTypeContext(TryCast(startNode, ExpressionSyntax)) OrElse Me.InNamespaceOrType
        End Function
 
        Private Sub MinimallyQualify(symbol As INamespaceSymbol, emittedName As String, parentsEmittedName As String)
            Debug.Assert(symbol.ContainingNamespace IsNot Nothing OrElse symbol.IsGlobalNamespace)
 
            ' NOTE(cyrusn): We only call this once we've already checked if there is an alias that
            ' corresponds to this namespace. 
 
            If symbol.IsGlobalNamespace Then
                ' nothing to add for global namespace itself
                Return
            End If
 
            Dim visitedParent = False
 
            ' Check if the name of this namespace binds to the same namespace symbol.  If so,
            ' then that's all we need to add.  Otherwise, we will add the minimally qualified
            ' version of our parent, and then add ourselves to that.
            Dim symbols = If(
                ShouldRestrictMinimallyQualifyLookupToNamespacesAndTypes(),
                SemanticModelOpt.LookupNamespacesAndTypes(PositionOpt, name:=symbol.Name),
                SemanticModelOpt.LookupSymbols(PositionOpt, name:=symbol.Name))
            Dim lookupResult As NamespaceSymbol = Nothing
 
            If symbols.Length = 1 Then
                lookupResult = TryCast(symbols(0), NamespaceSymbol)
            End If
 
            ' It is possible to get NamespaceSymbol with compilation extent here.
            ' Let's check this case.
            If lookupResult IsNot Nothing Then
                Debug.Assert(lookupResult.Extent.Kind = NamespaceKind.Module OrElse lookupResult.Extent.Kind = NamespaceKind.Compilation)
 
                If lookupResult IsNot symbol AndAlso lookupResult.Extent.Kind = NamespaceKind.Compilation Then
                    Dim ns = TryCast(symbol, NamespaceSymbol)
 
                    If ns IsNot Nothing AndAlso ns.Extent.Kind <> NamespaceKind.Compilation AndAlso
                       lookupResult.Extent.Compilation.GetCompilationNamespace(ns) Is lookupResult Then
                        lookupResult = ns
                    End If
                End If
            End If
 
            If lookupResult IsNot symbol Then
                ' Just the name alone didn't bind properly.  Add our minimally qualified parent
                ' (if we have one), a dot, and then our name.
                Dim containingNamespace = symbol.ContainingNamespace
                If containingNamespace IsNot Nothing Then
                    If containingNamespace.IsGlobalNamespace Then
 
                        Debug.Assert(Format.GlobalNamespaceStyle = SymbolDisplayGlobalNamespaceStyle.Included OrElse
                                          Format.GlobalNamespaceStyle = SymbolDisplayGlobalNamespaceStyle.Omitted OrElse
                                          Format.GlobalNamespaceStyle = SymbolDisplayGlobalNamespaceStyle.OmittedAsContaining)
 
                        If Format.GlobalNamespaceStyle = SymbolDisplayGlobalNamespaceStyle.Included Then
                            AddGlobalNamespace(containingNamespace)
                            AddOperator(SyntaxKind.DotToken)
 
                            visitedParent = True
                        End If
                    Else
                        VisitNamespace(containingNamespace, parentsEmittedName)
 
                        AddOperator(SyntaxKind.DotToken)
                        visitedParent = True
                    End If
                End If
            End If
 
            Builder.Add(CreatePart(SymbolDisplayPartKind.NamespaceName, symbol, emittedName, visitedParent))
        End Sub
 
        Private Sub MinimallyQualify(symbol As INamedTypeSymbol)
            ' NOTE(cyrusn): We only call this once we've already checked if there is an alias or
            ' special type that corresponds to this type.
            '
            ' We first start by trying to bind just our name and type arguments.  If they bind to the
            ' symbol that we were constructed from.  Otherwise, we get the minimal name of our
            ' parent, add a dot, and then add ourselves.
 
            Dim visitedParents As Boolean = False
 
            If Not (symbol.IsAnonymousType OrElse symbol.IsTupleType) Then
                If Not NameBoundSuccessfullyToSameSymbol(symbol) Then
                    If IncludeNamedType(symbol.ContainingType) Then
                        symbol.ContainingType.Accept(NotFirstVisitor)
                        AddOperator(SyntaxKind.DotToken)
                    ElseIf symbol.ContainingNamespace IsNot Nothing Then
                        If symbol.ContainingNamespace.IsGlobalNamespace Then
                            ' Error symbols are put into the global namespace if the compiler has no
                            ' better guess for it, so we shouldn't go spitting it everywhere.
                            If symbol.TypeKind <> TypeKind.Error Then
                                AddKeyword(SyntaxKind.GlobalKeyword)
                                AddOperator(SyntaxKind.DotToken)
                            End If
                        Else
                            symbol.ContainingNamespace.Accept(NotFirstVisitor)
                            AddOperator(SyntaxKind.DotToken)
                        End If
                    End If
 
                    visitedParents = True
                End If
            End If
 
            AddNameAndTypeArgumentsOrParameters(symbol, visitedParents)
        End Sub
 
        Private Function TryAddAlias(
            symbol As INamespaceOrTypeSymbol,
            builder As ArrayBuilder(Of SymbolDisplayPart)) As Boolean
 
            Dim [alias] = GetAliasSymbol(symbol)
            If Not [alias] Is Nothing Then
                ' We must verify that the alias actually binds back to the thing it's aliasing. It's
                ' possible there's another symbol with the same name as the alias that binds first
 
                Dim aliasName = [alias].Name
                Dim boundSymbols = SemanticModelOpt.LookupNamespacesAndTypes(PositionOpt, name:=aliasName)
 
                If boundSymbols.Length = 1 Then
                    Dim boundAlias = TryCast(boundSymbols(0), IAliasSymbol)
                    If boundAlias IsNot Nothing AndAlso boundAlias.Target.Equals(symbol) Then
                        builder.Add(CreatePart(SymbolDisplayPartKind.AliasName, [alias], aliasName, False))
                        Return True
                    End If
                End If
            End If
 
            Return False
        End Function
 
        Private Function GetAliasSymbol(symbol As INamespaceOrTypeSymbol) As IAliasSymbol
            If Not Me.IsMinimizing Then
                Return Nothing
            End If
 
            Dim token = SemanticModelOpt.SyntaxTree.GetRoot().FindToken(PositionOpt)
            Dim startNode = token.Parent
 
            ' NOTE(cyrusn): If we're in an imports clause, we can't use aliases.
            Dim clause = startNode.AncestorsAndSelf().OfType(Of ImportsClauseSyntax).FirstOrDefault()
            If clause IsNot Nothing Then
                Return Nothing
            End If
 
            Dim compilation = SemanticModelOpt.Compilation
 
            Dim sourceModule = DirectCast(compilation.SourceModule, SourceModuleSymbol)
            Dim sourceFile = sourceModule.TryGetSourceFile(DirectCast(GetSyntaxTree(SemanticModelOpt), VisualBasicSyntaxTree))
            Debug.Assert(sourceFile IsNot Nothing)
 
            If Not sourceFile.AliasImportsOpt Is Nothing Then
                For Each [alias] In sourceFile.AliasImportsOpt.Values
                    If [alias].Alias.Target = DirectCast(symbol, NamespaceOrTypeSymbol) Then
                        Return [alias].Alias
                    End If
                Next
            End If
 
            Return Nothing
        End Function
 
        Private Function GetSyntaxTree(semanticModel As SemanticModel) As SyntaxTree
            If Not semanticModel.IsSpeculativeSemanticModel Then
                Return semanticModel.SyntaxTree
            End If
 
            Debug.Assert(semanticModel.ParentModel IsNot Nothing)
            Debug.Assert(Not semanticModel.ParentModel.IsSpeculativeSemanticModel)
            Return semanticModel.ParentModel.SyntaxTree
        End Function
 
        Private Function RemoveAttributeSuffixIfNecessary(symbol As INamedTypeSymbol, symbolName As String) As String
            If Format.MiscellaneousOptions.IncludesOption(SymbolDisplayMiscellaneousOptions.RemoveAttributeSuffix) AndAlso IsDerivedFromAttributeType(symbol) Then
 
                Dim nameWithoutAttributeSuffix As String = Nothing
                If symbolName.TryGetWithoutAttributeSuffix(False, nameWithoutAttributeSuffix) Then
                    Dim token = SyntaxFactory.ParseToken(nameWithoutAttributeSuffix)
                    If token.Kind = SyntaxKind.IdentifierToken Then
                        symbolName = nameWithoutAttributeSuffix
                    End If
                End If
            End If
 
            Return symbolName
        End Function
 
        Private Function IsDerivedFromAttributeType(ByVal derivedType As INamedTypeSymbol) As Boolean
            Return SemanticModelOpt IsNot Nothing AndAlso
                DirectCast(derivedType, NamedTypeSymbol).IsOrDerivedFromWellKnownClass(WellKnownType.System_Attribute,
                                                                                       DirectCast(SemanticModelOpt.Compilation, VisualBasicCompilation),
                                                                                       useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded)
        End Function
    End Class
End Namespace