/// <summary> /// Marks the given event as fully analyzed for the given analyzers. /// </summary> public void MarkEventComplete(CompilationEvent compilationEvent, IEnumerable <DiagnosticAnalyzer> analyzers) { foreach (var analyzer in analyzers) { GetAnalyzerState(analyzer).MarkEventComplete(compilationEvent); } }
/// <summary> /// Invoke this method at completion of event processing for the given analyzers. /// 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 async Task OnCompilationEventProcessedAsync(CompilationEvent compilationEvent, ImmutableArray <DiagnosticAnalyzer> analyzers, Func <ISymbol, DiagnosticAnalyzer, Task> onSymbolAndMembersProcessedAsync) { // Analyze if the symbol and all its declaring syntax references are analyzed. var symbolDeclaredEvent = compilationEvent as SymbolDeclaredCompilationEvent; if (symbolDeclaredEvent != null) { await OnSymbolDeclaredEventProcessedAsync(symbolDeclaredEvent, analyzers, onSymbolAndMembersProcessedAsync).ConfigureAwait(false); } // Check if event is fully analyzed for all analyzers. foreach (var analyzerState in _analyzerStates) { if (!analyzerState.IsEventAnalyzed(compilationEvent)) { return; } } // Remove the event from event map. // Note: We do not pass in the cancellationToken to DisposableWait to ensure the state is updated. using (_gate.DisposableWait()) { UpdateEventsMap_NoLock(compilationEvent, add: false); } }
private void UpdateEventsMap_NoLock(CompilationEvent compilationEvent, bool add) { var 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 (var 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. var compilationUnitCompletedEvent = compilationEvent as CompilationUnitCompletedEvent; if (compilationUnitCompletedEvent != null) { var 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); } } }
public void OnCompilationEventGenerated(CompilationEvent compilationEvent, AnalyzerActionCounts actionCounts) { lock (_gate) { var symbolEvent = compilationEvent as SymbolDeclaredCompilationEvent; if (symbolEvent != null) { var needsAnalysis = false; var symbol = symbolEvent.Symbol; var skipSymbolAnalysis = AnalysisScope.ShouldSkipSymbolAnalysis(symbolEvent); if (!skipSymbolAnalysis && actionCounts.SymbolActionsCount > 0) { needsAnalysis = true; _pendingSymbols[symbol] = null; } var skipDeclarationAnalysis = AnalysisScope.ShouldSkipDeclarationAnalysis(symbol); if (!skipDeclarationAnalysis && actionCounts.HasAnyExecutableCodeActions) { needsAnalysis = true; _pendingDeclarations[symbol] = _currentlyAnalyzingDeclarationsMapPool.Allocate(); } if (actionCounts.SymbolStartActionsCount > 0 && (!skipSymbolAnalysis || !skipDeclarationAnalysis)) { needsAnalysis = true; _lazyPendingSymbolEndAnalyses = _lazyPendingSymbolEndAnalyses ?? new Dictionary <ISymbol, AnalyzerStateData>(); _lazyPendingSymbolEndAnalyses[symbol] = null; } 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 void RemovePendingSourceEvent_NoLock(SyntaxTree tree, CompilationEvent compilationEvent) { HashSet <CompilationEvent> currentEvents; if (_pendingSourceEvents.TryGetValue(tree, out currentEvents)) { if (currentEvents.Remove(compilationEvent) && currentEvents.Count == 0) { _pendingSourceEvents.Remove(tree); _compilationData.RemoveCachedSemanticModel(tree); } } }
private void AddPendingSourceEvent_NoLock(SyntaxTree tree, CompilationEvent compilationEvent) { HashSet <CompilationEvent> currentEvents; if (!_pendingSourceEvents.TryGetValue(tree, out currentEvents)) { currentEvents = new HashSet <CompilationEvent>(); _pendingSourceEvents[tree] = currentEvents; _compilationData.RemoveCachedSemanticModel(tree); } currentEvents.Add(compilationEvent); }
private static bool HasActionsForEvent(CompilationEvent compilationEvent, AnalyzerActionCounts actionCounts) { if (compilationEvent is CompilationStartedEvent) { return(actionCounts.CompilationActionsCount > 0 || actionCounts.SyntaxTreeActionsCount > 0); } else if (compilationEvent is CompilationCompletedEvent) { return(actionCounts.CompilationEndActionsCount > 0); } else if (compilationEvent is SymbolDeclaredCompilationEvent) { return(actionCounts.SymbolActionsCount > 0 || actionCounts.HasAnyExecutableCodeActions); } else { return(actionCounts.SemanticModelActionsCount > 0); } }
public bool IsEventAnalyzed(CompilationEvent compilationEvent) { return(IsEntityFullyProcessed(compilationEvent, _pendingEvents)); }
public void MarkEventComplete(CompilationEvent compilationEvent) { MarkEntityProcessed(compilationEvent, _pendingEvents, _analyzerStateDataPool); }
public bool TryStartProcessingEvent(CompilationEvent compilationEvent, out AnalyzerStateData state) { return(TryStartProcessingEntity(compilationEvent, _pendingEvents, _analyzerStateDataPool, out state)); }
/// <summary> /// Checks if the given event has been fully analyzed for the given analyzer. /// </summary> public bool IsEventComplete(CompilationEvent compilationEvent, DiagnosticAnalyzer analyzer) { return(GetAnalyzerState(analyzer).IsEventAnalyzed(compilationEvent)); }
/// <summary> /// Marks the given event as fully analyzed for the given analyzer. /// </summary> public void MarkEventComplete(CompilationEvent compilationEvent, DiagnosticAnalyzer analyzer) { GetAnalyzerState(analyzer).MarkEventComplete(compilationEvent); }
/// <summary> /// Attempts to start processing a compilation event for the given analyzer. /// </summary> /// <returns> /// Returns false if the event has already been processed for the analyzer OR is currently being processed by another task. /// If true, then it returns a non-null <paramref name="state"/> representing partial analysis state for the given event for the given analyzer. /// </returns> public bool TryStartProcessingEvent(CompilationEvent compilationEvent, DiagnosticAnalyzer analyzer, out AnalyzerStateData state) { return(GetAnalyzerState(analyzer).TryStartProcessingEvent(compilationEvent, out state)); }