提交 34460a3c 编写于 作者: M Manish Vasani

[Performance] Make core AnalyzerExecutor async

This change replaces synchronous lock statements in the core analyzer executor and analyzer state tracker (for IDE live analysis) with semaphore slim DisposableWaitAsync invocations. This ensures that most of the analyzer driver and analyzer executor code is now async, with only the eventual callback into the analyzers being a synchronous method ([ExecuteAndCatchIfThrows_NoLock](http://source.roslyn.io/Microsoft.CodeAnalysis/R/02d7df8203d3591e.html))

Testing: I verified that the self-build time of Roslyn.sln (which uses a few analyzers), is almost identical after this change. We are hoping that this will improve build performance when there is lot of lock contention, which has shown up from perf traces (see https://github.com/dotnet/roslyn/issues/6053).

Fixes #6399
上级 80d3bb71
......@@ -184,6 +184,8 @@
<Compile Include="InternalUtilities\CompilerOptionParseUtilities.cs" />
<Compile Include="InternalUtilities\ImmutableArrayInterop.cs" />
<Compile Include="InternalUtilities\ReflectionUtilities.cs" />
<Compile Include="InternalUtilities\SemaphoreSlimExtensions.cs" />
<Compile Include="InternalUtilities\SemaphoreSlimFactory.cs" />
<Compile Include="CorLightup.cs" />
<Compile Include="Desktop\AssemblyPortabilityPolicy.cs" />
<Compile Include="Desktop\AssemblyVersion.cs" />
......
......@@ -4,6 +4,8 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Diagnostics.Telemetry;
using Roslyn.Utilities;
......@@ -16,7 +18,7 @@ internal partial class AnalysisState
{
private class PerAnalyzerState
{
private readonly object _gate = new object();
private readonly SemaphoreSlim _gate = new SemaphoreSlim(initialCount: 1);
private readonly Dictionary<CompilationEvent, AnalyzerStateData> _pendingEvents = new Dictionary<CompilationEvent, AnalyzerStateData>();
private readonly Dictionary<ISymbol, AnalyzerStateData> _pendingSymbols = new Dictionary<ISymbol, AnalyzerStateData>();
private readonly Dictionary<SyntaxNode, DeclarationAnalyzerStateData> _pendingDeclarations = new Dictionary<SyntaxNode, DeclarationAnalyzerStateData>();
......@@ -33,35 +35,36 @@ public PerAnalyzerState(ObjectPool<AnalyzerStateData> analyzerStateDataPool, Obj
public IEnumerable<CompilationEvent> PendingEvents_NoLock => _pendingEvents.Keys;
public bool HasPendingSyntaxAnalysis(SyntaxTree treeOpt)
public async Task<bool> HasPendingSyntaxAnalysisAsync(SyntaxTree treeOpt, CancellationToken cancellationToken)
{
lock (_gate)
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
{
return _lazyPendingSyntaxAnalysisTrees != null &&
(treeOpt != null ? _lazyPendingSyntaxAnalysisTrees.ContainsKey(treeOpt) : _lazyPendingSyntaxAnalysisTrees.Count > 0);
}
}
public bool HasPendingSymbolAnalysis(ISymbol symbol)
public async Task<bool> HasPendingSymbolAnalysisAsync(ISymbol symbol, CancellationToken cancellationToken)
{
lock (_gate)
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
{
return _pendingSymbols.ContainsKey(symbol);
}
}
private bool TryStartProcessingEntity<TAnalysisEntity, TAnalyzerStateData>(TAnalysisEntity analysisEntity, Dictionary<TAnalysisEntity, TAnalyzerStateData> pendingEntities, ObjectPool<TAnalyzerStateData> pool, out TAnalyzerStateData newState)
private async Task<TAnalyzerStateData> TryStartProcessingEntityAsync<TAnalysisEntity, TAnalyzerStateData>(TAnalysisEntity analysisEntity, Dictionary<TAnalysisEntity, TAnalyzerStateData> pendingEntities, ObjectPool<TAnalyzerStateData> pool, CancellationToken cancellationToken)
where TAnalyzerStateData : AnalyzerStateData, new()
{
lock (_gate)
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
{
return TryStartProcessingEntity_NoLock(analysisEntity, pendingEntities, pool, out newState);
return TryStartProcessingEntity_NoLock(analysisEntity, pendingEntities, pool);
}
}
private static bool TryStartProcessingEntity_NoLock<TAnalysisEntity, TAnalyzerStateData>(TAnalysisEntity analysisEntity, Dictionary<TAnalysisEntity, TAnalyzerStateData> pendingEntities, ObjectPool<TAnalyzerStateData> pool, out TAnalyzerStateData state)
private static TAnalyzerStateData TryStartProcessingEntity_NoLock<TAnalysisEntity, TAnalyzerStateData>(TAnalysisEntity analysisEntity, Dictionary<TAnalysisEntity, TAnalyzerStateData> pendingEntities, ObjectPool<TAnalyzerStateData> pool)
where TAnalyzerStateData : AnalyzerStateData
{
TAnalyzerStateData state;
if (pendingEntities.TryGetValue(analysisEntity, out state) &&
(state == null || state.StateKind == StateKind.ReadyToProcess))
{
......@@ -73,17 +76,16 @@ public bool HasPendingSymbolAnalysis(ISymbol symbol)
state.SetStateKind(StateKind.InProcess);
Debug.Assert(state.StateKind == StateKind.InProcess);
pendingEntities[analysisEntity] = state;
return true;
return state;
}
state = null;
return false;
return null;
}
private void MarkEntityProcessed<TAnalysisEntity, TAnalyzerStateData>(TAnalysisEntity analysisEntity, Dictionary<TAnalysisEntity, TAnalyzerStateData> pendingEntities, ObjectPool<TAnalyzerStateData> pool)
private async Task MarkEntityProcessedAsync<TAnalysisEntity, TAnalyzerStateData>(TAnalysisEntity analysisEntity, Dictionary<TAnalysisEntity, TAnalyzerStateData> pendingEntities, ObjectPool<TAnalyzerStateData> pool, CancellationToken cancellationToken)
where TAnalyzerStateData : AnalyzerStateData
{
lock (_gate)
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
{
MarkEntityProcessed_NoLock(analysisEntity, pendingEntities, pool);
}
......@@ -104,10 +106,10 @@ public bool HasPendingSymbolAnalysis(ISymbol symbol)
}
}
private bool IsEntityFullyProcessed<TAnalysisEntity, TAnalyzerStateData>(TAnalysisEntity analysisEntity, Dictionary<TAnalysisEntity, TAnalyzerStateData> pendingEntities)
private async Task<bool> IsEntityFullyProcessedAsync<TAnalysisEntity, TAnalyzerStateData>(TAnalysisEntity analysisEntity, Dictionary<TAnalysisEntity, TAnalyzerStateData> pendingEntities, CancellationToken cancellationToken)
where TAnalyzerStateData : AnalyzerStateData
{
lock (_gate)
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
{
return IsEntityFullyProcessed_NoLock(analysisEntity, pendingEntities);
}
......@@ -119,58 +121,58 @@ public bool HasPendingSymbolAnalysis(ISymbol symbol)
return !pendingEntities.ContainsKey(analysisEntity);
}
public bool TryStartProcessingEvent(CompilationEvent compilationEvent, out AnalyzerStateData state)
public Task<AnalyzerStateData> TryStartProcessingEventAsync(CompilationEvent compilationEvent, CancellationToken cancellationToken)
{
return TryStartProcessingEntity(compilationEvent, _pendingEvents, _analyzerStateDataPool, out state);
return TryStartProcessingEntityAsync(compilationEvent, _pendingEvents, _analyzerStateDataPool, cancellationToken);
}
public void MarkEventComplete(CompilationEvent compilationEvent)
public Task MarkEventCompleteAsync(CompilationEvent compilationEvent, CancellationToken cancellationToken)
{
MarkEntityProcessed(compilationEvent, _pendingEvents, _analyzerStateDataPool);
return MarkEntityProcessedAsync(compilationEvent, _pendingEvents, _analyzerStateDataPool, cancellationToken);
}
public bool TryStartAnalyzingSymbol(ISymbol symbol, out AnalyzerStateData state)
public Task<AnalyzerStateData> TryStartAnalyzingSymbolAsync(ISymbol symbol, CancellationToken cancellationToken)
{
return TryStartProcessingEntity(symbol, _pendingSymbols, _analyzerStateDataPool, out state);
return TryStartProcessingEntityAsync(symbol, _pendingSymbols, _analyzerStateDataPool, cancellationToken);
}
public void MarkSymbolComplete(ISymbol symbol)
public Task MarkSymbolCompleteAsync(ISymbol symbol, CancellationToken cancellationToken)
{
MarkEntityProcessed(symbol, _pendingSymbols, _analyzerStateDataPool);
return MarkEntityProcessedAsync(symbol, _pendingSymbols, _analyzerStateDataPool, cancellationToken);
}
public bool TryStartAnalyzingDeclaration(SyntaxReference decl, out DeclarationAnalyzerStateData state)
public Task<DeclarationAnalyzerStateData> TryStartAnalyzingDeclarationAsync(SyntaxReference decl, CancellationToken cancellationToken)
{
return TryStartProcessingEntity(decl.GetSyntax(), _pendingDeclarations, _declarationAnalyzerStateDataPool, out state);
return TryStartProcessingEntityAsync(decl.GetSyntax(), _pendingDeclarations, _declarationAnalyzerStateDataPool, cancellationToken);
}
public bool IsDeclarationComplete(SyntaxNode decl)
public Task<bool> IsDeclarationCompleteAsync(SyntaxNode decl, CancellationToken cancellationToken)
{
return IsEntityFullyProcessed(decl, _pendingDeclarations);
return IsEntityFullyProcessedAsync(decl, _pendingDeclarations, cancellationToken);
}
public void MarkDeclarationComplete(SyntaxReference decl)
public Task MarkDeclarationCompleteAsync(SyntaxReference decl, CancellationToken cancellationToken)
{
MarkEntityProcessed(decl.GetSyntax(), _pendingDeclarations, _declarationAnalyzerStateDataPool);
return MarkEntityProcessedAsync(decl.GetSyntax(), _pendingDeclarations, _declarationAnalyzerStateDataPool, cancellationToken);
}
public bool TryStartSyntaxAnalysis(SyntaxTree tree, out AnalyzerStateData state)
public Task<AnalyzerStateData> TryStartSyntaxAnalysisAsync(SyntaxTree tree, CancellationToken cancellationToken)
{
Debug.Assert(_lazyPendingSyntaxAnalysisTrees != null);
return TryStartProcessingEntity(tree, _lazyPendingSyntaxAnalysisTrees, _analyzerStateDataPool, out state);
return TryStartProcessingEntityAsync(tree, _lazyPendingSyntaxAnalysisTrees, _analyzerStateDataPool, cancellationToken);
}
public void MarkSyntaxAnalysisComplete(SyntaxTree tree)
public async Task MarkSyntaxAnalysisCompleteAsync(SyntaxTree tree, CancellationToken cancellationToken)
{
if (_lazyPendingSyntaxAnalysisTrees != null)
{
MarkEntityProcessed(tree, _lazyPendingSyntaxAnalysisTrees, _analyzerStateDataPool);
await MarkEntityProcessedAsync(tree, _lazyPendingSyntaxAnalysisTrees, _analyzerStateDataPool, cancellationToken).ConfigureAwait(false);
}
}
public void MarkDeclarationsComplete(ImmutableArray<SyntaxReference> declarations)
public async Task MarkDeclarationsCompleteAsync(ImmutableArray<SyntaxReference> declarations, CancellationToken cancellationToken)
{
lock (_gate)
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
{
foreach (var syntaxRef in declarations)
{
......@@ -179,9 +181,9 @@ public void MarkDeclarationsComplete(ImmutableArray<SyntaxReference> declaration
}
}
public void OnCompilationEventGenerated(CompilationEvent compilationEvent, AnalyzerActionCounts actionCounts)
public async Task OnCompilationEventGeneratedAsync(CompilationEvent compilationEvent, AnalyzerActionCounts actionCounts, CancellationToken cancellationToken)
{
lock (_gate)
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
{
var symbolEvent = compilationEvent as SymbolDeclaredCompilationEvent;
if (symbolEvent != null)
......@@ -235,14 +237,14 @@ public void OnCompilationEventGenerated(CompilationEvent compilationEvent, Analy
}
}
public bool IsEventAnalyzed(CompilationEvent compilationEvent)
public Task<bool> IsEventAnalyzedAsync(CompilationEvent compilationEvent, CancellationToken cancellationToken)
{
return IsEntityFullyProcessed(compilationEvent, _pendingEvents);
return IsEntityFullyProcessedAsync(compilationEvent, _pendingEvents, cancellationToken);
}
public void OnSymbolDeclaredEventProcessed(SymbolDeclaredCompilationEvent symbolDeclaredEvent)
public async Task OnSymbolDeclaredEventProcessedAsync(SymbolDeclaredCompilationEvent symbolDeclaredEvent, CancellationToken cancellationToken)
{
lock (_gate)
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
{
OnSymbolDeclaredEventProcessed_NoLock(symbolDeclaredEvent);
}
......
......@@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics
/// </summary>
internal partial class AnalysisState
{
private readonly object _gate;
private readonly SemaphoreSlim _gate;
/// <summary>
/// Per-analyzer analysis state map.
......@@ -60,7 +60,7 @@ internal partial class AnalysisState
public AnalysisState(ImmutableArray<DiagnosticAnalyzer> analyzers)
{
_gate = new object();
_gate = new SemaphoreSlim(initialCount: 1);
_analyzerStateMap = CreateAnalyzerStateMap(analyzers, out _analyzerStates);
_pendingSourceEvents = new Dictionary<SyntaxTree, HashSet<CompilationEvent>>();
_pendingNonSourceEvents = new HashSet<CompilationEvent>();
......@@ -100,13 +100,13 @@ public async Task OnCompilationEventsGeneratedAsync(ImmutableArray<CompilationEv
{
await EnsureAnalyzerActionCountsInitializedAsync(driver, cancellationToken).ConfigureAwait(false);
lock (_gate)
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
{
OnCompilationEventsGenerated_NoLock(compilationEvents, driver, cancellationToken);
await OnCompilationEventsGenerated_NoLockAsync(compilationEvents, driver, cancellationToken).ConfigureAwait(false);
}
}
private void OnCompilationEventsGenerated_NoLock(ImmutableArray<CompilationEvent> compilationEvents, AnalyzerDriver driver, CancellationToken cancellationToken)
private async Task OnCompilationEventsGenerated_NoLockAsync(ImmutableArray<CompilationEvent> compilationEvents, AnalyzerDriver driver, CancellationToken cancellationToken)
{
Debug.Assert(_lazyAnalyzerActionCountsMap != null);
......@@ -126,7 +126,7 @@ private void OnCompilationEventsGenerated_NoLock(ImmutableArray<CompilationEvent
if (HasActionsForEvent(compilationEvent, actionCounts))
{
_pooledEventsWithAnyActionsSet.Add(compilationEvent);
analyzerState.OnCompilationEventGenerated(compilationEvent, actionCounts);
await analyzerState.OnCompilationEventGeneratedAsync(compilationEvent, actionCounts, cancellationToken).ConfigureAwait(false);
}
}
}
......@@ -284,12 +284,12 @@ private static bool HasActionsForEvent(CompilationEvent compilationEvent, Analyz
}
}
private void OnSymbolDeclaredEventProcessed(SymbolDeclaredCompilationEvent symbolDeclaredEvent, ImmutableArray<DiagnosticAnalyzer> analyzers)
private async Task OnSymbolDeclaredEventProcessedAsync(SymbolDeclaredCompilationEvent symbolDeclaredEvent, ImmutableArray<DiagnosticAnalyzer> analyzers, CancellationToken cancellationToken)
{
foreach (var analyzer in analyzers)
{
var analyzerState = GetAnalyzerState(analyzer);
analyzerState.OnSymbolDeclaredEventProcessed(symbolDeclaredEvent);
await analyzerState.OnSymbolDeclaredEventProcessedAsync(symbolDeclaredEvent, cancellationToken).ConfigureAwait(false);
}
}
......@@ -297,26 +297,27 @@ private void OnSymbolDeclaredEventProcessed(SymbolDeclaredCompilationEvent symbo
/// 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)
public async Task OnCompilationEventProcessedAsync(CompilationEvent compilationEvent, AnalysisScope analysisScope, CancellationToken cancellationToken)
{
// Analyze if the symbol and all its declaring syntax references are analyzed.
var symbolDeclaredEvent = compilationEvent as SymbolDeclaredCompilationEvent;
if (symbolDeclaredEvent != null)
{
OnSymbolDeclaredEventProcessed(symbolDeclaredEvent, analysisScope.Analyzers);
await OnSymbolDeclaredEventProcessedAsync(symbolDeclaredEvent, analysisScope.Analyzers, cancellationToken).ConfigureAwait(false);
}
// Check if event is fully analyzed for all analyzers.
foreach (var analyzerState in _analyzerStates)
{
if (!analyzerState.IsEventAnalyzed(compilationEvent))
var eventAnalyzed = await analyzerState.IsEventAnalyzedAsync(compilationEvent, cancellationToken).ConfigureAwait(false);
if (!eventAnalyzed)
{
return;
}
}
// Remove the event from event map.
lock (_gate)
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
{
UpdateEventsMap_NoLock(compilationEvent, add: false);
}
......@@ -330,9 +331,9 @@ public void OnCompilationEventProcessed(CompilationEvent compilationEvent, Analy
/// <summary>
/// Gets pending events for given set of analyzers for the given syntax tree.
/// </summary>
public ImmutableArray<CompilationEvent> GetPendingEvents(ImmutableArray<DiagnosticAnalyzer> analyzers, SyntaxTree tree)
public async Task<ImmutableArray<CompilationEvent>> GetPendingEventsAsync(ImmutableArray<DiagnosticAnalyzer> analyzers, SyntaxTree tree, CancellationToken cancellationToken)
{
lock (_gate)
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
{
return GetPendingEvents_NoLock(analyzers, tree);
}
......@@ -389,9 +390,10 @@ private ImmutableArray<CompilationEvent> GetPendingEvents_NoLock(ImmutableArray<
/// <param name="analyzers"></param>
/// <param name="includeSourceEvents">Indicates if source events (symbol declared, compilation unit completed event) should be included.</param>
/// <param name="includeNonSourceEvents">Indicates if compilation wide events (compilation started and completed event) should be included.</param>
public ImmutableArray<CompilationEvent> GetPendingEvents(ImmutableArray<DiagnosticAnalyzer> analyzers, bool includeSourceEvents, bool includeNonSourceEvents)
/// <param name="cancellationToken">Cancellation token.</param>
public async Task<ImmutableArray<CompilationEvent>> GetPendingEventsAsync(ImmutableArray<DiagnosticAnalyzer> analyzers, bool includeSourceEvents, bool includeNonSourceEvents, CancellationToken cancellationToken)
{
lock (_gate)
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
{
return GetPendingEvents_NoLock(analyzers, includeSourceEvents, includeNonSourceEvents);
}
......@@ -451,7 +453,7 @@ private void Free(HashSet<CompilationEvent> events)
/// <summary>
/// Returns true if we have any pending syntax analysis for given analysis scope.
/// </summary>
public bool HasPendingSyntaxAnalysis(AnalysisScope analysisScope)
public async Task<bool> HasPendingSyntaxAnalysisAsync(AnalysisScope analysisScope, CancellationToken cancellationToken)
{
if (analysisScope.IsTreeAnalysis && !analysisScope.IsSyntaxOnlyTreeAnalysis)
{
......@@ -461,7 +463,7 @@ public bool HasPendingSyntaxAnalysis(AnalysisScope analysisScope)
foreach (var analyzer in analysisScope.Analyzers)
{
var analyzerState = GetAnalyzerState(analyzer);
if (analyzerState.HasPendingSyntaxAnalysis(analysisScope.FilterTreeOpt))
if (await analyzerState.HasPendingSyntaxAnalysisAsync(analysisScope.FilterTreeOpt, cancellationToken).ConfigureAwait(false))
{
return true;
}
......@@ -473,11 +475,11 @@ public bool HasPendingSyntaxAnalysis(AnalysisScope analysisScope)
/// <summary>
/// Returns true if we have any pending symbol analysis for given analysis scope.
/// </summary>
public bool HasPendingSymbolAnalysis(AnalysisScope analysisScope)
public async Task<bool> HasPendingSymbolAnalysisAsync(AnalysisScope analysisScope, CancellationToken cancellationToken)
{
Debug.Assert(analysisScope.FilterTreeOpt != null);
var symbolDeclaredEvents = GetPendingSymbolDeclaredEvents(analysisScope.FilterTreeOpt);
var symbolDeclaredEvents = await GetPendingSymbolDeclaredEventsAsync(analysisScope.FilterTreeOpt, cancellationToken).ConfigureAwait(false);
foreach (var symbolDeclaredEvent in symbolDeclaredEvents)
{
if (analysisScope.ShouldAnalyze(symbolDeclaredEvent.Symbol))
......@@ -485,7 +487,7 @@ public bool HasPendingSymbolAnalysis(AnalysisScope analysisScope)
foreach (var analyzer in analysisScope.Analyzers)
{
var analyzerState = GetAnalyzerState(analyzer);
if (analyzerState.HasPendingSymbolAnalysis(symbolDeclaredEvent.Symbol))
if (await analyzerState.HasPendingSymbolAnalysisAsync(symbolDeclaredEvent.Symbol, cancellationToken).ConfigureAwait(false))
{
return true;
}
......@@ -496,11 +498,11 @@ public bool HasPendingSymbolAnalysis(AnalysisScope analysisScope)
return false;
}
private ImmutableArray<SymbolDeclaredCompilationEvent> GetPendingSymbolDeclaredEvents(SyntaxTree tree)
private async Task<ImmutableArray<SymbolDeclaredCompilationEvent>> GetPendingSymbolDeclaredEventsAsync(SyntaxTree tree, CancellationToken cancellationToken)
{
Debug.Assert(tree != null);
lock (_gate)
using (await _gate.DisposableWaitAsync(cancellationToken).ConfigureAwait(false))
{
HashSet<CompilationEvent> compilationEvents;
if (!_pendingSourceEvents.TryGetValue(tree, out compilationEvents))
......@@ -516,62 +518,63 @@ private ImmutableArray<SymbolDeclaredCompilationEvent> GetPendingSymbolDeclaredE
/// 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 null if the event has already been processed for the analyzer OR is currently being processed by another task.
/// Otherwise, returns a non-null state representing partial analysis state for the given event for the given analyzer.
/// </returns>
public bool TryStartProcessingEvent(CompilationEvent compilationEvent, DiagnosticAnalyzer analyzer, out AnalyzerStateData state)
public Task<AnalyzerStateData> TryStartProcessingEventAsync(CompilationEvent compilationEvent, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
{
return GetAnalyzerState(analyzer).TryStartProcessingEvent(compilationEvent, out state);
return GetAnalyzerState(analyzer).TryStartProcessingEventAsync(compilationEvent, cancellationToken);
}
/// <summary>
/// Marks the given event as fully analyzed for the given analyzer.
/// </summary>
public void MarkEventComplete(CompilationEvent compilationEvent, DiagnosticAnalyzer analyzer)
public Task MarkEventCompleteAsync(CompilationEvent compilationEvent, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
{
GetAnalyzerState(analyzer).MarkEventComplete(compilationEvent);
return GetAnalyzerState(analyzer).MarkEventCompleteAsync(compilationEvent, cancellationToken);
}
/// <summary>
/// Attempts to start processing a symbol for the given analyzer's symbol actions.
/// </summary>
/// <returns>
/// Returns false if the symbol 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 symbol for the given analyzer.
/// Returns null if the symbol has already been processed for the analyzer OR is currently being processed by another task.
/// Otherwise, returns a non-null state representing partial analysis state for the given symbol for the given analyzer.
/// </returns>
public bool TryStartAnalyzingSymbol(ISymbol symbol, DiagnosticAnalyzer analyzer, out AnalyzerStateData state)
public Task<AnalyzerStateData> TryStartAnalyzingSymbolAsync(ISymbol symbol, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
{
return GetAnalyzerState(analyzer).TryStartAnalyzingSymbol(symbol, out state);
return GetAnalyzerState(analyzer).TryStartAnalyzingSymbolAsync(symbol, cancellationToken);
}
/// <summary>
/// Marks the given symbol as fully analyzed for the given analyzer.
/// </summary>
public void MarkSymbolComplete(ISymbol symbol, DiagnosticAnalyzer analyzer)
public Task MarkSymbolCompleteAsync(ISymbol symbol, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
{
GetAnalyzerState(analyzer).MarkSymbolComplete(symbol);
return GetAnalyzerState(analyzer).MarkSymbolCompleteAsync(symbol, cancellationToken);
}
/// <summary>
/// Attempts to start processing a symbol declaration for the given analyzer's syntax node and code block actions.
/// </summary>
/// <returns>
/// Returns false if the declaration 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 declaration for the given analyzer.
/// Returns null if the declaration has already been processed for the analyzer OR is currently being processed by another task.
/// Otherwise, returns a non-null state representing partial analysis state for the given declaration for the given analyzer.
/// </returns>
public bool TryStartAnalyzingDeclaration(SyntaxReference decl, DiagnosticAnalyzer analyzer, out DeclarationAnalyzerStateData state)
public Task<DeclarationAnalyzerStateData> TryStartAnalyzingDeclarationAsync(SyntaxReference decl, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
{
return GetAnalyzerState(analyzer).TryStartAnalyzingDeclaration(decl, out state);
return GetAnalyzerState(analyzer).TryStartAnalyzingDeclarationAsync(decl, cancellationToken);
}
/// <summary>
/// True if the given symbol declaration is fully analyzed.
/// Returns true if the given symbol declaration is fully analyzed.
/// </summary>
public bool IsDeclarationComplete(SyntaxNode decl)
public async Task<bool> IsDeclarationCompleteAsync(SyntaxNode decl, CancellationToken cancellationToken)
{
foreach (var analyzerState in _analyzerStates)
{
if (!analyzerState.IsDeclarationComplete(decl))
var declarationComplete = await analyzerState.IsDeclarationCompleteAsync(decl, cancellationToken).ConfigureAwait(false);
if (!declarationComplete)
{
return false;
}
......@@ -583,19 +586,19 @@ public bool IsDeclarationComplete(SyntaxNode decl)
/// <summary>
/// Marks the given symbol declaration as fully analyzed for the given analyzer.
/// </summary>
public void MarkDeclarationComplete(SyntaxReference decl, DiagnosticAnalyzer analyzer)
public Task MarkDeclarationCompleteAsync(SyntaxReference decl, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
{
GetAnalyzerState(analyzer).MarkDeclarationComplete(decl);
return GetAnalyzerState(analyzer).MarkDeclarationCompleteAsync(decl, cancellationToken);
}
/// <summary>
/// Marks all the symbol declarations for the given symbol as fully analyzed for all the given analyzers.
/// </summary>
public void MarkDeclarationsComplete(ImmutableArray<SyntaxReference> declarations, IEnumerable<DiagnosticAnalyzer> analyzers)
public async Task MarkDeclarationsCompleteAsync(ImmutableArray<SyntaxReference> declarations, IEnumerable<DiagnosticAnalyzer> analyzers, CancellationToken cancellationToken)
{
foreach (var analyzer in analyzers)
{
GetAnalyzerState(analyzer).MarkDeclarationsComplete(declarations);
await GetAnalyzerState(analyzer).MarkDeclarationsCompleteAsync(declarations, cancellationToken).ConfigureAwait(false);
}
}
......@@ -603,20 +606,20 @@ public void MarkDeclarationsComplete(ImmutableArray<SyntaxReference> declaration
/// Attempts to start processing a syntax tree for the given analyzer's syntax tree actions.
/// </summary>
/// <returns>
/// Returns false if the tree 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 syntax analysis state for the given tree for the given analyzer.
/// Returns null if the tree has already been processed for the analyzer OR is currently being processed by another task.
/// Otherwise, returns a non-null state representing partial syntax analysis state for the given tree for the given analyzer.
/// </returns>
public bool TryStartSyntaxAnalysis(SyntaxTree tree, DiagnosticAnalyzer analyzer, out AnalyzerStateData state)
public Task<AnalyzerStateData> TryStartSyntaxAnalysisAsync(SyntaxTree tree, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
{
return GetAnalyzerState(analyzer).TryStartSyntaxAnalysis(tree, out state);
return GetAnalyzerState(analyzer).TryStartSyntaxAnalysisAsync(tree, cancellationToken);
}
/// <summary>
/// Marks the given tree as fully syntactically analyzed for the given analyzer.
/// </summary>
public void MarkSyntaxAnalysisComplete(SyntaxTree tree, DiagnosticAnalyzer analyzer)
public Task MarkSyntaxAnalysisCompleteAsync(SyntaxTree tree, DiagnosticAnalyzer analyzer, CancellationToken cancellationToken)
{
GetAnalyzerState(analyzer).MarkSyntaxAnalysisComplete(tree);
return GetAnalyzerState(analyzer).MarkSyntaxAnalysisCompleteAsync(tree, cancellationToken);
}
}
}
......@@ -8,7 +8,6 @@
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.Semantics;
using Microsoft.CodeAnalysis.Diagnostics.Telemetry;
using Roslyn.Utilities;
......@@ -160,7 +159,7 @@ private void Initialize(AnalyzerExecutor analyzerExecutor, DiagnosticQueue diagn
}
// Assume all analyzers are non-thread safe.
var singleThreadedAnalyzerToGateMap = ImmutableDictionary.CreateRange(analyzers.Select(a => KeyValuePair.Create(a, new object())));
var singleThreadedAnalyzerToGateMap = ImmutableDictionary.CreateRange(analyzers.Select(a => KeyValuePair.Create(a, new SemaphoreSlim(initialCount: 1))));
if (analysisOptions.LogAnalyzerExecutionTime)
{
......@@ -169,7 +168,7 @@ private void Initialize(AnalyzerExecutor analyzerExecutor, DiagnosticQueue diagn
var unused = compilation.GetTypeByMetadataName("System.Object");
}
Func<DiagnosticAnalyzer, object> getAnalyzerGate = analyzer => singleThreadedAnalyzerToGateMap[analyzer];
Func<DiagnosticAnalyzer, SemaphoreSlim> getAnalyzerGate = analyzer => singleThreadedAnalyzerToGateMap[analyzer];
var analyzerExecutor = AnalyzerExecutor.Create(compilation, analysisOptions.Options ?? AnalyzerOptions.Empty, addDiagnostic, newOnAnalyzerException, IsCompilerAnalyzer,
analyzerManager, getAnalyzerGate, analysisOptions.LogAnalyzerExecutionTime, addLocalDiagnosticOpt, addNonLocalDiagnosticOpt, cancellationToken);
......@@ -287,7 +286,7 @@ private static void OnDriverException(Task faultedTask, AnalyzerExecutor analyze
analyzerExecutor.OnAnalyzerException(innerException, analyzer, diagnostic);
}
private void ExecuteSyntaxTreeActions(AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
private async Task ExecuteSyntaxTreeActionsAsync(AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
{
if (analysisScope.IsTreeAnalysis && !analysisScope.IsSyntaxOnlyTreeAnalysis)
{
......@@ -305,11 +304,11 @@ private void ExecuteSyntaxTreeActions(AnalysisScope analysisScope, AnalysisState
if (_syntaxTreeActionsMap.TryGetValue(analyzer, out syntaxTreeActions))
{
// Execute actions for a given analyzer sequentially.
analyzerExecutor.ExecuteSyntaxTreeActions(syntaxTreeActions, analyzer, tree, analysisScope, analysisStateOpt);
await analyzerExecutor.ExecuteSyntaxTreeActionsAsync(syntaxTreeActions, analyzer, tree, analysisScope, analysisStateOpt).ConfigureAwait(false);
}
else
else if (analysisStateOpt != null)
{
analysisStateOpt?.MarkSyntaxAnalysisComplete(tree, analyzer);
await analysisStateOpt.MarkSyntaxAnalysisCompleteAsync(tree, analyzer, cancellationToken).ConfigureAwait(false);
}
}
}
......@@ -397,7 +396,7 @@ public async Task<ImmutableArray<Diagnostic>> GetDiagnosticsAsync(Compilation co
if (reportSuppressedDiagnostics || !d.IsSuppressed)
{
allDiagnostics.Add(d);
}
}
}
return allDiagnostics.ToReadOnlyAndFree();
......@@ -537,7 +536,7 @@ private async Task ProcessCompilationEventsAsync(AnalysisScope analysisScope, An
cancellationToken.ThrowIfCancellationRequested();
// Kick off tasks to execute syntax tree actions.
var syntaxTreeActionsTask = Task.Run(() => ExecuteSyntaxTreeActions(analysisScope, analysisStateOpt, cancellationToken));
var syntaxTreeActionsTask = ExecuteSyntaxTreeActionsAsync(analysisScope, analysisStateOpt, cancellationToken);
// Wait for all worker threads to complete processing events.
await Task.WhenAll(workerTasks.Concat(syntaxTreeActionsTask)).ConfigureAwait(false);
......@@ -555,13 +554,13 @@ private async Task ProcessCompilationEventsAsync(AnalysisScope analysisScope, An
{
completedEvent = await ProcessCompilationEventsCoreAsync(analysisScope, analysisStateOpt, prePopulatedEventQueue, cancellationToken).ConfigureAwait(false);
ExecuteSyntaxTreeActions(analysisScope, analysisStateOpt, cancellationToken);
await ExecuteSyntaxTreeActionsAsync(analysisScope, analysisStateOpt, cancellationToken).ConfigureAwait(false);
}
// Finally process the compilation completed event, if any.
if (completedEvent != null)
{
ProcessEvent(completedEvent, analysisScope, analysisStateOpt, cancellationToken);
await ProcessEventAsync(completedEvent, analysisScope, analysisStateOpt, cancellationToken).ConfigureAwait(false);
}
}
catch (Exception e) when (FatalError.ReportUnlessCanceled(e))
......@@ -618,7 +617,7 @@ private async Task<CompilationCompletedEvent> ProcessCompilationEventsCoreAsync(
continue;
}
ProcessEvent(e, analysisScope, analysisStateOpt, cancellationToken);
await ProcessEventAsync(e, analysisScope, analysisStateOpt, cancellationToken).ConfigureAwait(false);
}
return completedEvent;
......@@ -629,48 +628,52 @@ private async Task<CompilationCompletedEvent> ProcessCompilationEventsCoreAsync(
}
}
private void ProcessEvent(CompilationEvent e, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
private async Task ProcessEventAsync(CompilationEvent e, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
{
ProcessEventCore(e, analysisScope, analysisStateOpt, cancellationToken);
analysisStateOpt?.OnCompilationEventProcessed(e, analysisScope);
await ProcessEventCoreAsync(e, analysisScope, analysisStateOpt, cancellationToken).ConfigureAwait(false);
if (analysisStateOpt != null)
{
await analysisStateOpt.OnCompilationEventProcessedAsync(e, analysisScope, cancellationToken).ConfigureAwait(false);
}
}
private void ProcessEventCore(CompilationEvent e, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
private async Task ProcessEventCoreAsync(CompilationEvent e, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var symbolEvent = e as SymbolDeclaredCompilationEvent;
if (symbolEvent != null)
{
ProcessSymbolDeclared(symbolEvent, analysisScope, analysisStateOpt, cancellationToken);
await ProcessSymbolDeclaredAsync(symbolEvent, analysisScope, analysisStateOpt, cancellationToken).ConfigureAwait(false);
return;
}
var completedEvent = e as CompilationUnitCompletedEvent;
if (completedEvent != null)
{
ProcessCompilationUnitCompleted(completedEvent, analysisScope, analysisStateOpt, cancellationToken);
await ProcessCompilationUnitCompletedAsync(completedEvent, analysisScope, analysisStateOpt, cancellationToken).ConfigureAwait(false);
return;
}
var endEvent = e as CompilationCompletedEvent;
if (endEvent != null)
{
ProcessCompilationCompleted(endEvent, analysisScope, analysisStateOpt, cancellationToken);
await ProcessCompilationCompletedAsync(endEvent, analysisScope, analysisStateOpt, cancellationToken).ConfigureAwait(false);
return;
}
var startedEvent = e as CompilationStartedEvent;
if (startedEvent != null)
{
ProcessCompilationStarted(startedEvent, analysisScope, analysisStateOpt, cancellationToken);
await ProcessCompilationStartedAsync(startedEvent, analysisScope, analysisStateOpt, cancellationToken).ConfigureAwait(false);
return;
}
throw new InvalidOperationException("Unexpected compilation event of type " + e.GetType().Name);
}
private void ProcessSymbolDeclared(SymbolDeclaredCompilationEvent symbolEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
private async Task ProcessSymbolDeclaredAsync(SymbolDeclaredCompilationEvent symbolEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
{
try
{
......@@ -679,12 +682,12 @@ private void ProcessSymbolDeclared(SymbolDeclaredCompilationEvent symbolEvent, A
var references = symbolEvent.DeclaringSyntaxReferences;
if (!AnalysisScope.ShouldSkipSymbolAnalysis(symbolEvent))
{
ExecuteSymbolActions(symbolEvent, analysisScope, analysisStateOpt, cancellationToken);
await ExecuteSymbolActionsAsync(symbolEvent, analysisScope, analysisStateOpt, cancellationToken).ConfigureAwait(false);
}
if (!AnalysisScope.ShouldSkipDeclarationAnalysis(symbol))
{
ExecuteDeclaringReferenceActions(symbolEvent, analysisScope, analysisStateOpt, cancellationToken);
await ExecuteDeclaringReferenceActionsAsync(symbolEvent, analysisScope, analysisStateOpt, cancellationToken).ConfigureAwait(false);
}
}
finally
......@@ -693,7 +696,7 @@ private void ProcessSymbolDeclared(SymbolDeclaredCompilationEvent symbolEvent, A
}
}
private void ExecuteSymbolActions(SymbolDeclaredCompilationEvent symbolEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
private async Task ExecuteSymbolActionsAsync(SymbolDeclaredCompilationEvent symbolEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
{
var symbol = symbolEvent.Symbol;
if (!analysisScope.ShouldAnalyze(symbol))
......@@ -707,11 +710,11 @@ private void ExecuteSymbolActions(SymbolDeclaredCompilationEvent symbolEvent, An
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);
await analyzerExecutor.ExecuteSymbolActionsAsync(actionsByKind[(int)symbol.Kind], analyzer, symbol, GetTopmostNodeForAnalysis, analysisScope, analysisStateOpt).ConfigureAwait(false);
}
else
else if (analysisStateOpt != null)
{
analysisStateOpt?.MarkSymbolComplete(symbol, analyzer);
await analysisStateOpt.MarkSymbolCompleteAsync(symbol, analyzer, cancellationToken).ConfigureAwait(false);
}
}
}
......@@ -722,9 +725,9 @@ private static SyntaxNode GetTopmostNodeForAnalysis(ISymbol symbol, SyntaxRefere
return model.GetTopmostNodeForDiagnosticAnalysis(symbol, syntaxReference.GetSyntax());
}
protected abstract void ExecuteDeclaringReferenceActions(SymbolDeclaredCompilationEvent symbolEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken);
protected abstract Task ExecuteDeclaringReferenceActionsAsync(SymbolDeclaredCompilationEvent symbolEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken);
private void ProcessCompilationUnitCompleted(CompilationUnitCompletedEvent completedEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
private async Task ProcessCompilationUnitCompletedAsync(CompilationUnitCompletedEvent completedEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
{
// When the compiler is finished with a compilation unit, we can run user diagnostics which
// might want to ask the compiler for all the diagnostics in the source file, for example
......@@ -747,11 +750,11 @@ private void ProcessCompilationUnitCompleted(CompilationUnitCompletedEvent compl
if (_semanticModelActionsMap.TryGetValue(analyzer, out semanticModelActions))
{
// Execute actions for a given analyzer sequentially.
analyzerExecutor.ExecuteSemanticModelActions(semanticModelActions, analyzer, semanticModel, completedEvent, analysisScope, analysisStateOpt);
await analyzerExecutor.ExecuteSemanticModelActionsAsync(semanticModelActions, analyzer, semanticModel, completedEvent, analysisScope, analysisStateOpt).ConfigureAwait(false);
}
else
else if (analysisStateOpt != null)
{
analysisStateOpt?.MarkEventComplete(completedEvent, analyzer);
await analysisStateOpt.MarkEventCompleteAsync(completedEvent, analyzer, cancellationToken).ConfigureAwait(false);
}
}
}
......@@ -761,17 +764,17 @@ private void ProcessCompilationUnitCompleted(CompilationUnitCompletedEvent compl
}
}
private void ProcessCompilationStarted(CompilationStartedEvent startedEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
private Task ProcessCompilationStartedAsync(CompilationStartedEvent startedEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
{
ExecuteCompilationActions(_compilationActionsMap, startedEvent, analysisScope, analysisStateOpt, cancellationToken);
return ExecuteCompilationActionsAsync(_compilationActionsMap, startedEvent, analysisScope, analysisStateOpt, cancellationToken);
}
private void ProcessCompilationCompleted(CompilationCompletedEvent endEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
private Task ProcessCompilationCompletedAsync(CompilationCompletedEvent endEvent, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
{
ExecuteCompilationActions(_compilationEndActionsMap, endEvent, analysisScope, analysisStateOpt, cancellationToken);
return ExecuteCompilationActionsAsync(_compilationEndActionsMap, endEvent, analysisScope, analysisStateOpt, cancellationToken);
}
private void ExecuteCompilationActions(
private async Task ExecuteCompilationActionsAsync(
ImmutableDictionary<DiagnosticAnalyzer, ImmutableArray<CompilationAnalyzerAction>> compilationActionsMap,
CompilationEvent compilationEvent,
AnalysisScope analysisScope,
......@@ -787,11 +790,11 @@ private void ProcessCompilationCompleted(CompilationCompletedEvent endEvent, Ana
ImmutableArray<CompilationAnalyzerAction> compilationActions;
if (compilationActionsMap.TryGetValue(analyzer, out compilationActions))
{
analyzerExecutor.ExecuteCompilationActions(compilationActions, analyzer, compilationEvent, analysisScope, analysisStateOpt);
await analyzerExecutor.ExecuteCompilationActionsAsync(compilationActions, analyzer, compilationEvent, analysisScope, analysisStateOpt).ConfigureAwait(false);
}
else
else if (analysisStateOpt != null)
{
analysisStateOpt?.MarkEventComplete(compilationEvent, analyzer);
await analysisStateOpt.MarkEventCompleteAsync(compilationEvent, analyzer, cancellationToken).ConfigureAwait(false);
}
}
}
......@@ -988,14 +991,14 @@ internal AnalyzerDriver(ImmutableArray<DiagnosticAnalyzer> analyzers, Func<Synta
if (analyzerAndActions.Any())
{
actionsByKind = AnalyzerExecutor.GetOperationActionsByKind(analyzerAndActions);
}
}
else
{
actionsByKind = ImmutableDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>>.Empty;
}
builder.Add(analyzerAndActions.Key, actionsByKind);
}
}
analyzerActionsByKind = builder.ToImmutable();
}
......@@ -1116,7 +1119,7 @@ private bool ShouldExecuteOperationBlockActions(AnalysisScope analysisScope, ISy
return ShouldExecuteBlockActions(this.OperationBlockStartActionsByAnalyzer, this.OperationBlockActionsByAnalyzer, analysisScope, symbol);
}
protected override void ExecuteDeclaringReferenceActions(
protected override async Task ExecuteDeclaringReferenceActionsAsync(
SymbolDeclaredCompilationEvent symbolEvent,
AnalysisScope analysisScope,
AnalysisState analysisStateOpt,
......@@ -1136,18 +1139,18 @@ private bool ShouldExecuteOperationBlockActions(AnalysisScope analysisScope, ISy
if (analysisScope.FilterTreeOpt == null || analysisScope.FilterTreeOpt == decl.SyntaxTree)
{
ExecuteDeclaringReferenceActions(decl, symbolEvent, analysisScope, analysisStateOpt, executeSyntaxNodeActions, executeOperationActions, executeCodeBlockActions, executeOperationBlockActions, cancellationToken);
await ExecuteDeclaringReferenceActionsAsync(decl, symbolEvent, analysisScope, analysisStateOpt, executeSyntaxNodeActions, executeOperationActions, executeCodeBlockActions, executeOperationBlockActions, cancellationToken).ConfigureAwait(false);
}
}
}
else if (analysisStateOpt != null)
{
cancellationToken.ThrowIfCancellationRequested();
analysisStateOpt.MarkDeclarationsComplete(symbolEvent.DeclaringSyntaxReferences, analysisScope.Analyzers);
await analysisStateOpt.MarkDeclarationsCompleteAsync(symbolEvent.DeclaringSyntaxReferences, analysisScope.Analyzers, cancellationToken).ConfigureAwait(false);
foreach (var decl in symbolEvent.DeclaringSyntaxReferences)
{
ClearCachedAnalysisDataIfAnalyzed(decl, decl.GetSyntax(), symbolEvent.Compilation, analysisStateOpt);
await ClearCachedAnalysisDataIfAnalyzedAsync(decl, decl.GetSyntax(), symbolEvent.Compilation, analysisStateOpt, cancellationToken).ConfigureAwait(false);
}
}
}
......@@ -1187,13 +1190,13 @@ private bool ShouldExecuteOperationBlockActions(AnalysisScope analysisScope, ISy
return data;
}
private void ClearCachedAnalysisDataIfAnalyzed(SyntaxReference declaration, SyntaxNode node, Compilation compilation, AnalysisState analysisState)
private async Task ClearCachedAnalysisDataIfAnalyzedAsync(SyntaxReference declaration, SyntaxNode node, Compilation compilation, AnalysisState analysisState, CancellationToken cancellationToken)
{
Debug.Assert(analysisState != null);
CompilationData compilationData;
if (!s_compilationDataCache.TryGetValue(compilation, out compilationData) ||
!analysisState.IsDeclarationComplete(node))
!(await analysisState.IsDeclarationCompleteAsync(node, cancellationToken).ConfigureAwait(false)))
{
return;
}
......@@ -1251,7 +1254,7 @@ private static void ComputeDeclarationsInNode(SemanticModel semanticModel, ISymb
semanticModel.ComputeDeclarationsInNode(topmostNodeForAnalysis, getSymbol, builder, cancellationToken, levelsToCompute);
}
private void ExecuteDeclaringReferenceActions(
private async Task ExecuteDeclaringReferenceActionsAsync(
SyntaxReference decl,
SymbolDeclaredCompilationEvent symbolEvent,
AnalysisScope analysisScope,
......@@ -1292,8 +1295,8 @@ private static void ComputeDeclarationsInNode(SemanticModel semanticModel, ISymb
ImmutableDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> nodeActionsByKind;
if (this.NodeActionsByAnalyzerAndKind.TryGetValue(analyzer, out nodeActionsByKind))
{
analyzerExecutor.ExecuteSyntaxNodeActions(nodesToAnalyze, nodeActionsByKind,
analyzer, semanticModel, _getKind, declarationAnalysisData.TopmostNodeForAnalysis.FullSpan, decl, analysisScope, analysisStateOpt);
await analyzerExecutor.ExecuteSyntaxNodeActionsAsync(nodesToAnalyze, nodeActionsByKind,
analyzer, semanticModel, _getKind, declarationAnalysisData.TopmostNodeForAnalysis.FullSpan, decl, analysisScope, analysisStateOpt).ConfigureAwait(false);
}
}
}
......@@ -1331,8 +1334,8 @@ private static void ComputeDeclarationsInNode(SemanticModel semanticModel, ISymb
ImmutableDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> operationActionsByKind;
if (this.OperationActionsByAnalyzerAndKind.TryGetValue(analyzer, out operationActionsByKind))
{
analyzerExecutor.ExecuteOperationActions(operationsToAnalyze, operationActionsByKind,
analyzer, semanticModel, declarationAnalysisData.TopmostNodeForAnalysis.FullSpan, decl, analysisScope, analysisStateOpt);
await analyzerExecutor.ExecuteOperationActionsAsync(operationsToAnalyze, operationActionsByKind,
analyzer, semanticModel, declarationAnalysisData.TopmostNodeForAnalysis.FullSpan, decl, analysisScope, analysisStateOpt).ConfigureAwait(false);
}
}
}
......@@ -1341,28 +1344,28 @@ private static void ComputeDeclarationsInNode(SemanticModel semanticModel, ISymb
{
foreach (var analyzerActions in codeBlockActions)
{
analyzerExecutor.ExecuteOperationBlockActions(
await analyzerExecutor.ExecuteOperationBlockActionsAsync(
analyzerActions.OperationBlockStartActions, analyzerActions.OperationBlockActions,
analyzerActions.OpererationBlockEndActions, analyzerActions.Analyzer, declarationAnalysisData.TopmostNodeForAnalysis, symbol,
operationBlocksToAnalyze, operationsToAnalyze, semanticModel, decl, analysisScope, analysisStateOpt);
operationBlocksToAnalyze, operationsToAnalyze, semanticModel, decl, analysisScope, analysisStateOpt).ConfigureAwait(false);
}
}
}
}
break;
break;
}
}
}
}
if (executableCodeBlocks.Any() && shouldExecuteCodeBlockActions)
{
foreach (var analyzerActions in codeBlockActions)
{
analyzerExecutor.ExecuteCodeBlockActions(
await analyzerExecutor.ExecuteCodeBlockActionsAsync(
analyzerActions.CodeBlockStartActions, analyzerActions.CodeBlockActions,
analyzerActions.CodeBlockEndActions, analyzerActions.Analyzer, declarationAnalysisData.TopmostNodeForAnalysis, symbol,
executableCodeBlocks, semanticModel, _getKind, decl, analysisScope, analysisStateOpt);
executableCodeBlocks, semanticModel, _getKind, decl, analysisScope, analysisStateOpt).ConfigureAwait(false);
}
}
}
......@@ -1372,12 +1375,12 @@ private static void ComputeDeclarationsInNode(SemanticModel semanticModel, ISymb
{
foreach (var analyzer in analysisScope.Analyzers)
{
analysisStateOpt.MarkDeclarationComplete(decl, analyzer);
await analysisStateOpt.MarkDeclarationCompleteAsync(decl, analyzer, cancellationToken).ConfigureAwait(false);
}
if (cacheAnalysisData)
{
ClearCachedAnalysisDataIfAnalyzed(decl, declarationAnalysisData.DeclaringReferenceSyntax, symbolEvent.Compilation, analysisStateOpt);
await ClearCachedAnalysisDataIfAnalyzedAsync(decl, declarationAnalysisData.DeclaringReferenceSyntax, symbolEvent.Compilation, analysisStateOpt, cancellationToken).ConfigureAwait(false);
}
}
}
......
......@@ -15,9 +15,8 @@
using AnalyzerStateData = Microsoft.CodeAnalysis.Diagnostics.AnalysisState.AnalyzerStateData;
using SyntaxNodeAnalyzerStateData = Microsoft.CodeAnalysis.Diagnostics.AnalysisState.SyntaxNodeAnalyzerStateData;
using OperationAnalyzerStateData = Microsoft.CodeAnalysis.Diagnostics.AnalysisState.OperationAnalyzerStateData;
using CodeBlockAnalyzerStateData = Microsoft.CodeAnalysis.Diagnostics.AnalysisState.CodeBlockAnalyzerStateData;
using DeclarationAnalyzerStateData = Microsoft.CodeAnalysis.Diagnostics.AnalysisState.DeclarationAnalyzerStateData;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.Diagnostics
{
......@@ -40,7 +39,7 @@ internal class AnalyzerExecutor
private readonly Action<Exception, DiagnosticAnalyzer, Diagnostic> _onAnalyzerException;
private readonly AnalyzerManager _analyzerManager;
private readonly Func<DiagnosticAnalyzer, bool> _isCompilerAnalyzer;
private readonly Func<DiagnosticAnalyzer, object> _getAnalyzerGateOpt;
private readonly Func<DiagnosticAnalyzer, SemaphoreSlim> _getAnalyzerGateOpt;
private readonly ConcurrentDictionary<DiagnosticAnalyzer, TimeSpan> _analyzerExecutionTimeMapOpt;
private readonly CancellationToken _cancellationToken;
......@@ -74,7 +73,7 @@ internal class AnalyzerExecutor
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
Func<DiagnosticAnalyzer, bool> isCompilerAnalyzer,
AnalyzerManager analyzerManager,
Func<DiagnosticAnalyzer, object> getAnalyzerGate,
Func<DiagnosticAnalyzer, SemaphoreSlim> getAnalyzerGate,
bool logExecutionTime = false,
Action<Diagnostic, DiagnosticAnalyzer, bool> addLocalDiagnosticOpt = null,
Action<Diagnostic, DiagnosticAnalyzer> addNonLocalDiagnosticOpt = null,
......@@ -123,7 +122,7 @@ internal class AnalyzerExecutor
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
Func<DiagnosticAnalyzer, bool> isCompilerAnalyzer,
AnalyzerManager analyzerManager,
Func<DiagnosticAnalyzer, object> getAnalyzerGateOpt,
Func<DiagnosticAnalyzer, SemaphoreSlim> getAnalyzerGateOpt,
ConcurrentDictionary<DiagnosticAnalyzer, TimeSpan> analyzerExecutionTimeMapOpt,
Action<Diagnostic, DiagnosticAnalyzer, bool> addLocalDiagnosticOpt,
Action<Diagnostic, DiagnosticAnalyzer> addNonLocalDiagnosticOpt,
......@@ -166,13 +165,13 @@ public AnalyzerExecutor WithCancellationToken(CancellationToken cancellationToke
/// <param name="sessionScope">Session scope to store register session wide analyzer actions.</param>
/// <remarks>
/// Note that this API doesn't execute any <see cref="CompilationStartAnalyzerAction"/> registered by the Initialize invocation.
/// Use <see cref="ExecuteCompilationStartActions(ImmutableArray{CompilationStartAnalyzerAction}, HostCompilationStartAnalysisScope)"/> API
/// Use <see cref="ExecuteCompilationStartActionsAsync(ImmutableArray{CompilationStartAnalyzerAction}, HostCompilationStartAnalysisScope)"/> API
/// to get execute these actions to get the per-compilation analyzer actions.
/// </remarks>
public void ExecuteInitializeMethod(DiagnosticAnalyzer analyzer, HostSessionStartAnalysisScope sessionScope)
public async Task ExecuteInitializeMethodAsync(DiagnosticAnalyzer analyzer, HostSessionStartAnalysisScope sessionScope)
{
// The Initialize method should be run asynchronously in case it is not well behaved, e.g. does not terminate.
ExecuteAndCatchIfThrows(analyzer, () => analyzer.Initialize(new AnalyzerAnalysisContext(analyzer, sessionScope)));
await ExecuteAndCatchIfThrowsAsync(analyzer, () => analyzer.Initialize(new AnalyzerAnalysisContext(analyzer, sessionScope))).ConfigureAwait(false);
}
/// <summary>
......@@ -180,13 +179,13 @@ public void ExecuteInitializeMethod(DiagnosticAnalyzer analyzer, HostSessionStar
/// </summary>
/// <param name="actions"><see cref="AnalyzerActions"/> whose compilation start actions are to be executed.</param>
/// <param name="compilationScope">Compilation scope to store the analyzer actions.</param>
public void ExecuteCompilationStartActions(ImmutableArray<CompilationStartAnalyzerAction> actions, HostCompilationStartAnalysisScope compilationScope)
public async Task ExecuteCompilationStartActionsAsync(ImmutableArray<CompilationStartAnalyzerAction> actions, HostCompilationStartAnalysisScope compilationScope)
{
foreach (var startAction in actions)
{
_cancellationToken.ThrowIfCancellationRequested();
ExecuteAndCatchIfThrows(startAction.Analyzer,
() => startAction.Action(new AnalyzerCompilationStartAnalysisContext(startAction.Analyzer, compilationScope, _compilation, _analyzerOptions, _cancellationToken)));
await ExecuteAndCatchIfThrowsAsync(startAction.Analyzer,
() => startAction.Action(new AnalyzerCompilationStartAnalysisContext(startAction.Analyzer, compilationScope, _compilation, _analyzerOptions, _cancellationToken))).ConfigureAwait(false);
}
}
......@@ -198,7 +197,7 @@ public void ExecuteCompilationStartActions(ImmutableArray<CompilationStartAnalyz
/// <param name="compilationEvent">Compilation event.</param>
/// <param name="analysisScope">Scope for analyzer execution.</param>
/// <param name="analysisStateOpt">An optional object to track analysis state.</param>
public void ExecuteCompilationActions(
public async Task ExecuteCompilationActionsAsync(
ImmutableArray<CompilationAnalyzerAction> compilationActions,
DiagnosticAnalyzer analyzer,
CompilationEvent compilationEvent,
......@@ -211,10 +210,15 @@ public void ExecuteCompilationStartActions(ImmutableArray<CompilationStartAnalyz
try
{
if (TryStartProcessingEvent(compilationEvent, analyzer, analysisScope, analysisStateOpt, out analyzerStateOpt))
analyzerStateOpt = await TryStartProcessingEventAsync(compilationEvent, analyzer, analysisScope, analysisStateOpt, _cancellationToken).ConfigureAwait(false);
if (analysisStateOpt == null || analyzerStateOpt != null)
{
ExecuteCompilationActionsCore(compilationActions, analyzer, analyzerStateOpt);
analysisStateOpt?.MarkEventComplete(compilationEvent, analyzer);
await ExecuteCompilationActionsCoreAsync(compilationActions, analyzer, analyzerStateOpt).ConfigureAwait(false);
if (analysisStateOpt != null)
{
await analysisStateOpt.MarkEventCompleteAsync(compilationEvent, analyzer, _cancellationToken).ConfigureAwait(false);
}
}
}
finally
......@@ -223,7 +227,7 @@ public void ExecuteCompilationStartActions(ImmutableArray<CompilationStartAnalyz
}
}
private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAction> compilationActions, DiagnosticAnalyzer analyzer, AnalyzerStateData analyzerStateOpt)
private async Task ExecuteCompilationActionsCoreAsync(ImmutableArray<CompilationAnalyzerAction> compilationActions, DiagnosticAnalyzer analyzer, AnalyzerStateData analyzerStateOpt)
{
var addDiagnostic = GetAddCompilationDiagnostic(analyzer);
......@@ -233,9 +237,9 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
if (ShouldExecuteAction(analyzerStateOpt, endAction))
{
ExecuteAndCatchIfThrows(endAction.Analyzer,
await ExecuteAndCatchIfThrowsAsync(endAction.Analyzer,
() => endAction.Action(new CompilationAnalysisContext(_compilation, _analyzerOptions, addDiagnostic,
d => IsSupportedDiagnostic(endAction.Analyzer, d), _cancellationToken)));
d => IsSupportedDiagnostic(endAction.Analyzer, d), _cancellationToken))).ConfigureAwait(false);
analyzerStateOpt?.ProcessedActions.Add(endAction);
}
......@@ -251,7 +255,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
/// <param name="getTopMostNodeForAnalysis">Delegate to get topmost declaration node for a symbol declaration reference.</param>
/// <param name="analysisScope">Scope for analyzer execution.</param>
/// <param name="analysisStateOpt">An optional object to track analysis state.</param>
public void ExecuteSymbolActions(
public async Task ExecuteSymbolActionsAsync(
ImmutableArray<SymbolAnalyzerAction> symbolActions,
DiagnosticAnalyzer analyzer,
ISymbol symbol,
......@@ -263,10 +267,15 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
try
{
if (TryStartAnalyzingSymbol(symbol, analyzer, analysisScope, analysisStateOpt, out analyzerStateOpt))
analyzerStateOpt = await TryStartAnalyzingSymbolAsync(symbol, analyzer, analysisScope, analysisStateOpt, _cancellationToken).ConfigureAwait(false);
if (analysisStateOpt == null || analyzerStateOpt != null)
{
ExecuteSymbolActionsCore(symbolActions, analyzer, symbol, getTopMostNodeForAnalysis, analyzerStateOpt);
analysisStateOpt?.MarkSymbolComplete(symbol, analyzer);
await ExecuteSymbolActionsCoreAsync(symbolActions, analyzer, symbol, getTopMostNodeForAnalysis, analyzerStateOpt).ConfigureAwait(false);
if (analysisStateOpt != null)
{
await analysisStateOpt.MarkSymbolCompleteAsync(symbol, analyzer, _cancellationToken).ConfigureAwait(false);
}
}
}
finally
......@@ -275,7 +284,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
}
}
private void ExecuteSymbolActionsCore(
private async Task ExecuteSymbolActionsCoreAsync(
ImmutableArray<SymbolAnalyzerAction> symbolActions,
DiagnosticAnalyzer analyzer,
ISymbol symbol,
......@@ -297,9 +306,9 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
_cancellationToken.ThrowIfCancellationRequested();
ExecuteAndCatchIfThrows(symbolAction.Analyzer,
await ExecuteAndCatchIfThrowsAsync(symbolAction.Analyzer,
() => action(new SymbolAnalysisContext(symbol, _compilation, _analyzerOptions, addDiagnostic,
d => IsSupportedDiagnostic(symbolAction.Analyzer, d), _cancellationToken)));
d => IsSupportedDiagnostic(symbolAction.Analyzer, d), _cancellationToken))).ConfigureAwait(false);
analyzerStateOpt?.ProcessedActions.Add(symbolAction);
}
......@@ -316,7 +325,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
/// <param name="compilationUnitCompletedEvent">Compilation event for semantic model analysis.</param>
/// <param name="analysisScope">Scope for analyzer execution.</param>
/// <param name="analysisStateOpt">An optional object to track analysis state.</param>
public void ExecuteSemanticModelActions(
public async Task ExecuteSemanticModelActionsAsync(
ImmutableArray<SemanticModelAnalyzerAction> semanticModelActions,
DiagnosticAnalyzer analyzer,
SemanticModel semanticModel,
......@@ -328,10 +337,15 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
try
{
if (TryStartProcessingEvent(compilationUnitCompletedEvent, analyzer, analysisScope, analysisStateOpt, out analyzerStateOpt))
analyzerStateOpt = await TryStartProcessingEventAsync(compilationUnitCompletedEvent, analyzer, analysisScope, analysisStateOpt, _cancellationToken).ConfigureAwait(false);
if (analysisStateOpt == null || analyzerStateOpt != null)
{
ExecuteSemanticModelActionsCore(semanticModelActions, analyzer, semanticModel, analyzerStateOpt);
analysisStateOpt?.MarkEventComplete(compilationUnitCompletedEvent, analyzer);
await ExecuteSemanticModelActionsCoreAsync(semanticModelActions, analyzer, semanticModel, analyzerStateOpt).ConfigureAwait(false);
if (analysisStateOpt != null)
{
await analysisStateOpt.MarkEventCompleteAsync(compilationUnitCompletedEvent, analyzer, _cancellationToken).ConfigureAwait(false);
}
}
}
finally
......@@ -340,7 +354,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
}
}
private void ExecuteSemanticModelActionsCore(
private async Task ExecuteSemanticModelActionsCoreAsync(
ImmutableArray<SemanticModelAnalyzerAction> semanticModelActions,
DiagnosticAnalyzer analyzer,
SemanticModel semanticModel,
......@@ -355,9 +369,9 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
_cancellationToken.ThrowIfCancellationRequested();
// Catch Exception from action.
ExecuteAndCatchIfThrows(semanticModelAction.Analyzer,
await ExecuteAndCatchIfThrowsAsync(semanticModelAction.Analyzer,
() => semanticModelAction.Action(new SemanticModelAnalysisContext(semanticModel, _analyzerOptions, addDiagnostic,
d => IsSupportedDiagnostic(semanticModelAction.Analyzer, d), _cancellationToken)));
d => IsSupportedDiagnostic(semanticModelAction.Analyzer, d), _cancellationToken))).ConfigureAwait(false);
analyzerStateOpt?.ProcessedActions.Add(semanticModelAction);
}
......@@ -372,7 +386,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
/// <param name="tree">Syntax tree to analyze.</param>
/// <param name="analysisScope">Scope for analyzer execution.</param>
/// <param name="analysisStateOpt">An optional object to track analysis state.</param>
public void ExecuteSyntaxTreeActions(
public async Task ExecuteSyntaxTreeActionsAsync(
ImmutableArray<SyntaxTreeAnalyzerAction> syntaxTreeActions,
DiagnosticAnalyzer analyzer,
SyntaxTree tree,
......@@ -383,10 +397,15 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
try
{
if (TryStartSyntaxAnalysis(tree, analyzer, analysisScope, analysisStateOpt, out analyzerStateOpt))
analyzerStateOpt = await TryStartSyntaxAnalysis(tree, analyzer, analysisScope, analysisStateOpt, _cancellationToken).ConfigureAwait(false);
if (analysisStateOpt == null || analyzerStateOpt != null)
{
ExecuteSyntaxTreeActionsCore(syntaxTreeActions, analyzer, tree, analyzerStateOpt);
analysisStateOpt?.MarkSyntaxAnalysisComplete(tree, analyzer);
await ExecuteSyntaxTreeActionsCoreAsync(syntaxTreeActions, analyzer, tree, analyzerStateOpt).ConfigureAwait(false);
if (analysisStateOpt != null)
{
await analysisStateOpt.MarkSyntaxAnalysisCompleteAsync(tree, analyzer, _cancellationToken).ConfigureAwait(false);
}
}
}
finally
......@@ -395,7 +414,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
}
}
private void ExecuteSyntaxTreeActionsCore(
private async Task ExecuteSyntaxTreeActionsCoreAsync(
ImmutableArray<SyntaxTreeAnalyzerAction> syntaxTreeActions,
DiagnosticAnalyzer analyzer,
SyntaxTree tree,
......@@ -410,16 +429,16 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
_cancellationToken.ThrowIfCancellationRequested();
// Catch Exception from action.
ExecuteAndCatchIfThrows(syntaxTreeAction.Analyzer,
await ExecuteAndCatchIfThrowsAsync(syntaxTreeAction.Analyzer,
() => syntaxTreeAction.Action(new SyntaxTreeAnalysisContext(tree, _analyzerOptions, addDiagnostic,
d => IsSupportedDiagnostic(syntaxTreeAction.Analyzer, d), _cancellationToken)));
d => IsSupportedDiagnostic(syntaxTreeAction.Analyzer, d), _cancellationToken))).ConfigureAwait(false);
analyzerStateOpt?.ProcessedActions.Add(syntaxTreeAction);
}
}
}
private void ExecuteSyntaxNodeAction<TLanguageKindEnum>(
private async Task ExecuteSyntaxNodeActionAsync<TLanguageKindEnum>(
SyntaxNodeAnalyzerAction<TLanguageKindEnum> syntaxNodeAction,
SyntaxNode node,
SemanticModel semanticModel,
......@@ -433,13 +452,13 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
var syntaxNodeContext = new SyntaxNodeAnalysisContext(node, semanticModel, _analyzerOptions, addDiagnostic,
d => IsSupportedDiagnostic(syntaxNodeAction.Analyzer, d), _cancellationToken);
ExecuteAndCatchIfThrows(syntaxNodeAction.Analyzer, () => syntaxNodeAction.Action(syntaxNodeContext));
await ExecuteAndCatchIfThrowsAsync(syntaxNodeAction.Analyzer, () => syntaxNodeAction.Action(syntaxNodeContext)).ConfigureAwait(false);
analyzerStateOpt?.ProcessedActions.Add(syntaxNodeAction);
}
}
private void ExecuteOperationAction(
private async Task ExecuteOperationActionAsync(
OperationAnalyzerAction operationAction,
IOperation operation,
Action<Diagnostic> addDiagnostic,
......@@ -450,13 +469,13 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
if (ShouldExecuteAction(analyzerStateOpt, operationAction))
{
var operationContext = new OperationAnalysisContext(operation, _analyzerOptions, _addDiagnostic, d => IsSupportedDiagnostic(operationAction.Analyzer, d), _cancellationToken);
ExecuteAndCatchIfThrows(operationAction.Analyzer, () => operationAction.Action(operationContext));
await ExecuteAndCatchIfThrowsAsync(operationAction.Analyzer, () => operationAction.Action(operationContext)).ConfigureAwait(false);
analyzerStateOpt?.ProcessedActions.Add(operationAction);
}
}
public void ExecuteCodeBlockActions<TLanguageKindEnum>(
public async Task ExecuteCodeBlockActionsAsync<TLanguageKindEnum>(
IEnumerable<CodeBlockStartAnalyzerAction<TLanguageKindEnum>> codeBlockStartActions,
IEnumerable<CodeBlockAnalyzerAction> codeBlockActions,
IEnumerable<CodeBlockAnalyzerAction> codeBlockEndActions,
......@@ -475,11 +494,12 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
try
{
if (TryStartAnalyzingSyntaxRefence(declaration, analyzer, analysisScope, analysisStateOpt, out analyzerStateOpt))
analyzerStateOpt = await TryStartAnalyzingSyntaxReferenceAsync(declaration, analyzer, analysisScope, analysisStateOpt, _cancellationToken).ConfigureAwait(false);
if (analysisStateOpt == null || analyzerStateOpt != null)
{
ExecuteBlockActionsCore<CodeBlockStartAnalyzerAction<TLanguageKindEnum>, CodeBlockAnalyzerAction, SyntaxNodeAnalyzerAction<TLanguageKindEnum>, SyntaxNodeAnalyzerStateData, SyntaxNode, TLanguageKindEnum>(
await ExecuteBlockActionsCoreAsync<CodeBlockStartAnalyzerAction<TLanguageKindEnum>, CodeBlockAnalyzerAction, SyntaxNodeAnalyzerAction<TLanguageKindEnum>, SyntaxNodeAnalyzerStateData, SyntaxNode, TLanguageKindEnum>(
codeBlockStartActions, codeBlockActions, codeBlockEndActions, analyzer,
declaredNode, declaredSymbol, executableCodeBlocks, (codeBlocks) => codeBlocks.SelectMany(cb => cb.DescendantNodesAndSelf()), semanticModel, getKind, analyzerStateOpt?.CodeBlockAnalysisState);
declaredNode, declaredSymbol, executableCodeBlocks, (codeBlocks) => codeBlocks.SelectMany(cb => cb.DescendantNodesAndSelf()), semanticModel, getKind, analyzerStateOpt?.CodeBlockAnalysisState).ConfigureAwait(false);
}
}
finally
......@@ -488,7 +508,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
}
}
public void ExecuteOperationBlockActions(
public async Task ExecuteOperationBlockActionsAsync(
IEnumerable<OperationBlockStartAnalyzerAction> operationBlockStartActions,
IEnumerable<OperationBlockAnalyzerAction> operationBlockActions,
IEnumerable<OperationBlockAnalyzerAction> operationBlockEndActions,
......@@ -506,11 +526,12 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
try
{
if (TryStartAnalyzingSyntaxRefence(declaration, analyzer, analysisScope, analysisStateOpt, out analyzerStateOpt))
analyzerStateOpt = await TryStartAnalyzingSyntaxReferenceAsync(declaration, analyzer, analysisScope, analysisStateOpt, _cancellationToken).ConfigureAwait(false);
if (analysisStateOpt == null || analysisStateOpt != null)
{
ExecuteBlockActionsCore<OperationBlockStartAnalyzerAction, OperationBlockAnalyzerAction, OperationAnalyzerAction, OperationAnalyzerStateData, IOperation, int>(
await ExecuteBlockActionsCoreAsync<OperationBlockStartAnalyzerAction, OperationBlockAnalyzerAction, OperationAnalyzerAction, OperationAnalyzerStateData, IOperation, int>(
operationBlockStartActions, operationBlockActions, operationBlockEndActions, analyzer,
declaredNode, declaredSymbol, operationBlocks, (blocks) => operations, semanticModel, null, analyzerStateOpt?.OperationBlockAnalysisState);
declaredNode, declaredSymbol, operationBlocks, (blocks) => operations, semanticModel, null, analyzerStateOpt?.OperationBlockAnalysisState).ConfigureAwait(false);
}
}
finally
......@@ -519,7 +540,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
}
}
private void ExecuteBlockActionsCore<TBlockStartAction, TBlockAction, TNodeAction, TNodeStateData, TNode, TLanguageKindEnum>(
private async Task ExecuteBlockActionsCoreAsync<TBlockStartAction, TBlockAction, TNodeAction, TNodeStateData, TNode, TLanguageKindEnum>(
IEnumerable<TBlockStartAction> startActions,
IEnumerable<TBlockAction> actions,
IEnumerable<TBlockAction> endActions,
......@@ -582,7 +603,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
var codeBlockEndActions = blockEndActions as PooledHashSet<CodeBlockAnalyzerAction>;
// Catch Exception from the start action.
ExecuteAndCatchIfThrows(startAction.Analyzer, () =>
await ExecuteAndCatchIfThrowsAsync(startAction.Analyzer, () =>
{
var codeBlockScope = new HostCodeBlockStartAnalysisScope<TLanguageKindEnum>();
var blockStartContext = new AnalyzerCodeBlockStartAnalysisContext<TLanguageKindEnum>(startAction.Analyzer,
......@@ -590,7 +611,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
codeBlockStartAction.Action(blockStartContext);
codeBlockEndActions.AddAll(codeBlockScope.CodeBlockEndActions);
syntaxNodeActions.AddRange(codeBlockScope.SyntaxNodeActions);
});
}).ConfigureAwait(false);
}
else
{
......@@ -599,7 +620,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
var operationBlockEndActions = blockEndActions as PooledHashSet<OperationBlockAnalyzerAction>;
// Catch Exception from the start action.
ExecuteAndCatchIfThrows(startAction.Analyzer, () =>
await ExecuteAndCatchIfThrowsAsync(startAction.Analyzer, () =>
{
var operationBlockScope = new HostOperationBlockStartAnalysisScope();
var operationStartContext = new AnalyzerOperationBlockStartAnalysisContext(startAction.Analyzer,
......@@ -607,7 +628,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
operationBlockStartAction.Action(operationStartContext);
operationBlockEndActions.AddAll(operationBlockScope.OperationBlockEndActions);
operationActions.AddRange(operationBlockScope.OperationActions);
});
}).ConfigureAwait(false);
}
}
......@@ -631,23 +652,23 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
var executableNodeActionsByKind = GetNodeActionsByKind(syntaxNodeActions);
var syntaxNodesToAnalyze = (IEnumerable<SyntaxNode>)getNodesToAnalyze(executableBlocks);
ExecuteSyntaxNodeActions(syntaxNodesToAnalyze, executableNodeActionsByKind, semanticModel, getKind, addDiagnostic, analyzerStateOpt?.ExecutableNodesAnalysisState as SyntaxNodeAnalyzerStateData);
await ExecuteSyntaxNodeActionsAsync(syntaxNodesToAnalyze, executableNodeActionsByKind, semanticModel, getKind, addDiagnostic, analyzerStateOpt?.ExecutableNodesAnalysisState as SyntaxNodeAnalyzerStateData).ConfigureAwait(false);
}
else if (operationActions != null)
{
var operationActionsByKind = GetOperationActionsByKind(operationActions);
var operationsToAnalyze = (IEnumerable<IOperation>)getNodesToAnalyze(executableBlocks);
ExecuteOperationActions(operationsToAnalyze, operationActionsByKind, addDiagnostic, analyzerStateOpt?.ExecutableNodesAnalysisState as OperationAnalyzerStateData);
await ExecuteOperationActionsAsync(operationsToAnalyze, operationActionsByKind, addDiagnostic, analyzerStateOpt?.ExecutableNodesAnalysisState as OperationAnalyzerStateData).ConfigureAwait(false);
}
}
executableNodeActions.Free();
ExecuteBlockActions(blockActions, declaredNode, declaredSymbol, semanticModel, operationBlocks, addDiagnostic, analyzerStateOpt);
ExecuteBlockActions(blockEndActions, declaredNode, declaredSymbol, semanticModel, operationBlocks, addDiagnostic, analyzerStateOpt);
await ExecuteBlockActionsAsync(blockActions, declaredNode, declaredSymbol, semanticModel, operationBlocks, addDiagnostic, analyzerStateOpt).ConfigureAwait(false);
await ExecuteBlockActionsAsync(blockEndActions, declaredNode, declaredSymbol, semanticModel, operationBlocks, addDiagnostic, analyzerStateOpt).ConfigureAwait(false);
}
private void ExecuteBlockActions<TBlockAction, TNodeStateData>(
private async Task ExecuteBlockActionsAsync<TBlockAction, TNodeStateData>(
PooledHashSet<TBlockAction> blockActions,
SyntaxNode declaredNode,
ISymbol declaredSymbol,
......@@ -666,18 +687,18 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
Func<Diagnostic, bool> isSupportedDiagnostic = d => IsSupportedDiagnostic(blockAction.Analyzer, d);
if (codeBlockAction != null)
{
ExecuteAndCatchIfThrows(
await ExecuteAndCatchIfThrowsAsync(
codeBlockAction.Analyzer,
() => codeBlockAction.Action(new CodeBlockAnalysisContext(declaredNode, declaredSymbol, semanticModel, _analyzerOptions, addDiagnostic, isSupportedDiagnostic, _cancellationToken)));
() => codeBlockAction.Action(new CodeBlockAnalysisContext(declaredNode, declaredSymbol, semanticModel, _analyzerOptions, addDiagnostic, isSupportedDiagnostic, _cancellationToken))).ConfigureAwait(false);
}
else
{
var operationBlockAction = blockAction as OperationBlockAnalyzerAction;
if (operationBlockAction != null)
{
ExecuteAndCatchIfThrows(
await ExecuteAndCatchIfThrowsAsync(
operationBlockAction.Analyzer,
() => operationBlockAction.Action(new OperationBlockAnalysisContext(operationBlocks, declaredSymbol, _analyzerOptions, addDiagnostic, isSupportedDiagnostic, _cancellationToken)));
() => operationBlockAction.Action(new OperationBlockAnalysisContext(operationBlocks, declaredSymbol, _analyzerOptions, addDiagnostic, isSupportedDiagnostic, _cancellationToken))).ConfigureAwait(false);
}
}
......@@ -715,7 +736,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
return map;
}
public void ExecuteSyntaxNodeActions<TLanguageKindEnum>(
public async Task ExecuteSyntaxNodeActionsAsync<TLanguageKindEnum>(
IEnumerable<SyntaxNode> nodesToAnalyze,
IDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> nodeActionsByKind,
DiagnosticAnalyzer analyzer,
......@@ -731,9 +752,10 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
try
{
if (TryStartAnalyzingSyntaxRefence(declaration, analyzer, analysisScope, analysisStateOpt, out analyzerStateOpt))
analyzerStateOpt = await TryStartAnalyzingSyntaxReferenceAsync(declaration, analyzer, analysisScope, analysisStateOpt, _cancellationToken).ConfigureAwait(false);
if (analysisStateOpt == null || analyzerStateOpt != null)
{
ExecuteSyntaxNodeActionsCore(nodesToAnalyze, nodeActionsByKind, analyzer, model, getKind, filterSpan, analyzerStateOpt);
await ExecuteSyntaxNodeActionsCoreAsync(nodesToAnalyze, nodeActionsByKind, analyzer, model, getKind, filterSpan, analyzerStateOpt).ConfigureAwait(false);
}
}
finally
......@@ -742,7 +764,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
}
}
private void ExecuteSyntaxNodeActionsCore<TLanguageKindEnum>(
private async Task ExecuteSyntaxNodeActionsCoreAsync<TLanguageKindEnum>(
IEnumerable<SyntaxNode> nodesToAnalyze,
IDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> nodeActionsByKind,
DiagnosticAnalyzer analyzer,
......@@ -753,10 +775,10 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
where TLanguageKindEnum : struct
{
var addDiagnostic = GetAddDiagnostic(model.SyntaxTree, filterSpan, analyzer, isSyntaxDiagnostic: false);
ExecuteSyntaxNodeActions(nodesToAnalyze, nodeActionsByKind, model, getKind, addDiagnostic, analyzerStateOpt);
await ExecuteSyntaxNodeActionsAsync(nodesToAnalyze, nodeActionsByKind, model, getKind, addDiagnostic, analyzerStateOpt).ConfigureAwait(false);
}
private void ExecuteSyntaxNodeActions<TLanguageKindEnum>(
private async Task ExecuteSyntaxNodeActionsAsync<TLanguageKindEnum>(
IEnumerable<SyntaxNode> nodesToAnalyze,
IDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> nodeActionsByKind,
SemanticModel model,
......@@ -771,7 +793,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
SyntaxNode partiallyProcessedNode = analyzerStateOpt?.CurrentNode;
if (partiallyProcessedNode != null)
{
ExecuteSyntaxNodeActions(partiallyProcessedNode, nodeActionsByKind, model, getKind, addDiagnostic, analyzerStateOpt);
await ExecuteSyntaxNodeActionsAsync(partiallyProcessedNode, nodeActionsByKind, model, getKind, addDiagnostic, analyzerStateOpt).ConfigureAwait(false);
}
foreach (var child in nodesToAnalyze)
......@@ -780,12 +802,12 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
SetCurrentNode(analyzerStateOpt, child);
ExecuteSyntaxNodeActions(child, nodeActionsByKind, model, getKind, addDiagnostic, analyzerStateOpt);
await ExecuteSyntaxNodeActionsAsync(child, nodeActionsByKind, model, getKind, addDiagnostic, analyzerStateOpt).ConfigureAwait(false);
}
}
}
private void ExecuteSyntaxNodeActions<TLanguageKindEnum>(
private async Task ExecuteSyntaxNodeActionsAsync<TLanguageKindEnum>(
SyntaxNode node,
IDictionary<TLanguageKindEnum, ImmutableArray<SyntaxNodeAnalyzerAction<TLanguageKindEnum>>> nodeActionsByKind,
SemanticModel model,
......@@ -799,7 +821,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
foreach (var action in actionsForKind)
{
ExecuteSyntaxNodeAction(action, node, model, addDiagnostic, analyzerStateOpt);
await ExecuteSyntaxNodeActionAsync(action, node, model, addDiagnostic, analyzerStateOpt).ConfigureAwait(false);
}
}
......@@ -831,7 +853,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
return map;
}
public void ExecuteOperationActions(
public async Task ExecuteOperationActionsAsync(
IEnumerable<IOperation> operationsToAnalyze,
IDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> operationActionsByKind,
DiagnosticAnalyzer analyzer,
......@@ -845,9 +867,10 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
try
{
if (TryStartAnalyzingOperationReference(declaration, analyzer, analysisScope, analysisStateOpt, out analyzerStateOpt))
analyzerStateOpt = await TryStartAnalyzingOperationReferenceAsync(declaration, analyzer, analysisScope, analysisStateOpt, _cancellationToken).ConfigureAwait(false);
if (analysisStateOpt == null || analyzerStateOpt != null)
{
ExecuteOperationActionsCore(operationsToAnalyze, operationActionsByKind, analyzer, model, filterSpan, analyzerStateOpt);
await ExecuteOperationActionsCoreAsync(operationsToAnalyze, operationActionsByKind, analyzer, model, filterSpan, analyzerStateOpt).ConfigureAwait(false);
}
}
finally
......@@ -856,7 +879,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
}
}
private void ExecuteOperationActionsCore(
private async Task ExecuteOperationActionsCoreAsync(
IEnumerable<IOperation> operationsToAnalyze,
IDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> operationActionsByKind,
DiagnosticAnalyzer analyzer,
......@@ -865,10 +888,10 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
OperationAnalyzerStateData analyzerStateOpt)
{
var addDiagnostic = GetAddDiagnostic(model.SyntaxTree, filterSpan, analyzer, isSyntaxDiagnostic: false);
ExecuteOperationActions(operationsToAnalyze, operationActionsByKind, addDiagnostic, analyzerStateOpt);
await ExecuteOperationActionsAsync(operationsToAnalyze, operationActionsByKind, addDiagnostic, analyzerStateOpt).ConfigureAwait(false);
}
private void ExecuteOperationActions(
private async Task ExecuteOperationActionsAsync(
IEnumerable<IOperation> operationsToAnalyze,
IDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> operationActionsByKind,
Action<Diagnostic> addDiagnostic,
......@@ -880,7 +903,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
IOperation partiallyProcessedNode = analyzerStateOpt?.CurrentOperation;
if (partiallyProcessedNode != null)
{
ExecuteOperationActions(partiallyProcessedNode, operationActionsByKind, addDiagnostic, analyzerStateOpt);
await ExecuteOperationActionsAsync(partiallyProcessedNode, operationActionsByKind, addDiagnostic, analyzerStateOpt).ConfigureAwait(false);
}
foreach (var child in operationsToAnalyze)
......@@ -889,12 +912,12 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
SetCurrentOperation(analyzerStateOpt, child);
ExecuteOperationActions(child, operationActionsByKind, addDiagnostic, analyzerStateOpt);
await ExecuteOperationActionsAsync(child, operationActionsByKind, addDiagnostic, analyzerStateOpt).ConfigureAwait(false);
}
}
}
private void ExecuteOperationActions(
private async Task ExecuteOperationActionsAsync(
IOperation operation,
IDictionary<OperationKind, ImmutableArray<OperationAnalyzerAction>> operationActionsByKind,
Action<Diagnostic> addDiagnostic,
......@@ -905,7 +928,7 @@ private void ExecuteCompilationActionsCore(ImmutableArray<CompilationAnalyzerAct
{
foreach (var action in actionsForKind)
{
ExecuteOperationAction(action, operation, addDiagnostic, analyzerStateOpt);
await ExecuteOperationActionAsync(action, operation, addDiagnostic, analyzerStateOpt).ConfigureAwait(false);
}
}
......@@ -931,12 +954,12 @@ internal static bool CanHaveExecutableCodeBlock(ISymbol symbol)
}
}
internal void ExecuteAndCatchIfThrows(DiagnosticAnalyzer analyzer, Action analyze)
internal async Task ExecuteAndCatchIfThrowsAsync(DiagnosticAnalyzer analyzer, Action analyze)
{
object gate = _getAnalyzerGateOpt?.Invoke(analyzer);
SemaphoreSlim gate = _getAnalyzerGateOpt?.Invoke(analyzer);
if (gate != null)
{
lock (gate)
using (await gate.DisposableWaitAsync(_cancellationToken).ConfigureAwait(false))
{
ExecuteAndCatchIfThrows_NoLock(analyzer, analyze);
}
......@@ -1187,58 +1210,66 @@ private static void SetCurrentOperation(OperationAnalyzerStateData analyzerState
}
}
private static bool TryStartProcessingEvent(CompilationEvent nonSymbolCompilationEvent, DiagnosticAnalyzer analyzer, AnalysisScope analysisScope, AnalysisState analysisStateOpt, out AnalyzerStateData analyzerStateOpt)
private static async Task<AnalyzerStateData> TryStartProcessingEventAsync(CompilationEvent nonSymbolCompilationEvent, DiagnosticAnalyzer analyzer, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
{
Debug.Assert(!(nonSymbolCompilationEvent is SymbolDeclaredCompilationEvent));
Debug.Assert(analysisScope.Analyzers.Contains(analyzer));
analyzerStateOpt = null;
return analysisStateOpt == null || analysisStateOpt.TryStartProcessingEvent(nonSymbolCompilationEvent, analyzer, out analyzerStateOpt);
if (analysisStateOpt == null)
{
return null;
}
return await analysisStateOpt.TryStartProcessingEventAsync(nonSymbolCompilationEvent, analyzer, cancellationToken).ConfigureAwait(false);
}
private static bool TryStartSyntaxAnalysis(SyntaxTree tree, DiagnosticAnalyzer analyzer, AnalysisScope analysisScope, AnalysisState analysisStateOpt, out AnalyzerStateData analyzerStateOpt)
private static async Task<AnalyzerStateData> TryStartSyntaxAnalysis(SyntaxTree tree, DiagnosticAnalyzer analyzer, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
{
Debug.Assert(analysisScope.Analyzers.Contains(analyzer));
analyzerStateOpt = null;
return analysisStateOpt == null || analysisStateOpt.TryStartSyntaxAnalysis(tree, analyzer, out analyzerStateOpt);
if (analysisStateOpt == null)
{
return null;
}
return await analysisStateOpt.TryStartSyntaxAnalysisAsync(tree, analyzer, cancellationToken).ConfigureAwait(false);
}
private static bool TryStartAnalyzingSymbol(ISymbol symbol, DiagnosticAnalyzer analyzer, AnalysisScope analysisScope, AnalysisState analysisStateOpt, out AnalyzerStateData analyzerStateOpt)
private static async Task<AnalyzerStateData> TryStartAnalyzingSymbolAsync(ISymbol symbol, DiagnosticAnalyzer analyzer, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
{
Debug.Assert(analysisScope.Analyzers.Contains(analyzer));
analyzerStateOpt = null;
return analysisStateOpt == null || analysisStateOpt.TryStartAnalyzingSymbol(symbol, analyzer, out analyzerStateOpt);
if (analysisStateOpt == null)
{
return null;
}
return await analysisStateOpt.TryStartAnalyzingSymbolAsync(symbol, analyzer, cancellationToken).ConfigureAwait(false);
}
private static bool TryStartAnalyzingSyntaxRefence(SyntaxReference syntaxReference, DiagnosticAnalyzer analyzer, AnalysisScope analysisScope, AnalysisState analysisStateOpt, out DeclarationAnalyzerStateData analyzerStateOpt)
private static async Task<DeclarationAnalyzerStateData> TryStartAnalyzingSyntaxReferenceAsync(SyntaxReference syntaxReference, DiagnosticAnalyzer analyzer, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
{
Debug.Assert(analysisScope.Analyzers.Contains(analyzer));
analyzerStateOpt = null;
return analysisStateOpt == null || analysisStateOpt.TryStartAnalyzingDeclaration(syntaxReference, analyzer, out analyzerStateOpt);
if (analysisStateOpt == null)
{
return null;
}
return await analysisStateOpt.TryStartAnalyzingDeclarationAsync(syntaxReference, analyzer, cancellationToken).ConfigureAwait(false);
}
private static bool TryStartAnalyzingOperationReference(SyntaxReference syntaxReference, DiagnosticAnalyzer analyzer, AnalysisScope analysisScope, AnalysisState analysisStateOpt, out OperationAnalyzerStateData analyzerStateOpt)
private static async Task<OperationAnalyzerStateData> TryStartAnalyzingOperationReferenceAsync(SyntaxReference syntaxReference, DiagnosticAnalyzer analyzer, AnalysisScope analysisScope, AnalysisState analysisStateOpt, CancellationToken cancellationToken)
{
Debug.Assert(analysisScope.Analyzers.Contains(analyzer));
analyzerStateOpt = null;
DeclarationAnalyzerStateData declarationAnalyzerStateOpt;
if (analysisStateOpt == null)
{
return true;
}
if (analysisStateOpt.TryStartAnalyzingDeclaration(syntaxReference, analyzer, out declarationAnalyzerStateOpt))
{
analyzerStateOpt = declarationAnalyzerStateOpt.OperationBlockAnalysisState.ExecutableNodesAnalysisState;
return true;
return null;
}
analyzerStateOpt = null;
return false;
var declarationAnalyzerStateOpt = await analysisStateOpt.TryStartAnalyzingDeclarationAsync(syntaxReference, analyzer, cancellationToken).ConfigureAwait(false);
return declarationAnalyzerStateOpt?.OperationBlockAnalysisState.ExecutableNodesAnalysisState;
}
internal TimeSpan ResetAnalyzerExecutionTime(DiagnosticAnalyzer analyzer)
......
......@@ -55,10 +55,10 @@ internal partial class AnalyzerManager
{
Func<Compilation, Task<HostCompilationStartAnalysisScope>> getTask = comp =>
{
return Task.Run(() =>
return Task.Run(async() =>
{
var compilationAnalysisScope = new HostCompilationStartAnalysisScope(sessionScope);
analyzerExecutor.ExecuteCompilationStartActions(sessionScope.CompilationStartActions, compilationAnalysisScope);
await analyzerExecutor.ExecuteCompilationStartActionsAsync(sessionScope.CompilationStartActions, compilationAnalysisScope).ConfigureAwait(false);
return compilationAnalysisScope;
}, analyzerExecutor.CancellationToken);
};
......@@ -100,10 +100,10 @@ internal partial class AnalyzerManager
{
Func<DiagnosticAnalyzer, Task<HostSessionStartAnalysisScope>> getTask = a =>
{
return Task.Run(() =>
return Task.Run(async() =>
{
var sessionScope = new HostSessionStartAnalysisScope();
analyzerExecutor.ExecuteInitializeMethod(a, sessionScope);
await analyzerExecutor.ExecuteInitializeMethodAsync(a, sessionScope).ConfigureAwait(false);
return sessionScope;
}, analyzerExecutor.CancellationToken);
};
......@@ -160,14 +160,14 @@ public async Task<AnalyzerActions> GetAnalyzerActionsAsync(DiagnosticAnalyzer an
var supportedDiagnostics = ImmutableArray<DiagnosticDescriptor>.Empty;
// Catch Exception from analyzer.SupportedDiagnostics
analyzerExecutor.ExecuteAndCatchIfThrows(analyzer, () =>
analyzerExecutor.ExecuteAndCatchIfThrowsAsync(analyzer, () =>
{
var supportedDiagnosticsLocal = analyzer.SupportedDiagnostics;
if (!supportedDiagnosticsLocal.IsDefaultOrEmpty)
{
supportedDiagnostics = supportedDiagnosticsLocal;
}
});
}).Wait(analyzerExecutor.CancellationToken);
EventHandler<Exception> handler = null;
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = analyzerExecutor.OnAnalyzerException;
......
......@@ -68,7 +68,7 @@ public class CompilationWithAnalyzers
/// Pool of event queues to serve each diagnostics request.
/// </summary>
private static readonly ObjectPool<AsyncQueue<CompilationEvent>> s_eventQueuePool = new ObjectPool<AsyncQueue<CompilationEvent>>(() => new AsyncQueue<CompilationEvent>());
private static readonly AsyncQueue<CompilationEvent> s_EmptyEventQueue = new AsyncQueue<CompilationEvent>();
private static readonly Task<AsyncQueue<CompilationEvent>> s_EmptyEventQueueTask = Task.FromResult(new AsyncQueue<CompilationEvent>());
/// <summary>
......@@ -362,11 +362,11 @@ private async Task<ImmutableArray<Diagnostic>> GetAnalyzerDiagnosticsCoreAsync(I
}
};
Func<AsyncQueue<CompilationEvent>> getEventQueue = () =>
GetPendingEvents(analyzers, includeSourceEvents, includeNonSourceEvents);
Func<Task<AsyncQueue<CompilationEvent>>> getEventQueueTask = () =>
GetPendingEventsAsync(analyzers, includeSourceEvents, includeNonSourceEvents, cancellationToken);
// Compute the analyzer diagnostics for the given analysis scope.
await ComputeAnalyzerDiagnosticsAsync(analysisScope, generateCompilationEvents, getEventQueue, newTaskToken: 0, cancellationToken: cancellationToken).ConfigureAwait(false);
await ComputeAnalyzerDiagnosticsAsync(analysisScope, generateCompilationEvents, getEventQueueTask, newTaskToken: 0, cancellationToken: cancellationToken).ConfigureAwait(false);
// Return computed analyzer diagnostics for the given analysis scope.
var analyzerDiagnostics = _analysisResult.GetDiagnostics(analysisScope, getLocalDiagnostics: includeSourceEvents, getNonLocalDiagnostics: includeNonSourceEvents);
......@@ -420,7 +420,7 @@ private async Task<ImmutableArray<Diagnostic>> GetAnalyzerSyntaxDiagnosticsCoreA
var analysisScope = new AnalysisScope(analyzers, tree, filterSpan: null, syntaxAnalysis: true, concurrentAnalysis: _analysisOptions.ConcurrentAnalysis, categorizeDiagnostics: true);
Action generateCompilationEvents = null;
Func<AsyncQueue<CompilationEvent>> getEventQueue = () => s_EmptyEventQueue;
Func<Task<AsyncQueue<CompilationEvent>>> getEventQueue = () => s_EmptyEventQueueTask;
// Compute the analyzer diagnostics for the given analysis scope.
await ComputeAnalyzerDiagnosticsAsync(analysisScope, generateCompilationEvents, getEventQueue, taskToken, cancellationToken).ConfigureAwait(false);
......@@ -487,14 +487,15 @@ private async Task<ImmutableArray<Diagnostic>> GetAnalyzerSemanticDiagnosticsCor
Action generateCompilationEvents = () =>
AnalyzerDriver.GetOrCreateCachedSemanticModel(model.SyntaxTree, _compilation, cancellationToken);
Func<AsyncQueue<CompilationEvent>> getEventQueue = () => GetPendingEvents(analyzers, model.SyntaxTree);
Func<Task<AsyncQueue<CompilationEvent>>> getEventQueueTask = () => GetPendingEventsAsync(analyzers, model.SyntaxTree, cancellationToken);
// Compute the analyzer diagnostics for the given analysis scope.
// We need to loop till symbol analysis is complete for any partial symbols being processed for other tree diagnostic requests.
do
{
await ComputeAnalyzerDiagnosticsAsync(analysisScope, generateCompilationEvents, getEventQueue, taskToken, cancellationToken).ConfigureAwait(false);
} while (_analysisOptions.ConcurrentAnalysis && _analysisState.HasPendingSymbolAnalysis(analysisScope));
await ComputeAnalyzerDiagnosticsAsync(analysisScope, generateCompilationEvents, getEventQueueTask, taskToken, cancellationToken).ConfigureAwait(false);
} while (_analysisOptions.ConcurrentAnalysis &&
(await _analysisState.HasPendingSymbolAnalysisAsync(analysisScope, cancellationToken).ConfigureAwait(false)));
// Return computed analyzer diagnostics for the given analysis scope.
return _analysisResult.GetDiagnostics(analysisScope, getLocalDiagnostics: true, getNonLocalDiagnostics: false);
......@@ -505,7 +506,7 @@ private async Task<ImmutableArray<Diagnostic>> GetAnalyzerSemanticDiagnosticsCor
}
}
private async Task ComputeAnalyzerDiagnosticsAsync(AnalysisScope analysisScope, Action generateCompilationEventsOpt, Func<AsyncQueue<CompilationEvent>> getEventQueue, int newTaskToken, CancellationToken cancellationToken)
private async Task ComputeAnalyzerDiagnosticsAsync(AnalysisScope analysisScope, Action generateCompilationEventsOpt, Func<Task<AsyncQueue<CompilationEvent>>> getEventQueueTask, int newTaskToken, CancellationToken cancellationToken)
{
try
{
......@@ -552,11 +553,11 @@ private async Task ComputeAnalyzerDiagnosticsAsync(AnalysisScope analysisScope,
AsyncQueue<CompilationEvent> eventQueue = null;
try
{
// Get event queue with pending events to analyze.
eventQueue = getEventQueue();
// Get event queue with pending events to analyze.
eventQueue = await getEventQueueTask().ConfigureAwait(false);
// Execute analyzer driver on the given analysis scope with the given event queue.
await ComputeAnalyzerDiagnosticsCoreAsync(driver, eventQueue, analysisScope, cancellationToken: linkedCts.Token).ConfigureAwait(false);
// Execute analyzer driver on the given analysis scope with the given event queue.
await ComputeAnalyzerDiagnosticsCoreAsync(driver, eventQueue, analysisScope, cancellationToken: linkedCts.Token).ConfigureAwait(false);
}
finally
{
......@@ -568,7 +569,7 @@ private async Task ComputeAnalyzerDiagnosticsAsync(AnalysisScope analysisScope,
throw ExceptionUtilities.Unreachable;
}
},
linkedCts.Token),
linkedCts.Token),
cts);
// Wait for higher priority tree document tasks to complete.
......@@ -671,7 +672,7 @@ private async Task ComputeAnalyzerDiagnosticsCoreAsync(AnalyzerDriver driver, As
{
Debug.Assert(!driver.WhenInitializedTask.IsCanceled);
if (eventQueue.Count > 0 || _analysisState.HasPendingSyntaxAnalysis(analysisScope))
if (eventQueue.Count > 0 || (await _analysisState.HasPendingSyntaxAnalysisAsync(analysisScope, cancellationToken).ConfigureAwait(false)))
{
try
{
......@@ -891,13 +892,14 @@ private ImmutableArray<CompilationEvent> DequeueGeneratedCompilationEvents()
return builder.ToImmutable();
}
private AsyncQueue<CompilationEvent> GetPendingEvents(ImmutableArray<DiagnosticAnalyzer> analyzers, SyntaxTree tree)
private async Task<AsyncQueue<CompilationEvent>> GetPendingEventsAsync(ImmutableArray<DiagnosticAnalyzer> analyzers, SyntaxTree tree, CancellationToken cancellationToken)
{
var eventQueue = s_eventQueuePool.Allocate();
Debug.Assert(!eventQueue.IsCompleted);
Debug.Assert(eventQueue.Count == 0);
foreach (var compilationEvent in _analysisState.GetPendingEvents(analyzers, tree))
var pendingEvents = await _analysisState.GetPendingEventsAsync(analyzers, tree, cancellationToken).ConfigureAwait(false);
foreach (var compilationEvent in pendingEvents)
{
eventQueue.Enqueue(compilationEvent);
}
......@@ -905,7 +907,7 @@ private AsyncQueue<CompilationEvent> GetPendingEvents(ImmutableArray<DiagnosticA
return eventQueue;
}
private AsyncQueue<CompilationEvent> GetPendingEvents(ImmutableArray<DiagnosticAnalyzer> analyzers, bool includeSourceEvents, bool includeNonSourceEvents)
private async Task<AsyncQueue<CompilationEvent>> GetPendingEventsAsync(ImmutableArray<DiagnosticAnalyzer> analyzers, bool includeSourceEvents, bool includeNonSourceEvents, CancellationToken cancellationToken)
{
Debug.Assert(includeSourceEvents || includeNonSourceEvents);
......@@ -913,7 +915,8 @@ private AsyncQueue<CompilationEvent> GetPendingEvents(ImmutableArray<DiagnosticA
Debug.Assert(!eventQueue.IsCompleted);
Debug.Assert(eventQueue.Count == 0);
foreach (var compilationEvent in _analysisState.GetPendingEvents(analyzers, includeSourceEvents, includeNonSourceEvents))
var pendingEvents = await _analysisState.GetPendingEventsAsync(analyzers, includeSourceEvents, includeNonSourceEvents, cancellationToken).ConfigureAwait(false);
foreach (var compilationEvent in pendingEvents)
{
eventQueue.Enqueue(compilationEvent);
}
......@@ -923,7 +926,7 @@ private AsyncQueue<CompilationEvent> GetPendingEvents(ImmutableArray<DiagnosticA
private void FreeEventQueue(AsyncQueue<CompilationEvent> eventQueue)
{
if (eventQueue == null || ReferenceEquals(eventQueue, s_EmptyEventQueue))
if (eventQueue == null || ReferenceEquals(eventQueue, s_EmptyEventQueueTask.Result))
{
return;
}
......
......@@ -118,6 +118,12 @@
<Compile Include="..\..\..\Compilers\Core\Portable\InternalUtilities\ReferenceEqualityComparer.cs">
<Link>InternalUtilities\ReferenceEqualityComparer.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Core\Portable\InternalUtilities\SemaphoreSlimExtensions.cs">
<Link>InternalUtilities\SemaphoreSlimExtensions.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Core\Portable\InternalUtilities\SemaphoreSlimFactory.cs">
<Link>InternalUtilities\SemaphoreSlimFactory.cs</Link>
</Compile>
<Compile Include="..\..\..\Compilers\Core\Portable\InternalUtilities\SpecializedCollections.cs">
<Link>InternalUtilities\SpecializedCollections.cs</Link>
</Compile>
......@@ -787,7 +793,6 @@
<Compile Include="Utilities\AbstractSpeculationAnalyzer.cs" />
<Compile Include="Utilities\AnnotationTable.cs" />
<Compile Include="Utilities\AsyncLazy`1.cs" />
<Compile Include="Utilities\SemaphoreSlimFactory.cs" />
<Compile Include="Utilities\BidirectionalMap.cs" />
<Compile Include="Utilities\CancellableLazy.cs" />
<Compile Include="Utilities\CancellableLazy`1.cs" />
......@@ -806,7 +811,6 @@
<Compile Include="Utilities\LazyInitialization.cs" />
<Compile Include="Utilities\ObjectPools\Extensions.cs" />
<Compile Include="Utilities\ObjectPools\SharedPools.cs" />
<Compile Include="Utilities\SemaphoreSlimExtensions.cs" />
<Compile Include="Utilities\SerializableBytes.cs" />
<Compile Include="Utilities\SimpleTaskQueue.cs" />
<Compile Include="Utilities\SpecializedTasks.cs" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册