如何在Visual Studio 2017中编程运行静态代码分析并自动化获取结果?
解决方案
1. 使用EnvDte实现原生代码分析自动化
VS的EnvDte API可以直接调用代码分析命令并读取错误列表中的结果,这是最贴合你现有插件技术栈的方案:
触发代码分析
首先通过ExecuteCommand调用VS内置的代码分析命令,然后监听构建完成事件等待分析结束:
var dte = (EnvDte80.DTE2)Package.GetGlobalService(typeof(EnvDte.DTE)); // 执行解决方案级代码分析 dte.ExecuteCommand("Build.RunCodeAnalysisOnSolution"); // 监听构建完成事件,确认分析结束 dte.Events.BuildEvents.OnBuildDone += (scope, action) => { if (action == EnvDte.vsBuildAction.vsBuildActionBuild) { // 这里开始提取分析结果 ExtractCodeAnalysisResults(dte); } };
提取CA13xx警告
分析完成后,直接读取错误列表中的条目,筛选CA13开头的全球化警告:
private void ExtractCodeAnalysisResults(EnvDte80.DTE2 dte) { var errorList = dte.ToolWindows.ErrorList; foreach (EnvDte.Error error in errorList.ErrorItems) { // 只处理CA13系列的全球化警告 if (error.ErrorNumber.StartsWith("CA13") && error.ErrorLevel == EnvDte.vsErrorLevel.vsErrorLevelWarning) { string warningId = error.ErrorNumber; string description = error.Description; string filePath = error.FileName; int lineNumber = error.Line; // 这里可以将结果写入日志、生成报告或进行后续处理 Console.WriteLine($"[{warningId}] {description} - {filePath}:{lineNumber}"); } } }
这种方案的优点是无需额外依赖,直接复用VS的原生代码分析能力,缺点是对警告的结构化解析能力较弱,只能拿到基础的文本和位置信息。
2. 使用Roslyn实现更灵活的代码分析
如果你需要更精细的控制(比如在代码层面直接分析、修改代码),Roslyn是更好的选择,它可以直接加载解决方案并运行诊断分析:
准备工作
在你的插件项目中安装以下NuGet包:
Microsoft.CodeAnalysisMicrosoft.CodeAnalysis.CSharpMicrosoft.CodeAnalysis.DiagnosticsMicrosoft.CodeAnalysis.Workspaces.MSBuild
加载解决方案并分析CA13xx警告
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; using System.Collections.Immutable; using System.Linq; // 创建MSBuild工作区 var workspace = MSBuildWorkspace.Create(); // 加载目标解决方案 var solution = await workspace.OpenSolutionAsync(@"C:\Path\To\Your\Solution.sln"); // 获取所有CA13系列的诊断规则 var globalizationDiagnostics = DiagnosticDescriptor.GetDiagnostics() .Where(d => d.Id.StartsWith("CA13")) .ToImmutableArray(); // 遍历每个项目进行分析 foreach (var project in solution.Projects) { var compilation = await project.GetCompilationAsync(); if (compilation == null) continue; // 运行诊断分析 var diagnostics = await compilation.WithAnalyzers(globalizationDiagnostics) .GetAllDiagnosticsAsync(); // 处理CA13xx警告 foreach (var diag in diagnostics.Where(d => d.Id.StartsWith("CA13"))) { string warningId = diag.Id; string message = diag.GetMessage(); var location = diag.Location; string filePath = location.SourceTree?.FilePath; var linePosition = location.GetLineSpan().StartLinePosition; int lineNumber = linePosition.Line + 1; // Roslyn行号从0开始,转换为VS的1-based行号 // 这里可以进行更复杂的处理,比如定位代码节点、自动修复等 Console.WriteLine($"[{warningId}] {message} - {filePath}:{lineNumber}"); } }
这种方案的优势是完全脱离VS的UI层,直接操作代码语法树,你可以基于分析结果实现自动化修复(比如将硬编码字符串替换为资源文件引用),适合需要深度定制的场景。
3. 注意事项
- 使用EnvDte时,确保所有操作在VS主线程执行,避免跨线程访问UI元素的异常。
- Roslyn方案中,注意处理异步操作,避免阻塞插件的UI线程。
- CA13xx系列包含多个具体规则(如CA1303:不要将文本作为本地化参数传递,CA1305:指定IFormatProvider等),你可以根据需求筛选特定的规则ID进行处理。
内容的提问来源于stack exchange,提问作者reckface
相关产品推荐
相关产品推荐

