File: DiagnosticAnalyzer\DiagnosticStartAnalysisScope.cs
Web Access
Project: src\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis)
// 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.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.CodeAnalysis.FlowAnalysis;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.Diagnostics
{
    /// <summary>
    /// Scope for setting up analyzers for an entire session, automatically associating actions with analyzers.
    /// </summary>
    internal sealed class AnalyzerAnalysisContext : AnalysisContext
    {
        private readonly HostSessionStartAnalysisScope _scope;
 
        public AnalyzerAnalysisContext(HostSessionStartAnalysisScope scope, SeverityFilter severityFilter)
        {
            _scope = scope;
            MinimumReportedSeverity = severityFilter.GetMinimumUnfilteredSeverity();
        }
 
        public override void RegisterCompilationStartAction(Action<CompilationStartAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterCompilationStartAction(action);
        }
 
        public override void RegisterCompilationAction(Action<CompilationAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterCompilationAction(action);
        }
 
        public override void RegisterSyntaxTreeAction(Action<SyntaxTreeAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterSyntaxTreeAction(action);
        }
 
        public override void RegisterAdditionalFileAction(Action<AdditionalFileAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterAdditionalFileAction(action);
        }
 
        public override void RegisterSemanticModelAction(Action<SemanticModelAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterSemanticModelAction(action);
        }
 
        public override void RegisterSymbolAction(Action<SymbolAnalysisContext> action, ImmutableArray<SymbolKind> symbolKinds)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action, symbolKinds);
            _scope.RegisterSymbolAction(action, symbolKinds);
        }
 
        public override void RegisterSymbolStartAction(Action<SymbolStartAnalysisContext> action, SymbolKind symbolKind)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterSymbolStartAction(action, symbolKind);
        }
 
        public override void RegisterCodeBlockStartAction<TLanguageKindEnum>(Action<CodeBlockStartAnalysisContext<TLanguageKindEnum>> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterCodeBlockStartAction<TLanguageKindEnum>(action);
        }
 
        public override void RegisterCodeBlockAction(Action<CodeBlockAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterCodeBlockAction(action);
        }
 
        public override void RegisterSyntaxNodeAction<TLanguageKindEnum>(Action<SyntaxNodeAnalysisContext> action, ImmutableArray<TLanguageKindEnum> syntaxKinds)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action, syntaxKinds);
            _scope.RegisterSyntaxNodeAction(action, syntaxKinds);
        }
 
        public override void RegisterOperationAction(Action<OperationAnalysisContext> action, ImmutableArray<OperationKind> operationKinds)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action, operationKinds);
            _scope.RegisterOperationAction(action, operationKinds);
        }
 
        public override void RegisterOperationBlockStartAction(Action<OperationBlockStartAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterOperationBlockStartAction(action);
        }
 
        public override void RegisterOperationBlockAction(Action<OperationBlockAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterOperationBlockAction(action);
        }
 
        public override void EnableConcurrentExecution()
        {
            _scope.EnableConcurrentExecution();
        }
 
        public override void ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags mode)
        {
            _scope.ConfigureGeneratedCodeAnalysis(mode);
        }
 
        public override DiagnosticSeverity MinimumReportedSeverity { get; }
    }
 
    /// <summary>
    /// Scope for setting up analyzers for a compilation, automatically associating actions with analyzers.
    /// </summary>
    internal sealed class AnalyzerCompilationStartAnalysisContext : CompilationStartAnalysisContext
    {
        private readonly HostCompilationStartAnalysisScope _scope;
        private readonly CompilationAnalysisValueProviderFactory _compilationAnalysisValueProviderFactory;
 
        public AnalyzerCompilationStartAnalysisContext(
            HostCompilationStartAnalysisScope scope,
            Compilation compilation,
            AnalyzerOptions options,
            CompilationAnalysisValueProviderFactory compilationAnalysisValueProviderFactory,
            CancellationToken cancellationToken)
            : base(compilation, options, cancellationToken)
        {
            _scope = scope;
            _compilationAnalysisValueProviderFactory = compilationAnalysisValueProviderFactory;
        }
 
        public override void RegisterCompilationEndAction(Action<CompilationAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterCompilationEndAction(action);
        }
 
        public override void RegisterSyntaxTreeAction(Action<SyntaxTreeAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterSyntaxTreeAction(action);
        }
 
        public override void RegisterAdditionalFileAction(Action<AdditionalFileAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterAdditionalFileAction(action);
        }
 
        public override void RegisterSemanticModelAction(Action<SemanticModelAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterSemanticModelAction(action);
        }
 
        public override void RegisterSymbolAction(Action<SymbolAnalysisContext> action, ImmutableArray<SymbolKind> symbolKinds)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action, symbolKinds);
            _scope.RegisterSymbolAction(action, symbolKinds);
        }
 
        public override void RegisterSymbolStartAction(Action<SymbolStartAnalysisContext> action, SymbolKind symbolKind)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterSymbolStartAction(action, symbolKind);
        }
 
        public override void RegisterCodeBlockStartAction<TLanguageKindEnum>(Action<CodeBlockStartAnalysisContext<TLanguageKindEnum>> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterCodeBlockStartAction<TLanguageKindEnum>(action);
        }
 
        public override void RegisterCodeBlockAction(Action<CodeBlockAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterCodeBlockAction(action);
        }
 
        public override void RegisterSyntaxNodeAction<TLanguageKindEnum>(Action<SyntaxNodeAnalysisContext> action, ImmutableArray<TLanguageKindEnum> syntaxKinds)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action, syntaxKinds);
            _scope.RegisterSyntaxNodeAction(action, syntaxKinds);
        }
 
        public override void RegisterOperationBlockStartAction(Action<OperationBlockStartAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterOperationBlockStartAction(action);
        }
 
        public override void RegisterOperationBlockAction(Action<OperationBlockAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterOperationBlockAction(action);
        }
 
        public override void RegisterOperationAction(Action<OperationAnalysisContext> action, ImmutableArray<OperationKind> operationKinds)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action, operationKinds);
            _scope.RegisterOperationAction(action, operationKinds);
        }
 
        internal override bool TryGetValueCore<TKey, TValue>(TKey key, AnalysisValueProvider<TKey, TValue> valueProvider, [MaybeNullWhen(false)] out TValue value)
        {
            var compilationAnalysisValueProvider = _compilationAnalysisValueProviderFactory.GetValueProvider(valueProvider);
            return compilationAnalysisValueProvider.TryGetValue(key, out value);
        }
    }
 
    /// <summary>
    /// Scope for setting up analyzers for code within a symbol and its members.
    /// </summary>
    internal sealed class AnalyzerSymbolStartAnalysisContext : SymbolStartAnalysisContext
    {
        private readonly HostSymbolStartAnalysisScope _scope;
 
        internal AnalyzerSymbolStartAnalysisContext(
                                                       HostSymbolStartAnalysisScope scope,
                                                       ISymbol owningSymbol,
                                                       Compilation compilation,
                                                       AnalyzerOptions options,
                                                       bool isGeneratedCode,
                                                       SyntaxTree? filterTree,
                                                       TextSpan? filterSpan,
                                                       CancellationToken cancellationToken)
            : base(owningSymbol, compilation, options, isGeneratedCode, filterTree, filterSpan, cancellationToken)
        {
            _scope = scope;
        }
 
        public override void RegisterSymbolEndAction(Action<SymbolAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterSymbolEndAction(action);
        }
 
        public override void RegisterCodeBlockStartAction<TLanguageKindEnum>(Action<CodeBlockStartAnalysisContext<TLanguageKindEnum>> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterCodeBlockStartAction<TLanguageKindEnum>(action);
        }
 
        public override void RegisterCodeBlockAction(Action<CodeBlockAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterCodeBlockAction(action);
        }
 
        public override void RegisterSyntaxNodeAction<TLanguageKindEnum>(Action<SyntaxNodeAnalysisContext> action, ImmutableArray<TLanguageKindEnum> syntaxKinds)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action, syntaxKinds);
            _scope.RegisterSyntaxNodeAction(action, syntaxKinds);
        }
 
        public override void RegisterOperationBlockStartAction(Action<OperationBlockStartAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterOperationBlockStartAction(action);
        }
 
        public override void RegisterOperationBlockAction(Action<OperationBlockAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterOperationBlockAction(action);
        }
 
        public override void RegisterOperationAction(Action<OperationAnalysisContext> action, ImmutableArray<OperationKind> operationKinds)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action, operationKinds);
            _scope.RegisterOperationAction(action, operationKinds);
        }
    }
 
    /// <summary>
    /// Scope for setting up analyzers for a code block, automatically associating actions with analyzers.
    /// </summary>
    internal sealed class AnalyzerCodeBlockStartAnalysisContext<TLanguageKindEnum> : CodeBlockStartAnalysisContext<TLanguageKindEnum> where TLanguageKindEnum : struct
    {
        private readonly HostCodeBlockStartAnalysisScope<TLanguageKindEnum> _scope;
 
        internal AnalyzerCodeBlockStartAnalysisContext(
                                                       HostCodeBlockStartAnalysisScope<TLanguageKindEnum> scope,
                                                       SyntaxNode codeBlock,
                                                       ISymbol owningSymbol,
                                                       SemanticModel semanticModel,
                                                       AnalyzerOptions options,
                                                       TextSpan? filterSpan,
                                                       bool isGeneratedCode,
                                                       CancellationToken cancellationToken)
            : base(codeBlock, owningSymbol, semanticModel, options, filterSpan, isGeneratedCode, cancellationToken)
        {
            _scope = scope;
        }
 
        public override void RegisterCodeBlockEndAction(Action<CodeBlockAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterCodeBlockEndAction(action);
        }
 
        public override void RegisterSyntaxNodeAction(Action<SyntaxNodeAnalysisContext> action, ImmutableArray<TLanguageKindEnum> syntaxKinds)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action, syntaxKinds);
            _scope.RegisterSyntaxNodeAction(action, syntaxKinds);
        }
    }
 
    /// <summary>
    /// Scope for setting up analyzers for an operation block, automatically associating actions with analyzers.
    /// </summary>
    internal sealed class AnalyzerOperationBlockStartAnalysisContext : OperationBlockStartAnalysisContext
    {
        private readonly HostOperationBlockStartAnalysisScope _scope;
 
        internal AnalyzerOperationBlockStartAnalysisContext(
                                                            HostOperationBlockStartAnalysisScope scope,
                                                            ImmutableArray<IOperation> operationBlocks,
                                                            ISymbol owningSymbol,
                                                            Compilation compilation,
                                                            AnalyzerOptions options,
                                                            Func<IOperation, ControlFlowGraph> getControlFlowGraph,
                                                            SyntaxTree filterTree,
                                                            TextSpan? filterSpan,
                                                            bool isGeneratedCode,
                                                            CancellationToken cancellationToken)
            : base(operationBlocks, owningSymbol, compilation, options, getControlFlowGraph, filterTree, filterSpan, isGeneratedCode, cancellationToken)
        {
            _scope = scope;
        }
 
        public override void RegisterOperationBlockEndAction(Action<OperationBlockAnalysisContext> action)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action);
            _scope.RegisterOperationBlockEndAction(action);
        }
 
        public override void RegisterOperationAction(Action<OperationAnalysisContext> action, ImmutableArray<OperationKind> operationKinds)
        {
            DiagnosticAnalysisContextHelpers.VerifyArguments(action, operationKinds);
            _scope.RegisterOperationAction(action, operationKinds);
        }
    }
 
    /// <summary>
    /// Scope for setting up analyzers for an entire session, capable of retrieving the actions.
    /// </summary>
    internal sealed class HostSessionStartAnalysisScope(DiagnosticAnalyzer analyzer)
        : HostAnalysisScope(analyzer)
    {
        private bool _isConcurrent;
        private GeneratedCodeAnalysisFlags _generatedCodeConfiguration = AnalyzerDriver.DefaultGeneratedCodeAnalysisFlags;
 
        public bool IsConcurrentAnalyzer()
        {
            return _isConcurrent;
        }
 
        public GeneratedCodeAnalysisFlags GetGeneratedCodeAnalysisFlags()
        {
            return _generatedCodeConfiguration;
        }
 
        public void RegisterCompilationStartAction(Action<CompilationStartAnalysisContext> action)
        {
            CompilationStartAnalyzerAction analyzerAction = new CompilationStartAnalyzerAction(action, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddCompilationStartAction(analyzerAction);
        }
 
        public void EnableConcurrentExecution()
        {
            _isConcurrent = true;
            GetOrCreateAnalyzerActions().Value.EnableConcurrentExecution();
        }
 
        public void ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags mode)
        {
            _generatedCodeConfiguration = mode;
        }
    }
 
    /// <summary>
    /// Scope for setting up analyzers for a compilation, capable of retrieving the actions.
    /// </summary>
    internal sealed class HostCompilationStartAnalysisScope : HostAnalysisScope
    {
        private readonly HostSessionStartAnalysisScope _sessionScope;
 
        public HostCompilationStartAnalysisScope(HostSessionStartAnalysisScope sessionScope)
            : base(sessionScope.Analyzer)
        {
            _sessionScope = sessionScope;
        }
 
        public override AnalyzerActions GetAnalyzerActions()
        {
            AnalyzerActions compilationActions = base.GetAnalyzerActions();
            AnalyzerActions sessionActions = _sessionScope.GetAnalyzerActions();
 
            if (sessionActions.IsEmpty)
            {
                return compilationActions;
            }
 
            if (compilationActions.IsEmpty)
            {
                return sessionActions;
            }
 
            return compilationActions.Append(in sessionActions);
        }
    }
 
    /// <summary>
    /// Scope for setting up analyzers for analyzing a symbol and its members.
    /// </summary>
    internal sealed class HostSymbolStartAnalysisScope(DiagnosticAnalyzer analyzer)
        : HostAnalysisScope(analyzer)
    {
    }
 
    /// <summary>
    /// Scope for setting up analyzers for a code block, capable of retrieving the actions.
    /// </summary>
    internal sealed class HostCodeBlockStartAnalysisScope<TLanguageKindEnum>(DiagnosticAnalyzer analyzer) where TLanguageKindEnum : struct
    {
        private ImmutableArray<CodeBlockAnalyzerAction> _codeBlockEndActions = ImmutableArray<CodeBlockAnalyzerAction>.Empty;
        private ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>> _syntaxNodeActions = ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>.Empty;
 
        private DiagnosticAnalyzer Analyzer { get; } = analyzer;
 
        public ImmutableArray<CodeBlockAnalyzerAction> CodeBlockEndActions
        {
            get { return _codeBlockEndActions; }
        }
 
        public ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>> SyntaxNodeActions
        {
            get { return _syntaxNodeActions; }
        }
 
        public void RegisterCodeBlockEndAction(Action<CodeBlockAnalysisContext> action)
        {
            _codeBlockEndActions = _codeBlockEndActions.Add(new CodeBlockAnalyzerAction(action, Analyzer));
        }
 
        public void RegisterSyntaxNodeAction(Action<SyntaxNodeAnalysisContext> action, ImmutableArray<TLanguageKindEnum> syntaxKinds)
        {
            _syntaxNodeActions = _syntaxNodeActions.Add(new SyntaxNodeAnalyzerAction<TLanguageKindEnum>(action, syntaxKinds, Analyzer));
        }
    }
 
    internal sealed class HostOperationBlockStartAnalysisScope(DiagnosticAnalyzer analyzer)
    {
        private ImmutableArray<OperationBlockAnalyzerAction> _operationBlockEndActions = ImmutableArray<OperationBlockAnalyzerAction>.Empty;
        private ImmutableArray<OperationAnalyzerAction> _operationActions = ImmutableArray<OperationAnalyzerAction>.Empty;
 
        private DiagnosticAnalyzer Analyzer { get; } = analyzer;
 
        public ImmutableArray<OperationBlockAnalyzerAction> OperationBlockEndActions => _operationBlockEndActions;
 
        public ImmutableArray<OperationAnalyzerAction> OperationActions => _operationActions;
 
        public void RegisterOperationBlockEndAction(Action<OperationBlockAnalysisContext> action)
        {
            _operationBlockEndActions = _operationBlockEndActions.Add(new OperationBlockAnalyzerAction(action, Analyzer));
        }
 
        public void RegisterOperationAction(Action<OperationAnalysisContext> action, ImmutableArray<OperationKind> operationKinds)
        {
            _operationActions = _operationActions.Add(new OperationAnalyzerAction(action, operationKinds, Analyzer));
        }
    }
 
    internal abstract class HostAnalysisScope(DiagnosticAnalyzer analyzer)
    {
        private StrongBox<AnalyzerActions>? _analyzerActions;
 
        internal DiagnosticAnalyzer Analyzer { get; } = analyzer;
 
        public virtual AnalyzerActions GetAnalyzerActions()
        {
            return this.GetOrCreateAnalyzerActions().Value;
        }
 
        public void RegisterCompilationAction(Action<CompilationAnalysisContext> action)
        {
            CompilationAnalyzerAction analyzerAction = new CompilationAnalyzerAction(action, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddCompilationAction(analyzerAction);
        }
 
        public void RegisterCompilationEndAction(Action<CompilationAnalysisContext> action)
        {
            CompilationAnalyzerAction analyzerAction = new CompilationAnalyzerAction(action, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddCompilationEndAction(analyzerAction);
        }
 
        public void RegisterSemanticModelAction(Action<SemanticModelAnalysisContext> action)
        {
            SemanticModelAnalyzerAction analyzerAction = new SemanticModelAnalyzerAction(action, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddSemanticModelAction(analyzerAction);
        }
 
        public void RegisterSyntaxTreeAction(Action<SyntaxTreeAnalysisContext> action)
        {
            SyntaxTreeAnalyzerAction analyzerAction = new SyntaxTreeAnalyzerAction(action, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddSyntaxTreeAction(analyzerAction);
        }
 
        public void RegisterAdditionalFileAction(Action<AdditionalFileAnalysisContext> action)
        {
            var analyzerAction = new AdditionalFileAnalyzerAction(action, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddAdditionalFileAction(analyzerAction);
        }
 
        public void RegisterSymbolAction(Action<SymbolAnalysisContext> action, ImmutableArray<SymbolKind> symbolKinds)
        {
            SymbolAnalyzerAction analyzerAction = new SymbolAnalyzerAction(action, symbolKinds, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddSymbolAction(analyzerAction);
 
            // The SymbolAnalyzerAction does not handle SymbolKind.Parameter because the compiler
            // does not make CompilationEvents for them. As a workaround, handle them specially by
            // registering further SymbolActions (for Methods) and utilize the results to construct
            // the necessary SymbolAnalysisContexts.
 
            if (symbolKinds.Contains(SymbolKind.Parameter))
            {
                RegisterSymbolAction(
                    context =>
                    {
                        ImmutableArray<IParameterSymbol> parameters;
 
                        switch (context.Symbol.Kind)
                        {
                            case SymbolKind.Method:
                                parameters = ((IMethodSymbol)context.Symbol).Parameters;
                                break;
                            case SymbolKind.Property:
                                parameters = ((IPropertySymbol)context.Symbol).Parameters;
                                break;
                            case SymbolKind.NamedType:
                                var namedType = (INamedTypeSymbol)context.Symbol;
                                var delegateInvokeMethod = namedType.DelegateInvokeMethod;
                                parameters = delegateInvokeMethod?.Parameters ?? ImmutableArray.Create<IParameterSymbol>();
                                break;
                            default:
                                throw new ArgumentException($"{context.Symbol.Kind} is not supported.", nameof(context));
                        }
 
                        foreach (var parameter in parameters)
                        {
                            if (!parameter.IsImplicitlyDeclared)
                            {
                                action(new SymbolAnalysisContext(
                                    parameter,
                                    context.Compilation,
                                    context.Options,
                                    context.ReportDiagnostic,
                                    context.IsSupportedDiagnostic,
                                    context.IsGeneratedCode,
                                    context.FilterTree,
                                    context.FilterSpan,
                                    context.CancellationToken));
                            }
                        }
                    },
                    ImmutableArray.Create(SymbolKind.Method, SymbolKind.Property, SymbolKind.NamedType));
            }
        }
 
        public void RegisterSymbolStartAction(Action<SymbolStartAnalysisContext> action, SymbolKind symbolKind)
        {
            var analyzerAction = new SymbolStartAnalyzerAction(action, symbolKind, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddSymbolStartAction(analyzerAction);
        }
 
        public void RegisterSymbolEndAction(Action<SymbolAnalysisContext> action)
        {
            var analyzerAction = new SymbolEndAnalyzerAction(action, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddSymbolEndAction(analyzerAction);
        }
 
        public void RegisterCodeBlockStartAction<TLanguageKindEnum>(Action<CodeBlockStartAnalysisContext<TLanguageKindEnum>> action) where TLanguageKindEnum : struct
        {
            CodeBlockStartAnalyzerAction<TLanguageKindEnum> analyzerAction = new CodeBlockStartAnalyzerAction<TLanguageKindEnum>(action, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddCodeBlockStartAction(analyzerAction);
        }
 
        public void RegisterCodeBlockEndAction(Action<CodeBlockAnalysisContext> action)
        {
            CodeBlockAnalyzerAction analyzerAction = new CodeBlockAnalyzerAction(action, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddCodeBlockEndAction(analyzerAction);
        }
 
        public void RegisterCodeBlockAction(Action<CodeBlockAnalysisContext> action)
        {
            CodeBlockAnalyzerAction analyzerAction = new CodeBlockAnalyzerAction(action, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddCodeBlockAction(analyzerAction);
        }
 
        public void RegisterSyntaxNodeAction<TLanguageKindEnum>(Action<SyntaxNodeAnalysisContext> action, ImmutableArray<TLanguageKindEnum> syntaxKinds) where TLanguageKindEnum : struct
        {
            SyntaxNodeAnalyzerAction<TLanguageKindEnum> analyzerAction = new SyntaxNodeAnalyzerAction<TLanguageKindEnum>(action, syntaxKinds, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddSyntaxNodeAction(analyzerAction);
        }
 
        public void RegisterOperationBlockStartAction(Action<OperationBlockStartAnalysisContext> action)
        {
            OperationBlockStartAnalyzerAction analyzerAction = new OperationBlockStartAnalyzerAction(action, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddOperationBlockStartAction(analyzerAction);
        }
 
        public void RegisterOperationBlockEndAction(Action<OperationBlockAnalysisContext> action)
        {
            OperationBlockAnalyzerAction analyzerAction = new OperationBlockAnalyzerAction(action, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddOperationBlockEndAction(analyzerAction);
        }
 
        public void RegisterOperationBlockAction(Action<OperationBlockAnalysisContext> action)
        {
            OperationBlockAnalyzerAction analyzerAction = new OperationBlockAnalyzerAction(action, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddOperationBlockAction(analyzerAction);
        }
 
        public void RegisterOperationAction(Action<OperationAnalysisContext> action, ImmutableArray<OperationKind> operationKinds)
        {
            OperationAnalyzerAction analyzerAction = new OperationAnalyzerAction(action, operationKinds, Analyzer);
            this.GetOrCreateAnalyzerActions().Value.AddOperationAction(analyzerAction);
        }
 
        protected StrongBox<AnalyzerActions> GetOrCreateAnalyzerActions()
        {
            return InterlockedOperations.Initialize(ref _analyzerActions, static () => new StrongBox<AnalyzerActions>(AnalyzerActions.Empty));
        }
    }
 
    /// <summary>
    /// Actions registered by a particular analyzer.
    /// </summary>
    // ToDo: AnalyzerActions, and all of the mechanism around it, can be eliminated if the IDE diagnostic analyzer driver
    // moves from an analyzer-centric model to an action-centric model. For example, the driver would need to stop asking
    // if a particular analyzer can analyze syntax trees, and instead ask if any syntax tree actions are present. Also,
    // the driver needs to apply all relevant actions rather then applying the actions of individual analyzers.
    internal struct AnalyzerActions
    {
        public static readonly AnalyzerActions Empty = new AnalyzerActions(concurrent: false);
 
        private ImmutableArray<CompilationStartAnalyzerAction> _compilationStartActions;
        private ImmutableArray<CompilationAnalyzerAction> _compilationEndActions;
        private ImmutableArray<CompilationAnalyzerAction> _compilationActions;
        private ImmutableArray<SyntaxTreeAnalyzerAction> _syntaxTreeActions;
        private ImmutableArray<AdditionalFileAnalyzerAction> _additionalFileActions;
        private ImmutableArray<SemanticModelAnalyzerAction> _semanticModelActions;
        private ImmutableArray<SymbolAnalyzerAction> _symbolActions;
        private ImmutableArray<SymbolStartAnalyzerAction> _symbolStartActions;
        private ImmutableArray<SymbolEndAnalyzerAction> _symbolEndActions;
        private ImmutableArray<AnalyzerAction> _codeBlockStartActions;
        private ImmutableArray<CodeBlockAnalyzerAction> _codeBlockEndActions;
        private ImmutableArray<CodeBlockAnalyzerAction> _codeBlockActions;
        private ImmutableArray<OperationBlockStartAnalyzerAction> _operationBlockStartActions;
        private ImmutableArray<OperationBlockAnalyzerAction> _operationBlockEndActions;
        private ImmutableArray<OperationBlockAnalyzerAction> _operationBlockActions;
        private ImmutableArray<AnalyzerAction> _syntaxNodeActions;
        private ImmutableArray<OperationAnalyzerAction> _operationActions;
        private bool _concurrent;
 
        internal AnalyzerActions(bool concurrent)
        {
            _compilationStartActions = ImmutableArray<CompilationStartAnalyzerAction>.Empty;
            _compilationEndActions = ImmutableArray<CompilationAnalyzerAction>.Empty;
            _compilationActions = ImmutableArray<CompilationAnalyzerAction>.Empty;
            _syntaxTreeActions = ImmutableArray<SyntaxTreeAnalyzerAction>.Empty;
            _additionalFileActions = ImmutableArray<AdditionalFileAnalyzerAction>.Empty;
            _semanticModelActions = ImmutableArray<SemanticModelAnalyzerAction>.Empty;
            _symbolActions = ImmutableArray<SymbolAnalyzerAction>.Empty;
            _symbolStartActions = ImmutableArray<SymbolStartAnalyzerAction>.Empty;
            _symbolEndActions = ImmutableArray<SymbolEndAnalyzerAction>.Empty;
            _codeBlockStartActions = ImmutableArray<AnalyzerAction>.Empty;
            _codeBlockEndActions = ImmutableArray<CodeBlockAnalyzerAction>.Empty;
            _codeBlockActions = ImmutableArray<CodeBlockAnalyzerAction>.Empty;
            _operationBlockStartActions = ImmutableArray<OperationBlockStartAnalyzerAction>.Empty;
            _operationBlockEndActions = ImmutableArray<OperationBlockAnalyzerAction>.Empty;
            _operationBlockActions = ImmutableArray<OperationBlockAnalyzerAction>.Empty;
            _syntaxNodeActions = ImmutableArray<AnalyzerAction>.Empty;
            _operationActions = ImmutableArray<OperationAnalyzerAction>.Empty;
            _concurrent = concurrent;
 
            IsEmpty = true;
        }
 
        public AnalyzerActions(
            ImmutableArray<CompilationStartAnalyzerAction> compilationStartActions,
            ImmutableArray<CompilationAnalyzerAction> compilationEndActions,
            ImmutableArray<CompilationAnalyzerAction> compilationActions,
            ImmutableArray<SyntaxTreeAnalyzerAction> syntaxTreeActions,
            ImmutableArray<AdditionalFileAnalyzerAction> additionalFileActions,
            ImmutableArray<SemanticModelAnalyzerAction> semanticModelActions,
            ImmutableArray<SymbolAnalyzerAction> symbolActions,
            ImmutableArray<SymbolStartAnalyzerAction> symbolStartActions,
            ImmutableArray<SymbolEndAnalyzerAction> symbolEndActions,
            ImmutableArray<AnalyzerAction> codeBlockStartActions,
            ImmutableArray<CodeBlockAnalyzerAction> codeBlockEndActions,
            ImmutableArray<CodeBlockAnalyzerAction> codeBlockActions,
            ImmutableArray<OperationBlockStartAnalyzerAction> operationBlockStartActions,
            ImmutableArray<OperationBlockAnalyzerAction> operationBlockEndActions,
            ImmutableArray<OperationBlockAnalyzerAction> operationBlockActions,
            ImmutableArray<AnalyzerAction> syntaxNodeActions,
            ImmutableArray<OperationAnalyzerAction> operationActions,
            bool concurrent,
            bool isEmpty)
        {
            _compilationStartActions = compilationStartActions;
            _compilationEndActions = compilationEndActions;
            _compilationActions = compilationActions;
            _syntaxTreeActions = syntaxTreeActions;
            _additionalFileActions = additionalFileActions;
            _semanticModelActions = semanticModelActions;
            _symbolActions = symbolActions;
            _symbolStartActions = symbolStartActions;
            _symbolEndActions = symbolEndActions;
            _codeBlockStartActions = codeBlockStartActions;
            _codeBlockEndActions = codeBlockEndActions;
            _codeBlockActions = codeBlockActions;
            _operationBlockStartActions = operationBlockStartActions;
            _operationBlockEndActions = operationBlockEndActions;
            _operationBlockActions = operationBlockActions;
            _syntaxNodeActions = syntaxNodeActions;
            _operationActions = operationActions;
            _concurrent = concurrent;
            IsEmpty = isEmpty;
        }
 
        public readonly int CompilationStartActionsCount { get { return _compilationStartActions.Length; } }
        public readonly int CompilationEndActionsCount { get { return _compilationEndActions.Length; } }
        public readonly int CompilationActionsCount { get { return _compilationActions.Length; } }
        public readonly int SyntaxTreeActionsCount { get { return _syntaxTreeActions.Length; } }
        public readonly int AdditionalFileActionsCount { get { return _additionalFileActions.Length; } }
        public readonly int SemanticModelActionsCount { get { return _semanticModelActions.Length; } }
        public readonly int SymbolActionsCount { get { return _symbolActions.Length; } }
        public readonly int SymbolStartActionsCount { get { return _symbolStartActions.Length; } }
        public readonly int SymbolEndActionsCount { get { return _symbolEndActions.Length; } }
        public readonly int SyntaxNodeActionsCount { get { return _syntaxNodeActions.Length; } }
        public readonly int OperationActionsCount { get { return _operationActions.Length; } }
        public readonly int OperationBlockStartActionsCount { get { return _operationBlockStartActions.Length; } }
        public readonly int OperationBlockEndActionsCount { get { return _operationBlockEndActions.Length; } }
        public readonly int OperationBlockActionsCount { get { return _operationBlockActions.Length; } }
        public readonly int CodeBlockStartActionsCount { get { return _codeBlockStartActions.Length; } }
        public readonly int CodeBlockEndActionsCount { get { return _codeBlockEndActions.Length; } }
        public readonly int CodeBlockActionsCount { get { return _codeBlockActions.Length; } }
        public readonly bool Concurrent => _concurrent;
        public bool IsEmpty { readonly get; private set; }
        public readonly bool IsDefault => _compilationStartActions.IsDefault;
 
        internal readonly ImmutableArray<CompilationStartAnalyzerAction> CompilationStartActions
        {
            get { return _compilationStartActions; }
        }
 
        internal readonly ImmutableArray<CompilationAnalyzerAction> CompilationEndActions
        {
            get { return _compilationEndActions; }
        }
 
        internal readonly ImmutableArray<CompilationAnalyzerAction> CompilationActions
        {
            get { return _compilationActions; }
        }
 
        internal readonly ImmutableArray<SyntaxTreeAnalyzerAction> SyntaxTreeActions
        {
            get { return _syntaxTreeActions; }
        }
 
        internal readonly ImmutableArray<AdditionalFileAnalyzerAction> AdditionalFileActions
        {
            get { return _additionalFileActions; }
        }
 
        internal readonly ImmutableArray<SemanticModelAnalyzerAction> SemanticModelActions
        {
            get { return _semanticModelActions; }
        }
 
        internal readonly ImmutableArray<SymbolAnalyzerAction> SymbolActions
        {
            get { return _symbolActions; }
        }
 
        internal readonly ImmutableArray<SymbolStartAnalyzerAction> SymbolStartActions
        {
            get { return _symbolStartActions; }
        }
 
        internal readonly ImmutableArray<SymbolEndAnalyzerAction> SymbolEndActions
        {
            get { return _symbolEndActions; }
        }
 
        internal readonly ImmutableArray<CodeBlockAnalyzerAction> CodeBlockEndActions
        {
            get { return _codeBlockEndActions; }
        }
 
        internal readonly ImmutableArray<CodeBlockAnalyzerAction> CodeBlockActions
        {
            get { return _codeBlockActions; }
        }
 
        internal readonly ImmutableArray<CodeBlockStartAnalyzerAction<TLanguageKindEnum>> GetCodeBlockStartActions<TLanguageKindEnum>() where TLanguageKindEnum : struct
        {
            return _codeBlockStartActions.OfType<CodeBlockStartAnalyzerAction<TLanguageKindEnum>>().ToImmutableArray();
        }
 
        internal readonly ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>> GetSyntaxNodeActions<TLanguageKindEnum>() where TLanguageKindEnum : struct
        {
            return _syntaxNodeActions.OfType<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>().ToImmutableArray();
        }
 
        internal readonly ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>> GetSyntaxNodeActions<TLanguageKindEnum>(DiagnosticAnalyzer analyzer) where TLanguageKindEnum : struct
        {
            var builder = ArrayBuilder<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>.GetInstance();
            foreach (var action in _syntaxNodeActions)
            {
                if (action.Analyzer == analyzer &&
                    action is SyntaxNodeAnalyzerAction<TLanguageKindEnum> syntaxNodeAction)
                {
                    builder.Add(syntaxNodeAction);
                }
            }
 
            return builder.ToImmutableAndFree();
        }
 
        internal readonly ImmutableArray<OperationBlockAnalyzerAction> OperationBlockActions
        {
            get { return _operationBlockActions; }
        }
 
        internal readonly ImmutableArray<OperationBlockAnalyzerAction> OperationBlockEndActions
        {
            get { return _operationBlockEndActions; }
        }
 
        internal readonly ImmutableArray<OperationBlockStartAnalyzerAction> OperationBlockStartActions
        {
            get { return _operationBlockStartActions; }
        }
 
        internal readonly ImmutableArray<OperationAnalyzerAction> OperationActions
        {
            get { return _operationActions; }
        }
 
        internal void AddCompilationStartAction(CompilationStartAnalyzerAction action)
        {
            _compilationStartActions = _compilationStartActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddCompilationEndAction(CompilationAnalyzerAction action)
        {
            _compilationEndActions = _compilationEndActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddCompilationAction(CompilationAnalyzerAction action)
        {
            _compilationActions = _compilationActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddSyntaxTreeAction(SyntaxTreeAnalyzerAction action)
        {
            _syntaxTreeActions = _syntaxTreeActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddAdditionalFileAction(AdditionalFileAnalyzerAction action)
        {
            _additionalFileActions = _additionalFileActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddSemanticModelAction(SemanticModelAnalyzerAction action)
        {
            _semanticModelActions = _semanticModelActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddSymbolAction(SymbolAnalyzerAction action)
        {
            _symbolActions = _symbolActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddSymbolStartAction(SymbolStartAnalyzerAction action)
        {
            _symbolStartActions = _symbolStartActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddSymbolEndAction(SymbolEndAnalyzerAction action)
        {
            _symbolEndActions = _symbolEndActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddCodeBlockStartAction<TLanguageKindEnum>(CodeBlockStartAnalyzerAction<TLanguageKindEnum> action) where TLanguageKindEnum : struct
        {
            _codeBlockStartActions = _codeBlockStartActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddCodeBlockEndAction(CodeBlockAnalyzerAction action)
        {
            _codeBlockEndActions = _codeBlockEndActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddCodeBlockAction(CodeBlockAnalyzerAction action)
        {
            _codeBlockActions = _codeBlockActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddSyntaxNodeAction<TLanguageKindEnum>(SyntaxNodeAnalyzerAction<TLanguageKindEnum> action) where TLanguageKindEnum : struct
        {
            _syntaxNodeActions = _syntaxNodeActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddOperationBlockStartAction(OperationBlockStartAnalyzerAction action)
        {
            _operationBlockStartActions = _operationBlockStartActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddOperationBlockAction(OperationBlockAnalyzerAction action)
        {
            _operationBlockActions = _operationBlockActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddOperationBlockEndAction(OperationBlockAnalyzerAction action)
        {
            _operationBlockEndActions = _operationBlockEndActions.Add(action);
            IsEmpty = false;
        }
 
        internal void AddOperationAction(OperationAnalyzerAction action)
        {
            _operationActions = _operationActions.Add(action);
            IsEmpty = false;
        }
 
        internal void EnableConcurrentExecution()
        {
            _concurrent = true;
        }
 
        /// <summary>
        /// Append analyzer actions from <paramref name="otherActions"/> to actions from this instance.
        /// </summary>
        /// <param name="otherActions">Analyzer actions to append</param>.
        public readonly AnalyzerActions Append(in AnalyzerActions otherActions, bool appendSymbolStartAndSymbolEndActions = true)
        {
            if (otherActions.IsDefault)
            {
                throw new ArgumentNullException(nameof(otherActions));
            }
 
            AnalyzerActions actions = new AnalyzerActions(concurrent: _concurrent || otherActions.Concurrent);
            actions._compilationStartActions = _compilationStartActions.AddRange(otherActions._compilationStartActions);
            actions._compilationEndActions = _compilationEndActions.AddRange(otherActions._compilationEndActions);
            actions._compilationActions = _compilationActions.AddRange(otherActions._compilationActions);
            actions._syntaxTreeActions = _syntaxTreeActions.AddRange(otherActions._syntaxTreeActions);
            actions._additionalFileActions = _additionalFileActions.AddRange(otherActions._additionalFileActions);
            actions._semanticModelActions = _semanticModelActions.AddRange(otherActions._semanticModelActions);
            actions._symbolActions = _symbolActions.AddRange(otherActions._symbolActions);
            actions._symbolStartActions = appendSymbolStartAndSymbolEndActions ? _symbolStartActions.AddRange(otherActions._symbolStartActions) : _symbolStartActions;
            actions._symbolEndActions = appendSymbolStartAndSymbolEndActions ? _symbolEndActions.AddRange(otherActions._symbolEndActions) : _symbolEndActions;
            actions._codeBlockStartActions = _codeBlockStartActions.AddRange(otherActions._codeBlockStartActions);
            actions._codeBlockEndActions = _codeBlockEndActions.AddRange(otherActions._codeBlockEndActions);
            actions._codeBlockActions = _codeBlockActions.AddRange(otherActions._codeBlockActions);
            actions._syntaxNodeActions = _syntaxNodeActions.AddRange(otherActions._syntaxNodeActions);
            actions._operationActions = _operationActions.AddRange(otherActions._operationActions);
            actions._operationBlockStartActions = _operationBlockStartActions.AddRange(otherActions._operationBlockStartActions);
            actions._operationBlockEndActions = _operationBlockEndActions.AddRange(otherActions._operationBlockEndActions);
            actions._operationBlockActions = _operationBlockActions.AddRange(otherActions._operationBlockActions);
            actions.IsEmpty = IsEmpty && otherActions.IsEmpty;
 
            return actions;
        }
    }
}