private void OnSymbolDeclaredEventProcessed(SymbolDeclaredCompilationEvent symbolDeclaredEvent, ImmutableArray <DiagnosticAnalyzer> analyzers) { foreach (var analyzer in analyzers) { _analyzerStateMap[analyzer].OnSymbolDeclaredEventProcessed(symbolDeclaredEvent); } }
/// <summary> /// Invoke this method at completion of event processing for the given analysis scope. /// It updates the analysis state of this event for each analyzer and if the event has been fully processed for all analyzers, then removes it from our event cache. /// </summary> public void OnCompilationEventProcessed(CompilationEvent compilationEvent, AnalysisScope analysisScope) { // Analyze if the symbol and all its declaring syntax references are analyzed. SymbolDeclaredCompilationEvent symbolDeclaredEvent = compilationEvent as SymbolDeclaredCompilationEvent; if (symbolDeclaredEvent != null) { OnSymbolDeclaredEventProcessed(symbolDeclaredEvent, analysisScope.Analyzers); } // Check if event is fully analyzed for all analyzers. foreach (PerAnalyzerState analyzerState in _analyzerStates) { if (!analyzerState.IsEventAnalyzed(compilationEvent)) { return; } } // Remove the event from event map. lock (_gate) { UpdateEventsMap_NoLock(compilationEvent, add: false); } }
public bool OnSymbolDeclaredEventProcessed(SymbolDeclaredCompilationEvent symbolDeclaredEvent) { lock (_gate) { return(OnSymbolDeclaredEventProcessed_NoLock(symbolDeclaredEvent)); } }
private bool OnSymbolDeclaredEventProcessed_NoLock(SymbolDeclaredCompilationEvent symbolDeclaredEvent) { // Check if the symbol event has been completely processed or not. // Have the symbol actions executed? if (!IsEntityFullyProcessed_NoLock(symbolDeclaredEvent.Symbol, _pendingSymbols)) { return(false); } // Have the node/code block actions executed for all symbol declarations? if (!AreDeclarationsProcessed_NoLock(symbolDeclaredEvent.Symbol, symbolDeclaredEvent.DeclaringSyntaxReferences.Length)) { return(false); } // Have the symbol end actions, if any, executed? if (_lazyPendingSymbolEndAnalyses != null && !IsEntityFullyProcessed_NoLock(symbolDeclaredEvent.Symbol, _lazyPendingSymbolEndAnalyses)) { return(false); } // Mark declarations completely processed. MarkDeclarationsProcessed_NoLock(symbolDeclaredEvent.Symbol); // Mark the symbol event completely processed. return(MarkEntityProcessed_NoLock(symbolDeclaredEvent, _pendingEvents, _analyzerStateDataPool)); }
public void OnSymbolDeclaredEventProcessed(SymbolDeclaredCompilationEvent symbolDeclaredEvent) { lock (_gate) { OnSymbolDeclaredEventProcessed_NoLock(symbolDeclaredEvent); } }
public async Task OnSymbolDeclaredEventProcessedAsync(SymbolDeclaredCompilationEvent symbolDeclaredEvent, CancellationToken cancellationToken) { using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false)) { OnSymbolDeclaredEventProcessed_NoLock(symbolDeclaredEvent); } }
private async Task ProcessSymbolDeclaredAsync(SymbolDeclaredCompilationEvent symbolEvent, CancellationToken cancellationToken) { // Create a task per-analyzer to execute analyzer actions. // We execute analyzers in parallel, but for a given analyzer we execute actions sequentially. var tasksMap = PooledDictionary <DiagnosticAnalyzer, Task> .GetInstance(); try { var symbol = symbolEvent.Symbol; // Skip symbol actions for implicitly declared symbols. if (!symbol.IsImplicitlyDeclared) { AddTasksForExecutingSymbolActions(symbolEvent, tasksMap, cancellationToken); } // Skip syntax actions for implicitly declared symbols, except for implicitly declared global namespace symbols. if (!symbol.IsImplicitlyDeclared || (symbol.Kind == SymbolKind.Namespace && ((INamespaceSymbol)symbol).IsGlobalNamespace)) { AddTasksForExecutingDeclaringReferenceActions(symbolEvent, tasksMap, cancellationToken); } // Execute all analyzer actions. await Task.WhenAll(tasksMap.Values).ConfigureAwait(false); } finally { tasksMap.Free(); symbolEvent.FlushCache(); } }
private void OnCompilationEventsGenerated_NoLock(ImmutableArray <CompilationEvent> compilationEvents, SyntaxTree filterTreeOpt, AnalyzerDriver driver, CancellationToken cancellationToken) { Debug.Assert(_lazyAnalyzerActionCountsMap != null); // Add the events to our global pending events map. AddToEventsMap_NoLock(compilationEvents, filterTreeOpt); // Mark the events for analysis for each analyzer. ArrayBuilder <ISymbol> newPartialSymbols = null; Debug.Assert(_pooledEventsWithAnyActionsSet.Count == 0); foreach (KeyValuePair <DiagnosticAnalyzer, int> kvp in _analyzerStateMap) { DiagnosticAnalyzer analyzer = kvp.Key; PerAnalyzerState analyzerState = _analyzerStates[kvp.Value]; AnalyzerActionCounts actionCounts = _lazyAnalyzerActionCountsMap[analyzer]; foreach (CompilationEvent compilationEvent in compilationEvents) { if (HasActionsForEvent(compilationEvent, actionCounts)) { _pooledEventsWithAnyActionsSet.Add(compilationEvent); SymbolDeclaredCompilationEvent symbolDeclaredEvent = compilationEvent as SymbolDeclaredCompilationEvent; if (symbolDeclaredEvent?.DeclaringSyntaxReferences.Length > 1) { if (_partialSymbolsWithGeneratedSourceEvents.Contains(symbolDeclaredEvent.Symbol)) { // already processed. continue; } else { newPartialSymbols = newPartialSymbols ?? ArrayBuilder <ISymbol> .GetInstance(); newPartialSymbols.Add(symbolDeclaredEvent.Symbol); } } analyzerState.OnCompilationEventGenerated(compilationEvent, actionCounts); } } } foreach (CompilationEvent compilationEvent in compilationEvents) { if (!_pooledEventsWithAnyActionsSet.Remove(compilationEvent)) { // Event has no relevant actions to execute, so mark it as complete. UpdateEventsMap_NoLock(compilationEvent, add: false); } } if (newPartialSymbols != null) { _partialSymbolsWithGeneratedSourceEvents.AddAll(newPartialSymbols); newPartialSymbols.Free(); } }
private async Task OnSymbolDeclaredEventProcessedAsync(SymbolDeclaredCompilationEvent symbolDeclaredEvent, ImmutableArray <DiagnosticAnalyzer> analyzers, CancellationToken cancellationToken) { foreach (var analyzer in analyzers) { var analyzerState = GetAnalyzerState(analyzer); await analyzerState.OnSymbolDeclaredEventProcessedAsync(symbolDeclaredEvent, cancellationToken).ConfigureAwait(false); } }
private void OnSymbolDeclaredEventProcessed(SymbolDeclaredCompilationEvent symbolDeclaredEvent, ImmutableArray <DiagnosticAnalyzer> analyzers) { foreach (DiagnosticAnalyzer analyzer in analyzers) { PerAnalyzerState analyzerState = GetAnalyzerState(analyzer); analyzerState.OnSymbolDeclaredEventProcessed(symbolDeclaredEvent); } }
private void UpdateEventsMap_NoLock(CompilationEvent compilationEvent, bool add) { SymbolDeclaredCompilationEvent symbolEvent = compilationEvent as SymbolDeclaredCompilationEvent; if (symbolEvent != null) { // Add/remove symbol events. // Any diagnostics request for a tree should trigger symbol and syntax node analysis for symbols with at least one declaring reference in the tree. foreach (Location location in symbolEvent.Symbol.Locations) { if (location.SourceTree != null) { if (add) { AddPendingSourceEvent_NoLock(location.SourceTree, compilationEvent); } else { RemovePendingSourceEvent_NoLock(location.SourceTree, compilationEvent); } } } } else { // Add/remove compilation unit completed events. CompilationUnitCompletedEvent compilationUnitCompletedEvent = compilationEvent as CompilationUnitCompletedEvent; if (compilationUnitCompletedEvent != null) { SyntaxTree tree = compilationUnitCompletedEvent.SemanticModel.SyntaxTree; if (add) { AddPendingSourceEvent_NoLock(tree, compilationEvent); } else { RemovePendingSourceEvent_NoLock(tree, compilationEvent); } } else if (compilationEvent is CompilationStartedEvent || compilationEvent is CompilationCompletedEvent) { // Add/remove compilation events. if (add) { _pendingNonSourceEvents.Add(compilationEvent); } else { _pendingNonSourceEvents.Remove(compilationEvent); } } else { throw new InvalidOperationException("Unexpected compilation event of type " + compilationEvent.GetType().Name); } } }
private Task ProcessSymbolDeclared(SymbolDeclaredCompilationEvent symbolEvent, CancellationToken cancellationToken) { try { return(AnalyzeSymbol(symbolEvent, cancellationToken)); } finally { symbolEvent.FlushCache(); } }
private async Task OnSymbolDeclaredEventProcessedAsync( SymbolDeclaredCompilationEvent symbolDeclaredEvent, ImmutableArray <DiagnosticAnalyzer> analyzers, Func <ISymbol, DiagnosticAnalyzer, Task> onSymbolAndMembersProcessedAsync) { foreach (var analyzer in analyzers) { var analyzerState = GetAnalyzerState(analyzer); if (analyzerState.OnSymbolDeclaredEventProcessed(symbolDeclaredEvent)) { await onSymbolAndMembersProcessedAsync(symbolDeclaredEvent.Symbol, analyzer).ConfigureAwait(false); } } }
private void AddTasksForExecutingSymbolActions(SymbolDeclaredCompilationEvent symbolEvent, IDictionary <DiagnosticAnalyzer, Task> taskMap, CancellationToken cancellationToken) { var symbol = symbolEvent.Symbol; Action <Diagnostic> addDiagnosticForSymbol = GetDiagnosticSinkWithSuppression(DiagnosticQueue.Enqueue, _compilation, symbol); foreach (var analyzerAndActions in _symbolActionsByKind) { var analyzer = analyzerAndActions.Key; var actionsByKind = analyzerAndActions.Value; Action executeSymbolActionsForAnalyzer = () => ExecuteSymbolActionsForAnalyzer(symbol, analyzer, actionsByKind, addDiagnosticForSymbol, cancellationToken); AddAnalyzerActionsExecutor(taskMap, analyzer, executeSymbolActionsForAnalyzer, cancellationToken); } }
public void OnCompilationEventGenerated(CompilationEvent compilationEvent, AnalyzerActionCounts actionCounts) { lock (_gate) { SymbolDeclaredCompilationEvent symbolEvent = compilationEvent as SymbolDeclaredCompilationEvent; if (symbolEvent != null) { bool needsAnalysis = false; ISymbol symbol = symbolEvent.Symbol; if (!AnalysisScope.ShouldSkipSymbolAnalysis(symbolEvent) && actionCounts.SymbolActionsCount > 0) { needsAnalysis = true; _pendingSymbols[symbol] = null; } if (!AnalysisScope.ShouldSkipDeclarationAnalysis(symbol) && actionCounts.HasAnyExecutableCodeActions) { needsAnalysis = true; _pendingDeclarations[symbol] = _currentlyAnalyzingDeclarationsMapPool.Allocate(); } if (!needsAnalysis) { return; } } else if (compilationEvent is CompilationStartedEvent) { if (actionCounts.SyntaxTreeActionsCount > 0) { _lazySyntaxTreesWithAnalysisData = new Dictionary <SyntaxTree, AnalyzerStateData>(); _pendingSyntaxAnalysisTreesCount = compilationEvent.Compilation.SyntaxTrees.Count(); } if (actionCounts.CompilationActionsCount == 0) { return; } } _pendingEvents[compilationEvent] = null; } }
private Task AnalyzeSymbol(SymbolDeclaredCompilationEvent symbolEvent, CancellationToken cancellationToken) { var symbol = symbolEvent.Symbol; Action <Diagnostic> addDiagnosticForSymbol = GetDiagnosticSinkWithSuppression(symbol); var tasks = ArrayBuilder <Task> .GetInstance(); if ((int)symbol.Kind < declarationAnalyzersByKind.Length) { foreach (var da in declarationAnalyzersByKind[(int)symbol.Kind]) { // TODO: is the overhead of creating tasks here too high compared to the cost of running them sequentially? tasks.Add(Task.Run(() => { // Catch Exception from da.AnalyzeSymbol ExecuteAndCatchIfThrows(da, addDiagnostic, continueOnError, cancellationToken, () => { cancellationToken.ThrowIfCancellationRequested(); da.AnalyzeSymbol(symbol, compilation, addDiagnosticForSymbol, this.analyzerOptions, cancellationToken); }); })); } } // TODO: what about syntax references elsewhere, for example in a class base clause? switch (symbol.Kind) { // TODO: what about other syntax, such as base clauses, using directives, top-level attributes, etc? case SymbolKind.Method: case SymbolKind.Field: case SymbolKind.Event: // TODO: should this be restricted to field-like events? foreach (var decl in symbol.DeclaringSyntaxReferences) { tasks.Add(AnalyzeDeclaringReference(symbolEvent, decl, addDiagnostic, cancellationToken)); } break; } return(Task.WhenAll(tasks.ToImmutableAndFree())); }
private void OnSymbolDeclaredEventProcessed_NoLock(SymbolDeclaredCompilationEvent symbolDeclaredEvent) { // Check if the symbol event has been completely processed or not. // Have the symbol actions executed? if (!IsEntityFullyProcessed_NoLock(symbolDeclaredEvent.Symbol, _pendingSymbols)) { return; } // Have the node/code block actions executed for all symbol declarations? foreach (var syntaxRef in symbolDeclaredEvent.DeclaringSyntaxReferences) { if (!IsEntityFullyProcessed_NoLock(syntaxRef.GetSyntax(), _pendingDeclarations)) { return; } } // Mark the symbol event completely processed. MarkEntityProcessed_NoLock(symbolDeclaredEvent, _pendingEvents, _analyzerStateDataPool); }
private void AddTasksForExecutingSymbolActions(SymbolDeclaredCompilationEvent symbolEvent, IDictionary<DiagnosticAnalyzer, ArrayBuilder<Action>> actionsMap, CancellationToken cancellationToken) { var symbol = symbolEvent.Symbol; Action<Diagnostic> addDiagnosticForSymbol = GetDiagnosticSinkWithSuppression(DiagnosticQueue.Enqueue, _compilation, symbol); foreach (var analyzerAndActions in _symbolActionsByKind) { var analyzer = analyzerAndActions.Key; var actionsByKind = analyzerAndActions.Value; Action executeSymbolActionsForAnalyzer = () => ExecuteSymbolActionsForAnalyzer(symbol, analyzer, actionsByKind, addDiagnosticForSymbol, cancellationToken); AddAnalyzerActionsExecutor(actionsMap, analyzer, executeSymbolActionsForAnalyzer); } }
protected abstract void AddTasksForExecutingDeclaringReferenceActions(SymbolDeclaredCompilationEvent symbolEvent, IDictionary<DiagnosticAnalyzer, ArrayBuilder<Action>> actionsMap, CancellationToken cancellationToken);
protected abstract Task AnalyzeDeclaringReference(SymbolDeclaredCompilationEvent symbolEvent, SyntaxReference decl, Action <Diagnostic> addDiagnostic, CancellationToken cancellationToken);
protected abstract bool TryExecuteDeclaringReferenceActions(SymbolDeclaredCompilationEvent symbolEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, bool isGeneratedCodeSymbol, CancellationToken cancellationToken);
private async Task OnSymbolDeclaredEventProcessedAsync(SymbolDeclaredCompilationEvent symbolDeclaredEvent, ImmutableArray<DiagnosticAnalyzer> analyzers, CancellationToken cancellationToken) { foreach (var analyzer in analyzers) { var analyzerState = GetAnalyzerState(analyzer); await analyzerState.OnSymbolDeclaredEventProcessedAsync(symbolDeclaredEvent, cancellationToken).ConfigureAwait(false); } }
private void ExecuteSymbolActions(SymbolDeclaredCompilationEvent symbolEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken) { var symbol = symbolEvent.Symbol; if (!analysisScope.ShouldAnalyze(symbol)) { return; } Action<Diagnostic> addDiagnosticForSymbol = GetDiagnosticSinkWithSuppression(DiagnosticQueue.Enqueue, symbolEvent.Compilation, symbol); Action<Diagnostic, DiagnosticAnalyzer, bool> addLocalDiagnosticForSymbol = analysisScope.CategorizeDiagnostics ? GetDiagnosticSinkWithSuppression(DiagnosticQueue.EnqueueLocal, symbolEvent.Compilation, symbol) : null; Action<Diagnostic, DiagnosticAnalyzer> addNonLocalDiagnosticForSymbol = analysisScope.CategorizeDiagnostics ? GetDiagnosticSinkWithSuppression(DiagnosticQueue.EnqueueNonLocal, symbolEvent.Compilation, symbol) : null; foreach (var analyzer in analysisScope.Analyzers) { // Invoke symbol analyzers only for source symbols. ImmutableArray<ImmutableArray<SymbolAnalyzerAction>> actionsByKind; if (_symbolActionsByKind.TryGetValue(analyzer, out actionsByKind) && (int)symbol.Kind < actionsByKind.Length) { analyzerExecutor.ExecuteSymbolActions(actionsByKind[(int)symbol.Kind], analyzer, symbol, addDiagnosticForSymbol, addLocalDiagnosticForSymbol, addNonLocalDiagnosticForSymbol, GetTopmostNodeForAnalysis, analysisScope, analysisStateOpt); } else { analysisStateOpt?.MarkSymbolComplete(symbol, analyzer); } } }
public static bool ShouldSkipSymbolAnalysis(SymbolDeclaredCompilationEvent symbolEvent) { // Skip symbol actions for implicitly declared symbols and non-source symbols. return symbolEvent.Symbol.IsImplicitlyDeclared || symbolEvent.DeclaringSyntaxReferences.All(s => s.SyntaxTree == null); }
private SymbolDeclaredCompilationEvent(SymbolDeclaredCompilationEvent original, SemanticModel newSemanticModel) : this(original.Compilation, original.Symbol) { _semanticModel = newSemanticModel; }
private async Task ProcessSymbolDeclaredAsync(SymbolDeclaredCompilationEvent symbolEvent, CancellationToken cancellationToken) { // Collect all the analyzer action executors grouped by analyzer. // NOTE: Right now we execute all the actions sequentially, but there is scope to fine tune this to execute certain actions in parallel. var actionsMap = PooledDictionary<DiagnosticAnalyzer, ArrayBuilder<Action>>.GetInstance(); try { var symbol = symbolEvent.Symbol; // Skip symbol actions for implicitly declared symbols. if (!symbol.IsImplicitlyDeclared) { AddTasksForExecutingSymbolActions(symbolEvent, actionsMap, cancellationToken); } // Skip syntax actions for implicitly declared symbols, except for implicitly declared global namespace symbols. if (!symbol.IsImplicitlyDeclared || (symbol.Kind == SymbolKind.Namespace && ((INamespaceSymbol)symbol).IsGlobalNamespace)) { AddTasksForExecutingDeclaringReferenceActions(symbolEvent, actionsMap, cancellationToken); } // Execute all analyzer actions. await Task.Run(() => { foreach (var builder in actionsMap.Values) { foreach (var action in builder) { action(); } builder.Free(); }; }, cancellationToken).ConfigureAwait(false); } finally { actionsMap.Free(); symbolEvent.FlushCache(); } }
protected abstract Task AnalyzeDeclaringReferenceAsync(SymbolDeclaredCompilationEvent symbolEvent, SyntaxReference decl, Action<Diagnostic> addDiagnostic, CancellationToken cancellationToken);
private Task AnalyzeSymbol(SymbolDeclaredCompilationEvent symbolEvent, CancellationToken cancellationToken) { var symbol = symbolEvent.Symbol; Action<Diagnostic> addDiagnosticForSymbol = GetDiagnosticSinkWithSuppression(symbol); var tasks = ArrayBuilder<Task>.GetInstance(); // Invoke symbol analyzers only for source symbols. var declaringSyntaxRefs = symbol.DeclaringSyntaxReferences; if ((int)symbol.Kind < declarationAnalyzersByKind.Length && declaringSyntaxRefs.Any(s => s.SyntaxTree != null)) { foreach (var da in declarationAnalyzersByKind[(int)symbol.Kind]) { // TODO: is the overhead of creating tasks here too high compared to the cost of running them sequentially? tasks.Add(Task.Run(() => { // Catch Exception from da.AnalyzeSymbol ExecuteAndCatchIfThrows(da, addDiagnostic, continueOnAnalyzerException, cancellationToken, () => { cancellationToken.ThrowIfCancellationRequested(); da.AnalyzeSymbol(symbol, compilation, addDiagnosticForSymbol, this.analyzerOptions, cancellationToken); }); })); } } foreach (var decl in declaringSyntaxRefs) { tasks.Add(AnalyzeDeclaringReferenceAsync(symbolEvent, decl, addDiagnostic, cancellationToken)); } return Task.WhenAll(tasks.ToImmutableAndFree()); }
private Task ProcessSymbolDeclared(SymbolDeclaredCompilationEvent symbolEvent, CancellationToken cancellationToken) { try { return AnalyzeSymbol(symbolEvent, cancellationToken); } finally { symbolEvent.FlushCache(); } }
protected abstract void AddTasksForExecutingDeclaringReferenceActions(SymbolDeclaredCompilationEvent symbolEvent, IDictionary<DiagnosticAnalyzer, Task> taskMap, Action<Diagnostic> addDiagnostic, CancellationToken cancellationToken);
private void ExecuteSymbolActions(SymbolDeclaredCompilationEvent symbolEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken) { var symbol = symbolEvent.Symbol; if (!analysisScope.ShouldAnalyze(symbol)) { return; } foreach (var analyzer in analysisScope.Analyzers) { // Invoke symbol analyzers only for source symbols. ImmutableArray<ImmutableArray<SymbolAnalyzerAction>> actionsByKind; if (_symbolActionsByKind.TryGetValue(analyzer, out actionsByKind) && (int)symbol.Kind < actionsByKind.Length) { analyzerExecutor.ExecuteSymbolActions(actionsByKind[(int)symbol.Kind], analyzer, symbol, GetTopmostNodeForAnalysis, analysisScope, analysisStateOpt); } else { analysisStateOpt?.MarkSymbolComplete(symbol, analyzer); } } }
private void OnSymbolDeclaredEventProcessed(SymbolDeclaredCompilationEvent symbolDeclaredEvent, ImmutableArray<DiagnosticAnalyzer> analyzers) { foreach (var analyzer in analyzers) { _analyzerStateMap[analyzer].OnSymbolDeclaredEventProcessed(symbolDeclaredEvent); } }
private void ProcessSymbolDeclared(SymbolDeclaredCompilationEvent symbolEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken) { try { // Execute all analyzer actions. var symbol = symbolEvent.Symbol; var references = symbolEvent.DeclaringSyntaxReferences; if (!AnalysisScope.ShouldSkipSymbolAnalysis(symbolEvent)) { ExecuteSymbolActions(symbolEvent, analysisScope, analysisStateOpt, cancellationToken); } if (!AnalysisScope.ShouldSkipDeclarationAnalysis(symbol)) { ExecuteDeclaringReferenceActions(symbolEvent, analysisScope, analysisStateOpt, cancellationToken); } } finally { symbolEvent.FlushCache(); } }
public static bool ShouldSkipSymbolAnalysis(SymbolDeclaredCompilationEvent symbolEvent) { // Skip symbol actions for implicitly declared symbols and non-source symbols. return(symbolEvent.Symbol.IsImplicitlyDeclared || symbolEvent.DeclaringSyntaxReferences.All(s => s.SyntaxTree == null)); }
protected abstract void ExecuteDeclaringReferenceActions(SymbolDeclaredCompilationEvent symbolEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken);
private Task AnalyzeSymbol(SymbolDeclaredCompilationEvent symbolEvent, CancellationToken cancellationToken) { var symbol = symbolEvent.Symbol; Action<Diagnostic> addDiagnosticForSymbol = GetDiagnosticSinkWithSuppression(symbol); var tasks = ArrayBuilder<Task>.GetInstance(); if ((int)symbol.Kind < declarationAnalyzersByKind.Length) { foreach (var da in declarationAnalyzersByKind[(int)symbol.Kind]) { // TODO: is the overhead of creating tasks here too high compared to the cost of running them sequentially? tasks.Add(Task.Run(() => { // Catch Exception from da.AnalyzeSymbol ExecuteAndCatchIfThrows(da, addDiagnostic, continueOnError, cancellationToken, () => { cancellationToken.ThrowIfCancellationRequested(); da.AnalyzeSymbol(symbol, compilation, addDiagnosticForSymbol, this.analyzerOptions, cancellationToken); }); })); } } // TODO: what about syntax references elsewhere, for example in a class base clause? switch (symbol.Kind) { // TODO: what about other syntax, such as base clauses, using directives, top-level attributes, etc? case SymbolKind.Method: case SymbolKind.Field: case SymbolKind.Event: // TODO: should this be restricted to field-like events? foreach (var decl in symbol.DeclaringSyntaxReferences) { tasks.Add(AnalyzeDeclaringReference(symbolEvent, decl, addDiagnostic, cancellationToken)); } break; } return Task.WhenAll(tasks.ToImmutableAndFree()); }
private async Task ProcessSymbolDeclaredAsync(SymbolDeclaredCompilationEvent symbolEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken) { try { // Execute all analyzer actions. var symbol = symbolEvent.Symbol; var references = symbolEvent.DeclaringSyntaxReferences; if (!AnalysisScope.ShouldSkipSymbolAnalysis(symbolEvent)) { await ExecuteSymbolActionsAsync(symbolEvent, analysisScope, analysisStateOpt, cancellationToken).ConfigureAwait(false); } if (!AnalysisScope.ShouldSkipDeclarationAnalysis(symbol)) { await ExecuteDeclaringReferenceActionsAsync(symbolEvent, analysisScope, analysisStateOpt, cancellationToken).ConfigureAwait(false); } } finally { symbolEvent.FlushCache(); } }
/// <summary> /// Tries to execute symbol and declaration actions for the given symbol. /// </summary> /// <returns> /// True, if successfully executed the actions for the given analysis scope OR no actions were required to be executed for the given analysis scope. /// False, otherwise. /// </returns> private bool TryProcessSymbolDeclared(SymbolDeclaredCompilationEvent symbolEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken) { try { // Attempt to execute all analyzer actions. var success = true; var symbol = symbolEvent.Symbol; var isGeneratedCodeSymbol = IsGeneratedCodeSymbol(symbol); if (!AnalysisScope.ShouldSkipSymbolAnalysis(symbolEvent) && !TryExecuteSymbolActions(symbolEvent, analysisScope, analysisStateOpt, isGeneratedCodeSymbol, cancellationToken)) { success = false; } if (!AnalysisScope.ShouldSkipDeclarationAnalysis(symbol) && !TryExecuteDeclaringReferenceActions(symbolEvent, analysisScope, analysisStateOpt, isGeneratedCodeSymbol, cancellationToken)) { success = false; } return success; } finally { symbolEvent.FlushCache(); } }
protected abstract void AddTasksForExecutingDeclaringReferenceActions(SymbolDeclaredCompilationEvent symbolEvent, IDictionary <DiagnosticAnalyzer, Task> taskMap, CancellationToken cancellationToken);
private async Task ProcessSymbolDeclaredAsync(SymbolDeclaredCompilationEvent symbolEvent, CancellationToken cancellationToken) { // Create a task per-analyzer to execute analyzer actions. // We execute analyzers in parallel, but for a given analyzer we execute actions sequentially. var tasksMap = PooledDictionary<DiagnosticAnalyzer, Task>.GetInstance(); try { var symbol = symbolEvent.Symbol; // Skip symbol actions for implicitly declared symbols. if (!symbol.IsImplicitlyDeclared) { AddTasksForExecutingSymbolActions(symbolEvent, tasksMap, cancellationToken); } // Skip syntax actions for implicitly declared symbols, except for implicitly declared global namespace symbols. if (!symbol.IsImplicitlyDeclared || (symbol.Kind == SymbolKind.Namespace && ((INamespaceSymbol)symbol).IsGlobalNamespace)) { AddTasksForExecutingDeclaringReferenceActions(symbolEvent, tasksMap, _addDiagnostic, cancellationToken); } // Execute all analyzer actions. await Task.WhenAll(tasksMap.Values).ConfigureAwait(false); } finally { tasksMap.Free(); symbolEvent.FlushCache(); } }