// 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. using System; using System.Collections.Concurrent; using Microsoft.CodeAnalysis; namespace Analyzer.Utilities { /// <summary> /// Cache ISymbol.ToDisplayName() results, to avoid performance concerns. /// </summary> internal sealed class SymbolDisplayStringCache { /// <summary> /// Caches by compilation. /// </summary> private static readonly BoundedCacheWithFactory<Compilation, ConcurrentDictionary<SymbolDisplayFormat, SymbolDisplayStringCache>> s_byCompilationCache = new(); /// <summary> /// ConcurrentDictionary key for a null SymbolDisplayFormat. /// </summary> private static readonly SymbolDisplayFormat NullSymbolDisplayFormat = new(); /// <summary> /// Mapping of a symbol to its ToDisplayString(). /// </summary> private readonly ConcurrentDictionary<ISymbol, string> SymbolToDisplayNames = new(); private readonly SymbolDisplayFormat? Format; /// <summary> /// Privately constructs. /// </summary> /// <param name="format">SymbolDisplayFormat to use, or null for the default.</param> private SymbolDisplayStringCache(SymbolDisplayFormat? format = null) { this.Format = Object.ReferenceEquals(format, NullSymbolDisplayFormat) ? null : format; } /// <summary> /// Gets the symbol display string cache for the compilation. /// </summary> /// <param name="compilation">Compilation that this cache is for.</param> /// <param name="format">A singleton SymbolDisplayFormat to use, or null for the default.</param> /// <returns>A SymbolDisplayStringCache.</returns> public static SymbolDisplayStringCache GetOrCreate(Compilation compilation, SymbolDisplayFormat? format = null) { ConcurrentDictionary<SymbolDisplayFormat, SymbolDisplayStringCache> dict = s_byCompilationCache.GetOrCreateValue(compilation, CreateConcurrentDictionary); return dict.GetOrAdd(format ?? NullSymbolDisplayFormat, CreateSymbolDisplayStringCache); // Local functions static ConcurrentDictionary<SymbolDisplayFormat, SymbolDisplayStringCache> CreateConcurrentDictionary(Compilation compilation) => new(); static SymbolDisplayStringCache CreateSymbolDisplayStringCache(SymbolDisplayFormat? format) => new(format); } /// <summary> /// Gets the symbol's display string. /// </summary> /// <param name="symbol">Symbol to get the display string.</param> /// <returns>The symbol's display string.</returns> public string GetDisplayString(ISymbol symbol) { return this.SymbolToDisplayNames.GetOrAdd(symbol, s => s.ToDisplayString(this.Format)); } } } |