| File: DiagnosticAnalyzer\AnalyzerDriver.GroupedAnalyzerActionsForAnalyzer.cs | Web Access |
| Project: src\roslyn\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.Collections.Immutable; using System.Diagnostics; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.Diagnostics { internal partial class AnalyzerDriver<TLanguageKindEnum> : AnalyzerDriver where TLanguageKindEnum : struct { private sealed class GroupedAnalyzerActionsForAnalyzer { private readonly DiagnosticAnalyzer _analyzer; private readonly bool _analyzerActionsNeedFiltering; private ImmutableSegmentedDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> _lazyNodeActionsByKind; private ImmutableSegmentedDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> _lazyOperationActionsByKind; private ImmutableArray<CodeBlockStartAnalyzerAction<TLanguageKindEnum>> _lazyCodeBlockStartActions; private ImmutableArray<CodeBlockAnalyzerAction> _lazyCodeBlockEndActions; private ImmutableArray<CodeBlockAnalyzerAction> _lazyCodeBlockActions; private ImmutableArray<OperationBlockStartAnalyzerAction> _lazyOperationBlockStartActions; private ImmutableArray<OperationBlockAnalyzerAction> _lazyOperationBlockActions; private ImmutableArray<OperationBlockAnalyzerAction> _lazyOperationBlockEndActions; public GroupedAnalyzerActionsForAnalyzer(DiagnosticAnalyzer analyzer, in AnalyzerActions analyzerActions, bool analyzerActionsNeedFiltering) { Debug.Assert(!analyzerActions.IsEmpty); _analyzer = analyzer; AnalyzerActions = analyzerActions; _analyzerActionsNeedFiltering = analyzerActionsNeedFiltering; } public AnalyzerActions AnalyzerActions { get; } [Conditional("DEBUG")] private static void VerifyActions<TAnalyzerAction>(ArrayBuilder<TAnalyzerAction> actions, DiagnosticAnalyzer analyzer) where TAnalyzerAction : AnalyzerAction { foreach (var action in actions) { Debug.Assert(action.Analyzer == analyzer); } } private void AddFilteredActions<TAnalyzerAction>( ImmutableArray<TAnalyzerAction> actions, ArrayBuilder<TAnalyzerAction> builder) where TAnalyzerAction : AnalyzerAction { AddFilteredActions(actions, _analyzer, _analyzerActionsNeedFiltering, builder); } private static void AddFilteredActions<TAnalyzerAction>( in ImmutableArray<TAnalyzerAction> actions, DiagnosticAnalyzer analyzer, bool analyzerActionsNeedFiltering, ArrayBuilder<TAnalyzerAction> builder) where TAnalyzerAction : AnalyzerAction { if (!analyzerActionsNeedFiltering) { builder.AddRange(actions); } else { foreach (var action in actions) { if (action.Analyzer == analyzer) builder.Add(action); } } } public ImmutableSegmentedDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> NodeActionsByAnalyzerAndKind { get { if (_lazyNodeActionsByKind == null) { var nodeActions = ArrayBuilder<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>.GetInstance(); if (_analyzerActionsNeedFiltering) AnalyzerActions.AddSyntaxNodeActions(_analyzer, nodeActions); else AnalyzerActions.AddSyntaxNodeActions(nodeActions); VerifyActions(nodeActions, _analyzer); RoslynImmutableInterlocked.InterlockedInitialize(ref _lazyNodeActionsByKind, AnalyzerExecutor.GetNodeActionsByKind(nodeActions)); nodeActions.Free(); } return _lazyNodeActionsByKind; } } public ImmutableSegmentedDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> OperationActionsByAnalyzerAndKind { get { if (_lazyOperationActionsByKind == null) { var operationActions = ArrayBuilder<OperationAnalyzerAction>.GetInstance(); AddFilteredActions(AnalyzerActions.OperationActions, operationActions); VerifyActions(operationActions, _analyzer); RoslynImmutableInterlocked.InterlockedInitialize(ref _lazyOperationActionsByKind, AnalyzerExecutor.GetOperationActionsByKind(operationActions)); operationActions.Free(); } return _lazyOperationActionsByKind; } } private ImmutableArray<CodeBlockStartAnalyzerAction<TLanguageKindEnum>> CodeBlockStartActions { get { if (_lazyCodeBlockStartActions.IsDefault) { var codeBlockActions = ArrayBuilder<CodeBlockStartAnalyzerAction<TLanguageKindEnum>>.GetInstance(); AddFilteredActions(AnalyzerActions.GetCodeBlockStartActions<TLanguageKindEnum>(), codeBlockActions); VerifyActions(codeBlockActions, _analyzer); ImmutableInterlocked.InterlockedInitialize(ref _lazyCodeBlockStartActions, codeBlockActions.ToImmutableAndFree()); } return _lazyCodeBlockStartActions; } } private ImmutableArray<CodeBlockAnalyzerAction> CodeBlockEndActions => GetExecutableCodeActions(ref _lazyCodeBlockEndActions, AnalyzerActions.CodeBlockEndActions, _analyzer, _analyzerActionsNeedFiltering); private ImmutableArray<CodeBlockAnalyzerAction> CodeBlockActions => GetExecutableCodeActions(ref _lazyCodeBlockActions, AnalyzerActions.CodeBlockActions, _analyzer, _analyzerActionsNeedFiltering); private ImmutableArray<OperationBlockStartAnalyzerAction> OperationBlockStartActions => GetExecutableCodeActions(ref _lazyOperationBlockStartActions, AnalyzerActions.OperationBlockStartActions, _analyzer, _analyzerActionsNeedFiltering); private ImmutableArray<OperationBlockAnalyzerAction> OperationBlockEndActions => GetExecutableCodeActions(ref _lazyOperationBlockEndActions, AnalyzerActions.OperationBlockEndActions, _analyzer, _analyzerActionsNeedFiltering); private ImmutableArray<OperationBlockAnalyzerAction> OperationBlockActions => GetExecutableCodeActions(ref _lazyOperationBlockActions, AnalyzerActions.OperationBlockActions, _analyzer, _analyzerActionsNeedFiltering); public bool HasCodeBlockStartActions => !CodeBlockStartActions.IsEmpty; public bool HasOperationBlockStartActions => !OperationBlockStartActions.IsEmpty; private static ImmutableArray<ActionType> GetExecutableCodeActions<ActionType>( ref ImmutableArray<ActionType> lazyCodeBlockActions, ImmutableArray<ActionType> codeBlockActions, DiagnosticAnalyzer analyzer, bool analyzerActionsNeedFiltering) where ActionType : AnalyzerAction { if (lazyCodeBlockActions.IsDefault) { var finalActions = ArrayBuilder<ActionType>.GetInstance(); AddFilteredActions(codeBlockActions, analyzer, analyzerActionsNeedFiltering, finalActions); VerifyActions(finalActions, analyzer); ImmutableInterlocked.InterlockedInitialize(ref lazyCodeBlockActions, finalActions.ToImmutableAndFree()); } return lazyCodeBlockActions; } public bool TryGetExecutableCodeBlockActions(out ExecutableCodeBlockAnalyzerActions actions) { if (!OperationBlockStartActions.IsEmpty || !OperationBlockActions.IsEmpty || !OperationBlockEndActions.IsEmpty || !CodeBlockStartActions.IsEmpty || !CodeBlockActions.IsEmpty || !CodeBlockEndActions.IsEmpty) { actions = new ExecutableCodeBlockAnalyzerActions { Analyzer = _analyzer, CodeBlockStartActions = CodeBlockStartActions, CodeBlockActions = CodeBlockActions, CodeBlockEndActions = CodeBlockEndActions, OperationBlockStartActions = OperationBlockStartActions, OperationBlockActions = OperationBlockActions, OperationBlockEndActions = OperationBlockEndActions }; return true; } actions = default; return false; } } } }