通过roslyn在语句后插入新表达式

时间:2015-05-08 14:30:54

标签: c# roslyn

我在使用Roslyn向SyntaxTree添加表达式时遇到了一些问题。我需要实现的目标如下: 每当我找到一个特殊的陈述时,我想在这个陈述之后插入一个或多个表达式

让我们说我要插入声明" myVar = myVar + 1"在每个写入变量" testVar"。

的语句之后

以下代码段:

 a = 10;
 testVar = 50;
 a = testVar / a;
 testVar = a;

应该变成这段代码:

 a = 10;
 testVar = 50;
 myVar = myVar + 1;
 a = testVar / a;
 testVar = a;
 myVar = myVar + 1;

我当前的方法使用SyntaxVisitor和方法' SyntaxNode VisitExpressionStatement(ExpressionStatement node)'。 此方法访问SyntaxTree中的所有表达式,并允许使用它返回的SyntaxNode替换访问过的表达式。 但是,我不想替换语句,而是在它们之后添加新表达式,这基本上需要返回两个表达式。 我发现的唯一解决方案是使用" BlockSyntax"它充当两个表达式的容器(参见代码片段[0])。不幸的是," BlockSyntax"在自身周围引入花括号,这导致以下结果:

 a = 10;
 {
     testVar = 50;
     myVar = myVar + 1;
 }
 a = testVar / a;
 {
     testVar = a;
     myVar = myVar + 1;
 }

这种方法对我来说是不可接受的,因为我不想操纵范围。 有没有办法在我选择的位置使用Roslyn插入任意表达式?

[0]

public SyntaxNode VisitExpressionStatement(ExpressionStatement node){
    if(node has special characteristics){
        var newExpression = ...

        var newStatmentList = new Roslyn.Compilers.CSharp.SyntaxList<StatementSyntax>();
        newStatmentList = newStatmentList.Insert(newStatmentList.Count, node);
        newStatmentList = newStatmentList.Insert(newStatmentList.Count, newExpression);

        BlockSyntax newBlock = Syntax.Block(newStatmentList);
        return newBlock;

    }
    else {
        return node;
    }
}

1 个答案:

答案 0 :(得分:1)

我的策略是欺骗BlockSyntax。查看我的similar question

所以我添加了BlockSyntax,但我通过将{}令牌标记为缺失来“删除”它们。我还没有遇到过这种方法的任何问题,但它似乎更像是一种解决方法而非解决方案。

var statements = new SyntaxList<StatementSyntax>();
//Tried bundling newNode and invocation together
statements.Add(SyntaxFactory.ExpressionStatement(newNode));
statements.Add(SyntaxFactory.ExpressionStatement(invocation));
var wrapper = SyntaxFactory.Block(statements);

//Now we can remove the { and } braces
wrapper = wrapper.WithOpenBraceToken(SyntaxFactory.MissingToken(SyntaxKind.OpenBraceToken))
.WithCloseBraceToken(SyntaxFactory.MissingToken(SyntaxKind.CloseBraceToken));

请注意,我说我正在“删除”它们。这里的问题是你生成的SyntaxTree仍然会出现在C#编译器中,就好像它放置了BlockSyntax一样。这可能也可能不重要。

例如:

  • 如果您将此树作为字符串输出到文件,您会没事的。

  • 如果您正在编译此树,我相信编译器会将BlockSyntax解释为您重写它的现有位置,并且所有作用域语义仍将被强制执行,就好像它在那里一样。 / p>

有关生成“奇怪”树木的更多信息,请查看我的博文:Don't Trust SyntaxNode.ToFullString()