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

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Runtime.CompilerServices;
using System.Threading;

namespace Microsoft.CodeAnalysis.Diagnostics
{
    internal abstract partial class AnalyzerDriver : IDisposable
    {
13
        protected static readonly ConditionalWeakTable<Compilation, CompilationData> s_compilationDataCache = new ConditionalWeakTable<Compilation, CompilationData>();
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

        internal class CompilationData
        {
            /// <summary>
            /// Cached semantic model for the compilation trees.
            /// PERF: This cache enables us to re-use semantic model's bound node cache across analyzer execution and diagnostic queries.
            /// </summary>
            private readonly Dictionary<SyntaxTree, SemanticModel> _semanticModelsMap;

            public CompilationData(Compilation comp)
            {
                _semanticModelsMap = new Dictionary<SyntaxTree, SemanticModel>();
                this.SuppressMessageAttributeState = new SuppressMessageAttributeState(comp);
                this.DeclarationAnalysisDataMap = new Dictionary<SyntaxReference, DeclarationAnalysisData>();
            }

            public SuppressMessageAttributeState SuppressMessageAttributeState { get; }
            public Dictionary<SyntaxReference, DeclarationAnalysisData> DeclarationAnalysisDataMap { get; }

            public SemanticModel GetOrCreateCachedSemanticModel(SyntaxTree tree, Compilation compilation, CancellationToken cancellationToken)
            {
                SemanticModel model;
                lock (_semanticModelsMap)
                {
                    if (_semanticModelsMap.TryGetValue(tree, out model))
                    {
                        return model;
                    }
                }
43
                
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
                model = compilation.GetSemanticModel(tree);

                // Invoke GetDiagnostics to populate the compilation's CompilationEvent queue.
                model.GetDiagnostics(null, cancellationToken);

                lock (_semanticModelsMap)
                {
                    _semanticModelsMap[tree] = model;
                }

                return model;
            }

            public bool RemoveCachedSemanticModel(SyntaxTree tree)
            {
                lock (_semanticModelsMap)
                {
                    return _semanticModelsMap.Remove(tree);
                }
            }
        }

        internal class DeclarationAnalysisData
        {
            /// <summary>
            /// GetSyntax() for the given SyntaxReference.
            /// </summary>
            public SyntaxNode DeclaringReferenceSyntax { get; set; }

            /// <summary>
            /// Topmost declaration node for analysis.
            /// </summary>
            public SyntaxNode TopmostNodeForAnalysis { get; set; }

            /// <summary>
            /// All member declarations within the declaration.
            /// </summary>
            public List<DeclarationInfo> DeclarationsInNode { get; }

            /// <summary>
            /// All descendant nodes for syntax node actions.
            /// </summary>
            public List<SyntaxNode> DescendantNodesToAnalyze { get; }

            /// <summary>
            /// Flag indicating if this is a partial analysis.
            /// </summary>
            public bool IsPartialAnalysis { get; set; }

            public DeclarationAnalysisData()
            {
                this.DeclarationsInNode = new List<DeclarationInfo>();
                this.DescendantNodesToAnalyze = new List<SyntaxNode>();
            }

            public void Free()
            {
                DeclaringReferenceSyntax = null;
                TopmostNodeForAnalysis = null;
                DeclarationsInNode.Clear();
                DescendantNodesToAnalyze.Clear();
                IsPartialAnalysis = false;
            }
        }

109
        internal static CompilationData GetOrCreateCachedCompilationData(Compilation compilation)
110
        {
111
            return s_compilationDataCache.GetValue(compilation, c => new CompilationData(c));
112 113
        }

114
        internal static bool RemoveCachedCompilationData(Compilation compilation)
115
        {
116
            return s_compilationDataCache.Remove(compilation);
117 118 119 120
        }

        public static SemanticModel GetOrCreateCachedSemanticModel(SyntaxTree tree, Compilation compilation, CancellationToken cancellationToken)
        {
121
            var compilationData = GetOrCreateCachedCompilationData(compilation);
122 123 124
            return compilationData.GetOrCreateCachedSemanticModel(tree, compilation, cancellationToken);
        }

125
        public static bool RemoveCachedSemanticModel(SyntaxTree tree, Compilation compilation)
126 127
        {
            CompilationData compilationData;
128
            return s_compilationDataCache.TryGetValue(compilation, out compilationData) &&
129 130 131 132
                compilationData.RemoveCachedSemanticModel(tree);
        }
    }
}