diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs
index c451c9c929f36bf76d6424992bbda5e8a190a779..61a39b3cb2103a6da773bae7db0fdbefb69200e9 100644
--- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs
+++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs
@@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.Diagnostics
///
internal partial class AnalysisState
{
- private readonly object _gate;
+ private readonly SemaphoreSlim _gate;
///
/// Per-analyzer analysis state map.
@@ -61,7 +61,7 @@ internal partial class AnalysisState
public AnalysisState(ImmutableArray analyzers, CompilationData compilationData, CompilationOptions compilationOptions)
{
- _gate = new object();
+ _gate = new SemaphoreSlim(initialCount: 1);
_analyzerStateMap = CreateAnalyzerStateMap(analyzers, out _analyzerStates);
_compilationData = compilationData;
_compilationOptions = compilationOptions;
@@ -135,7 +135,7 @@ private PerAnalyzerState GetAnalyzerState(DiagnosticAnalyzer analyzer)
AnalyzerDriver driver,
CancellationToken cancellationToken)
{
- lock (_gate)
+ using (_gate.DisposableWait(cancellationToken))
{
if (_treesWithGeneratedSourceEvents.Contains(tree))
{
@@ -147,7 +147,7 @@ private PerAnalyzerState GetAnalyzerState(DiagnosticAnalyzer analyzer)
var symbols = GetDeclaredSymbolsInTree(tree, compilation, getCachedSemanticModel, cancellationToken);
var compilationEvents = CreateCompilationEventsForTree(symbols.Concat(globalNs), tree, compilation);
- lock (_gate)
+ using (_gate.DisposableWait(cancellationToken))
{
if (_treesWithGeneratedSourceEvents.Contains(tree))
{
@@ -191,7 +191,7 @@ private static ImmutableArray CreateCompilationEventsForTree(I
private void GenerateSimulatedCompilationNonSourceEvent(Compilation compilation, AnalyzerDriver driver, bool started, CancellationToken cancellationToken)
{
- lock (_gate)
+ using (_gate.DisposableWait(cancellationToken))
{
var eventAlreadyGenerated = started ? _compilationStartGenerated : _compilationEndGenerated;
if (eventAlreadyGenerated)
@@ -218,7 +218,7 @@ public async Task OnCompilationEventsGeneratedAsync(ImmutableArray
/// Gets pending events for given set of analyzers for the given syntax tree.
///
- public ImmutableArray GetPendingEvents(ImmutableArray analyzers, SyntaxTree tree)
+ public ImmutableArray GetPendingEvents(ImmutableArray analyzers, SyntaxTree tree, CancellationToken cancellationToken)
{
- lock (_gate)
+ using (_gate.DisposableWait(cancellationToken))
{
return GetPendingEvents_NoLock(analyzers, tree);
}
@@ -544,9 +545,14 @@ private ImmutableArray GetPendingEvents_NoLock(ImmutableArray<
///
/// Indicates if source events (symbol declared, compilation unit completed event) should be included.
/// Indicates if compilation wide events (compilation started and completed event) should be included.
- public ImmutableArray GetPendingEvents(ImmutableArray analyzers, bool includeSourceEvents, bool includeNonSourceEvents)
+ /// Cancellation token.
+ public ImmutableArray GetPendingEvents(
+ ImmutableArray analyzers,
+ bool includeSourceEvents,
+ bool includeNonSourceEvents,
+ CancellationToken cancellationToken)
{
- lock (_gate)
+ using (_gate.DisposableWait(cancellationToken))
{
return GetPendingEvents_NoLock(analyzers, includeSourceEvents, includeNonSourceEvents);
}
@@ -628,11 +634,11 @@ public bool HasPendingSyntaxAnalysis(AnalysisScope analysisScope)
///
/// Returns true if we have any pending symbol analysis for given analysis scope.
///
- public bool HasPendingSymbolAnalysis(AnalysisScope analysisScope)
+ public bool HasPendingSymbolAnalysis(AnalysisScope analysisScope, CancellationToken cancellationToken)
{
Debug.Assert(analysisScope.FilterTreeOpt != null);
- var symbolDeclaredEvents = GetPendingSymbolDeclaredEvents(analysisScope.FilterTreeOpt);
+ var symbolDeclaredEvents = GetPendingSymbolDeclaredEvents(analysisScope.FilterTreeOpt, cancellationToken);
foreach (var symbolDeclaredEvent in symbolDeclaredEvents)
{
if (analysisScope.ShouldAnalyze(symbolDeclaredEvent.Symbol))
@@ -651,11 +657,11 @@ public bool HasPendingSymbolAnalysis(AnalysisScope analysisScope)
return false;
}
- private ImmutableArray GetPendingSymbolDeclaredEvents(SyntaxTree tree)
+ private ImmutableArray GetPendingSymbolDeclaredEvents(SyntaxTree tree, CancellationToken cancellationToken)
{
Debug.Assert(tree != null);
- lock (_gate)
+ using (_gate.DisposableWait(cancellationToken))
{
HashSet compilationEvents;
if (!_pendingSourceEvents.TryGetValue(tree, out compilationEvents))
diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs
index 044b30e837c1dcc39969f5360e640cd7bc4c190c..ac74d0e36231fb634a50383624d5156baa99b7ed 100644
--- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs
+++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/CompilationWithAnalyzers.cs
@@ -355,7 +355,7 @@ private async Task> GetAnalyzerCompilationDiagnostics
var diagnostics = ImmutableArray.Empty;
var analysisScope = new AnalysisScope(_compilation, analyzers, _analysisOptions.ConcurrentAnalysis, categorizeDiagnostics: true);
Func> getEventQueue = () =>
- GetPendingEvents(analyzers, includeSourceEvents: true, includeNonSourceEvents: true);
+ GetPendingEvents(analyzers, includeSourceEvents: true, includeNonSourceEvents: true, cancellationToken);
// Compute the analyzer diagnostics for the given analysis scope.
await ComputeAnalyzerDiagnosticsAsync(analysisScope, getEventQueue, newTaskToken: 0, cancellationToken: cancellationToken).ConfigureAwait(false);
@@ -580,18 +580,20 @@ private async Task> GetAnalyzerSemanticDiagnosticsCor
{
var pendingAnalysisScope = pendingAnalyzers.Length < analyzers.Length ? analysisScope.WithAnalyzers(pendingAnalyzers) : analysisScope;
- Func> getEventQueue = () => GetPendingEvents(analyzers, model.SyntaxTree);
+ Func> getEventQueue = () => GetPendingEvents(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
{
+ cancellationToken.ThrowIfCancellationRequested();
+
(ImmutableArray compilationEvents, bool hasSymbolStartActions) = await ComputeAnalyzerDiagnosticsAsync(pendingAnalysisScope, getEventQueue, taskToken, cancellationToken).ConfigureAwait(false);
if (hasSymbolStartActions)
{
await processPartialSymbolLocationsAsync(compilationEvents, analysisScope).ConfigureAwait(false);
}
- } while (_analysisOptions.ConcurrentAnalysis && _analysisState.HasPendingSymbolAnalysis(pendingAnalysisScope));
+ } while (_analysisOptions.ConcurrentAnalysis && _analysisState.HasPendingSymbolAnalysis(pendingAnalysisScope, cancellationToken));
if (_analysisOptions.ConcurrentAnalysis)
{
@@ -642,12 +644,24 @@ async Task processPartialSymbolLocationsAsync(ImmutableArray c
if (partialTrees != null)
{
- await Task.WhenAll(partialTrees.Select(t =>
- Task.Run(() =>
+ if (AnalysisOptions.ConcurrentAnalysis)
+ {
+ await Task.WhenAll(partialTrees.Select(tree =>
+ Task.Run(() =>
+ {
+ var treeModel = _compilationData.GetOrCreateCachedSemanticModel(tree, _compilation, cancellationToken);
+ return GetAnalyzerSemanticDiagnosticsAsync(treeModel, filterSpan: null, cancellationToken);
+ }, cancellationToken))).ConfigureAwait(false);
+ }
+ else
+ {
+ foreach (var tree in partialTrees)
{
- var treeModel = _compilationData.GetOrCreateCachedSemanticModel(t, _compilation, cancellationToken);
- return GetAnalyzerSemanticDiagnosticsAsync(treeModel, filterSpan: null, cancellationToken);
- }))).ConfigureAwait(false);
+ cancellationToken.ThrowIfCancellationRequested();
+ var treeModel = _compilationData.GetOrCreateCachedSemanticModel(tree, _compilation, cancellationToken);
+ await GetAnalyzerSemanticDiagnosticsAsync(treeModel, filterSpan: null, cancellationToken).ConfigureAwait(false);
+ }
+ }
}
}
}
@@ -1062,13 +1076,13 @@ private void ClearExecutingTask(Task computeTask, SyntaxTree treeOpt)
}
}
- private AsyncQueue GetPendingEvents(ImmutableArray analyzers, SyntaxTree tree)
+ private AsyncQueue GetPendingEvents(ImmutableArray analyzers, SyntaxTree tree, CancellationToken cancellationToken)
{
var eventQueue = _eventQueuePool.Allocate();
Debug.Assert(!eventQueue.IsCompleted);
Debug.Assert(eventQueue.Count == 0);
- foreach (var compilationEvent in _analysisState.GetPendingEvents(analyzers, tree))
+ foreach (var compilationEvent in _analysisState.GetPendingEvents(analyzers, tree, cancellationToken))
{
eventQueue.TryEnqueue(compilationEvent);
}
@@ -1076,7 +1090,11 @@ private AsyncQueue GetPendingEvents(ImmutableArray GetPendingEvents(ImmutableArray analyzers, bool includeSourceEvents, bool includeNonSourceEvents)
+ private AsyncQueue GetPendingEvents(
+ ImmutableArray analyzers,
+ bool includeSourceEvents,
+ bool includeNonSourceEvents,
+ CancellationToken cancellationToken)
{
Debug.Assert(includeSourceEvents || includeNonSourceEvents);
@@ -1084,7 +1102,7 @@ private AsyncQueue GetPendingEvents(ImmutableArray