AliasSymbolCache.cs 3.5 KB
Newer Older
1
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.
P
Pilchie 已提交
2 3 4 5 6 7 8 9 10 11 12

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Runtime.CompilerServices;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Shared.Utilities
{
    using SymbolMap = ImmutableDictionary<INamespaceOrTypeSymbol, IAliasSymbol>;
C
CyrusNajmabadi 已提交
13
    using TreeMap = ConcurrentDictionary<(SyntaxTree tree, int namespaceId), ImmutableDictionary<INamespaceOrTypeSymbol, IAliasSymbol>>;
P
Pilchie 已提交
14 15 16 17 18 19

    internal static class AliasSymbolCache
    {
        // NOTE : I chose to cache on compilation assuming this cache will be quite small. usually number of times alias is used is quite small.
        //        but if that turns out not true, we can move this cache to be based on semantic model. unlike compilation that would be cached
        //        in compilation cache in certain host (VS), semantic model comes and goes more frequently which will release cache more often.
20 21 22
        private static readonly ConditionalWeakTable<Compilation, TreeMap> s_treeAliasMap = new ConditionalWeakTable<Compilation, TreeMap>();
        private static readonly ConditionalWeakTable<Compilation, TreeMap>.CreateValueCallback s_createTreeMap = c => new TreeMap();
        private static readonly Func<ISymbol, string> s_symbolToName = s => s.Name;
P
Pilchie 已提交
23 24 25 26 27 28 29

        public static bool TryGetAliasSymbol(SemanticModel semanticModel, int namespaceId, INamespaceOrTypeSymbol targetSymbol, out IAliasSymbol aliasSymbol)
        {
            // TODO: given semantic model must be not speculative semantic model for now. 
            // currently it can't be checked since it is not exposed to common layer yet.
            // once exposed, this method itself will make sure it use original semantic model
            aliasSymbol = null;
C
CyrusNajmabadi 已提交
30 31
            if (!s_treeAliasMap.TryGetValue(semanticModel.Compilation, out var treeMap) ||
                !treeMap.TryGetValue((semanticModel.SyntaxTree, namespaceId), out var symbolMap))
P
Pilchie 已提交
32 33 34 35 36 37 38 39 40 41 42
            {
                return false;
            }

            symbolMap.TryGetValue(targetSymbol, out aliasSymbol);
            return true;
        }

        public static void AddAliasSymbols(SemanticModel semanticModel, int namespaceId, IEnumerable<IAliasSymbol> aliasSymbols)
        {
            // given semantic model must be the original semantic model for now
43
            var treeMap = s_treeAliasMap.GetValue(semanticModel.Compilation, s_createTreeMap);
P
Pilchie 已提交
44 45

            // check again to see whether somebody has beaten us
C
Cyrus Najmabadi 已提交
46
            var key = (tree: semanticModel.SyntaxTree, namespaceId);
P
Pilchie 已提交
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
            if (treeMap.ContainsKey(key))
            {
                return;
            }

            var builder = ImmutableDictionary.CreateBuilder<INamespaceOrTypeSymbol, IAliasSymbol>();
            foreach (var alias in aliasSymbols)
            {
                if (builder.ContainsKey(alias.Target))
                {
                    continue;
                }

                // only put the first one.
                builder.Add(alias.Target, alias);
            }

P
Pharring 已提交
64 65
            // Use namespace id rather than holding onto namespace node directly, that will keep the tree alive as long as
            // the compilation is alive. In the current design, a node can come and go even if compilation is alive through recoverable tree.
P
Pilchie 已提交
66 67 68
            treeMap.TryAdd(key, builder.ToImmutable());
        }
    }
S
Sam Harwell 已提交
69
}