internal void ExecuteCodeBlockActions <TLanguageKindEnum>( IEnumerable <CodeBlockStartAnalyzerAction <TLanguageKindEnum> > codeBlockStartActions, IEnumerable <CodeBlockAnalyzerAction> codeBlockActions, IEnumerable <CodeBlockAnalyzerAction> codeBlockEndActions, SyntaxNode declaredNode, ISymbol declaredSymbol, ImmutableArray <SyntaxNode> executableCodeBlocks, SemanticModel semanticModel, Func <SyntaxNode, TLanguageKindEnum> getKind) where TLanguageKindEnum : struct { Debug.Assert(declaredNode != null); Debug.Assert(declaredSymbol != null); Debug.Assert(CanHaveExecutableCodeBlock(declaredSymbol)); Debug.Assert(codeBlockStartActions.Any() || codeBlockEndActions.Any() || codeBlockActions.Any()); Debug.Assert(executableCodeBlocks.Any()); // Compute the sets of code block end, code block, and stateful syntax node actions. var blockEndActions = PooledHashSet <CodeBlockAnalyzerAction> .GetInstance(); var blockActions = PooledHashSet <CodeBlockAnalyzerAction> .GetInstance(); var executableNodeActions = ArrayBuilder <SyntaxNodeAnalyzerAction <TLanguageKindEnum> > .GetInstance(); // Include the code block actions. blockActions.AddAll(codeBlockActions); // Include the initial code block end actions. blockEndActions.AddAll(codeBlockEndActions); // Include the stateful actions. foreach (var da in codeBlockStartActions) { // Catch Exception from the start action. ExecuteAndCatchIfThrows(da.Analyzer, () => { var codeBlockScope = new HostCodeBlockStartAnalysisScope <TLanguageKindEnum>(); var blockStartContext = new AnalyzerCodeBlockStartAnalysisContext <TLanguageKindEnum>(da.Analyzer, codeBlockScope, declaredNode, declaredSymbol, semanticModel, _analyzerOptions, _cancellationToken); da.Action(blockStartContext); blockEndActions.AddAll(codeBlockScope.CodeBlockEndActions); executableNodeActions.AddRange(codeBlockScope.SyntaxNodeActions); }); } // Execute stateful executable node analyzers, if any. if (executableNodeActions.Any()) { var executableNodeActionsByKind = GetNodeActionsByKind(executableNodeActions); var nodesToAnalyze = executableCodeBlocks.SelectMany(cb => cb.DescendantNodesAndSelf()); ExecuteSyntaxNodeActions(nodesToAnalyze, executableNodeActionsByKind, semanticModel, getKind); } executableNodeActions.Free(); ExecuteCodeBlockActions(blockActions, declaredNode, declaredSymbol, semanticModel); ExecuteCodeBlockActions(blockEndActions, declaredNode, declaredSymbol, semanticModel); }
private void ExecuteCodeBlockActionsCore <TLanguageKindEnum>( IEnumerable <CodeBlockStartAnalyzerAction <TLanguageKindEnum> > codeBlockStartActions, IEnumerable <CodeBlockAnalyzerAction> codeBlockActions, IEnumerable <CodeBlockAnalyzerAction> codeBlockEndActions, DiagnosticAnalyzer analyzer, SyntaxNode declaredNode, ISymbol declaredSymbol, ImmutableArray <SyntaxNode> executableCodeBlocks, SemanticModel semanticModel, Func <SyntaxNode, TLanguageKindEnum> getKind, CodeBlockAnalyzerStateData analyzerStateOpt) where TLanguageKindEnum : struct { Debug.Assert(declaredNode != null); Debug.Assert(declaredSymbol != null); Debug.Assert(CanHaveExecutableCodeBlock(declaredSymbol)); Debug.Assert(codeBlockStartActions.Any() || codeBlockEndActions.Any() || codeBlockActions.Any()); Debug.Assert(executableCodeBlocks.Any()); // Compute the sets of code block end, code block, and stateful syntax node actions. var blockEndActions = PooledHashSet <CodeBlockAnalyzerAction> .GetInstance(); var blockActions = PooledHashSet <CodeBlockAnalyzerAction> .GetInstance(); var executableNodeActions = ArrayBuilder <SyntaxNodeAnalyzerAction <TLanguageKindEnum> > .GetInstance(); // Include the code block actions. blockActions.AddAll(codeBlockActions); // Include the initial code block end actions. if (analyzerStateOpt?.CurrentCodeBlockEndActions != null) { // We have partially processed the code block actions. blockEndActions.AddAll(analyzerStateOpt.CurrentCodeBlockEndActions.Cast <CodeBlockAnalyzerAction>()); executableNodeActions.AddRange(analyzerStateOpt.CurrentCodeBlockNodeActions.Cast <SyntaxNodeAnalyzerAction <TLanguageKindEnum> >()); } else { // We have beginning to process the code block actions. blockEndActions.AddAll(codeBlockEndActions); } var addDiagnostic = GetAddDiagnostic(semanticModel.SyntaxTree, declaredNode.FullSpan, analyzer, isSyntaxDiagnostic: false); try { // Include the stateful actions. foreach (var da in codeBlockStartActions) { if (ShouldExecuteAction(analyzerStateOpt, da)) { // Catch Exception from the start action. ExecuteAndCatchIfThrows(da.Analyzer, () => { var codeBlockScope = new HostCodeBlockStartAnalysisScope <TLanguageKindEnum>(); var blockStartContext = new AnalyzerCodeBlockStartAnalysisContext <TLanguageKindEnum>(da.Analyzer, codeBlockScope, declaredNode, declaredSymbol, semanticModel, _analyzerOptions, _cancellationToken); da.Action(blockStartContext); blockEndActions.AddAll(codeBlockScope.CodeBlockEndActions); executableNodeActions.AddRange(codeBlockScope.SyntaxNodeActions); }); analyzerStateOpt?.ProcessedActions.Add(da); } } } finally { if (analyzerStateOpt != null) { analyzerStateOpt.CurrentCodeBlockEndActions = blockEndActions.ToImmutableHashSet <AnalyzerAction>(); analyzerStateOpt.CurrentCodeBlockNodeActions = executableNodeActions.ToImmutableHashSet <AnalyzerAction>(); } } // Execute stateful executable node analyzers, if any. if (executableNodeActions.Any()) { var executableNodeActionsByKind = GetNodeActionsByKind(executableNodeActions); var nodesToAnalyze = executableCodeBlocks.SelectMany(cb => cb.DescendantNodesAndSelf()); ExecuteSyntaxNodeActions(nodesToAnalyze, executableNodeActionsByKind, semanticModel, getKind, addDiagnostic, analyzerStateOpt?.ExecutableNodesAnalysisState); } executableNodeActions.Free(); ExecuteCodeBlockActions(blockActions, declaredNode, declaredSymbol, semanticModel, addDiagnostic, analyzerStateOpt); ExecuteCodeBlockActions(blockEndActions, declaredNode, declaredSymbol, semanticModel, addDiagnostic, analyzerStateOpt); }
internal static void ExecuteCodeBlockActions <TLanguageKindEnum>( IEnumerable <CodeBlockStartAnalyzerAction <TLanguageKindEnum> > codeBlockStartActions, IEnumerable <CodeBlockEndAnalyzerAction> codeBlockEndActions, SyntaxNode declaredNode, ISymbol declaredSymbol, ImmutableArray <SyntaxNode> executableCodeBlocks, AnalyzerOptions analyzerOptions, SemanticModel semanticModel, Action <Diagnostic> addDiagnostic, Func <Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException, Func <SyntaxNode, TLanguageKindEnum> getKind, CancellationToken cancellationToken) where TLanguageKindEnum : struct { Debug.Assert(declaredNode != null); Debug.Assert(declaredSymbol != null); Debug.Assert(CanHaveExecutableCodeBlock(declaredSymbol)); Debug.Assert(codeBlockStartActions.Any() || codeBlockEndActions.Any()); Debug.Assert(executableCodeBlocks.Any()); // Compute the sets of code block end and stateful syntax node actions. var endedActions = PooledHashSet <CodeBlockEndAnalyzerAction> .GetInstance(); var executableNodeActions = ArrayBuilder <SyntaxNodeAnalyzerAction <TLanguageKindEnum> > .GetInstance(); // Include the stateless code block actions. endedActions.AddAll(codeBlockEndActions); // Include the stateful actions. foreach (var da in codeBlockStartActions) { // Catch Exception from the start action. ExecuteAndCatchIfThrows(da.Analyzer, addDiagnostic, continueOnAnalyzerException, () => { HostCodeBlockStartAnalysisScope <TLanguageKindEnum> codeBlockScope = new HostCodeBlockStartAnalysisScope <TLanguageKindEnum>(); CodeBlockStartAnalysisContext <TLanguageKindEnum> blockStartContext = new AnalyzerCodeBlockStartAnalysisContext <TLanguageKindEnum>(da.Analyzer, codeBlockScope, declaredNode, declaredSymbol, semanticModel, analyzerOptions, cancellationToken); da.Action(blockStartContext); endedActions.AddAll(codeBlockScope.CodeBlockEndActions); executableNodeActions.AddRange(codeBlockScope.SyntaxNodeActions); }, cancellationToken); } // Execute stateful executable node analyzers, if any. if (executableNodeActions.Any()) { var executableNodeActionsByKind = GetNodeActionsByKind(executableNodeActions, addDiagnostic); var nodesToAnalyze = executableCodeBlocks.SelectMany(cb => cb.DescendantNodesAndSelf()); ExecuteSyntaxNodeActions(nodesToAnalyze, executableNodeActionsByKind, semanticModel, analyzerOptions, addDiagnostic, continueOnAnalyzerException, getKind, cancellationToken); } // Execute code block end actions. foreach (var a in endedActions) { // Catch Exception from a.OnCodeBlockEnded ExecuteAndCatchIfThrows(a.Analyzer, addDiagnostic, continueOnAnalyzerException, () => a.Action(new CodeBlockEndAnalysisContext(declaredNode, declaredSymbol, semanticModel, analyzerOptions, addDiagnostic, cancellationToken)), cancellationToken); } endedActions.Free(); executableNodeActions.Free(); }