如何仅获取CSharpCompilation增量部分的错误诊断?
我之前在处理大型项目的Roslyn代码改写时,也遇到过一模一样的问题——全局调用Compilation.GetDiagnostics()实在太慢,哪怕用了增量编译也没明显改善。核心原因是默认的全局诊断会遍历整个编译的所有节点,哪怕你只改了一个方法。下面几个可行的方案,能帮你只针对增量部分获取诊断:
针对修改的语法节点调用SemanticModel.GetDiagnostics()
当你通过Compilation.Update得到新的编译实例后,别直接全局获取诊断,先定位到你改写的具体语法节点(比如MethodDeclarationSyntax),然后获取该节点对应的SemanticModel,再调用semanticModel.GetDiagnostics(node.Span)。这样Roslyn只会检查这个节点范围内的语法和语义错误,完全不用扫描整个项目。
举个简单的代码示例:// newCompilation是增量更新后的编译实例 // modifiedMethod是你改写后的MethodDeclarationSyntax节点 var semanticModel = newCompilation.GetSemanticModel(modifiedMethod.SyntaxTree); var diagnostics = semanticModel.GetDiagnostics(modifiedMethod.Span);利用CompilationWithAnalyzers做增量分析
如果你在代码操作中用到了Roslyn分析器,CompilationWithAnalyzers提供了更精准的增量诊断能力。你可以跟踪哪些SyntaxTree被修改,创建CompilationWithAnalyzers实例后,调用GetAnalyzerDiagnosticsAsync时指定只分析变化的树。这种方式会直接跳过未修改的部分,速度提升非常明显。过滤全局诊断到增量区域
如果出于某些原因必须调用全局的Compilation.GetDiagnostics(),你可以在获取所有诊断后,过滤出属于你修改的SyntaxTree或具体节点的诊断。比如:var allDiagnostics = newCompilation.GetDiagnostics(); var relevantDiagnostics = allDiagnostics.Where(d => d.Location.SourceTree == modifiedSyntaxTree && modifiedMethod.Span.Contains(d.Location.SourceSpan) ).ToList();不过这个方案效率不如前两个,因为它还是会先扫描整个项目,只是后续做了过滤,适合一些简单场景。
另外要注意:确保你正确使用Compilation.Update——只替换真正修改过的SyntaxTree,其他树复用原来的实例,这样Roslyn才能真正利用增量编译的优化,避免不必要的全量重新编译。
内容的提问来源于stack exchange,提问作者m1o2

