/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Symbols/MergedNamespaceSymbol.vb
718 строк
34 KB
Jeff Robison
Reduce allocations in MergedNamespaceSymbol.SlowGetChildNames (#68614)
16 июн 2023, 20:23
Не верифицирован
16 июн 2023, 20:23
8681fc3
Код
Авторство
О чём код?
' 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.Generic Imports System.Collections.Immutable Imports System.Collections.ObjectModel Imports System.Threading Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' <summary> ''' A MergedNamespaceSymbol represents a namespace that merges the contents of two or more other ''' namespaces. Any sub-namespaces with the same names are also merged if they have two or more ''' instances. ''' ''' Merged namespaces are used to merged the symbols from multiple metadata modules and the source "module" ''' into a single symbol tree that represents all the available symbols. The compiler resolves names ''' against Me merged set of symbols. ''' ''' Typically there will not be very many merged namespaces in a Compilation: only the root namespaces and ''' namespaces that are used in multiple referenced modules. (Microsoft, System, System.Xml, ''' System.Diagnostics, System.Threading, ...) ''' </summary> Friend MustInherit Class MergedNamespaceSymbol Inherits PEOrSourceOrMergedNamespaceSymbol Protected ReadOnly _namespacesToMerge As ImmutableArray(Of NamespaceSymbol) Protected ReadOnly _containingNamespace As MergedNamespaceSymbol ' The cachedLookup caches results of lookups on the constituent namespaces so ' that subsequent lookups for the same name are much faster than having to ask ' each of the constituent namespaces. Private ReadOnly _cachedLookup As CachingDictionary(Of String, Symbol) ' This caches results of GetModuleMembers() Private _lazyModuleMembers As ImmutableArray(Of NamedTypeSymbol) ' This caches results of GetMembers() Private _lazyMembers As ImmutableArray(Of Symbol) Private _lazyEmbeddedKind As Integer = EmbeddedSymbolKind.Unset ''' <summary> ''' Create a possibly merged namespace symbol representing global namespace on an assembly level. ''' </summary> Public Shared Function CreateGlobalNamespace(extent As AssemblySymbol) As NamespaceSymbol ' Get the root namespace from each module, and merge them all together. If there is only one, ' then MergedNamespaceSymbol.Create will just return that one. Return MergedNamespaceSymbol.Create(extent, Nothing, ConstituentGlobalNamespaces(extent).AsImmutable()) End Function Private Shared Iterator Function ConstituentGlobalNamespaces(extent As AssemblySymbol) As IEnumerable(Of NamespaceSymbol) For Each m In extent.Modules Yield m.GlobalNamespace Next End Function ''' <summary> ''' Create a possibly merged namespace symbol. If only a single namespace is passed it, it is just returned directly. ''' If two or more namespaces are passed in, then a new merged namespace is created with the given extent and container. ''' </summary> ''' <param name="extent">The namespace extent to use, IF a merged namespace is created.</param> ''' <param name="containingNamespace">The containing namespace to used, IF a merged namespace is created.</param> ''' <param name="namespacesToMerge">One or more namespaces to merged. If just one, then it is returned. ''' The merged namespace symbol may hold onto the array.</param> ''' <returns></returns>A namespace symbol representing the merged namespace.(of /returns) Private Shared Function Create(extent As AssemblySymbol, containingNamespace As AssemblyMergedNamespaceSymbol, namespacesToMerge As ImmutableArray(Of NamespaceSymbol)) As NamespaceSymbol ' Currently, if we are just merging 1 namespace, we just return the namespace itself. This is ' by far the most efficient, because it means that we don't create merged namespaces (which have a fair amount ' of memory overhead) unless there is actual merging going on. However, it means that ' the child namespace of a Compilation extent namespace may be a Module extent namespace, and the containing of that ' module extent namespace will be another module extent namespace. This is basically no different than type members of namespaces, ' so it shouldn't be TOO unexpected. Debug.Assert(namespacesToMerge.Length <> 0) If namespacesToMerge.Length = 1 Then Dim result = namespacesToMerge(0) Return result Else Return New AssemblyMergedNamespaceSymbol(extent, containingNamespace, namespacesToMerge) End If End Function Friend Shared Function CreateForTestPurposes(extent As AssemblySymbol, namespacesToMerge As IEnumerable(Of NamespaceSymbol)) As NamespaceSymbol Return Create(extent, Nothing, namespacesToMerge.AsImmutable()) End Function ''' <summary> ''' Create a possibly merged namespace symbol representing global namespace on a compilation level. ''' </summary> Public Shared Function CreateGlobalNamespace(extent As VisualBasicCompilation) As NamespaceSymbol ' Get the root namespace from each module, and merge them all together. Return MergedNamespaceSymbol.Create(extent, Nothing, ConstituentGlobalNamespaces(extent)) End Function Private Shared Iterator Function ConstituentGlobalNamespaces(extent As VisualBasicCompilation) As IEnumerable(Of NamespaceSymbol) For Each m In extent.Assembly.Modules Yield m.GlobalNamespace Next For Each reference In extent.SourceModule.GetReferencedAssemblySymbols() For Each m In reference.Modules Yield m.GlobalNamespace Next Next End Function Private Shared Function Create(extent As VisualBasicCompilation, containingNamespace As CompilationMergedNamespaceSymbol, namespacesToMerge As IEnumerable(Of NamespaceSymbol)) As NamespaceSymbol Dim namespaceArray = ArrayBuilder(Of NamespaceSymbol).GetInstance() namespaceArray.AddRange(namespacesToMerge) ' Currently, if we are just merging 1 namespace, we just return the namespace itself. This is ' by far the most efficient, because it means that we don't create merged namespaces (which have a fair amount ' of memory overhead) unless there is actual merging going on. However, it means that ' the child namespace of a Compilation extent namespace may be a Module extent namespace, and the containing of that ' module extent namespace will be another module extent namespace. This is basically no different than type members of namespaces, ' so it shouldn't be TOO unexpected. Debug.Assert(namespaceArray.Count <> 0) If (namespaceArray.Count = 1) Then Dim result = namespaceArray(0) namespaceArray.Free() Return result Else Return New CompilationMergedNamespaceSymbol(extent, containingNamespace, namespaceArray.ToImmutableAndFree()) End If End Function ''' <summary> ''' Create a possibly merged namespace symbol (namespace group). If only a single namespace is passed it, it is just returned directly. ''' If two or more namespaces are passed in, then a new merged namespace is created ''' </summary> ''' <param name="namespacesToMerge">One or more namespaces to merged. If just one, then it is returned. ''' The merged namespace symbol may hold onto the array.</param> ''' <returns></returns>A namespace symbol representing the merged namespace.(of /returns) Public Shared Function CreateNamespaceGroup(namespacesToMerge As IEnumerable(Of NamespaceSymbol)) As NamespaceSymbol Return Create(NamespaceGroupSymbol.GlobalNamespace, namespacesToMerge) End Function Public Overridable Function Shrink(namespacesToMerge As IEnumerable(Of NamespaceSymbol)) As NamespaceSymbol Throw ExceptionUtilities.Unreachable End Function ''' <summary> ''' Create a possibly merged namespace symbol (namespace group). If only a single namespace is passed it, it is just returned directly. ''' If two or more namespaces are passed in, then a new merged namespace is created with the given extent and container. ''' </summary> ''' <param name="containingNamespace">The containing namespace to used, IF a merged namespace is created.</param> ''' <param name="namespacesToMerge">One or more namespaces to merged. If just one, then it is returned. ''' The merged namespace symbol may hold onto the array.</param> ''' <returns></returns>A namespace symbol representing the merged namespace.(of /returns) Private Shared Function Create(containingNamespace As NamespaceGroupSymbol, namespacesToMerge As IEnumerable(Of NamespaceSymbol)) As NamespaceSymbol Dim namespaceArray = ArrayBuilder(Of NamespaceSymbol).GetInstance() namespaceArray.AddRange(namespacesToMerge) ' Currently, if we are just merging 1 namespace, we just return the namespace itself. This is ' by far the most efficient, because it means that we don't create merged namespaces (which have a fair amount ' of memory overhead) unless there is actual merging going on. However, it means that ' the child namespace of a Compilation extent namespace may be a Module extent namespace, and the containing of that ' module extent namespace will be another module extent namespace. This is basically no different than type members of namespaces, ' so it shouldn't be TOO unexpected. Debug.Assert(namespaceArray.Count <> 0) If (namespaceArray.Count = 1) Then Dim result = namespaceArray(0) namespaceArray.Free() Return result Else Return New NamespaceGroupSymbol(containingNamespace, namespaceArray.ToImmutableAndFree()) End If End Function ' Constructor. Use static Create method to create instances. Private Sub New(containingNamespace As MergedNamespaceSymbol, namespacesToMerge As ImmutableArray(Of NamespaceSymbol)) Debug.Assert(namespacesToMerge.Distinct().Length = namespacesToMerge.Length) Me._namespacesToMerge = namespacesToMerge Me._containingNamespace = containingNamespace Me._cachedLookup = New CachingDictionary(Of String, Symbol)(AddressOf SlowGetChildrenOfName, AddressOf SlowGetChildNames, IdentifierComparison.Comparer) End Sub Friend Function GetConstituentForCompilation(compilation As VisualBasicCompilation) As NamespaceSymbol For Each constituent In _namespacesToMerge If constituent.IsFromCompilation(compilation) Then Return constituent End If Next Return Nothing End Function Public Overrides ReadOnly Property ConstituentNamespaces As ImmutableArray(Of NamespaceSymbol) Get Return _namespacesToMerge End Get End Property ''' <summary> ''' Method that is called from the CachingLookup to lookup the children of a given name. Looks ''' in all the constituent namespaces. ''' </summary> Private Function SlowGetChildrenOfName(name As String) As ImmutableArray(Of Symbol) Dim nsSymbols As ArrayBuilder(Of NamespaceSymbol) = Nothing Dim otherSymbols = ArrayBuilder(Of Symbol).GetInstance() ' Accumulate all the child namespaces and types. For Each nsSym As NamespaceSymbol In _namespacesToMerge For Each childSym As Symbol In nsSym.GetMembers(name) If (childSym.Kind = SymbolKind.Namespace) Then nsSymbols = If(nsSymbols, ArrayBuilder(Of NamespaceSymbol).GetInstance()) nsSymbols.Add(DirectCast(childSym, NamespaceSymbol)) Else otherSymbols.Add(childSym) End If Next Next If nsSymbols IsNot Nothing Then otherSymbols.Add(CreateChildMergedNamespaceSymbol(nsSymbols.ToImmutableAndFree())) End If Return otherSymbols.ToImmutableAndFree() End Function Protected MustOverride Function CreateChildMergedNamespaceSymbol(nsSymbols As ImmutableArray(Of NamespaceSymbol)) As NamespaceSymbol ''' <summary> ''' Method that is called from the CachingLookup to get all child names. Looks ''' in all constituent namespaces. ''' </summary> Private Function SlowGetChildNames(comparer As IEqualityComparer(Of String)) As SegmentedHashSet(Of String) ' compute an upper bound for the final capacity of the set we'll return, to reduce heap churn Dim childCount As Integer = 0 For Each nsSym As NamespaceSymbol In _namespacesToMerge childCount += nsSym.GetMembersUnordered().Length Next Dim childNames As New SegmentedHashSet(Of String)(childCount, comparer) For Each nsSym As NamespaceSymbol In _namespacesToMerge For Each childSym As NamespaceOrTypeSymbol In nsSym.GetMembersUnordered() childNames.Add(childSym.Name) Next Next Return childNames End Function Public Overrides ReadOnly Property Name As String Get Return _namespacesToMerge(0).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 ns In _namespacesToMerge value = value Or ns.EmbeddedSymbolKind Next Interlocked.CompareExchange(_lazyEmbeddedKind, value, EmbeddedSymbolKind.Unset) End If Return CType(_lazyEmbeddedKind, EmbeddedSymbolKind) End Get End Property ' This is very performance critical for type lookup. ' It's important that this NOT enumerable and instantiate all the members. Instead, we just want to return ' all the modules in all constituent namespaces, and cache that. Public Overrides Function GetModuleMembers() As ImmutableArray(Of NamedTypeSymbol) If _lazyModuleMembers.IsDefault Then Dim moduleMembers = ArrayBuilder(Of NamedTypeSymbol).GetInstance() ' Accumulate all the child modules. For Each nsSym As NamespaceSymbol In _namespacesToMerge moduleMembers.AddRange(nsSym.GetModuleMembers()) Next ImmutableInterlocked.InterlockedCompareExchange(_lazyModuleMembers, moduleMembers.ToImmutableAndFree, Nothing) End If Return _lazyModuleMembers End Function Public Overrides Function GetMembers() As ImmutableArray(Of Symbol) If _lazyMembers.IsDefault Then Dim builder = ArrayBuilder(Of Symbol).GetInstance() _cachedLookup.AddValues(builder) _lazyMembers = builder.ToImmutableAndFree() End If Return _lazyMembers End Function Public Overrides Function GetMembers(name As String) As ImmutableArray(Of Symbol) Return _cachedLookup(name) End Function Friend Overrides Function GetTypeMembersUnordered() As ImmutableArray(Of NamedTypeSymbol) Return ImmutableArray.CreateRange(Of NamedTypeSymbol)(GetMembersUnordered().OfType(Of NamedTypeSymbol)) End Function Public Overrides Function GetTypeMembers() As ImmutableArray(Of NamedTypeSymbol) Return ImmutableArray.CreateRange(Of NamedTypeSymbol)(GetMembers().OfType(Of NamedTypeSymbol)) End Function Public Overrides Function GetTypeMembers(name As String) As ImmutableArray(Of NamedTypeSymbol) 'TODO - Perf Return ImmutableArray.CreateRange(Of NamedTypeSymbol)(GetMembers(name).OfType(Of NamedTypeSymbol)) End Function Public Overrides ReadOnly Property ContainingSymbol As Symbol Get Return _containingNamespace End Get End Property Public Overrides ReadOnly Property ContainingAssembly As AssemblySymbol Get If Me.Extent.Kind = NamespaceKind.Module Then Return Me.Extent.Module.ContainingAssembly ElseIf Me.Extent.Kind = NamespaceKind.Assembly Then Return Me.Extent.Assembly Else Return Nothing End If End Get End Property Public Overrides ReadOnly Property Locations As ImmutableArray(Of Location) Get Return ImmutableArray.CreateRange(Of Location)((From ns In _namespacesToMerge, loc In ns.Locations Select loc)) End Get End Property Public Overrides ReadOnly Property DeclaringSyntaxReferences As ImmutableArray(Of SyntaxReference) Get Return ImmutableArray.CreateRange(Of SyntaxReference)(From ns In _namespacesToMerge, reference In ns.DeclaringSyntaxReferences Select reference) End Get End Property ''' <summary> ''' Calculate declared accessibility of most accessible type within this namespace or within a containing namespace recursively. ''' Expected to be called at most once per namespace symbol, unless there is a race condition. ''' ''' Valid return values: ''' Friend, ''' Public, ''' NotApplicable - if there are no types. ''' </summary> Protected NotOverridable Overrides Function GetDeclaredAccessibilityOfMostAccessibleDescendantType() As Accessibility Dim result As Accessibility = Accessibility.NotApplicable For Each nsSym As NamespaceSymbol In _namespacesToMerge Dim current As Accessibility = nsSym.DeclaredAccessibilityOfMostAccessibleDescendantType If current > result Then If current = Accessibility.Public Then Return Accessibility.Public End If result = current End If Next Return result End Function Friend Overrides Function IsDeclaredInSourceModule([module] As ModuleSymbol) As Boolean For Each nsSym As NamespaceSymbol In _namespacesToMerge If nsSym.IsDeclaredInSourceModule([module]) Then Return True End If Next Return False End Function ''' <summary> ''' For test purposes only. ''' </summary> Friend MustOverride ReadOnly Property RawContainsAccessibleTypes As ThreeState Private NotInheritable Class AssemblyMergedNamespaceSymbol Inherits MergedNamespaceSymbol Private ReadOnly _assembly As AssemblySymbol Public Sub New(assembly As AssemblySymbol, containingNamespace As AssemblyMergedNamespaceSymbol, namespacesToMerge As ImmutableArray(Of NamespaceSymbol)) MyBase.New(containingNamespace, namespacesToMerge) #If DEBUG Then ' We shouldn't merge merged namespaces. For Each ns In namespacesToMerge Debug.Assert(ns.ConstituentNamespaces.Length = 1) Next #End If Debug.Assert(namespacesToMerge.Length > 0) Debug.Assert(containingNamespace Is Nothing OrElse containingNamespace._assembly Is assembly) Me._assembly = assembly End Sub Friend Overrides ReadOnly Property Extent As NamespaceExtent Get Return New NamespaceExtent(_assembly) End Get End Property Protected Overrides Function CreateChildMergedNamespaceSymbol(nsSymbols As ImmutableArray(Of NamespaceSymbol)) As NamespaceSymbol Return MergedNamespaceSymbol.Create(_assembly, Me, nsSymbols) End Function Friend Overrides ReadOnly Property RawContainsAccessibleTypes As ThreeState Get Throw ExceptionUtilities.Unreachable End Get End Property Friend Overrides Sub BuildExtensionMethodsMap(map As Dictionary(Of String, ArrayBuilder(Of MethodSymbol))) ' Assembly merged namespace symbols aren't used by binders. Throw ExceptionUtilities.Unreachable End Sub Friend Overrides ReadOnly Property TypesToCheckForExtensionMethods As ImmutableArray(Of NamedTypeSymbol) Get ' Assembly merged namespace symbols aren't used by binders. Throw ExceptionUtilities.Unreachable End Get End Property End Class Private NotInheritable Class CompilationMergedNamespaceSymbol Inherits MergedNamespaceSymbol Private ReadOnly _compilation As VisualBasicCompilation Private _containsAccessibleTypes As ThreeState = ThreeState.Unknown Private _isDeclaredInSourceModule As ThreeState = ThreeState.Unknown Friend Overrides ReadOnly Property RawContainsAccessibleTypes As ThreeState Get Return _containsAccessibleTypes End Get End Property Public Sub New(compilation As VisualBasicCompilation, containingNamespace As CompilationMergedNamespaceSymbol, namespacesToMerge As ImmutableArray(Of NamespaceSymbol)) MyBase.New(containingNamespace, namespacesToMerge) #If DEBUG Then ' We shouldn't merge merged namespaces. For Each ns In namespacesToMerge Debug.Assert(ns.ConstituentNamespaces.Length = 1) Next #End If Debug.Assert(namespacesToMerge.Length > 0) Debug.Assert(containingNamespace Is Nothing OrElse containingNamespace._compilation Is compilation) Me._compilation = compilation End Sub Friend Overrides ReadOnly Property Extent As NamespaceExtent Get Return New NamespaceExtent(_compilation) End Get End Property Protected Overrides Function CreateChildMergedNamespaceSymbol(nsSymbols As ImmutableArray(Of NamespaceSymbol)) As NamespaceSymbol Return MergedNamespaceSymbol.Create(_compilation, Me, nsSymbols) End Function ''' <summary> ''' Returns true if namespace contains types accessible from the target assembly. ''' </summary> Friend Overrides Function ContainsTypesAccessibleFrom(fromAssembly As AssemblySymbol) As Boolean ' For a compilation merged namespace we only need to support scenario when ' [fromAssembly] is compilation's assembly, because this namespace symbol will never be ' "imported" namespace in context of other compilation. ' This allows us to do efficient caching of the result. Debug.Assert(fromAssembly Is _compilation.Assembly) If _containsAccessibleTypes.HasValue Then Return _containsAccessibleTypes = ThreeState.True End If If Me.RawLazyDeclaredAccessibilityOfMostAccessibleDescendantType = Accessibility.Public Then Return True End If Dim result As Boolean = False For Each nsSym As NamespaceSymbol In _namespacesToMerge If nsSym.ContainsTypesAccessibleFrom(fromAssembly) Then result = True Exit For End If Next If result Then _containsAccessibleTypes = ThreeState.True ' Bubble up the value. Dim parent = TryCast(Me.ContainingSymbol, CompilationMergedNamespaceSymbol) While parent IsNot Nothing AndAlso parent._containsAccessibleTypes = ThreeState.Unknown parent._containsAccessibleTypes = ThreeState.True parent = TryCast(parent.ContainingSymbol, CompilationMergedNamespaceSymbol) End While Else _containsAccessibleTypes = ThreeState.False End If Return result End Function Friend Overrides Function IsDeclaredInSourceModule([module] As ModuleSymbol) As Boolean ' For a compilation merged namespace we only need to support scenario when ' [module] is compilation's source module, because this namespace symbol will never be ' "imported" namespace in context of other compilation. ' This allows us to do efficient caching of the result. Debug.Assert([module] Is _compilation.SourceModule) If _isDeclaredInSourceModule.HasValue Then Return _isDeclaredInSourceModule = ThreeState.True End If Dim result = MyBase.IsDeclaredInSourceModule([module]) If result Then _isDeclaredInSourceModule = ThreeState.True ' Bubble up the value. Dim parent = TryCast(Me.ContainingSymbol, CompilationMergedNamespaceSymbol) While parent IsNot Nothing AndAlso parent._isDeclaredInSourceModule = ThreeState.Unknown parent._isDeclaredInSourceModule = ThreeState.True parent = TryCast(parent.ContainingSymbol, CompilationMergedNamespaceSymbol) End While Else _isDeclaredInSourceModule = ThreeState.False End If Return result End Function ''' <summary> ''' Populate the map with all extension methods declared within this namespace, so that methods from ''' the same type are grouped together within each bucket. ''' </summary> Friend Overrides Sub BuildExtensionMethodsMap(map As Dictionary(Of String, ArrayBuilder(Of MethodSymbol))) For Each nsSym As NamespaceSymbol In _namespacesToMerge ' CONSIDER: Is it worth using m_lazyExtensionMethodsMap for nsSym if we've built it already for a ' different compilation? nsSym.BuildExtensionMethodsMap(map) Next End Sub Friend Overrides Sub GetExtensionMethods(methods As ArrayBuilder(Of MethodSymbol), name As String) For Each nsSym As NamespaceSymbol In _namespacesToMerge nsSym.GetExtensionMethods(methods, name) Next End Sub Friend Overrides ReadOnly Property TypesToCheckForExtensionMethods As ImmutableArray(Of NamedTypeSymbol) Get ' We should override all callers of this function and go through implementation ' provided by each individual namespace symbol. Throw ExceptionUtilities.Unreachable End Get End Property End Class Private NotInheritable Class NamespaceGroupSymbol Inherits MergedNamespaceSymbol Public Shared ReadOnly GlobalNamespace As New NamespaceGroupSymbol(Nothing, ImmutableArray(Of NamespaceSymbol).Empty) Public Sub New(containingNamespace As NamespaceGroupSymbol, namespacesToMerge As ImmutableArray(Of NamespaceSymbol)) MyBase.New(containingNamespace, namespacesToMerge) #If DEBUG Then Dim name As String = If(namespacesToMerge.Length > 0, namespacesToMerge(0).Name, Nothing) For Each ns In namespacesToMerge Debug.Assert(ns.NamespaceKind = NamespaceKind.Module OrElse ns.NamespaceKind = NamespaceKind.Compilation) Debug.Assert(Not ns.IsGlobalNamespace) Debug.Assert(IdentifierComparison.Equals(name, ns.Name)) Next #End If Debug.Assert(containingNamespace Is Nothing OrElse namespacesToMerge.Length > 0) End Sub Public Overrides ReadOnly Property Name As String Get Return If(_namespacesToMerge.Length > 0, _namespacesToMerge(0).Name, "") End Get End Property #If DEBUG Then Shared Sub New() ' Below is a set of compile time asserts, they break build if violated. ' Assert(SymbolExtensions.NamespaceKindNamespaceGroup = 0) ' This is needed because we use default NamespaceExtent constructor in Extent property. Const assert01_1 As Integer = SymbolExtensions.NamespaceKindNamespaceGroup + Int32.MaxValue Const assert01_2 As Integer = SymbolExtensions.NamespaceKindNamespaceGroup + Int32.MinValue Dim dummy = assert01_1 + assert01_2 End Sub #End If Friend Overrides ReadOnly Property Extent As NamespaceExtent Get Return New NamespaceExtent() End Get End Property Friend Overrides ReadOnly Property RawContainsAccessibleTypes As ThreeState Get Throw ExceptionUtilities.Unreachable End Get End Property Friend Overrides ReadOnly Property TypesToCheckForExtensionMethods As ImmutableArray(Of NamedTypeSymbol) Get Throw ExceptionUtilities.Unreachable End Get End Property Friend Overrides Sub BuildExtensionMethodsMap(map As Dictionary(Of String, ArrayBuilder(Of MethodSymbol))) Throw ExceptionUtilities.Unreachable End Sub Protected Overrides Function CreateChildMergedNamespaceSymbol(nsSymbols As ImmutableArray(Of NamespaceSymbol)) As NamespaceSymbol Return MergedNamespaceSymbol.Create(Me, nsSymbols) End Function Public Overrides Function Shrink(namespacesToMerge As IEnumerable(Of NamespaceSymbol)) As NamespaceSymbol Dim namespaceArray = ArrayBuilder(Of NamespaceSymbol).GetInstance() namespaceArray.AddRange(namespacesToMerge) ' Currently, if we are just merging 1 namespace, we just return the namespace itself. This is ' by far the most efficient, because it means that we don't create merged namespaces (which have a fair amount ' of memory overhead) unless there is actual merging going on. Debug.Assert(namespaceArray.Count <> 0) If namespaceArray.Count = 0 Then namespaceArray.Free() Return Me End If ' New set of parts should be a subset of what we already have If namespaceArray.Count = 1 Then Dim result = namespaceArray(0) namespaceArray.Free() If _namespacesToMerge.Contains(result) Then Return result End If Throw ExceptionUtilities.Unreachable End If Dim lookup = New SmallDictionary(Of NamespaceSymbol, Boolean)() For Each item In _namespacesToMerge lookup(item) = False Next For Each item In namespaceArray If Not lookup.TryGetValue(item, Nothing) Then Debug.Assert(False) namespaceArray.Free() Return Me End If Next Return Shrink(namespaceArray.ToImmutableAndFree()) End Function Private Overloads Function Shrink(namespaceArray As ImmutableArray(Of NamespaceSymbol)) As NamespaceGroupSymbol Debug.Assert(namespaceArray.Length < _namespacesToMerge.Length) If namespaceArray.Length >= _namespacesToMerge.Length Then Debug.Assert(False) Return Me End If If _containingNamespace Is GlobalNamespace Then Return New NamespaceGroupSymbol(GlobalNamespace, namespaceArray) End If Dim parentsArray = ArrayBuilder(Of NamespaceSymbol).GetInstance(namespaceArray.Length) For Each item In namespaceArray parentsArray.Add(item.ContainingNamespace) Next Return New NamespaceGroupSymbol(DirectCast(_containingNamespace, NamespaceGroupSymbol).Shrink(parentsArray.ToImmutableAndFree()), namespaceArray) End Function End Class End Class End Namespace