提交 3bb47e19 编写于 作者: M Manish Vasani

Don't swallow OperationCanceledException fired with our cancellelationToken....

Don't swallow OperationCanceledException fired with our cancellelationToken. These are supposed to be handled up the stack and swallowing them would mean unnecessary computation would be done for result that would eventually be ignored.
上级 60add3c9
......@@ -25,7 +25,6 @@ internal class AnalyzerExecutor
private readonly Action<Diagnostic> _addDiagnostic;
private readonly Action<Exception, DiagnosticAnalyzer, Diagnostic> _onAnalyzerException;
private readonly CancellationToken _cancellationToken;
private readonly bool _calleeHandlesOperationCanceledException;
/// <summary>
/// Creates AnalyzerActionsExecutor to execute analyzer actions with given arguments
......@@ -45,7 +44,7 @@ internal class AnalyzerExecutor
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
CancellationToken cancellationToken)
{
return new AnalyzerExecutor(compilation, analyzerOptions, addDiagnostic, onAnalyzerException, calleeHandlesOperationCanceledException: false, cancellationToken: cancellationToken);
return new AnalyzerExecutor(compilation, analyzerOptions, addDiagnostic, onAnalyzerException, cancellationToken);
}
/// <summary>
......@@ -65,41 +64,20 @@ internal class AnalyzerExecutor
analyzerOptions: null,
addDiagnostic: null,
onAnalyzerException: onAnalyzerException,
calleeHandlesOperationCanceledException: false,
cancellationToken: cancellationToken);
}
/// <summary>
/// Returns a cloned instance of <see cref="AnalyzerExecutor"/>, except the fact that it doesn't handle <see cref="OperationCanceledException"/> for callbacks into the executor.
/// Callee of the AnalyzerExecutor methods should handle <see cref="OperationCanceledException"/>.
/// </summary>
internal AnalyzerExecutor WithCalleeHandledOperationCanceledException()
{
if (_calleeHandlesOperationCanceledException)
{
return this;
}
return new AnalyzerExecutor(
_compilation, _analyzerOptions,
_addDiagnostic, _onAnalyzerException,
calleeHandlesOperationCanceledException: true,
cancellationToken: _cancellationToken);
}
private AnalyzerExecutor(
Compilation compilation,
AnalyzerOptions analyzerOptions,
Action<Diagnostic> addDiagnostic,
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
bool calleeHandlesOperationCanceledException,
CancellationToken cancellationToken)
{
_compilation = compilation;
_analyzerOptions = analyzerOptions;
_addDiagnostic = addDiagnostic;
_onAnalyzerException = onAnalyzerException;
_calleeHandlesOperationCanceledException = calleeHandlesOperationCanceledException;
_cancellationToken = cancellationToken;
}
......@@ -383,7 +361,7 @@ public void ExecuteSyntaxTreeActions(ImmutableArray<SyntaxTreeAnalyzerAction> sy
executableNodeActions.Free();
ExecuteCodeBlockActions(blockActions, declaredNode, declaredSymbol, semanticModel);
ExecuteCodeBlockActions(blockEndActions, declaredNode, declaredSymbol, semanticModel);
ExecuteCodeBlockActions(blockEndActions, declaredNode, declaredSymbol, semanticModel);
}
private void ExecuteCodeBlockActions(PooledHashSet<CodeBlockAnalyzerAction> blockActions, SyntaxNode declaredNode, ISymbol declaredSymbol, SemanticModel semanticModel)
......@@ -468,21 +446,20 @@ internal static bool CanHaveExecutableCodeBlock(ISymbol symbol)
internal void ExecuteAndCatchIfThrows(DiagnosticAnalyzer analyzer, Action analyze)
{
ExecuteAndCatchIfThrows(analyzer, analyze, _onAnalyzerException, _calleeHandlesOperationCanceledException, _cancellationToken);
ExecuteAndCatchIfThrows(analyzer, analyze, _onAnalyzerException, _cancellationToken);
}
private static void ExecuteAndCatchIfThrows(
DiagnosticAnalyzer analyzer,
Action analyze,
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
bool calleeHandlesOperationCanceledException,
CancellationToken cancellationToken)
{
try
{
analyze();
}
catch (Exception e) when (!IsOperationCanceledThatShouldNotBeHandled(e, calleeHandlesOperationCanceledException, cancellationToken))
catch (Exception e) when (!IsCanceled(e, cancellationToken))
{
// Diagnostic for analyzer exception.
var diagnostic = GetAnalyzerExceptionDiagnostic(analyzer, e);
......@@ -490,21 +467,11 @@ internal void ExecuteAndCatchIfThrows(DiagnosticAnalyzer analyzer, Action analyz
}
}
internal static bool IsOperationCanceledThatShouldNotBeHandled(Exception ex, bool calleeHandlesOperationCanceledException, CancellationToken cancellationToken)
internal static bool IsCanceled(Exception ex, CancellationToken cancellationToken)
{
var operationCanceled = ex as OperationCanceledException;
if (operationCanceled == null)
{
return false;
}
// 1) Don't swallow operation canceled exceptions fired for our cancellation token.
// 2) Don't handle operation canceled if the callee explicitly wants to handle it in a custom way.
return operationCanceled.CancellationToken == cancellationToken || calleeHandlesOperationCanceledException;
return (ex as OperationCanceledException)?.CancellationToken == cancellationToken;
}
internal static Diagnostic GetAnalyzerExceptionDiagnostic(DiagnosticAnalyzer analyzer, Exception e)
{
var descriptor = new DiagnosticDescriptor(AnalyzerExceptionDiagnosticId,
......
......@@ -77,8 +77,6 @@ internal partial class AnalyzerManager
{
var analyzerAndOptions = new AnalyzerAndOptions(analyzer, analyzerExecutor.AnalyzerOptions);
analyzerExecutor = analyzerExecutor.WithCalleeHandledOperationCanceledException();
try
{
return await GetCompilationAnalysisScopeCoreAsync(analyzerAndOptions, sessionScope, analyzerExecutor).ConfigureAwait(false);
......@@ -118,8 +116,6 @@ internal partial class AnalyzerManager
DiagnosticAnalyzer analyzer,
AnalyzerExecutor analyzerExecutor)
{
analyzerExecutor = analyzerExecutor.WithCalleeHandledOperationCanceledException();
try
{
return await GetSessionAnalysisScopeCoreAsync(analyzer, analyzerExecutor).ConfigureAwait(false);
......
......@@ -260,7 +260,7 @@ public async Task<ImmutableArray<Diagnostic>> GetSyntaxDiagnosticsAsync(Diagnost
await documentAnalyzer.AnalyzeSyntaxAsync(_document, diagnostics.Add, _cancellationToken).ConfigureAwait(false);
return diagnostics.ToImmutableArrayOrEmpty();
}
catch (Exception e) when (!IsCanceled(e, _cancellationToken))
catch (Exception e) when (!AnalyzerExecutor.IsCanceled(e, _cancellationToken))
{
OnAnalyzerException(e, analyzer, compilation);
return ImmutableArray<Diagnostic>.Empty;
......@@ -307,11 +307,6 @@ private IEnumerable<Diagnostic> GetFilteredDocumentDiagnosticsCore(IEnumerable<D
: CompilationWithAnalyzers.GetEffectiveDiagnostics(diagsFilteredByLocation, compilation);
}
private static bool IsCanceled(Exception ex, CancellationToken cancellationToken)
{
return (ex as OperationCanceledException)?.CancellationToken == cancellationToken;
}
internal void OnAnalyzerException(Exception ex, DiagnosticAnalyzer analyzer, Compilation compilation)
{
var exceptionDiagnostic = AnalyzerExecutor.GetAnalyzerExceptionDiagnostic(analyzer, ex);
......@@ -380,7 +375,7 @@ public async Task<ImmutableArray<Diagnostic>> GetSemanticDiagnosticsAsync(Diagno
{
await documentAnalyzer.AnalyzeSemanticsAsync(_document, diagnostics.Add, _cancellationToken).ConfigureAwait(false);
}
catch (Exception e) when (!IsCanceled(e, _cancellationToken))
catch (Exception e) when (!AnalyzerExecutor.IsCanceled(e, _cancellationToken))
{
OnAnalyzerException(e, analyzer, compilation);
return ImmutableArray<Diagnostic>.Empty;
......@@ -456,7 +451,7 @@ private async Task GetProjectDiagnosticsWorkerAsync(DiagnosticAnalyzer analyzer,
{
await projectAnalyzer.AnalyzeProjectAsync(_project, diagnostics.Add, _cancellationToken).ConfigureAwait(false);
}
catch (Exception e) when (!IsCanceled(e, _cancellationToken))
catch (Exception e) when (!AnalyzerExecutor.IsCanceled(e, _cancellationToken))
{
var compilation = await _project.GetCompilationAsync(_cancellationToken).ConfigureAwait(false);
OnAnalyzerException(e, analyzer, compilation);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册