Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Visit and modify all documents in a solution using Roslyn

Tags:

c#

roslyn

I want to walk over all the documents in every project in a given solution using Roslyn.

This is the code I have now:

var msWorkspace = MSBuildWorkspace.Create();
var solution = await msWorkspace.OpenSolutionAsync(solutionPath);
foreach (var project in solution.Projects)
{
    foreach (var document in project.Documents)
    {
        if (document.SourceCodeKind != SourceCodeKind.Regular)
            continue;

        var doc = document;
        foreach (var rewriter in rewriters)
        {
            doc = await rewriter.Rewrite(doc);
        }

        if (doc != document)
        {
            Console.WriteLine("changed {0}",doc.Name);
            //save result

            //the solution is now changed and the next document to be processed will belong to the old solution
            msWorkspace.TryApplyChanges(doc.Project.Solution);
        }                    
    }
}

The problem here is that as Roslyn is largely immutable. After the first "msWorkspace.TryApplyChanges", the solution and the document are now replaced with new versions.

So the next iteration will still walk over the old versions. Is there any way to do this in a Roslyn idiomatic way? Or do I have to resort to some for(int projectIndex = 0;projectIndex < solution.Projects.count) { kind of hackery?

like image 283
Roger Johansson Avatar asked Aug 24 '15 07:08

Roger Johansson


People also ask

How do I create a namesyntax node in Roslyn?

You use the IdentifierName (String) method to create a NameSyntax node. Add the following code in your Main method in Program.cs: The preceding code creates an IdentifierNameSyntax object and assigns it to the variable name. Many of the Roslyn APIs return base classes to make it easier to work with related types.

What are the disadvantages of Roslyn?

One drawback of Roslyn’s immutability is that it can sometimes make it tricky to apply multiple changes to a Document or SyntaxTree. Immutability means that every time we apply changes to a syntax tree, we’re given an entirely new syntax tree.

What is immutable in Roslyn?

A fundamental tenet within Roslyn is that most objects are immutable. This means we can’t hold on to a reference to a solution and expect it to be up-to-date forever. The moment a change is made, this solution will be out of date and a new, updated solution will have been created. Workspaces are our root node.


1 Answers

This solution posted in the Roslyn gitter chat does the trick and solves the problem.

var solution = await msWorkspace.OpenSolutionAsync(solutionPath);

foreach (var projectId in solution.ProjectIds)
{
    var project = solution.GetProject(projectId);
    foreach (var documentId in project.DocumentIds)
    {
        Document document = project.GetDocument(documentId);

        if (document.SourceCodeKind != SourceCodeKind.Regular)
            continue;

        var doc = document;
        foreach (var rewriter in rewriters)
        {
            doc = await rewriter.Rewrite(doc);

        }

        project = doc.Project;
    }
    solution = project.Solution;
}
msWorkspace.TryApplyChanges(solution);

in this case, changes are no longer discarded between iterations as everything builds on the result of the last iteration. (that is, documents and projects are fetched by ID rather than from an enumerator that walks over the original structure)

like image 142
Roger Johansson Avatar answered Sep 21 '22 19:09

Roger Johansson