Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Edit loop in Roslyn

I am trying to understand how Roslyn Compiler is working.

I am trying to write simple function, which will analyze code and change loop statements from increasing to decreasing.

For example change:

for(int i=0; i<10; i++)
    int a = i;

to:

for(int i=9; i>=0; i--)
    int a=i;

I have written arleady code to find that loop, but I don't know how to edit it.

This is what i done so far:

SyntaxTree tree = CSharpSyntaxTree.ParseText(
    @"using System;
    using System.Collections.Generic;
    using System.Text;

        static void Main(string[] args)
        {
        for(int i=0; i<10; i++)
        int a = i;
        }");
var root = (CompilationUnitSyntax)tree.GetRoot();

IEnumerable<ForStatementSyntax> forStatementSyntaxs = root.DescendantNodes().OfType<ForStatementSyntax>();

ForStatementSyntax forStatementSyntax = forStatementSyntaxs.First();
ExpressionSyntax expressionSyntax = forStatementSyntax.Incrementors.First();

I would like to know how to change with Roslyn 'for loop' declaration. Additionally, how to change expressions which that loop contains.

like image 897
Tomasz Avatar asked Aug 28 '26 21:08

Tomasz


1 Answers

Create a SyntaxRewriter which is a visitor that can be used to replace nodes in your syntax tree with new nodes that you create. There are also methods for all nodes that can be used to create new nodes with a change to it.

In your case, you want to create a new ForStatementSyntax node with changed condition and statement. So you can use the WithCondition() and WithStatement() methods to make the updates respectively. You can create the new nodes by hand or you can parse a string using one of the many SyntaxFactory methods.

e.g.,

class Rewriter : CSharpSyntaxRewriter
{
    public override SyntaxNode VisitForStatement(ForStatementSyntax node)
    {
        // update the current node with the new condition and statement
        return node.WithCondition(
            SyntaxFactory.ParseExpression("i>=0")
        ).WithStatement(
            SyntaxFactory.ParseStatement(@"{
              Console.WriteLine(i);
              Console.WriteLine(i*2);
            }")
        );
    }
}

With the visitor created, you can just simply use it.

var root = SyntaxFactory.ParseCompilationUnit(
@"using System;
using System.Collections.Generic;
using System.Text;

static void Main(string[] args)
{
    for(int i=0; i<10; i++)
        int a = i;
}");
var rewritten = new Rewriter().Visit(root);

On the other hand, for simpler rewriting tasks, you don't necessarily need the rewriter. You can just use the Replace extension methods to replace nodes in a tree.

var forStmt = root.DescendantNodes().OfType<ForStatementSyntax>().Single();
var rewritten = root.ReplaceNode(forStmt,
    forStmt.WithCondition(
        SyntaxFactory.ParseExpression("i>=0")
    ).WithStatement(
        SyntaxFactory.ParseStatement(@"    {
          Console.WriteLine(i);
          Console.WriteLine(i*2);
        }
      ")
    ));
like image 87
Jeff Mercado Avatar answered Aug 31 '26 09:08

Jeff Mercado