C#代码分析器抛出AD0001异常:报告的诊断ID不被支持
C#代码分析器基类异常捕获问题
背景
我实现了一个C#代码分析器的抽象基类,基于它开发了多个具体的代码分析器。最初基类的AnalyzeNode方法没有try/catch块,一旦分析器抛出异常,会直接导致被分析项目的编译失败。由于这些分析器并非构建流程的核心依赖,我不希望它们的错误中断整体构建,因此给基类添加了try/catch逻辑,目的是将异常转换为包含错误文件、行号、异常信息的编译器警告,方便后续排查。
基类代码
using System; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using CodeQuality.Shared; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; namespace CodeQuality { internal abstract class CodeAnalyzerBase<TSyntaxNode> : DiagnosticAnalyzer where TSyntaxNode : SyntaxNode { private readonly object contextLock = new object(); private SyntaxNodeAnalysisContext context; public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(this.Rule, DiagnosticDescriptors.AnalyzerExceptionRule); /// <summary>The syntax kind to which you want to register the AnalyzeNode method</summary> /// <value>The kind of the syntax.</value> internal abstract SyntaxKind SyntaxKind { get; } protected abstract DiagnosticDescriptor Rule { get; } protected SyntaxNodeAnalysisContext Context { get { lock (this.contextLock) { return this.context; } } set { lock (this.contextLock) { this.context = value; } } } public override void Initialize(AnalysisContext context) { if (!Debugger.IsAttached) { // we want concurrent execution, but it's annoying while actively debugging context.EnableConcurrentExecution(); } context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.RegisterSyntaxNodeAction(this.AnalyzeNode, this.SyntaxKind); } internal void AnalyzeNode(SyntaxNodeAnalysisContext context) { try { this.Context = context; if (this.Context.Node.SyntaxTree == null) { return; } if (!(this.Context.Node is TSyntaxNode node)) { return; } this.AnalyzeNode(node); } catch (Exception e) { var location = this.Context.Node.GetLocation(); var lineSpan = location.GetLineSpan(); DebugHelper.LogException( e, lineSpan.Path, lineSpan.StartLinePosition.Line, $"Supported Rules: {string.Join(Environment.NewLine, this.SupportedDiagnostics.Select(r => r.Id))}"); var diagnostic = Diagnostic.Create( DiagnosticDescriptors.AnalyzerExceptionRule, location, $"File: {lineSpan.Path}", $"Line: {lineSpan.StartLinePosition.Line}", $"Exception message: {e.Message}", $"Inner Exception: {e.InnerException}", $"Stack Trace: {e.StackTrace}"); this.Context.ReportDiagnostic(diagnostic); } } internal abstract void AnalyzeNode(TSyntaxNode node); } }
具体分析器示例
以EmptyCatchBlockAnalyzer为例,它用于检查空catch块(除非块内包含注释):
// analyzes to ensure there are no empty catch blocks unless they contain comments [DiagnosticAnalyzer(LanguageNames.CSharp)] internal class EmptyCatchBlockAnalyzer : CodeAnalyzerBase<CatchClauseSyntax> { internal override SyntaxKind SyntaxKind => SyntaxKind.CatchClause; protected override DiagnosticDescriptor Rule => DiagnosticDescriptors.EmptyCatchBlockRule; internal override void AnalyzeNode(CatchClauseSyntax node) { if (node.Block == null) { return; } if (node.Block.Statements == null) { return; } if (!node.Block.Statements.Any() && !node.Block.DescendantTrivia().Any(trivia => trivia.IsKind(SyntaxKind.SingleLineCommentTrivia) || trivia.IsKind(SyntaxKind.MultiLineCommentTrivia))) { var diagnostic = Diagnostic.Create(this.Rule, node.CatchKeyword.GetLocation()); this.Context.ReportDiagnostic(diagnostic); } } }
诊断规则定义
分析器异常警告规则
internal static DiagnosticDescriptor AnalyzerExceptionRule => new DiagnosticDescriptor( "ID0000", "Code analyzer exception", $"An error occurred while attempting to run code analysis.", DiagnosticCategories.Usage, // "Usage" DiagnosticSeverity.Warning, isEnabledByDefault: true);
空catch块错误规则
internal static DiagnosticDescriptor EmptyCatchBlockRule => new DiagnosticDescriptor( "ID0050", "Empty Catch Block", "Code contains an empty catch block. Add code to handle the error or add a comment justifying the existence of this empty catch block.", DiagnosticCategories.Syntax, // "Syntax" DiagnosticSeverity.Error, isEnabledByDefault: true);
遇到的问题
将分析器DLL安装到解决方案项目后,具体分析器能正常捕获预期的异常,但偶尔会触发AD0001错误:
Analyzer '{具体实现类}' threw an exception of type 'System.ArgumentException' with message 'Reported diagnostic with ID '{DiagnosticDescriptors.AnalyzerExceptionRule.Id}' is not supported by the analyzer.'
调试时从未命中catch块,并且在报告警告诊断前添加日志输出SupportedDiagnostics,显示内容符合预期(包含具体分析器的规则和AnalyzerExceptionRule),但报告诊断时仍会抛出上述错误。
已做排查
- 在多个位置添加日志,确认分析器已正确构造并完成初始化
- 日志显示
SupportedDiagnostics确实包含AnalyzerExceptionRule的ID
内容的提问来源于stack exchange,提问作者Jeff
相关产品推荐
相关产品推荐

