简体   繁体   中英

Changing syntax token with Roslyn

I am trying to rewrite code with Roslyn. I want to change GreaterThanToken to EqualsEqualsToken. Here is my code so far:

ToParse.cs:

public class ToParse
{
    public bool MethodToConvert(int param)
    {
        return (1 > param);
    }
}

Program.cs:

class Rewriter : SyntaxRewriter
{
    private readonly SyntaxKind _replace;
    private readonly SyntaxKind _replacewith;
    public Rewriter(SyntaxKind replace, SyntaxKind replacewith)
    {
        _replace = replace;
        _replacewith = replacewith;
    }

    public override SyntaxToken VisitToken(SyntaxToken token)
    {
        if (token.Kind != _replace)
            return token;

        return Syntax.Token(_replacewith);
    }
}

Usage:

var code = new StreamReader("ToParse.cs").ReadToEnd();
var tree = SyntaxTree.ParseText(code);
var root = tree.GetRoot();
var rewriter = new Rewriter(SyntaxKind.GreaterThanToken, SyntaxKind.EqualsEqualsToken);
var newRoot = rewriter.Visit(root);

var newTree = SyntaxTree.Create((CompilationUnitSyntax)newRoot);
var compilation = Compilation.Create("TestAssembly.dll", 
      new CompilationOptions(OutputKind.DynamicallyLinkedLibrary),
      references: new[]{ new MetadataFileReference(typeof(object).Assembly.Location)},
      syntaxTrees: new[] { newTree });
Console.WriteLine(newTree);
EmitResult res;

using (var file = new FileStream("e:\\TestAssembly.dll", FileMode.Create))
   res = compilation.Emit(file);

After execution, Console.WriteLine prints changed tokens return (1 == param); But when I open testassembly.dll with ilspy I still see return 1 > param; Any suggestions?

[Note: You're using a slightly older version of Roslyn. This answer should work for that version too, but I may reference classes and members by more recent names so that they match the source available on CodePlex .]

The original tree that you've parsed contains a BinaryExpressionSyntax node with a SyntaxKind of GreaterThanExpression . When you swap out the GreaterThanToken with an EqualsEqualsToken inside this BinaryExpressionSyntax , it does not automatically adjust the containing SyntaxNode 's kind to EqualsExpression .

As a result, you end up with a GreaterThanExpression with an EqualsEqualsToken . Since this is not a syntax tree that could have been legally generated by the compiler itself, you may see unexpected behavior like this.

To generate a correct tree in this case, I'd recommend rewriting the node itself instead of the token by overriding CSharpSyntaxRewriter.VisitBinaryExpression and doing something like this:

public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node)
{
    if (node.CSharpKind() == SyntaxKind.GreaterThanExpression)
    {
        return SyntaxFactory.BinaryExpression(SyntaxKind.EqualsExpression, node.Left, node.Right);
    }

    return node;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM