通过CompilationAnalysisContext.ReportDiagnostic上报的Roslyn诊断在VS中不显示
Roslyn分析器:CompilationAction上报的诊断在Visual Studio中无法显示
问题背景
使用Visual Studio 2022的「Analyzer with Code Fix」模板创建Roslyn分析器,单元测试中Rule1(通过SymbolAction上报)和Rule2(通过CompilationAction上报)均能正常生成诊断,但在Visual Studio界面中仅能看到Rule1的诊断。调试确认两个context.ReportDiagnostic调用都已执行,且VS设置中未抑制任何诊断。由于业务需要检查多个符号间的关系,改用SymbolAnalysisContext.ReportDiagnostic重写成本过高。
复现代码
[DiagnosticAnalyzer(LanguageNames.CSharp)] public class DummyAnalyzer : DiagnosticAnalyzer { private static readonly DiagnosticDescriptor Rule1 = new ("D001", "SymbolAction", "SymbolAction", "Test", DiagnosticSeverity.Warning, true); private static readonly DiagnosticDescriptor Rule2 = new ("D002", "CompilationAction", "CompilationAction", "Test", DiagnosticSeverity.Warning, true); public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Rule1, Rule2]; public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.RegisterSymbolAction(c => c.ReportDiagnostic(Diagnostic.Create(Rule1, c.Symbol.Locations.FirstOrDefault())), SymbolKind.Method); context.RegisterCompilationAction(CompilationAction); } private void CompilationAction(CompilationAnalysisContext context) { foreach (var syntaxTree in context.Compilation.SyntaxTrees) { var compilationUnitSyntax = syntaxTree.GetRoot(context.CancellationToken) as CompilationUnitSyntax; var typeDeclarationSyntax = compilationUnitSyntax?.Members.OfType<BaseNamespaceDeclarationSyntax>().SelectMany(syntax => syntax.Members).OfType<TypeDeclarationSyntax>().FirstOrDefault(); if (typeDeclarationSyntax != null) context.ReportDiagnostic(Diagnostic.Create(Rule2, typeDeclarationSyntax.GetLocation())); } } }
解决方法
核心原因
Visual Studio的**实时分析(Live Analysis)**默认会跳过全编译级别的分析动作(如CompilationAction),因为这类动作遍历整个编译单元,性能开销较大,仅在全编译(如项目重建)时才会执行。
具体修复步骤
配置CompilationAction的执行上下文
在Initialize方法中,为RegisterCompilationAction添加分析选项,明确指定允许该动作在实时分析中执行:context.RegisterCompilationAction(CompilationAction, new CompilationAnalysisOptions(ExecutionContext = AnalysisExecutionContext.LiveAnalysis));优化CompilationAction的性能
实时分析会频繁触发,必须确保动作执行高效,避免卡顿。可以限制仅处理当前活跃文档的语法树:private void CompilationAction(CompilationAnalysisContext context) { // 获取当前活跃文档路径(仅在VS实时分析中有效) context.Options.AnalyzerConfigOptionsProvider.GlobalOptions.TryGetValue( "build_metadata.AdditionalFiles.ActiveDocumentPath", out var activeDocumentPath); foreach (var syntaxTree in context.Compilation.SyntaxTrees) { // 跳过非活跃文档的语法树,减少不必要的计算 if (!string.IsNullOrEmpty(activeDocumentPath) && !syntaxTree.FilePath.Equals(activeDocumentPath, StringComparison.OrdinalIgnoreCase)) { continue; } var compilationUnitSyntax = syntaxTree.GetRoot(context.CancellationToken) as CompilationUnitSyntax; var typeDeclarationSyntax = compilationUnitSyntax?.Members.OfType<BaseNamespaceDeclarationSyntax>() .SelectMany(syntax => syntax.Members) .OfType<TypeDeclarationSyntax>() .FirstOrDefault(); if (typeDeclarationSyntax != null) { context.ReportDiagnostic(Diagnostic.Create(Rule2, typeDeclarationSyntax.GetLocation())); } } }验证全编译场景
如果配置后实时分析仍未显示诊断,可以右键项目选择「重建」触发全编译,确认诊断是否出现,以此排除增量分析的干扰。
内容的提问来源于stack exchange,提问作者Dark Daskin
相关产品推荐
相关产品推荐

