@@ -16,27 +16,27 @@ internal class AnalyzerDriverHelper
16
16
private const string DiagnosticId = "AD0001" ;
17
17
private const string DiagnosticCategory = "Compiler" ;
18
18
19
+ private static event EventHandler < AnalyzerExceptionDiagnosticArgs > AnalyzerExceptionDiagnostic ;
20
+
19
21
/// <summary>
20
22
/// Executes the <see cref="DiagnosticAnalyzer.Initialize(AnalysisContext)"/> for the given analyzer.
21
23
/// </summary>
22
24
/// <param name="analyzer">Analyzer to get session wide analyzer actions.</param>
23
25
/// <param name="sessionScope">Session scope to store register session wide analyzer actions.</param>
24
- /// <param name="addDiagnostic">Delegate to add diagnostics.</param>
25
26
/// <param name="continueOnAnalyzerException">Predicate to decide if exceptions from the action should be handled or not.</param>
26
27
/// <param name="cancellationToken">Cancellation token.</param>
27
28
/// <remarks>
28
29
/// Note that this API doesn't execute any <see cref="CompilationStartAnalyzerAction"/> registered by the Initialize invocation.
29
- /// Use <see cref="ExecuteCompilationStartActions(ImmutableArray{CompilationStartAnalyzerAction}, HostCompilationStartAnalysisScope, Compilation, AnalyzerOptions, Action{Diagnostic}, Func{Exception, DiagnosticAnalyzer, bool}, CancellationToken)"/> API
30
+ /// Use <see cref="ExecuteCompilationStartActions(ImmutableArray{CompilationStartAnalyzerAction}, HostCompilationStartAnalysisScope, Compilation, AnalyzerOptions, Func{Exception, DiagnosticAnalyzer, bool}, CancellationToken)"/> API
30
31
/// to get execute these actions to get the per-compilation analyzer actions.
31
32
/// </remarks>
32
33
public static void ExecuteInitializeMethod (
33
34
DiagnosticAnalyzer analyzer ,
34
35
HostSessionStartAnalysisScope sessionScope ,
35
- Action < Diagnostic > addDiagnostic ,
36
36
Func < Exception , DiagnosticAnalyzer , bool > continueOnAnalyzerException ,
37
37
CancellationToken cancellationToken )
38
38
{
39
- ExecuteAndCatchIfThrows ( analyzer , addDiagnostic , continueOnAnalyzerException , ( ) =>
39
+ ExecuteAndCatchIfThrows ( analyzer , continueOnAnalyzerException , ( ) =>
40
40
{
41
41
// The Initialize method should be run asynchronously in case it is not well behaved, e.g. does not terminate.
42
42
analyzer . Initialize ( new AnalyzerAnalysisContext ( analyzer , sessionScope ) ) ;
@@ -50,22 +50,20 @@ public static void ExecuteInitializeMethod(
50
50
/// <param name="compilationScope">Compilation scope to store the analyzer actions.</param>
51
51
/// <param name="compilation">Compilation to be used in the analysis.</param>
52
52
/// <param name="analyzerOptions">Analyzer options.</param>
53
- /// <param name="addDiagnostic">Delegate to add diagnostics.</param>
54
53
/// <param name="continueOnAnalyzerException">Predicate to decide if exceptions from the action should be handled or not.</param>
55
54
/// <param name="cancellationToken">Cancellation token.</param>
56
55
public static void ExecuteCompilationStartActions (
57
56
ImmutableArray < CompilationStartAnalyzerAction > actions ,
58
57
HostCompilationStartAnalysisScope compilationScope ,
59
58
Compilation compilation ,
60
59
AnalyzerOptions analyzerOptions ,
61
- Action < Diagnostic > addDiagnostic ,
62
60
Func < Exception , DiagnosticAnalyzer , bool > continueOnAnalyzerException ,
63
61
CancellationToken cancellationToken )
64
62
{
65
63
foreach ( var startAction in actions )
66
64
{
67
65
cancellationToken . ThrowIfCancellationRequested ( ) ;
68
- ExecuteAndCatchIfThrows ( startAction . Analyzer , addDiagnostic , continueOnAnalyzerException , ( ) =>
66
+ ExecuteAndCatchIfThrows ( startAction . Analyzer , continueOnAnalyzerException , ( ) =>
69
67
{
70
68
startAction . Action ( new AnalyzerCompilationStartAnalysisContext ( startAction . Analyzer , compilationScope , compilation , analyzerOptions , cancellationToken ) ) ;
71
69
} , cancellationToken ) ;
@@ -94,7 +92,7 @@ public static void ExecuteCompilationEndActions(
94
92
foreach ( var endAction in actions . CompilationEndActions )
95
93
{
96
94
cancellationToken . ThrowIfCancellationRequested ( ) ;
97
- ExecuteAndCatchIfThrows ( endAction . Analyzer , addDiagnostic , continueOnAnalyzerException , ( ) =>
95
+ ExecuteAndCatchIfThrows ( endAction . Analyzer , continueOnAnalyzerException , ( ) =>
98
96
{
99
97
var context = new CompilationEndAnalysisContext ( compilation , analyzerOptions , addDiagnostic , cancellationToken ) ;
100
98
endAction . Action ( context ) ;
@@ -133,7 +131,7 @@ public static void ExecuteSymbolActions(
133
131
var symbolContext = new SymbolAnalysisContext ( symbol , compilation , analyzerOptions , addDiagnostic , cancellationToken ) ;
134
132
135
133
// Catch Exception from action.
136
- ExecuteAndCatchIfThrows ( symbolAction . Analyzer , addDiagnostic , continueOnAnalyzerException , ( ) => action ( symbolContext ) , cancellationToken ) ;
134
+ ExecuteAndCatchIfThrows ( symbolAction . Analyzer , continueOnAnalyzerException , ( ) => action ( symbolContext ) , cancellationToken ) ;
137
135
}
138
136
}
139
137
}
@@ -161,7 +159,7 @@ public static void ExecuteSemanticModelActions(
161
159
cancellationToken . ThrowIfCancellationRequested ( ) ;
162
160
163
161
// Catch Exception from action.
164
- ExecuteAndCatchIfThrows ( semanticModelAction . Analyzer , addDiagnostic , continueOnAnalyzerException , ( ) =>
162
+ ExecuteAndCatchIfThrows ( semanticModelAction . Analyzer , continueOnAnalyzerException , ( ) =>
165
163
{
166
164
var context = new SemanticModelAnalysisContext ( semanticModel , analyzerOptions , addDiagnostic , cancellationToken ) ;
167
165
semanticModelAction . Action ( context ) ;
@@ -191,7 +189,7 @@ public static void ExecuteSyntaxTreeActions(
191
189
cancellationToken . ThrowIfCancellationRequested ( ) ;
192
190
193
191
// Catch Exception from action.
194
- ExecuteAndCatchIfThrows ( syntaxTreeAction . Analyzer , addDiagnostic , continueOnAnalyzerException , ( ) =>
192
+ ExecuteAndCatchIfThrows ( syntaxTreeAction . Analyzer , continueOnAnalyzerException , ( ) =>
195
193
{
196
194
var context = new SyntaxTreeAnalysisContext ( syntaxTree , analyzerOptions , addDiagnostic , cancellationToken ) ;
197
195
syntaxTreeAction . Action ( context ) ;
@@ -251,7 +249,7 @@ internal static void ExecuteSyntaxNodeAction(
251
249
var syntaxNodeContext = new SyntaxNodeAnalysisContext ( node , semanticModel , analyzerOptions , addDiagnostic , cancellationToken ) ;
252
250
253
251
// Catch Exception from action.
254
- ExecuteAndCatchIfThrows ( analyzer , addDiagnostic , continueOnAnalyzerException , ( ) => syntaxNodeAction ( syntaxNodeContext ) , cancellationToken ) ;
252
+ ExecuteAndCatchIfThrows ( analyzer , continueOnAnalyzerException , ( ) => syntaxNodeAction ( syntaxNodeContext ) , cancellationToken ) ;
255
253
}
256
254
257
255
/// <summary>
@@ -329,7 +327,7 @@ internal static void ExecuteCodeBlockActions<TLanguageKindEnum>(
329
327
foreach ( var da in codeBlockStartActions )
330
328
{
331
329
// Catch Exception from the start action.
332
- ExecuteAndCatchIfThrows ( da . Analyzer , addDiagnostic , continueOnAnalyzerException , ( ) =>
330
+ ExecuteAndCatchIfThrows ( da . Analyzer , continueOnAnalyzerException , ( ) =>
333
331
{
334
332
HostCodeBlockStartAnalysisScope < TLanguageKindEnum > codeBlockScope = new HostCodeBlockStartAnalysisScope < TLanguageKindEnum > ( ) ;
335
333
CodeBlockStartAnalysisContext < TLanguageKindEnum > blockStartContext = new AnalyzerCodeBlockStartAnalysisContext < TLanguageKindEnum > ( da . Analyzer , codeBlockScope , declaredNode , declaredSymbol , semanticModel , analyzerOptions , cancellationToken ) ;
@@ -353,7 +351,7 @@ internal static void ExecuteCodeBlockActions<TLanguageKindEnum>(
353
351
foreach ( var a in endedActions )
354
352
{
355
353
// Catch Exception from a.OnCodeBlockEnded
356
- ExecuteAndCatchIfThrows ( a . Analyzer , addDiagnostic , continueOnAnalyzerException , ( ) => a . Action ( new CodeBlockEndAnalysisContext ( declaredNode , declaredSymbol , semanticModel , analyzerOptions , addDiagnostic , cancellationToken ) ) , cancellationToken ) ;
354
+ ExecuteAndCatchIfThrows ( a . Analyzer , continueOnAnalyzerException , ( ) => a . Action ( new CodeBlockEndAnalysisContext ( declaredNode , declaredSymbol , semanticModel , analyzerOptions , addDiagnostic , cancellationToken ) ) , cancellationToken ) ;
357
355
}
358
356
359
357
endedActions . Free ( ) ;
@@ -434,7 +432,7 @@ internal static bool CanHaveExecutableCodeBlock(ISymbol symbol)
434
432
}
435
433
}
436
434
437
- internal static void ExecuteAndCatchIfThrows ( DiagnosticAnalyzer analyzer , Action < Diagnostic > addDiagnostic , Func < Exception , DiagnosticAnalyzer , bool > continueOnAnalyzerException , Action analyze , CancellationToken cancellationToken )
435
+ internal static void ExecuteAndCatchIfThrows ( DiagnosticAnalyzer analyzer , Func < Exception , DiagnosticAnalyzer , bool > continueOnAnalyzerException , Action analyze , CancellationToken cancellationToken )
438
436
{
439
437
try
440
438
{
@@ -444,14 +442,18 @@ internal static void ExecuteAndCatchIfThrows(DiagnosticAnalyzer analyzer, Action
444
442
{
445
443
if ( oce . CancellationToken != cancellationToken )
446
444
{
447
- // Create a info diagnostic saying that the analyzer failed
448
- addDiagnostic ( GetAnalyzerDiagnostic ( analyzer , oce ) ) ;
445
+ // Raise an event with a diagnostic for analyzer exception
446
+ var diagnostic = GetAnalyzerDiagnostic ( analyzer , oce ) ;
447
+ var args = new AnalyzerExceptionDiagnosticArgs ( analyzer , diagnostic ) ;
448
+ AnalyzerExceptionDiagnostic ? . Invoke ( analyze , args ) ;
449
449
}
450
450
}
451
451
catch ( Exception e ) when ( continueOnAnalyzerException ( e , analyzer ) )
452
452
{
453
- // Create a info diagnostic saying that the analyzer failed
454
- addDiagnostic ( GetAnalyzerDiagnostic ( analyzer , e ) ) ;
453
+ // Raise an event with a diagnostic for analyzer exception
454
+ var diagnostic = GetAnalyzerDiagnostic ( analyzer , e ) ;
455
+ var args = new AnalyzerExceptionDiagnosticArgs ( analyzer , diagnostic ) ;
456
+ AnalyzerExceptionDiagnostic ? . Invoke ( analyze , args ) ;
455
457
}
456
458
}
457
459
@@ -471,11 +473,13 @@ internal static DiagnosticDescriptor GetDiagnosticDescriptor(string analyzerName
471
473
customTags : WellKnownDiagnosticTags . AnalyzerException ) ;
472
474
}
473
475
474
- internal static bool IsAnalyzerExceptionDiagnostic ( string diagnosticId , IEnumerable < string > customTags )
476
+ internal static bool IsAnalyzerExceptionDiagnostic ( Diagnostic diagnostic )
475
477
{
476
- if ( diagnosticId == DiagnosticId )
478
+ if ( diagnostic . Id == DiagnosticId )
477
479
{
478
- foreach ( var tag in customTags )
480
+ #pragma warning disable RS0013 // Its ok to realize the Descriptor for analyzer exception diagnostics, which are descriptor based and also rare.
481
+ foreach ( var tag in diagnostic . Descriptor . CustomTags )
482
+ #pragma warning restore RS0013
479
483
{
480
484
if ( tag == WellKnownDiagnosticTags . AnalyzerException )
481
485
{
@@ -484,7 +488,54 @@ internal static bool IsAnalyzerExceptionDiagnostic(string diagnosticId, IEnumera
484
488
}
485
489
}
486
490
487
- return false ;
491
+ return false ;
492
+ }
493
+
494
+ internal static EventHandler < AnalyzerExceptionDiagnosticArgs > RegisterAnalyzerExceptionDiagnosticHandler ( ImmutableArray < DiagnosticAnalyzer > analyzers , Func < Diagnostic , bool > addAnalyzerExceptionDiagnostic )
495
+ {
496
+ Action < object , AnalyzerExceptionDiagnosticArgs > onAnalyzerExceptionDiagnostic =
497
+ ( sender , args ) => addAnalyzerExceptionDiagnostic ( args . Diagnostic ) ;
498
+ return RegisterAnalyzerExceptionDiagnosticHandler ( analyzers , onAnalyzerExceptionDiagnostic ) ;
499
+ }
500
+
501
+ internal static EventHandler < AnalyzerExceptionDiagnosticArgs > RegisterAnalyzerExceptionDiagnosticHandler ( ImmutableArray < DiagnosticAnalyzer > analyzers , Action < object , AnalyzerExceptionDiagnosticArgs > onAnayzerExceptionDiagnostic )
502
+ {
503
+ EventHandler < AnalyzerExceptionDiagnosticArgs > handler = ( sender , args ) =>
504
+ {
505
+ if ( analyzers . Contains ( args . FaultedAnalyzer ) )
506
+ {
507
+ onAnayzerExceptionDiagnostic ( sender , args ) ;
508
+ }
509
+ } ;
510
+
511
+ AnalyzerExceptionDiagnostic += handler ;
512
+ return handler ;
513
+ }
514
+
515
+ internal static EventHandler < AnalyzerExceptionDiagnosticArgs > RegisterAnalyzerExceptionDiagnosticHandler ( DiagnosticAnalyzer analyzer , Func < Diagnostic , bool > addAnalyzerExceptionDiagnostic )
516
+ {
517
+ Action < object , AnalyzerExceptionDiagnosticArgs > onAnalyzerExceptionDiagnostic =
518
+ ( sender , args ) => addAnalyzerExceptionDiagnostic ( args . Diagnostic ) ;
519
+ return RegisterAnalyzerExceptionDiagnosticHandler ( analyzer , onAnalyzerExceptionDiagnostic ) ;
520
+ }
521
+
522
+ internal static EventHandler < AnalyzerExceptionDiagnosticArgs > RegisterAnalyzerExceptionDiagnosticHandler ( DiagnosticAnalyzer analyzer , Action < object , AnalyzerExceptionDiagnosticArgs > onAnayzerExceptionDiagnostic )
523
+ {
524
+ EventHandler < AnalyzerExceptionDiagnosticArgs > handler = ( sender , args ) =>
525
+ {
526
+ if ( analyzer == args . FaultedAnalyzer )
527
+ {
528
+ onAnayzerExceptionDiagnostic ( sender , args ) ;
529
+ }
530
+ } ;
531
+
532
+ AnalyzerExceptionDiagnostic += handler ;
533
+ return handler ;
534
+ }
535
+
536
+ internal static void UnregisterAnalyzerExceptionDiagnosticHandler ( EventHandler < AnalyzerExceptionDiagnosticArgs > handler )
537
+ {
538
+ AnalyzerExceptionDiagnostic -= handler ;
488
539
}
489
540
}
490
541
}
0 commit comments