SymbolTreeInfo_Source.cs 5.3 KB
Newer Older
1 2
using System;
using System.Collections.Generic;
C
CyrusNajmabadi 已提交
3
using System.Collections.Immutable;
4 5
using System.Threading;
using System.Threading.Tasks;
6
using Microsoft.CodeAnalysis.Collections;
7
using Microsoft.CodeAnalysis.Serialization;
8 9 10 11 12 13
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.FindSymbols
{
    internal partial class SymbolTreeInfo
    {
14 15 16 17 18 19 20 21 22 23 24 25 26 27
        private static SimplePool<MultiDictionary<string, ISymbol>> s_symbolMapPool =
            new SimplePool<MultiDictionary<string, ISymbol>>(() => new MultiDictionary<string, ISymbol>());

        private static MultiDictionary<string, ISymbol> AllocateSymbolMap()
        {
            return s_symbolMapPool.Allocate();
        }

        private static void FreeSymbolMap(MultiDictionary<string, ISymbol> symbolMap)
        {
            symbolMap.Clear();
            s_symbolMapPool.Free(symbolMap);
        }

28 29 30 31
        public static async Task<SymbolTreeInfo> GetInfoForSourceAssemblyAsync(
            Project project, CancellationToken cancellationToken)
        {
            var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
32 33
            var stateChecksums = await project.State.GetStateChecksumsAsync(cancellationToken).ConfigureAwait(false);

34
            var checksum = Checksum.Create(nameof(SymbolTreeInfo),
35
                new Checksum[] { stateChecksums.Documents.Checksum, stateChecksums.CompilationOptions, stateChecksums.ParseOptions });
36 37

            return await LoadOrCreateSourceSymbolTreeInfoAsync(
38
                project.Solution, compilation.Assembly, checksum, project.FilePath,
C
CyrusNajmabadi 已提交
39
                loadOnly: false, cancellationToken: cancellationToken).ConfigureAwait(false);
40 41 42
        }

        internal static SymbolTreeInfo CreateSourceSymbolTreeInfo(
43
            Solution solution, Checksum checksum, IAssemblySymbol assembly,
C
CyrusNajmabadi 已提交
44
            string filePath, CancellationToken cancellationToken)
45 46 47 48 49 50
        {
            if (assembly == null)
            {
                return null;
            }

51
            var unsortedNodes = ArrayBuilder<BuilderNode>.GetInstance();
52
            unsortedNodes.Add(new BuilderNode(assembly.GlobalNamespace.Name, RootNodeParentIndex));
53

C
CyrusNajmabadi 已提交
54
            GenerateSourceNodes(assembly.GlobalNamespace, unsortedNodes, s_getMembersNoPrivate);
55

C
CyrusNajmabadi 已提交
56
            return CreateSymbolTreeInfo(
57
                solution, checksum, filePath, unsortedNodes.ToImmutableAndFree(), 
C
CyrusNajmabadi 已提交
58
                inheritanceMap: new OrderPreservingMultiDictionary<string, string>());
59 60 61 62 63
        }

        // generate nodes for the global namespace an all descendants
        private static void GenerateSourceNodes(
            INamespaceSymbol globalNamespace,
64
            ArrayBuilder<BuilderNode> list,
65
            Action<ISymbol, MultiDictionary<string, ISymbol>> lookup)
66 67
        {
            // Add all child members
68 69 70 71
            var symbolMap = AllocateSymbolMap();
            try
            {
                lookup(globalNamespace, symbolMap);
72

73 74 75 76 77 78
                foreach (var kvp in symbolMap)
                {
                    GenerateSourceNodes(kvp.Key, 0 /*index of root node*/, kvp.Value, list, lookup);
                }
            }
            finally
79
            {
80
                FreeSymbolMap(symbolMap);
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
            }
        }

        private static readonly Func<ISymbol, bool> s_useSymbolNoPrivate =
            s => s.CanBeReferencedByName && s.DeclaredAccessibility != Accessibility.Private;

        private static readonly Func<ISymbol, bool> 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,
96
            MultiDictionary<string, ISymbol>.ValueSet symbolsWithSameName,
97
            ArrayBuilder<BuilderNode> list,
98
            Action<ISymbol, MultiDictionary<string, ISymbol>> lookup)
99
        {
100
            var node = new BuilderNode(name, parentIndex);
101 102 103
            var nodeIndex = list.Count;
            list.Add(node);

104 105 106 107 108 109 110 111
            var symbolMap = AllocateSymbolMap();
            try
            {
                // Add all child members
                foreach (var symbol in symbolsWithSameName)
                {
                    lookup(symbol, symbolMap);
                }
112

113 114 115 116 117 118
                foreach (var kvp in symbolMap)
                {
                    GenerateSourceNodes(kvp.Key, nodeIndex, kvp.Value, list, lookup);
                }
            }
            finally
119
            {
120
                FreeSymbolMap(symbolMap);
121 122 123
            }
        }

124 125
        private static Action<ISymbol, MultiDictionary<string, ISymbol>> s_getMembersNoPrivate =
            (symbol, symbolMap) => AddSymbol(symbol, symbolMap, s_useSymbolNoPrivate);
126

127
        private static void AddSymbol(ISymbol symbol, MultiDictionary<string, ISymbol> symbolMap, Func<ISymbol, bool> useSymbol)
128 129
        {
            var nt = symbol as INamespaceOrTypeSymbol;
130 131 132 133 134 135 136 137 138 139 140
            if (nt != null)
            {
                foreach (var member in nt.GetMembers())
                {
                    if (useSymbol(member))
                    {
                        symbolMap.Add(member.Name, member);
                    }
                }
            }
        }
141 142
    }
}