File: Symbols\Source\SourceNamespaceSymbol.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 System.Collections.Immutable
Imports System.Threading
Imports Microsoft.CodeAnalysis.ImmutableArrayExtensions
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
    Friend NotInheritable Class SourceNamespaceSymbol
        Inherits PEOrSourceOrMergedNamespaceSymbol
 
        Private ReadOnly _declaration As MergedNamespaceDeclaration
        Private ReadOnly _containingNamespace As SourceNamespaceSymbol
        Private ReadOnly _containingModule As SourceModuleSymbol
        Private _nameToMembersMap As Dictionary(Of String, ImmutableArray(Of NamespaceOrTypeSymbol))
        Private _nameToTypeMembersMap As Dictionary(Of String, ImmutableArray(Of NamedTypeSymbol))
        Private _lazyEmbeddedKind As Integer = EmbeddedSymbolKind.Unset
 
        ' lazily evaluated state of the symbol (StateFlags)
        Private _lazyState As Integer
 
        <Flags>
        Private Enum StateFlags As Integer
            HasMultipleSpellings = &H1     ' ReadOnly: Set if there are multiple declarations with different spellings (casing)
            AllMembersIsSorted = &H2       ' Set if "m_lazyAllMembers" is sorted.
            DeclarationValidated = &H4     ' Set by ValidateDeclaration.
        End Enum
 
        ' This caches results of GetModuleMembers()
        Private _lazyModuleMembers As ImmutableArray(Of NamedTypeSymbol)
 
        ' This caches results of GetMembers()
        Private _lazyAllMembers As ImmutableArray(Of Symbol)
 
        Private _lazyLexicalSortKey As LexicalSortKey = LexicalSortKey.NotInitialized
 
        Friend Sub New(decl As MergedNamespaceDeclaration, containingNamespace As SourceNamespaceSymbol, containingModule As SourceModuleSymbol)
            _declaration = decl
            _containingNamespace = containingNamespace
            _containingModule = containingModule
            If (containingNamespace IsNot Nothing AndAlso containingNamespace.HasMultipleSpellings) OrElse decl.HasMultipleSpellings Then
                _lazyState = StateFlags.HasMultipleSpellings
            End If
        End Sub
 
        ''' <summary>
        ''' Register COR types declared in this namespace, if any, in the COR types cache.
        ''' </summary>
        Private Sub RegisterDeclaredCorTypes()
 
            Dim containingAssembly As AssemblySymbol = Me.ContainingAssembly
 
            If (containingAssembly.KeepLookingForDeclaredSpecialTypes) Then
                ' Register newly declared COR types
                For Each array In _nameToMembersMap.Values
                    For Each member In array
                        Dim type = TryCast(member, NamedTypeSymbol)
                        If type IsNot Nothing AndAlso type.SpecialType <> SpecialType.None Then
                            containingAssembly.RegisterDeclaredSpecialType(type)
 
                            If Not containingAssembly.KeepLookingForDeclaredSpecialTypes Then
                                Return
                            End If
                        End If
                    Next
                Next
            End If
        End Sub
 
        Public Overrides ReadOnly Property Name As String
            Get
                Return _declaration.Name
            End Get
        End Property
 
        Friend Overrides ReadOnly Property EmbeddedSymbolKind As EmbeddedSymbolKind
            Get
                If _lazyEmbeddedKind = EmbeddedSymbolKind.Unset Then
                    Dim value As Integer = EmbeddedSymbolKind.None
                    For Each location In _declaration.NameLocations
                        Debug.Assert(location IsNot Nothing)
                        If location.Kind = LocationKind.None Then
                            Dim embeddedLocation = TryCast(location, EmbeddedTreeLocation)
                            If embeddedLocation IsNot Nothing Then
                                value = value Or embeddedLocation.EmbeddedKind
                            End If
                        End If
                    Next
                    Interlocked.CompareExchange(_lazyEmbeddedKind, value, EmbeddedSymbolKind.Unset)
                End If
 
                Return CType(_lazyEmbeddedKind, EmbeddedSymbolKind)
            End Get
        End Property
 
        Public Overrides ReadOnly Property ContainingSymbol As Symbol
            Get
                Return If(_containingNamespace, DirectCast(_containingModule, Symbol))
            End Get
        End Property
 
        Public Overrides ReadOnly Property ContainingAssembly As AssemblySymbol
            Get
                Return _containingModule.ContainingAssembly
            End Get
        End Property
 
        Public Overrides ReadOnly Property ContainingModule As ModuleSymbol
            Get
                Return Me._containingModule
            End Get
        End Property
 
        Friend Overrides ReadOnly Property Extent As NamespaceExtent
            Get
                Return New NamespaceExtent(_containingModule)
            End Get
        End Property
 
        Private Function GetNameToMembersMap() As Dictionary(Of String, ImmutableArray(Of NamespaceOrTypeSymbol))
            If _nameToMembersMap Is Nothing Then
                Dim map = MakeNameToMembersMap()
                If Interlocked.CompareExchange(_nameToMembersMap, map, Nothing) Is Nothing Then
                    RegisterDeclaredCorTypes()
                End If
            End If
 
            Return _nameToMembersMap
        End Function
 
        Private Function MakeNameToMembersMap() As Dictionary(Of String, ImmutableArray(Of NamespaceOrTypeSymbol))
            ' NOTE: Even though the resulting map stores ImmutableArray(Of NamespaceOrTypeSymbol) as 
            ' NOTE: values if the name is mapped into an array of named types, which is frequently 
            ' NOTE: the case, we actually create an array of NamedTypeSymbol[] and wrap it in 
            ' NOTE: ImmutableArray(Of NamespaceOrTypeSymbol) 
            ' NOTE: 
            ' NOTE: This way we can save time and memory in GetNameToTypeMembersMap() -- when we see that
            ' NOTE: a name maps into values collection containing types only instead of allocating another 
            ' NOTE: array of NamedTypeSymbol[] we downcast the array to ImmutableArray(Of NamedTypeSymbol)
 
            Dim builder As New Dictionary(Of String, Object)(_declaration.Children.Length, IdentifierComparison.Comparer)
            For Each declaration In _declaration.Children
                Dim symbol As NamespaceOrTypeSymbol = BuildSymbol(declaration)
                ImmutableArrayExtensions.AddToMultiValueDictionaryBuilder(builder, symbol.Name, symbol)
            Next
 
            ' TODO(cyrusn): The C# and VB impls differ here.  C# reports errors here and VB does not.
            ' Is that what we want?
 
            Dim result As New Dictionary(Of String, ImmutableArray(Of NamespaceOrTypeSymbol))(builder.Count, IdentifierComparison.Comparer)
            ImmutableArrayExtensions.CreateNameToMembersMap(Of String, NamespaceOrTypeSymbol, NamedTypeSymbol, NamespaceSymbol)(builder, result)
            Return result
        End Function
 
        Private Function BuildSymbol(decl As MergedNamespaceOrTypeDeclaration) As NamespaceOrTypeSymbol
            Dim namespaceDecl = TryCast(decl, MergedNamespaceDeclaration)
            If namespaceDecl IsNot Nothing Then
                Return New SourceNamespaceSymbol(namespaceDecl, Me, _containingModule)
            Else
                Dim typeDecl = DirectCast(decl, MergedTypeDeclaration)
#If DEBUG Then
                ' Ensure that the type declaration is either from user code or embedded
                ' code, but not merged across embedded code/user code boundary.
                Dim embedded = EmbeddedSymbolKind.Unset
                For Each ref In typeDecl.SyntaxReferences
                    Dim refKind = ref.SyntaxTree.GetEmbeddedKind()
                    If embedded <> EmbeddedSymbolKind.Unset Then
                        Debug.Assert(embedded = refKind)
                    Else
                        embedded = refKind
                    End If
                Next
                Debug.Assert(embedded <> EmbeddedSymbolKind.Unset)
#End If
                Return SourceNamedTypeSymbol.Create(typeDecl, Me, _containingModule)
            End If
        End Function
 
        Private Function GetNameToTypeMembersMap() As Dictionary(Of String, ImmutableArray(Of NamedTypeSymbol))
            If _nameToTypeMembersMap Is Nothing Then
 
                ' NOTE: This method depends on MakeNameToMembersMap() on creating a proper 
                ' NOTE: type of the array, see comments in MakeNameToMembersMap() for details
                Interlocked.CompareExchange(
                    _nameToTypeMembersMap,
                    ImmutableArrayExtensions.GetTypesFromMemberMap(Of String, NamespaceOrTypeSymbol, NamedTypeSymbol)(
                        Me.GetNameToMembersMap(), CaseInsensitiveComparison.Comparer),
                    comparand:=Nothing)
            End If
 
            Return _nameToTypeMembersMap
        End Function
 
        Public Overloads Overrides Function GetMembers() As ImmutableArray(Of Symbol)
            If (_lazyState And StateFlags.AllMembersIsSorted) <> 0 Then
                Return _lazyAllMembers
 
            Else
                Dim allMembers = Me.GetMembersUnordered()
 
                If allMembers.Length >= 2 Then
                    allMembers = allMembers.Sort(LexicalOrderSymbolComparer.Instance)
                    ImmutableInterlocked.InterlockedExchange(_lazyAllMembers, allMembers)
                End If
 
                ThreadSafeFlagOperations.Set(_lazyState, StateFlags.AllMembersIsSorted)
 
                Return allMembers
            End If
        End Function
 
        Friend Overloads Overrides Function GetMembersUnordered() As ImmutableArray(Of Symbol)
            If _lazyAllMembers.IsDefault Then
                Dim members = StaticCast(Of Symbol).From(Me.GetNameToMembersMap().Flatten())
                ImmutableInterlocked.InterlockedCompareExchange(_lazyAllMembers, members, Nothing)
            End If
 
            Return _lazyAllMembers.ConditionallyDeOrder()
        End Function
 
        Public Overloads Overrides Function GetMembers(name As String) As ImmutableArray(Of Symbol)
            Dim members As ImmutableArray(Of NamespaceOrTypeSymbol) = Nothing
            If Me.GetNameToMembersMap().TryGetValue(name, members) Then
                Return ImmutableArray(Of Symbol).CastUp(members)
            Else
                Return ImmutableArray(Of Symbol).Empty
            End If
        End Function
 
        Friend Overrides Function GetTypeMembersUnordered() As ImmutableArray(Of NamedTypeSymbol)
            Return Me.GetNameToTypeMembersMap().Flatten()
        End Function
 
        Public Overloads Overrides Function GetTypeMembers() As ImmutableArray(Of NamedTypeSymbol)
            Return Me.GetNameToTypeMembersMap().Flatten(LexicalOrderSymbolComparer.Instance)
        End Function
 
        Public Overloads Overrides Function GetTypeMembers(name As String) As ImmutableArray(Of NamedTypeSymbol)
            Dim members As ImmutableArray(Of NamedTypeSymbol) = Nothing
            If Me.GetNameToTypeMembersMap().TryGetValue(name, members) Then
                Return members
            Else
                Return ImmutableArray(Of NamedTypeSymbol).Empty
            End If
        End Function
 
        ' This is very performance critical for type lookup.
        Public Overrides Function GetModuleMembers() As ImmutableArray(Of NamedTypeSymbol)
            If _lazyModuleMembers.IsDefault Then
                Dim moduleMembers = ArrayBuilder(Of NamedTypeSymbol).GetInstance()
 
                ' look at all child declarations to find the modules.
                For Each childDecl In _declaration.Children
                    If childDecl.Kind = DeclarationKind.Module Then
                        moduleMembers.AddRange(GetModuleMembers(childDecl.Name))
                    End If
                Next
 
                ImmutableInterlocked.InterlockedCompareExchange(_lazyModuleMembers,
                                                    moduleMembers.ToImmutableAndFree(),
                                                    Nothing)
            End If
 
            Return _lazyModuleMembers
        End Function
 
        Friend Overrides Function GetLexicalSortKey() As LexicalSortKey
            ' WARNING: this should not allocate memory!
            If Not _lazyLexicalSortKey.IsInitialized Then
                _lazyLexicalSortKey.SetFrom(_declaration.GetLexicalSortKey(Me.DeclaringCompilation))
            End If
            Return _lazyLexicalSortKey
        End Function
 
        Public Overrides ReadOnly Property Locations As ImmutableArray(Of Location)
            Get
                Return StaticCast(Of Location).From(_declaration.NameLocations)
            End Get
        End Property
 
        Public Overrides ReadOnly Property DeclaringSyntaxReferences As ImmutableArray(Of SyntaxReference)
            Get
                Return ComputeDeclaringReferencesCore()
            End Get
        End Property
 
        Private Function ComputeDeclaringReferencesCore() As ImmutableArray(Of SyntaxReference)
            Dim declarations As ImmutableArray(Of SingleNamespaceDeclaration) = _declaration.Declarations
 
            Dim builder As ArrayBuilder(Of SyntaxReference) = ArrayBuilder(Of SyntaxReference).GetInstance(declarations.Length)
 
            ' SyntaxReference in the namespace declaration points to the name node of the namespace decl node not
            ' namespace decl node we want to return. here we will wrap the original syntax reference in 
            ' the translation syntax reference so that we can lazily manipulate a node return to the caller
            For Each decl In declarations
                Dim reference = decl.SyntaxReference
                If reference IsNot Nothing AndAlso Not reference.SyntaxTree.IsEmbeddedOrMyTemplateTree() Then
                    builder.Add(New NamespaceDeclarationSyntaxReference(reference))
                End If
            Next
 
            Return builder.ToImmutableAndFree()
        End Function
 
        Friend Overrides Function IsDefinedInSourceTree(tree As SyntaxTree, definedWithinSpan As TextSpan?, Optional cancellationToken As CancellationToken = Nothing) As Boolean
            If Me.IsGlobalNamespace Then
                Return True
            Else
                ' Check if any namespace declaration block intersects with the given tree/span.
                For Each decl In _declaration.Declarations
                    cancellationToken.ThrowIfCancellationRequested()
 
                    Dim reference = decl.SyntaxReference
                    If reference IsNot Nothing AndAlso reference.SyntaxTree Is tree Then
                        If Not reference.SyntaxTree.IsEmbeddedOrMyTemplateTree() Then
                            Dim syntaxRef = New NamespaceDeclarationSyntaxReference(reference)
                            Dim syntax = syntaxRef.GetSyntax(cancellationToken)
                            If TypeOf syntax Is NamespaceStatementSyntax Then
                                ' Get the parent NamespaceBlockSyntax
                                syntax = syntax.Parent
                            End If
 
                            If IsDefinedInSourceTree(syntax, tree, definedWithinSpan, cancellationToken) Then
                                Return True
                            End If
                        End If
 
                    ElseIf decl.IsPartOfRootNamespace
                        ' Root namespace is implicitly defined in every tree 
                        Return True
                    End If
                Next
 
                Return False
            End If
        End Function
 
        ' Force all declaration errors to be generated
        Friend Overrides Sub GenerateDeclarationErrors(cancellationToken As CancellationToken)
            MyBase.GenerateDeclarationErrors(cancellationToken)
 
            ValidateDeclaration(Nothing, cancellationToken)
 
            ' Getting all the members will force declaration errors for contained stuff.
            GetMembers()
        End Sub
 
        ' Force all declaration errors In Tree to be generated
        Friend Sub GenerateDeclarationErrorsInTree(tree As SyntaxTree, filterSpanWithinTree As TextSpan?, cancellationToken As CancellationToken)
 
            ValidateDeclaration(tree, cancellationToken)
 
            ' Getting all the members will force declaration errors for contained stuff.
            GetMembers()
        End Sub
 
        ' Validate a namespace declaration. This is called for each namespace being declared, so 
        ' for example, it is called twice on Namespace X.Y, once with "X" and once with "X.Y".
        ' It will also be called with the CompilationUnit.
        Private Sub ValidateDeclaration(tree As SyntaxTree, cancellationToken As CancellationToken)
            If (_lazyState And StateFlags.DeclarationValidated) <> 0 Then
                Return
            End If
 
            Dim diagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics:=True, withDependencies:=False)
            Dim reportedNamespaceMismatch As Boolean = False
 
            ' Check for a few issues with namespace declaration.
            For Each syntaxRef In _declaration.SyntaxReferences
                If tree IsNot Nothing AndAlso syntaxRef.SyntaxTree IsNot tree Then
                    Continue For
                End If
 
                Dim currentTree = syntaxRef.SyntaxTree
                Dim node As VisualBasicSyntaxNode = syntaxRef.GetVisualBasicSyntax(cancellationToken)
                Select Case node.Kind
                    Case SyntaxKind.IdentifierName
                        ValidateNamespaceNameSyntax(DirectCast(node, IdentifierNameSyntax), diagnostics.DiagnosticBag, reportedNamespaceMismatch)
                    Case SyntaxKind.QualifiedName
                        ValidateNamespaceNameSyntax(DirectCast(node, QualifiedNameSyntax).Right, diagnostics.DiagnosticBag, reportedNamespaceMismatch)
                    Case SyntaxKind.GlobalName
                        ValidateNamespaceGlobalSyntax(DirectCast(node, GlobalNameSyntax), diagnostics.DiagnosticBag)
                    Case SyntaxKind.CompilationUnit
                        ' nothing to validate
                    Case Else
                        Throw ExceptionUtilities.UnexpectedValue(node.Kind)
                End Select
 
                cancellationToken.ThrowIfCancellationRequested()
            Next
 
            If _containingModule.AtomicSetFlagAndStoreDiagnostics(_lazyState, StateFlags.DeclarationValidated, 0, diagnostics) Then
                DeclaringCompilation.SymbolDeclaredEvent(Me)
            End If
            diagnostics.Free()
        End Sub
 
        ' Validate a particular namespace name.
        Private Sub ValidateNamespaceNameSyntax(node As SimpleNameSyntax, diagnostics As DiagnosticBag, ByRef reportedNamespaceMismatch As Boolean)
            If (node.Identifier.GetTypeCharacter() <> TypeCharacter.None) Then
                Dim diag = New VBDiagnostic(ErrorFactory.ErrorInfo(ERRID.ERR_TypecharNotallowed), node.GetLocation())
                diagnostics.Add(diag)
            End If
 
            ' Warning should only be reported for the first mismatch for each namespace to
            ' avoid reporting a large number of warnings in projects with many files.
            ' This is by design
            ' TODO: do we really want to omit these warnings and display a new one after each fix?
            ' VS can display errors and warnings separately in the IDE, so it may be ok to flood the users with
            ' these warnings.
            If Not reportedNamespaceMismatch AndAlso
                String.Compare(node.Identifier.ValueText, Me.Name, StringComparison.Ordinal) <> 0 Then
                ' all namespace names from the declarations match following the VB identifier comparison rules,
                ' so we just need to check when they are not matching using case sensitive comparison.
 
                ' filename is the one where the correct declaration occurred in Dev10
                ' TODO: report "related location" rather than including path in the message:
                Dim path = GetSourcePathForDeclaration()
                Dim diag = New VBDiagnostic(ErrorFactory.ErrorInfo(ERRID.WRN_NamespaceCaseMismatch3, node.Identifier.ValueText, Me.Name, path), node.GetLocation())
                diagnostics.Add(diag)
                reportedNamespaceMismatch = True
            End If
 
            ' TODO: once the declarations are sorted, one might cache the filename if the first declaration matches the case. 
            ' then GetFilenameForDeclaration is only needed if the mismatch occurs before any matching declaration.
        End Sub
 
        ' Validate that Global namespace name can't be nested inside another namespace.
        Private Sub ValidateNamespaceGlobalSyntax(node As GlobalNameSyntax, diagnostics As DiagnosticBag)
            Dim ancestorNode = node.Parent
            Dim seenNamespaceBlock As Boolean = False
 
            ' Go up the syntax hierarchy and make sure we only hit one namespace block (our own).
            While ancestorNode IsNot Nothing
                If ancestorNode.Kind = SyntaxKind.NamespaceBlock Then
                    If seenNamespaceBlock Then
                        ' Our namespace block is nested within another. That's a no-no.
                        Dim diag = New VBDiagnostic(ErrorFactory.ErrorInfo(ERRID.ERR_NestedGlobalNamespace), node.GetLocation())
                        diagnostics.Add(diag)
                    Else
                        seenNamespaceBlock = True
                    End If
                End If
 
                ancestorNode = ancestorNode.Parent
            End While
        End Sub
 
        ''' <summary>
        ''' Gets the filename of the first declaration that matches the given namespace name case sensitively.
        ''' </summary>
        Private Function GetSourcePathForDeclaration() As Object
            Debug.Assert(_declaration.Declarations.Length > 0)
 
            ' unfortunately we cannot initialize with the filename of the first declaration because that filename might be nothing.
            Dim path = Nothing
 
            For Each declaration In _declaration.Declarations
                If String.Compare(Me.Name, declaration.Name, StringComparison.Ordinal) = 0 Then
                    If declaration.IsPartOfRootNamespace Then
                        'path = StringConstants.ProjectSettingLocationName
                        path = New LocalizableErrorArgument(ERRID.IDS_ProjectSettingsLocationName)
 
                    ElseIf declaration.SyntaxReference IsNot Nothing AndAlso
                                                    declaration.SyntaxReference.SyntaxTree.FilePath IsNot Nothing Then
 
                        Dim otherPath = declaration.SyntaxReference.SyntaxTree.FilePath
                        If path Is Nothing Then
                            path = otherPath
                        ElseIf String.Compare(path.ToString, otherPath.ToString, StringComparison.Ordinal) > 0 Then
                            path = otherPath
                        End If
                    End If
                End If
            Next
 
            Return path
        End Function
 
        ''' <summary>
        ''' Return the set of types that should be checked for presence of extension methods in order to build
        ''' a map of extension methods for the namespace. 
        ''' </summary>
        Friend Overrides ReadOnly Property TypesToCheckForExtensionMethods As ImmutableArray(Of NamedTypeSymbol)
            Get
                If _containingModule.MightContainExtensionMethods Then
                    ' Note that we are using GetModuleMembers because only Modules can contain extension methods in source.
                    Return Me.GetModuleMembers()
                End If
 
                Return ImmutableArray(Of NamedTypeSymbol).Empty
            End Get
        End Property
 
        ''' <summary>
        ''' Does this namespace have multiple different case-sensitive spellings
        ''' (i.e., "Namespace GOO" and "Namespace goo". Includes parent namespace(s).
        ''' </summary>
        Friend ReadOnly Property HasMultipleSpellings As Boolean
            Get
                Return (_lazyState And StateFlags.HasMultipleSpellings) <> 0
            End Get
        End Property
 
        ''' <summary>
        ''' Get the fully qualified namespace name using the spelling used in the declaration enclosing the given
        ''' syntax tree and location.
        ''' I.e., if this namespace was declared with:
        ''' Namespace zAp
        '''  Namespace GOO.bar
        '''    'location
        '''  End Namespace
        ''' End Namespace
        ''' Namespace ZAP
        '''  Namespace goo.bar
        '''  End Namespace
        ''' End Namespace
        ''' 
        ''' It would return "ProjectNamespace.zAp.GOO.bar".
        ''' </summary>
        Friend Function GetDeclarationSpelling(tree As SyntaxTree, location As Integer) As String
            If Not HasMultipleSpellings Then
                ' Only one spelling. Just return that.
                Return ToDisplayString(SymbolDisplayFormat.QualifiedNameOnlyFormat)
            Else
                ' Since the declaration builder has already resolved things like "Global", qualified names, etc, 
                ' just find the declaration that encloses the location (as opposed to recreating the name 
                ' by walking the syntax)
                Dim containingDecl = _declaration.Declarations.FirstOrDefault(Function(decl)
                                                                                  Dim nsBlock As NamespaceBlockSyntax = decl.GetNamespaceBlockSyntax()
                                                                                  Return nsBlock IsNot Nothing AndAlso nsBlock.SyntaxTree Is tree AndAlso nsBlock.Span.Contains(location)
                                                                              End Function)
                If containingDecl Is Nothing Then
                    ' Could be project namespace, which has no namespace block syntax.
                    containingDecl = _declaration.Declarations.FirstOrDefault(Function(decl) decl.GetNamespaceBlockSyntax() Is Nothing)
                End If
 
                Dim containingDeclName = If(containingDecl IsNot Nothing, containingDecl.Name, Me.Name)
                Dim containingNamespace = TryCast(Me.ContainingNamespace, SourceNamespaceSymbol)
                Dim fullDeclName As String
                If containingNamespace IsNot Nothing AndAlso containingNamespace.Name <> "" Then
                    fullDeclName = containingNamespace.GetDeclarationSpelling(tree, location) + "." + containingDeclName
                Else
                    fullDeclName = containingDeclName
                End If
 
                Debug.Assert(IdentifierComparison.Equals(fullDeclName, ToDisplayString(SymbolDisplayFormat.QualifiedNameOnlyFormat)))
                Return fullDeclName
            End If
        End Function
 
        Public ReadOnly Property MergedDeclaration As MergedNamespaceDeclaration
            Get
                Return _declaration
            End Get
        End Property
    End Class
End Namespace