You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 19:15:14