Insert new expression after statement via roslyn

I have some problems adding an expression to SyntaxTree with Roslyn. I have to achieve the following: Whenever I find a special operator, I want to insert one or more expressions after this operator.

Let's say I want to insert the instruction "myVar = myVar + 1" after each statement that writes the variable "testVar".

So the following snippet:

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

Should be turned into this piece of code:

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

My current approach uses SyntaxVisitor using the "SyntaxNode VisitExpressionStatement (ExpressionStatement node)" method. This method visits all expressions in SyntaxTree and allows you to replace the invited expression with the returned SyntaxNode. However, I do not want to perform replacements , but add new expressions after them, which basically require the return of two expressions. The only solution I found was to use "BlockSyntax", which serves as a container for two expressions (see Code Snippet [0]). Unfortunately, "BlockSyntax" introduces curly braces, which lead to the following result:

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

This approach is unacceptable to me because I do not want to manipulate areas. Is there a way to insert arbitrary expressions into my chosen place with 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; } } 
+5
source share
1 answer

My strategy was to spoof BlockSyntax . See my similar question .

So, I add BlockSyntax as you did, but then I β€œdelete” them, marking the tokens { and } as missing. I have not encountered any problems with this approach yet, but this seems like a workaround than a solution.

 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)); 

Notice that I say that I β€œdelete” them. The problem here is that the generated SyntaxTree will still be displayed to the C # compiler, as if it had BlockSyntax in the place where you placed it. It may or may not matter.

For instance:

  • If you output this tree as a string to a file, everything will be fine.

  • If you immediately compile this tree, I believe that the compiler will interpret BlockSyntax as existing, where you rewrote it, and all the semantics of the semantics will still be respected as if they were there.

Read more about creating weird trees in my blog post: Don't trust SyntaxNode.ToFullString()

+1
source

All Articles