提交 98ba9f79 编写于 作者: M Manish Vasani

Change AnalyzerException delegate from Func to Action.

上级 65532e93
......@@ -87,7 +87,7 @@ public void AnalyzerDriverIsSafeAgainstAnalyzerExceptions()
{
var compilation = CreateCompilationWithMscorlib45(TestResource.AllInOneCSharpCode, parseOptions: TestOptions.Regular);
ThrowingDiagnosticAnalyzer<SyntaxKind>.VerifyAnalyzerEngineIsSafeAgainstExceptions(analyzer =>
compilation.GetAnalyzerDiagnostics(new[] { analyzer }, null, CodeAnalysis.DiagnosticExtensions.AlwaysCatchAnalyzerExceptions));
compilation.GetAnalyzerDiagnostics(new[] { analyzer }, null, CodeAnalysis.DiagnosticExtensions.AlwaysCatchAnalyzerException));
}
[Fact]
......
......@@ -22,8 +22,7 @@ internal class AnalyzerExecutor
private readonly Compilation _compilation;
private readonly AnalyzerOptions _analyzerOptions;
private readonly Action<Diagnostic> _addDiagnostic;
private readonly Action<Diagnostic> _addExceptionDiagnostic;
private readonly Func<Exception, DiagnosticAnalyzer, bool> _continueOnAnalyzerException;
private readonly Action<Exception, DiagnosticAnalyzer, Diagnostic> _onAnalyzerException;
private readonly CancellationToken _cancellationToken;
/// <summary>
......@@ -32,45 +31,38 @@ internal class AnalyzerExecutor
/// <param name="compilation">Compilation to be used in the analysis.</param>
/// <param name="analyzerOptions">Analyzer options.</param>
/// <param name="addDiagnostic">Delegate to add analyzer diagnostics.</param>
/// <param name="addExceptionDiagnostic">Delegate to add diagnostics generated for handled exceptions from third party analyzers.</param>
/// <param name="continueOnAnalyzerException">Delegate which is invoked when an analyzer throws an exception.
/// If a non-null delegate is provided and it returns true, then the exception is handled and converted into a diagnostic and driver continues with other analyzers.
/// Otherwise if it returns false, then the exception is not handled by the executor.
/// If null, then the executor always handles the exception.
/// <param name="onAnalyzerException">
/// Optional delegate which is invoked when an analyzer throws an exception.
/// Delegate can do custom tasks such as report the given analyzer exception diagnostic, report a non-fatal watson for the exception, etc.
/// </param>
/// <param name="cancellationToken">Cancellation token.</param>
public static AnalyzerExecutor Create(
Compilation compilation,
AnalyzerOptions analyzerOptions,
Action<Diagnostic> addDiagnostic,
Action<Diagnostic> addExceptionDiagnostic,
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
CancellationToken cancellationToken)
{
return new AnalyzerExecutor(compilation, analyzerOptions, addDiagnostic, addExceptionDiagnostic, continueOnAnalyzerException, cancellationToken);
return new AnalyzerExecutor(compilation, analyzerOptions, addDiagnostic, onAnalyzerException, cancellationToken);
}
/// <summary>
/// Creates AnalyzerActionsExecutor to fetch <see cref="DiagnosticAnalyzer.SupportedDiagnostics"/>.
/// </summary>
/// <param name="addExceptionDiagnostic">Delegate to add diagnostics generated for handled exceptions from third party analyzers.</param>
/// <param name="continueOnAnalyzerException">Delegate which is invoked when an analyzer throws an exception.
/// If a non-null delegate is provided and it returns true, then the exception is handled and converted into a diagnostic and driver continues with other analyzers.
/// Otherwise if it returns false, then the exception is not handled by the executor.
/// If null, then the executor always handles the exception.
/// <param name="onAnalyzerException">
/// Optional delegate which is invoked when an analyzer throws an exception.
/// Delegate can do custom tasks such as report the given analyzer exception diagnostic, report a non-fatal watson for the exception, etc.
/// </param>
/// <param name="cancellationToken">Cancellation token.</param>
public static AnalyzerExecutor CreateForSupportedDiagnostics(
Action<Diagnostic> addExceptionDiagnostic,
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
CancellationToken cancellationToken)
{
return new AnalyzerExecutor(
compilation: null,
analyzerOptions: null,
addDiagnostic: null,
addExceptionDiagnostic: addExceptionDiagnostic,
continueOnAnalyzerException: continueOnAnalyzerException,
onAnalyzerException: onAnalyzerException,
cancellationToken: cancellationToken);
}
......@@ -78,15 +70,13 @@ internal class AnalyzerExecutor
Compilation compilation,
AnalyzerOptions analyzerOptions,
Action<Diagnostic> addDiagnostic,
Action<Diagnostic> addExceptionDiagnostic,
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
CancellationToken cancellationToken)
{
this._compilation = compilation;
this._analyzerOptions = analyzerOptions;
this._addDiagnostic = addDiagnostic;
this._addExceptionDiagnostic = addExceptionDiagnostic;
this._continueOnAnalyzerException = continueOnAnalyzerException;
this._onAnalyzerException = onAnalyzerException;
this._cancellationToken = cancellationToken;
}
......@@ -450,34 +440,33 @@ internal static bool CanHaveExecutableCodeBlock(ISymbol symbol)
internal void ExecuteAndCatchIfThrows(DiagnosticAnalyzer analyzer, Action analyze)
{
ExecuteAndCatchIfThrows(analyzer, analyze, _addExceptionDiagnostic, _continueOnAnalyzerException, _cancellationToken);
ExecuteAndCatchIfThrows(analyzer, analyze, _onAnalyzerException, _cancellationToken);
}
private static void ExecuteAndCatchIfThrows(
DiagnosticAnalyzer analyzer,
Action analyze,
Action<Diagnostic> addExceptionDiagnostic,
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
CancellationToken cancellationToken)
{
try
{
analyze();
}
catch (OperationCanceledException oce) when (continueOnAnalyzerException(oce, analyzer))
catch (OperationCanceledException oce)
{
if (oce.CancellationToken != cancellationToken)
{
// Add diagnostic for analyzer exception.
// Diagnostic for analyzer exception.
var diagnostic = GetAnalyzerDiagnostic(analyzer, oce);
addExceptionDiagnostic(diagnostic);
onAnalyzerException(oce, analyzer, diagnostic);
}
}
catch (Exception e) when (continueOnAnalyzerException(e, analyzer))
catch (Exception e)
{
// Add diagnostic for analyzer exception.
// Diagnostic for analyzer exception.
var diagnostic = GetAnalyzerDiagnostic(analyzer, e);
addExceptionDiagnostic(diagnostic);
onAnalyzerException(e, analyzer, diagnostic);
}
}
......
......@@ -1108,8 +1108,6 @@ End Class
[Fact]
public void SuppressDuplicateAnalyzerExceptionDiagnostics()
{
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException = (ex, a) => true;
VerifyCSharp(@"
public class C
{
......@@ -1122,7 +1120,7 @@ public class C2
}
",
new[] { new ThrowExceptionForEachNamedTypeAnalyzer() },
continueOnAnalyzerException,
DiagnosticExtensions.AlwaysCatchAnalyzerException,
Diagnostic("AD0001", null).WithLocation(1, 1));
}
......@@ -1133,9 +1131,9 @@ protected void VerifyCSharp(string source, DiagnosticAnalyzer[] analyzers, param
Verify(source, LanguageNames.CSharp, analyzers, diagnostics);
}
protected void VerifyCSharp(string source, DiagnosticAnalyzer[] analyzers, Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException, params DiagnosticDescription[] diagnostics)
protected void VerifyCSharp(string source, DiagnosticAnalyzer[] analyzers, Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException, params DiagnosticDescription[] diagnostics)
{
Verify(source, LanguageNames.CSharp, analyzers, diagnostics, continueOnAnalyzerException);
Verify(source, LanguageNames.CSharp, analyzers, diagnostics, onAnalyzerException);
}
protected void VerifyTokenDiagnosticsCSharp(string markup, params DiagnosticDescription[] diagnostics)
......@@ -1146,7 +1144,7 @@ protected void VerifyTokenDiagnosticsCSharp(string markup, params DiagnosticDesc
protected void VerifyBasic(string source, string rootNamespace, DiagnosticAnalyzer[] analyzers, params DiagnosticDescription[] diagnostics)
{
Assert.False(string.IsNullOrWhiteSpace(rootNamespace), string.Format("Invalid root namespace '{0}'", rootNamespace));
Verify(source, LanguageNames.VisualBasic, analyzers, diagnostics, continueOnAnalyzerException: null, rootNamespace: rootNamespace);
Verify(source, LanguageNames.VisualBasic, analyzers, diagnostics, onAnalyzerException: null, rootNamespace: rootNamespace);
}
protected void VerifyBasic(string source, DiagnosticAnalyzer[] analyzers, params DiagnosticDescription[] diagnostics)
......@@ -1154,9 +1152,9 @@ protected void VerifyBasic(string source, DiagnosticAnalyzer[] analyzers, params
Verify(source, LanguageNames.VisualBasic, analyzers, diagnostics);
}
protected void VerifyBasic(string source, DiagnosticAnalyzer[] analyzers, Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException, params DiagnosticDescription[] diagnostics)
protected void VerifyBasic(string source, DiagnosticAnalyzer[] analyzers, Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException, params DiagnosticDescription[] diagnostics)
{
Verify(source, LanguageNames.VisualBasic, analyzers, diagnostics, continueOnAnalyzerException);
Verify(source, LanguageNames.VisualBasic, analyzers, diagnostics, onAnalyzerException);
}
protected void VerifyTokenDiagnosticsBasic(string markup, params DiagnosticDescription[] diagnostics)
......@@ -1164,11 +1162,11 @@ protected void VerifyTokenDiagnosticsBasic(string markup, params DiagnosticDescr
VerifyTokenDiagnostics(markup, LanguageNames.VisualBasic, diagnostics);
}
protected virtual void Verify(string source, string language, DiagnosticAnalyzer[] analyzers, DiagnosticDescription[] diagnostics, Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException = null, string rootNamespace = null)
protected virtual void Verify(string source, string language, DiagnosticAnalyzer[] analyzers, DiagnosticDescription[] diagnostics, Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null, string rootNamespace = null)
{
Assert.True(analyzers != null && analyzers.Length > 0, "Must specify at least one diagnostic analyzer to test suppression");
var compilation = CreateCompilation(source, language, analyzers, rootNamespace);
compilation.VerifyAnalyzerDiagnostics(analyzers, continueOnAnalyzerException: continueOnAnalyzerException, expected: diagnostics);
compilation.VerifyAnalyzerDiagnostics(analyzers, onAnalyzerException: onAnalyzerException, expected: diagnostics);
}
// Generate a diagnostic on every token in the specified spans, and verify that only the specified diagnostics are not suppressed
......
......@@ -150,7 +150,7 @@ private Task ExecuteSyntaxTreeActions(CancellationToken cancellationToken)
public static AnalyzerDriver Create(
Compilation compilation,
ImmutableArray<DiagnosticAnalyzer> analyzers,
AnalyzerOptions options,
AnalyzerOptions options,
AnalyzerManager analyzerManager,
Action<Diagnostic> addExceptionDiagnostic,
out Compilation newCompilation,
......@@ -171,7 +171,14 @@ private Task ExecuteSyntaxTreeActions(CancellationToken cancellationToken)
throw new ArgumentException(CodeAnalysisResources.ArgumentElementCannotBeNull, nameof(analyzers));
}
return Create(compilation, analyzers, options, analyzerManager, addExceptionDiagnostic, out newCompilation, continueOnAnalyzerException: null, cancellationToken: cancellationToken);
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = (ex, analyzer, diagnostic) =>
{
if (addExceptionDiagnostic != null)
{
addExceptionDiagnostic(diagnostic);
}
};
return Create(compilation, analyzers, options, analyzerManager, onAnalyzerException, out newCompilation, cancellationToken: cancellationToken);
}
// internal for testing purposes
......@@ -180,21 +187,30 @@ private Task ExecuteSyntaxTreeActions(CancellationToken cancellationToken)
ImmutableArray<DiagnosticAnalyzer> analyzers,
AnalyzerOptions options,
AnalyzerManager analyzerManager,
Action<Diagnostic> addExceptionDiagnostic,
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
out Compilation newCompilation,
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
CancellationToken cancellationToken)
{
options = options ?? AnalyzerOptions.Empty;
AnalyzerDriver analyzerDriver = compilation.AnalyzerForLanguage(analyzers, analyzerManager, cancellationToken);
newCompilation = compilation.WithEventQueue(analyzerDriver.CompilationEventQueue);
continueOnAnalyzerException = continueOnAnalyzerException ?? ((exception, analyzer) => true);
var addDiagnostic = GetDiagnosticSinkWithSuppression(analyzerDriver.DiagnosticQueue.Enqueue, newCompilation);
addExceptionDiagnostic = addExceptionDiagnostic != null ?
GetDiagnosticSinkWithSuppression(addExceptionDiagnostic, newCompilation) :
addDiagnostic;
var analyzerExecutor = AnalyzerExecutor.Create(newCompilation, options, addDiagnostic, addExceptionDiagnostic, continueOnAnalyzerException, cancellationToken);
if (onAnalyzerException != null)
{
// Wrap onAnalyzerException to pass in filtered diagnostic.
var comp = newCompilation;
onAnalyzerException = (ex, analyzer, diagnostic) =>
onAnalyzerException(ex, analyzer, GetFilteredDiagnostic(diagnostic, comp));
}
else
{
// Add exception diagnostic to regular diagnostic bag.
onAnalyzerException = (ex, analyzer, diagnostic) => addDiagnostic(diagnostic);
}
var analyzerExecutor = AnalyzerExecutor.Create(newCompilation, options, addDiagnostic, onAnalyzerException, cancellationToken);
analyzerDriver.Initialize(newCompilation, analyzerExecutor, cancellationToken);
......@@ -515,18 +531,29 @@ internal static Action<Diagnostic> GetDiagnosticSinkWithSuppression(Action<Diagn
{
return diagnostic =>
{
var filteredDiagnostic = compilation.FilterDiagnostic(diagnostic);
var filteredDiagnostic = GetFilteredDiagnostic(diagnostic, compilation, symbolOpt);
if (filteredDiagnostic != null)
{
var suppressMessageState = SuppressMessageStateByCompilation.GetValue(compilation, (c) => new SuppressMessageAttributeState(c));
if (!suppressMessageState.IsDiagnosticSuppressed(filteredDiagnostic, symbolOpt: symbolOpt))
{
addDiagnosticCore(filteredDiagnostic);
}
addDiagnosticCore(filteredDiagnostic);
}
};
}
private static Diagnostic GetFilteredDiagnostic(Diagnostic diagnostic, Compilation compilation, ISymbol symbolOpt = null)
{
var filteredDiagnostic = compilation.FilterDiagnostic(diagnostic);
if (filteredDiagnostic != null)
{
var suppressMessageState = SuppressMessageStateByCompilation.GetValue(compilation, (c) => new SuppressMessageAttributeState(c));
if (suppressMessageState.IsDiagnosticSuppressed(filteredDiagnostic, symbolOpt: symbolOpt))
{
return null;
}
}
return filteredDiagnostic;
}
private static Task<AnalyzerActions> GetAnalyzerActionsAsync(
ImmutableArray<DiagnosticAnalyzer> analyzers,
AnalyzerManager analyzerManager,
......
......@@ -99,9 +99,14 @@ public static IEnumerable<Diagnostic> GetEffectiveDiagnostics(IEnumerable<Diagno
/// <summary>
/// Returns true if all the diagnostics that can be produced by this analyzer are suppressed through options.
/// <paramref name="continueOnAnalyzerException"/> says whether the caller would like the exception thrown by the analyzers to be handled or not. If true - Handles ; False - Not handled.
/// <param name="analyzer">Analyzer to be checked for suppression.</param>
/// <param name="options">Compilation options.</param>
/// <param name="onAnalyzerException">
/// Optional delegate which is invoked when an analyzer throws an exception.
/// Delegate can do custom tasks such as report the given analyzer exception diagnostic, report a non-fatal watson for the exception, etc.
/// </param>
/// </summary>
public static bool IsDiagnosticAnalyzerSuppressed(DiagnosticAnalyzer analyzer, CompilationOptions options, Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException)
public static bool IsDiagnosticAnalyzerSuppressed(DiagnosticAnalyzer analyzer, CompilationOptions options, Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null)
{
if (analyzer == null)
{
......@@ -113,14 +118,9 @@ public static bool IsDiagnosticAnalyzerSuppressed(DiagnosticAnalyzer analyzer, C
throw new ArgumentNullException(nameof(options));
}
if (continueOnAnalyzerException == null)
{
throw new ArgumentNullException(nameof(continueOnAnalyzerException));
}
// TODO: Public API change to surface exception diagnostics?
Action<Diagnostic> addExceptionDiagnostic = diagnostic => { };
var analyzerExecutor = AnalyzerExecutor.CreateForSupportedDiagnostics(addExceptionDiagnostic, continueOnAnalyzerException, CancellationToken.None);
Action<Exception, DiagnosticAnalyzer, Diagnostic> voidHandler = (ex, a, diag) => { };
onAnalyzerException = onAnalyzerException ?? voidHandler;
var analyzerExecutor = AnalyzerExecutor.CreateForSupportedDiagnostics(onAnalyzerException, CancellationToken.None);
return AnalyzerDriver.IsDiagnosticAnalyzerSuppressed(analyzer, options, AnalyzerManager.Instance, analyzerExecutor);
}
......
......@@ -1900,7 +1900,7 @@ static Microsoft.CodeAnalysis.Diagnostic.Create(Microsoft.CodeAnalysis.Diagnosti
static Microsoft.CodeAnalysis.Diagnostic.Create(Microsoft.CodeAnalysis.DiagnosticDescriptor descriptor, Microsoft.CodeAnalysis.Location location, params object[] messageArgs)
static Microsoft.CodeAnalysis.Diagnostic.Create(string id, string category, Microsoft.CodeAnalysis.LocalizableString message, Microsoft.CodeAnalysis.DiagnosticSeverity severity, Microsoft.CodeAnalysis.DiagnosticSeverity defaultSeverity, bool isEnabledByDefault, int warningLevel, Microsoft.CodeAnalysis.LocalizableString title = null, Microsoft.CodeAnalysis.LocalizableString description = null, string helpLink = null, Microsoft.CodeAnalysis.Location location = null, System.Collections.Generic.IEnumerable<Microsoft.CodeAnalysis.Location> additionalLocations = null, System.Collections.Generic.IEnumerable<string> customTags = null, System.Collections.Immutable.ImmutableDictionary<string, string> properties = null)
static Microsoft.CodeAnalysis.Diagnostics.CompilationWithAnalyzers.GetEffectiveDiagnostics(System.Collections.Generic.IEnumerable<Microsoft.CodeAnalysis.Diagnostic> diagnostics, Microsoft.CodeAnalysis.Compilation compilation)
static Microsoft.CodeAnalysis.Diagnostics.CompilationWithAnalyzers.IsDiagnosticAnalyzerSuppressed(Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer analyzer, Microsoft.CodeAnalysis.CompilationOptions options, System.Func<System.Exception, Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer, bool> continueOnAnalyzerException)
static Microsoft.CodeAnalysis.Diagnostics.CompilationWithAnalyzers.IsDiagnosticAnalyzerSuppressed(Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer analyzer, Microsoft.CodeAnalysis.CompilationOptions options, System.Action<System.Exception, Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer, Microsoft.CodeAnalysis.Diagnostic> onAnalyzerException = null)
static Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzerExtensions.WithAnalyzers(this Microsoft.CodeAnalysis.Compilation compilation, System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer> analyzers, Microsoft.CodeAnalysis.Diagnostics.AnalyzerOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken))
static Microsoft.CodeAnalysis.Emit.EditAndContinueMethodDebugInformation.Create(System.Collections.Immutable.ImmutableArray<byte> compressedSlotMap, System.Collections.Immutable.ImmutableArray<byte> compressedLambdaMap)
static Microsoft.CodeAnalysis.Emit.EmitBaseline.CreateInitialBaseline(Microsoft.CodeAnalysis.ModuleMetadata module, System.Func<System.Reflection.Metadata.MethodDefinitionHandle, Microsoft.CodeAnalysis.Emit.EditAndContinueMethodDebugInformation> debugInformationProvider)
......@@ -2017,8 +2017,8 @@ static Microsoft.CodeAnalysis.Text.LinePosition.operator >=(Microsoft.CodeAnalys
static Microsoft.CodeAnalysis.Text.LinePositionSpan.operator !=(Microsoft.CodeAnalysis.Text.LinePositionSpan left, Microsoft.CodeAnalysis.Text.LinePositionSpan right)
static Microsoft.CodeAnalysis.Text.LinePositionSpan.operator ==(Microsoft.CodeAnalysis.Text.LinePositionSpan left, Microsoft.CodeAnalysis.Text.LinePositionSpan right)
static Microsoft.CodeAnalysis.Text.SourceText.CalculateChecksum(byte[] buffer, int offset, int count, Microsoft.CodeAnalysis.Text.SourceHashAlgorithm algorithmId)
static Microsoft.CodeAnalysis.Text.SourceText.From(byte[] buffer, int length, System.Text.Encoding encoding = null, Microsoft.CodeAnalysis.Text.SourceHashAlgorithm checksumAlgorithm = Microsoft.CodeAnalysis.Text.SourceHashAlgorithm.Sha1, bool throwIfBinaryDetected = false)
static Microsoft.CodeAnalysis.Text.SourceText.From(System.IO.Stream stream, System.Text.Encoding encoding = null, Microsoft.CodeAnalysis.Text.SourceHashAlgorithm checksumAlgorithm = Microsoft.CodeAnalysis.Text.SourceHashAlgorithm.Sha1, bool throwIfBinaryDetected = false)
static Microsoft.CodeAnalysis.Text.SourceText.From(byte[] buffer, int length, System.Text.Encoding encoding = null, Microsoft.CodeAnalysis.Text.SourceHashAlgorithm checksumAlgorithm = Microsoft.CodeAnalysis.Text.SourceHashAlgorithm.Sha1, bool throwIfBinaryDetected = false)
static Microsoft.CodeAnalysis.Text.SourceText.From(string text, System.Text.Encoding encoding = null, Microsoft.CodeAnalysis.Text.SourceHashAlgorithm checksumAlgorithm = Microsoft.CodeAnalysis.Text.SourceHashAlgorithm.Sha1)
static Microsoft.CodeAnalysis.Text.TextChange.implicit operator Microsoft.CodeAnalysis.Text.TextChangeRange(Microsoft.CodeAnalysis.Text.TextChange change)
static Microsoft.CodeAnalysis.Text.TextChange.operator !=(Microsoft.CodeAnalysis.Text.TextChange left, Microsoft.CodeAnalysis.Text.TextChange right)
......@@ -2067,8 +2067,8 @@ virtual Microsoft.CodeAnalysis.Location.MetadataModule.get
virtual Microsoft.CodeAnalysis.Location.SourceSpan.get
virtual Microsoft.CodeAnalysis.Location.SourceTree.get
virtual Microsoft.CodeAnalysis.MetadataReference.Display.get
virtual Microsoft.CodeAnalysis.SemanticModel.IgnoresAccessibility.get
virtual Microsoft.CodeAnalysis.SemanticModel.GetTopmostNodeForDiagnosticAnalysis(Microsoft.CodeAnalysis.ISymbol symbol, Microsoft.CodeAnalysis.SyntaxNode declaringSyntax)
virtual Microsoft.CodeAnalysis.SemanticModel.IgnoresAccessibility.get
virtual Microsoft.CodeAnalysis.SymbolVisitor.DefaultVisit(Microsoft.CodeAnalysis.ISymbol symbol)
virtual Microsoft.CodeAnalysis.SymbolVisitor.Visit(Microsoft.CodeAnalysis.ISymbol symbol)
virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitAlias(Microsoft.CodeAnalysis.IAliasSymbol symbol)
......
......@@ -43,7 +43,7 @@ End Enum
Public Sub AnalyzerDriverIsSafeAgainstAnalyzerExceptions()
Dim compilation = CreateCompilationWithMscorlib({TestResource.AllInOneVisualBasicCode})
ThrowingDiagnosticAnalyzer(Of SyntaxKind).VerifyAnalyzerEngineIsSafeAgainstExceptions(
Function(analyzer) compilation.GetAnalyzerDiagnostics({analyzer}, Nothing, DiagnosticExtensions.AlwaysCatchAnalyzerExceptions))
Function(analyzer) compilation.GetAnalyzerDiagnostics({analyzer}, Nothing, DiagnosticExtensions.AlwaysCatchAnalyzerException))
End Sub
<Fact>
......
......@@ -44,7 +44,7 @@ public class Class6<TTypeParameter>
";
var diagnosticsBag = DiagnosticBag.GetInstance();
var documentsAndSpan = GetDocumentsAndSpans(new[] { source }, LanguageNames.CSharp);
AnalyzeDocumentCore(GetCSharpDiagnosticAnalyzer(), documentsAndSpan.Item1[0], diagnosticsBag.Add, null, continueOnAnalyzerException: DiagnosticExtensions.AlwaysCatchAnalyzerExceptions);
AnalyzeDocumentCore(GetCSharpDiagnosticAnalyzer(), documentsAndSpan.Item1[0], diagnosticsBag.Add, null, onAnalyzerException: DiagnosticExtensions.AlwaysCatchAnalyzerException);
var diagnostics = diagnosticsBag.ToReadOnlyAndFree();
Assert.True(diagnostics.Length > 0);
Assert.Equal(string.Format("info AD0001: " + AnalyzerDriverResources.AnalyzerThrows, GetCSharpDiagnosticAnalyzer().GetType(), "The method or operation is not implemented."),
......
......@@ -355,13 +355,13 @@ private static Compilation EnableAnalyzer(DiagnosticAnalyzer analyzer, Compilati
.ToImmutableDictionaryOrEmpty()));
}
protected static void AnalyzeDocumentCore(DiagnosticAnalyzer analyzer, Document document, Action<Diagnostic> addDiagnostic, TextSpan? span = null, Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException = null)
protected static void AnalyzeDocumentCore(DiagnosticAnalyzer analyzer, Document document, Action<Diagnostic> addDiagnostic, TextSpan? span = null, Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null)
{
var semanticModel = document.GetSemanticModelAsync().Result;
var compilation = semanticModel.Compilation;
compilation = EnableAnalyzer(analyzer, compilation);
var diagnostics = compilation.GetAnalyzerDiagnostics(new[] { analyzer }, continueOnAnalyzerException: continueOnAnalyzerException);
var diagnostics = compilation.GetAnalyzerDiagnostics(new[] { analyzer }, onAnalyzerException: onAnalyzerException);
foreach (var diagnostic in diagnostics)
{
if (!span.HasValue ||
......
......@@ -49,7 +49,7 @@ private static IEnumerable<Diagnostic> GetDiagnostics(DiagnosticAnalyzer analyze
syntaxNodeAnalyzerService: nodeInBodyAnalyzerService,
hostDiagnosticUpdateSource: exceptionDiagnosticsSource,
cancellationToken: CancellationToken.None,
testOnly_DonotCatchAnalyzerExceptions: donotCatchAnalyzerExceptions);
testOnly_RethrowAnalyzerException: donotCatchAnalyzerExceptions);
var diagnosticAnalyzerCategory = analyzer.GetDiagnosticAnalyzerCategory(driver);
bool supportsSemanticInSpan = (diagnosticAnalyzerCategory & DiagnosticAnalyzerCategory.SemanticSpanAnalysis) != 0;
if (supportsSemanticInSpan)
......
......@@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.UnitTests.Diagnostics
{
public class SuppressMessageAttributeWorkspaceTests : SuppressMessageAttributeTests
{
protected override void Verify(string source, string language, DiagnosticAnalyzer[] analyzers, DiagnosticDescription[] expectedDiagnostics, Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException = null, string rootNamespace = null)
protected override void Verify(string source, string language, DiagnosticAnalyzer[] analyzers, DiagnosticDescription[] expectedDiagnostics, Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null, string rootNamespace = null)
{
using (var workspace = CreateWorkspaceFromFile(source, language, rootNamespace))
{
......@@ -24,7 +24,7 @@ protected override void Verify(string source, string language, DiagnosticAnalyze
var actualDiagnostics = new List<Diagnostic>();
foreach (var analyzer in analyzers)
{
actualDiagnostics.AddRange(DiagnosticProviderTestUtilities.GetAllDiagnostics(analyzer, document, span, donotCatchAnalyzerExceptions: continueOnAnalyzerException == null));
actualDiagnostics.AddRange(DiagnosticProviderTestUtilities.GetAllDiagnostics(analyzer, document, span, donotCatchAnalyzerExceptions: onAnalyzerException == null));
}
actualDiagnostics.Verify(expectedDiagnostics);
......
......@@ -34,43 +34,41 @@ public static bool IsCompilerAnalyzer(DiagnosticAnalyzer analyzer)
return false;
}
public static Action<Diagnostic> GetAddExceptionDiagnosticDelegate(DiagnosticAnalyzer analyzer, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource, Project project)
internal static AnalyzerExecutor GetAnalyzerExecutorForSupportedDiagnostics(
DiagnosticAnalyzer analyzer,
AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource,
CancellationToken cancellationToken = default(CancellationToken))
{
return diagnostic =>
hostDiagnosticUpdateSource?.ReportAnalyzerDiagnostic(analyzer, diagnostic, project.Solution.Workspace, project);
}
// Skip telemetry logging if the exception is thrown as we are computing supported diagnostics and
// we can't determine if any descriptors support getting telemetry without having the descriptors.
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = (ex, a, diagnostic) =>
OnAnalyzerException_NoTelemetryLogging(ex, a, diagnostic, hostDiagnosticUpdateSource);
public static Action<Diagnostic> GetAddExceptionDiagnosticDelegate(DiagnosticAnalyzer analyzer, AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource, Workspace workspace)
{
return diagnostic =>
hostDiagnosticUpdateSource?.ReportAnalyzerDiagnostic(analyzer, diagnostic, workspace, null);
return AnalyzerExecutor.CreateForSupportedDiagnostics(onAnalyzerException, cancellationToken);
}
public static AnalyzerExecutor GetAnalyzerExecutorForSupportedDiagnostics(
DiagnosticAnalyzer analyzer,
internal static void OnAnalyzerException_NoTelemetryLogging(
Exception e,
DiagnosticAnalyzer analyzer,
Diagnostic diagnostic,
AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource,
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
CancellationToken cancellationToken)
Project projectOpt = null,
bool testOnly_RethrowAnalyzerException = false)
{
var addExceptionDiagnostic = GetAddExceptionDiagnosticDelegate(analyzer, hostDiagnosticUpdateSource, hostDiagnosticUpdateSource?.Workspace);
if (diagnostic != null)
{
hostDiagnosticUpdateSource?.ReportAnalyzerDiagnostic(analyzer, diagnostic, hostDiagnosticUpdateSource?.Workspace, projectOpt);
}
// Skip telemetry logging if the exception is thrown as we are computing supported diagnostics and
// we can't determine if any descriptors support getting telemetry without having the descriptors.
return AnalyzerExecutor.CreateForSupportedDiagnostics(addExceptionDiagnostic, continueOnAnalyzerException, cancellationToken);
}
public static AnalyzerExecutor GetAnalyzerExecutor(
DiagnosticAnalyzer analyzer,
AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource,
Project project,
Compilation compilation,
Action<Diagnostic> addDiagnostic,
AnalyzerOptions analyzerOptions,
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
CancellationToken cancellationToken)
{
var addExceptionDiagnostic = GetAddExceptionDiagnosticDelegate(analyzer, hostDiagnosticUpdateSource, project);
return AnalyzerExecutor.Create(compilation, analyzerOptions, addDiagnostic, addExceptionDiagnostic, continueOnAnalyzerException, cancellationToken);
if (testOnly_RethrowAnalyzerException)
{
throw e;
}
if (IsBuiltInAnalyzer(analyzer))
{
FatalError.ReportWithoutCrashUnlessCanceled(e);
}
}
}
}
\ No newline at end of file
......@@ -34,7 +34,7 @@ internal class DiagnosticAnalyzerDriver
private readonly ISyntaxFactsService _syntaxFacts;
private readonly IGeneratedCodeRecognitionService _generatedCodeService;
private readonly IAnalyzerDriverService _analyzerDriverService;
private readonly bool _testOnly_DonotCatchAnalyzerExceptions;
private readonly bool _testOnly_RethrowAnalyzerException;
private LogAggregator _logAggregator;
......@@ -64,7 +64,7 @@ public DiagnosticAnalyzerDriver(Project project, LogAggregator logAggregator, Ab
ISyntaxNodeAnalyzerService syntaxNodeAnalyzerService,
AbstractHostDiagnosticUpdateSource hostDiagnosticUpdateSource,
CancellationToken cancellationToken,
bool testOnly_DonotCatchAnalyzerExceptions = false)
bool testOnly_RethrowAnalyzerException = false)
{
_document = document;
_span = span;
......@@ -78,7 +78,7 @@ public DiagnosticAnalyzerDriver(Project project, LogAggregator logAggregator, Ab
_generatedCodeService = document.Project.Solution.Workspace.Services.GetService<IGeneratedCodeRecognitionService>();
_analyzerDriverService = document.Project.LanguageServices.GetService<IAnalyzerDriverService>();
_analyzerOptions = new WorkspaceAnalyzerOptions(_project.AnalyzerOptions, _project.Solution.Workspace);
_testOnly_DonotCatchAnalyzerExceptions = testOnly_DonotCatchAnalyzerExceptions;
_testOnly_RethrowAnalyzerException = testOnly_RethrowAnalyzerException;
}
// internal for testing purposes
......@@ -260,14 +260,9 @@ public async Task<ImmutableArray<Diagnostic>> GetSyntaxDiagnosticsAsync(Diagnost
await documentAnalyzer.AnalyzeSyntaxAsync(_document, diagnostics.Add, _cancellationToken).ConfigureAwait(false);
return diagnostics.ToImmutableArrayOrEmpty();
}
catch (Exception e) when (CatchAnalyzerException(e, analyzer))
catch (Exception e)
{
var exceptionDiagnostic = AnalyzerExceptionToDiagnostic(analyzer, e, _cancellationToken);
if (exceptionDiagnostic != null)
{
ReportAnalyzerExceptionDiagnostic(analyzer, exceptionDiagnostic, compilation);
}
OnAnalyzerException(e, analyzer, compilation);
return ImmutableArray<Diagnostic>.Empty;
}
}
......@@ -312,47 +307,21 @@ private IEnumerable<Diagnostic> GetFilteredDocumentDiagnosticsCore(IEnumerable<D
: CompilationWithAnalyzers.GetEffectiveDiagnostics(diagsFilteredByLocation, compilation);
}
internal void ReportAnalyzerExceptionDiagnostic(DiagnosticAnalyzer analyzer, Diagnostic exceptionDiagnostic, Compilation compilation)
internal void OnAnalyzerException(Exception ex, DiagnosticAnalyzer analyzer, Compilation compilation)
{
Contract.ThrowIfFalse(AnalyzerManager.IsAnalyzerExceptionDiagnostic(exceptionDiagnostic));
if (_hostDiagnosticUpdateSource == null)
{
return;
}
var exceptionDiagnostic = AnalyzerExceptionToDiagnostic(analyzer, ex, _cancellationToken);
if (compilation != null)
{
var effectiveDiagnostic = CompilationWithAnalyzers.GetEffectiveDiagnostics(ImmutableArray.Create(exceptionDiagnostic), compilation).SingleOrDefault();
if (effectiveDiagnostic == null)
{
return;
}
else
{
exceptionDiagnostic = effectiveDiagnostic;
}
exceptionDiagnostic = CompilationWithAnalyzers.GetEffectiveDiagnostics(ImmutableArray.Create(exceptionDiagnostic), compilation).SingleOrDefault();
}
_hostDiagnosticUpdateSource.ReportAnalyzerDiagnostic(analyzer, exceptionDiagnostic, this.Project.Solution.Workspace, this.Project);
}
private Action<Diagnostic> GetAddExceptionDiagnosticDelegate(DiagnosticAnalyzer analyzer)
{
return AnalyzerHelper.GetAddExceptionDiagnosticDelegate(analyzer, _hostDiagnosticUpdateSource, _project);
}
private AnalyzerExecutor GetAnalyzerExecutorForSupportedDiagnostics(DiagnosticAnalyzer analyzer)
{
// Skip telemetry logging if the exception is thrown as we are computing supported diagnostics and
// we can't determine if any descriptors support getting telemetry without having the descriptors.
return AnalyzerHelper.GetAnalyzerExecutorForSupportedDiagnostics(analyzer, _hostDiagnosticUpdateSource, CatchAnalyzerException_NoTelemetryLogging, _cancellationToken);
OnAnalyzerException(ex, analyzer, exceptionDiagnostic);
}
private AnalyzerExecutor GetAnalyzerExecutor(DiagnosticAnalyzer analyzer, Compilation compilation, Action<Diagnostic> addDiagnostic)
{
return AnalyzerHelper.GetAnalyzerExecutor(analyzer, _hostDiagnosticUpdateSource, _project,
compilation, addDiagnostic, _analyzerOptions, CatchAnalyzerException, _cancellationToken);
return AnalyzerExecutor.Create(compilation, _analyzerOptions, addDiagnostic, OnAnalyzerException, _cancellationToken);
}
public async Task<AnalyzerActions> GetAnalyzerActionsAsync(DiagnosticAnalyzer analyzer)
......@@ -370,7 +339,7 @@ public bool IsAnalyzerSuppressed(DiagnosticAnalyzer analyzer)
return false;
}
var analyzerExecutor = GetAnalyzerExecutorForSupportedDiagnostics(analyzer);
var analyzerExecutor = AnalyzerHelper.GetAnalyzerExecutorForSupportedDiagnostics(analyzer, _hostDiagnosticUpdateSource);
return AnalyzerManager.Instance.IsDiagnosticAnalyzerSuppressed(analyzer, options, AnalyzerHelper.IsCompilerAnalyzer, analyzerExecutor);
}
......@@ -406,14 +375,9 @@ public async Task<ImmutableArray<Diagnostic>> GetSemanticDiagnosticsAsync(Diagno
{
await documentAnalyzer.AnalyzeSemanticsAsync(_document, diagnostics.Add, _cancellationToken).ConfigureAwait(false);
}
catch (Exception e) when (CatchAnalyzerException(e, analyzer))
catch (Exception e)
{
var exceptionDiagnostic = AnalyzerExceptionToDiagnostic(analyzer, e, _cancellationToken);
if (exceptionDiagnostic != null)
{
ReportAnalyzerExceptionDiagnostic(analyzer, exceptionDiagnostic, compilation);
}
OnAnalyzerException(e, analyzer, compilation);
return ImmutableArray<Diagnostic>.Empty;
}
}
......@@ -487,14 +451,10 @@ private async Task GetProjectDiagnosticsWorkerAsync(DiagnosticAnalyzer analyzer,
{
await projectAnalyzer.AnalyzeProjectAsync(_project, diagnostics.Add, _cancellationToken).ConfigureAwait(false);
}
catch (Exception e) when (CatchAnalyzerException(e, analyzer))
catch (Exception e)
{
var exceptionDiagnostic = AnalyzerExceptionToDiagnostic(analyzer, e, _cancellationToken);
if (exceptionDiagnostic != null)
{
var compilation = await _project.GetCompilationAsync(_cancellationToken).ConfigureAwait(false);
ReportAnalyzerExceptionDiagnostic(analyzer, exceptionDiagnostic, compilation);
}
var compilation = await _project.GetCompilationAsync(_cancellationToken).ConfigureAwait(false);
OnAnalyzerException(e, analyzer, compilation);
}
}
......@@ -544,41 +504,21 @@ private static bool IsCanceled(Exception e, CancellationToken cancellationToken)
return canceled != null && canceled.CancellationToken == cancellationToken;
}
private bool CatchAnalyzerException(Exception e, DiagnosticAnalyzer analyzer)
private void OnAnalyzerException(Exception e, DiagnosticAnalyzer analyzer, Diagnostic diagnostic)
{
return CatchAnalyzerException(e, analyzer, _testOnly_DonotCatchAnalyzerExceptions);
OnAnalyzerException(e, analyzer, diagnostic, _testOnly_RethrowAnalyzerException);
}
private bool CatchAnalyzerException_NoTelemetryLogging(Exception e, DiagnosticAnalyzer analyzer)
private void OnAnalyzerException_NoTelemetryLogging(Exception e, DiagnosticAnalyzer analyzer, Diagnostic diagnostic)
{
return CatchAnalyzerException_NoTelemetryLogging(e, analyzer, _testOnly_DonotCatchAnalyzerExceptions);
AnalyzerHelper.OnAnalyzerException_NoTelemetryLogging(e, analyzer, diagnostic, _hostDiagnosticUpdateSource, _project, _testOnly_RethrowAnalyzerException);
}
internal bool CatchAnalyzerExceptionHandler(Exception e, DiagnosticAnalyzer analyzer)
{
return CatchAnalyzerException(e, analyzer, testOnly_DonotCatchAnalyzerExceptions: false);
}
private bool CatchAnalyzerException(Exception e, DiagnosticAnalyzer analyzer, bool testOnly_DonotCatchAnalyzerExceptions)
private void OnAnalyzerException(Exception e, DiagnosticAnalyzer analyzer, Diagnostic diagnostic, bool testOnly_RethrowAnalyzerException)
{
DiagnosticAnalyzerLogger.LogAnalyzerCrashCount(analyzer, e, _logAggregator);
return CatchAnalyzerException_NoTelemetryLogging(e, analyzer, testOnly_DonotCatchAnalyzerExceptions);
}
internal static bool CatchAnalyzerException_NoTelemetryLogging(Exception e, DiagnosticAnalyzer analyzer, bool testOnly_DonotCatchAnalyzerExceptions)
{
if (testOnly_DonotCatchAnalyzerExceptions)
{
return false;
}
if (AnalyzerHelper.IsBuiltInAnalyzer(analyzer))
{
return FatalError.ReportWithoutCrashUnlessCanceled(e);
}
return true;
AnalyzerHelper.OnAnalyzerException_NoTelemetryLogging(e, analyzer, diagnostic, _hostDiagnosticUpdateSource, _project, testOnly_RethrowAnalyzerException);
}
}
}
......@@ -81,8 +81,7 @@ public string GetAnalyzerReferenceIdentity(AnalyzerReference reference)
/// </summary>
public ImmutableArray<DiagnosticDescriptor> GetDiagnosticDescriptors(DiagnosticAnalyzer analyzer)
{
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException = (ex, a) => !AnalyzerHelper.IsBuiltInAnalyzer(analyzer);
var analyzerExecutor = AnalyzerHelper.GetAnalyzerExecutorForSupportedDiagnostics(analyzer, _hostDiagnosticUpdateSource, continueOnAnalyzerException, CancellationToken.None);
var analyzerExecutor = AnalyzerHelper.GetAnalyzerExecutorForSupportedDiagnostics(analyzer, _hostDiagnosticUpdateSource);
return AnalyzerManager.Instance.GetSupportedDiagnosticDescriptors(analyzer, analyzerExecutor);
}
......
......@@ -20,8 +20,8 @@ namespace Microsoft.CodeAnalysis
public static class DiagnosticExtensions
{
private const int EN_US = 1033;
public static Func<Exception, DiagnosticAnalyzer, bool> AlwaysCatchAnalyzerExceptions = (e, a) => true;
public static Func<Exception, DiagnosticAnalyzer, bool> DonotCatchAnalyzerExceptions = (e, a) => e is OperationCanceledException;
public static Action<Exception, DiagnosticAnalyzer, Diagnostic> AlwaysCatchAnalyzerException = (e, a, d) => { };
public static Action<Exception, DiagnosticAnalyzer, Diagnostic> RethrowAnalyzerException = (e, a, d) => { if (!(e is OperationCanceledException)) throw e; };
/// <summary>
/// This is obsolete. Use Verify instead.
......@@ -100,27 +100,39 @@ public static TCompilation VerifyDiagnostics<TCompilation>(this TCompilation c,
return c;
}
public static void VerifyAnalyzerOccurrenceCount<TCompilation>(this TCompilation c, DiagnosticAnalyzer[] analyzers, int expectedCount, Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException = null)
public static void VerifyAnalyzerOccurrenceCount<TCompilation>(
this TCompilation c,
DiagnosticAnalyzer[] analyzers,
int expectedCount,
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null)
where TCompilation : Compilation
{
Assert.Equal(expectedCount, c.GetAnalyzerDiagnostics(analyzers, null, continueOnAnalyzerException).Length);
Assert.Equal(expectedCount, c.GetAnalyzerDiagnostics(analyzers, null, onAnalyzerException).Length);
}
public static TCompilation VerifyAnalyzerDiagnostics<TCompilation>(
this TCompilation c, DiagnosticAnalyzer[] analyzers, AnalyzerOptions options = null, Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException = null, params DiagnosticDescription[] expected)
this TCompilation c,
DiagnosticAnalyzer[] analyzers,
AnalyzerOptions options = null,
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null,
params DiagnosticDescription[] expected)
where TCompilation : Compilation
{
ImmutableArray<Diagnostic> diagnostics;
c = c.GetAnalyzerDiagnostics(analyzers, options, continueOnAnalyzerException, diagnostics: out diagnostics);
c = c.GetAnalyzerDiagnostics(analyzers, options, onAnalyzerException, diagnostics: out diagnostics);
diagnostics.Verify(expected);
return c; // note this is a new compilation
}
public static ImmutableArray<Diagnostic> GetAnalyzerDiagnostics<TCompilation>(this TCompilation c, DiagnosticAnalyzer[] analyzers, AnalyzerOptions options = null, Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException = null)
public static ImmutableArray<Diagnostic> GetAnalyzerDiagnostics<TCompilation>(
this TCompilation c,
DiagnosticAnalyzer[] analyzers,
AnalyzerOptions options = null,
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException = null)
where TCompilation : Compilation
{
ImmutableArray<Diagnostic> diagnostics;
c = GetAnalyzerDiagnostics(c, analyzers, options, continueOnAnalyzerException, out diagnostics);
c = GetAnalyzerDiagnostics(c, analyzers, options, onAnalyzerException, out diagnostics);
return diagnostics;
}
......@@ -128,19 +140,30 @@ public static ImmutableArray<Diagnostic> GetAnalyzerDiagnostics<TCompilation>(th
this TCompilation c,
DiagnosticAnalyzer[] analyzers,
AnalyzerOptions options,
Func<Exception, DiagnosticAnalyzer, bool> continueOnAnalyzerException,
Action<Exception, DiagnosticAnalyzer, Diagnostic> onAnalyzerException,
out ImmutableArray<Diagnostic> diagnostics)
where TCompilation : Compilation
{
// We want unit tests to throw if any analyzer OR the driver throws, unless the test explicitly provides a delegate.
continueOnAnalyzerException = continueOnAnalyzerException ?? DonotCatchAnalyzerExceptions;
var analyzersArray = analyzers.ToImmutableArray();
var exceptionDiagnostics = new ConcurrentSet<Diagnostic>();
Action<Diagnostic> addExceptionDiagnostic = d => exceptionDiagnostics.Add(d);
if (onAnalyzerException != null)
{
onAnalyzerException = (ex, analyzer, diagnostic) =>
{
exceptionDiagnostics.Add(diagnostic);
onAnalyzerException(ex, analyzer, diagnostic);
};
}
else
{
// We want unit tests to throw if any analyzer OR the driver throws, unless the test explicitly provides a delegate.
onAnalyzerException = RethrowAnalyzerException;
}
Compilation newCompilation;
var driver = AnalyzerDriver.Create(c, analyzersArray, options, AnalyzerManager.Instance, addExceptionDiagnostic, out newCompilation, continueOnAnalyzerException, CancellationToken.None);
var driver = AnalyzerDriver.Create(c, analyzersArray, options, AnalyzerManager.Instance, onAnalyzerException, out newCompilation, CancellationToken.None);
var discarded = newCompilation.GetDiagnostics();
diagnostics = driver.GetDiagnosticsAsync().Result.AddRange(exceptionDiagnostics);
......@@ -165,7 +188,7 @@ public static IEnumerable<Diagnostic> GetEffectiveDiagnostics(this Compilation c
/// </summary>
public static bool IsDiagnosticAnalyzerSuppressed(this DiagnosticAnalyzer analyzer, CompilationOptions options)
{
return CompilationWithAnalyzers.IsDiagnosticAnalyzerSuppressed(analyzer, options, (exception, throwingAnalyzer) => true);
return CompilationWithAnalyzers.IsDiagnosticAnalyzerSuppressed(analyzer, options);
}
public static TCompilation VerifyEmitDiagnostics<TCompilation>(this TCompilation c, EmitOptions options, params DiagnosticDescription[] expected)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册