Roslyn-将编辑的文档保存到物理解决方案

时间:2019-11-27 11:55:21

标签: roslyn

我试图遍历所有文档,更改一些代码,然后使用新的语法重写分析的文档。我唯一的问题是我不知道如何通过工作区保存更改的文档。执行代码后,什么都没有发生。

var manager = new AnalyzerManager(slnPath);
        foreach (var project in manager.Projects.Values)
        {
            var workspace = project.GetWorkspace();
            var sln = workspace.CurrentSolution;

            foreach (var msBuildProject in sln.Projects)
            {
                foreach (var document in msBuildProject.Documents)
                {
                    var tree = await document.GetSyntaxTreeAsync();
                    var root = tree.GetRoot();
                    var compilation = await msBuildProject.GetCompilationAsync();
                    var walker = new CustomRewriter(compilation, tree);
                    var newRoot = walker.Visit(root);
                    if (!walker.Edited)
                        continue;
                    var editor = await DocumentEditor.CreateAsync(document);
                    editor.ReplaceNode(root, newRoot);
                    var newDocument = editor.GetChangedDocument();
                    workspace.TryApplyChanges(newDocument.Project.Solution);
                    break;
                }
            }
        }

编辑:借助Buildalyzer软件包获取工作区。

1 个答案:

答案 0 :(得分:1)

Buildalyzer使用不保留更改的临时工作空间。您要使用MSBuildWorkspace。

您应该有一个看起来像这样的项目文件

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net48</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Build.Locator" Version="1.2.6" />
    <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="2.9.8" PrivateAssets="all" />
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.3.1" />
    <PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="3.3.1" />
    <PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="3.3.1" />
  </ItemGroup>

</Project>

然后这就是我加载您的解决方案并运行您的重写器的方式

using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Build.Locator;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.MSBuild;

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}'");

            // Run your custome re-writer on the loaded solution
            foreach (var msBuildProject in solution.Projects) {
                foreach (var document in msBuildProject.Documents) {
                    var tree = await document.GetSyntaxTreeAsync();
                    var root = tree.GetRoot();
                    var compilation = await msBuildProject.GetCompilationAsync();
                    var walker = new CustomRewriter(compilation, tree);
                    var newRoot = walker.Visit(root);
                    if (!walker.Edited)
                        continue;
                    var editor = await DocumentEditor.CreateAsync(document);
                    editor.ReplaceNode(root, newRoot);
                    var newDocument = editor.GetChangedDocument();
                    workspace.TryApplyChanges(newDocument.Project.Solution);
                    break;
                }
            }
        }
    }

    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}");
        }
    }
}
相关问题