using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Serialization; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindSymbols { internal partial class SymbolTreeInfo { private static SimplePool> s_symbolMapPool = new SimplePool>(() => new MultiDictionary()); private static MultiDictionary AllocateSymbolMap() { return s_symbolMapPool.Allocate(); } private static void FreeSymbolMap(MultiDictionary symbolMap) { symbolMap.Clear(); s_symbolMapPool.Free(symbolMap); } public static async Task GetInfoForSourceAssemblyAsync( Project project, CancellationToken cancellationToken) { var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); var stateChecksums = await project.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false); var checksum = Checksum.Create(nameof(SymbolTreeInfo), new Checksum[] { stateChecksums.Documents.Checksum, stateChecksums.CompilationOptions, stateChecksums.ParseOptions }); return await LoadOrCreateSourceSymbolTreeInfoAsync( project.Solution, compilation.Assembly, checksum, project.FilePath, loadOnly: false, cancellationToken: cancellationToken).ConfigureAwait(false); } internal static SymbolTreeInfo CreateSourceSymbolTreeInfo( Solution solution, Checksum checksum, IAssemblySymbol assembly, string filePath, CancellationToken cancellationToken) { if (assembly == null) { return null; } var unsortedNodes = ArrayBuilder.GetInstance(); unsortedNodes.Add(new BuilderNode(assembly.GlobalNamespace.Name, RootNodeParentIndex)); GenerateSourceNodes(assembly.GlobalNamespace, unsortedNodes, s_getMembersNoPrivate); return CreateSymbolTreeInfo( solution, checksum, filePath, unsortedNodes.ToImmutableAndFree(), inheritanceMap: new OrderPreservingMultiDictionary()); } // generate nodes for the global namespace an all descendants private static void GenerateSourceNodes( INamespaceSymbol globalNamespace, ArrayBuilder list, Action> lookup) { // Add all child members var symbolMap = AllocateSymbolMap(); try { lookup(globalNamespace, symbolMap); foreach (var kvp in symbolMap) { GenerateSourceNodes(kvp.Key, 0 /*index of root node*/, kvp.Value, list, lookup); } } finally { FreeSymbolMap(symbolMap); } } private static readonly Func s_useSymbolNoPrivate = s => s.CanBeReferencedByName && s.DeclaredAccessibility != Accessibility.Private; private static readonly Func s_useSymbolNoPrivateOrInternal = s => s.CanBeReferencedByName && s.DeclaredAccessibility != Accessibility.Private && s.DeclaredAccessibility != Accessibility.Internal; // generate nodes for symbols that share the same name, and all their descendants private static void GenerateSourceNodes( string name, int parentIndex, MultiDictionary.ValueSet symbolsWithSameName, ArrayBuilder list, Action> lookup) { var node = new BuilderNode(name, parentIndex); var nodeIndex = list.Count; list.Add(node); var symbolMap = AllocateSymbolMap(); try { // Add all child members foreach (var symbol in symbolsWithSameName) { lookup(symbol, symbolMap); } foreach (var kvp in symbolMap) { GenerateSourceNodes(kvp.Key, nodeIndex, kvp.Value, list, lookup); } } finally { FreeSymbolMap(symbolMap); } } private static Action> s_getMembersNoPrivate = (symbol, symbolMap) => AddSymbol(symbol, symbolMap, s_useSymbolNoPrivate); private static void AddSymbol(ISymbol symbol, MultiDictionary symbolMap, Func useSymbol) { var nt = symbol as INamespaceOrTypeSymbol; if (nt != null) { foreach (var member in nt.GetMembers()) { if (useSymbol(member)) { symbolMap.Add(member.Name, member); } } } } } }