代码之家  ›  专栏  ›  技术社区  ›  Ivan Koshelev

使用MSBuildWorkspace从C解决方案获取错误列表的最快方法是什么?

  •  0
  • Ivan Koshelev  · 技术社区  · 8 年前

    我正在使用MSBuildWorkspace,需要分析C解决方案是否有错误。我不需要实际的编译结果(文件),只需要错误。

    从具有MSBuildWorkspace的解决方案中获取错误列表的最快方法是什么?

    2 回复  |  直到 8 年前
        1
  •  3
  •   JoshVarty Dean Poulin    8 年前

    您需要加载解决方案,然后遍历项目并查找所有错误。这不会创建任何文件(例如,不发射任何IL),但它确实需要大部分的编译器管道(词法、语法分析、绑定等)。

    //Replace with the correct filepath
    var filePath = @"SomeSolution.sln";
    var msbws = MSBuildWorkspace.Create();
    var soln = await msbws.OpenSolutionAsync(filePath);
    
    foreach(var proj in soln.Projects)
    {
        var name = proj.Name;
        var compilation = await proj.GetCompilationAsync();
        var errors = compilation.GetDiagnostics().Where(n => n.Severity == DiagnosticSeverity.Error).ToList();
        // TODO: Do something with the errors
    }
    

    OpenProjectAsync .

        2
  •  1
  •   Jonathon Marolf    8 年前

    JoshVarty's Answer

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.Build.Locator;
    using Microsoft.CodeAnalysis;
    using Microsoft.CodeAnalysis.CSharp;
    using Microsoft.CodeAnalysis.CSharp.Symbols;
    using Microsoft.CodeAnalysis.CSharp.Syntax;
    using Microsoft.CodeAnalysis.MSBuild;
    using Microsoft.CodeAnalysis.Text;
    
    class Program
    {
        static async Task Main(string[] args) {
            // Attempt to set the version of MSBuild.
            var visualStudioInstances = MSBuildLocator.QueryVisualStudioInstances().ToArray();
            var instance = visualStudioInstances.Length == 1
                // If there is only one instance of MSBuild on this machine, set that as the one to use.
                ? visualStudioInstances[0]
                // Handle selecting the version of MSBuild you want to use.
                : SelectVisualStudioInstance(visualStudioInstances);
    
            Console.WriteLine($"Using MSBuild at '{instance.MSBuildPath}' to load projects.");
    
            // NOTE: Be sure to register an instance with the MSBuildLocator 
            //       before calling MSBuildWorkspace.Create()
            //       otherwise, MSBuildWorkspace won't MEF compose.
            MSBuildLocator.RegisterInstance(instance);
    
            using (var workspace = MSBuildWorkspace.Create()) {
                // Print message for WorkspaceFailed event to help diagnosing project load failures.
                workspace.WorkspaceFailed += (o, e) => Console.WriteLine(e.Diagnostic.Message);
    
                var solutionPath = args[0];
                Console.WriteLine($"Loading solution '{solutionPath}'");
    
                // Attach progress reporter so we print projects as they are loaded.
                var solution = await workspace.OpenSolutionAsync(solutionPath, new ConsoleProgressReporter());
                Console.WriteLine($"Finished loading solution '{solutionPath}'");
    
                // Print the number of errors found for each project
                foreach(var project in solution.Projects) {
                    var name = project.Name;
                    var compilation = await project.GetCompilationAsync();
                    var errors = compilation.GetDiagnostics().Where(n => n.Severity == DiagnosticSeverity.Error);
                    Console.WriteLine($"project '{name}' contained '{errors.Count()}');
                }
            }
        }
    
        private static VisualStudioInstance SelectVisualStudioInstance(VisualStudioInstance[] visualStudioInstances) {
            Console.WriteLine("Multiple installs of MSBuild detected please select one:");
            for (int i = 0; i < visualStudioInstances.Length; i++) {
                Console.WriteLine($"Instance {i + 1}");
                Console.WriteLine($"    Name: {visualStudioInstances[i].Name}");
                Console.WriteLine($"    Version: {visualStudioInstances[i].Version}");
                Console.WriteLine($"    MSBuild Path: {visualStudioInstances[i].MSBuildPath}");
            }
    
            while (true) {
                var userResponse = Console.ReadLine();
                if (int.TryParse(userResponse, out int instanceNumber) &&
                    instanceNumber > 0 &&
                    instanceNumber <= visualStudioInstances.Length) {
                    return visualStudioInstances[instanceNumber - 1];
                }
                Console.WriteLine("Input not accepted, try again.");
            }
        }
    
        private class ConsoleProgressReporter : IProgress<ProjectLoadProgress> {
            public void Report(ProjectLoadProgress loadProgress) {
                var projectDisplay = Path.GetFileName(loadProgress.FilePath);
                if (loadProgress.TargetFramework != null) {
                    projectDisplay += $" ({loadProgress.TargetFramework})";
                }
    
                Console.WriteLine($"{loadProgress.Operation,-15} {loadProgress.ElapsedTime,-15:m\\:ss\\.fffffff} {projectDisplay}");
            }
        }
    }