Supernova
Supernova

Reputation: 147

Roslyn - How to add a statement before and after another statement

I have the following code to detect method invocations. I'd like to add to the source code a simple statement, (e.g., Console.WriteLine("Test"); ) before and one after that invocation statement, and save it back to the source file. Any code snippets or examples showing how to do that?

var methodDeclarations = classitem.DescendantNodes().OfType<MethodDeclarationSyntax>();
foreach (var memmeth in methodDeclarations)
{

    var varInvocations = memmeth.DescendantNodes().OfType<InvocationExpressionSyntax>();
    foreach (InvocationExpressionSyntax invoc in varInvocations)
    {
             // insert new statement before and after the invocation

Upvotes: 3

Views: 2435

Answers (1)

SJP
SJP

Reputation: 1010

You're trying to mix statements with expressions.

If I write

this.Test();

In my code, it is a SimpleExpressionStatement within an InvocationExpression within an ExpressionStatement.

The Statement is basically the element representing a single line of code, in our example this.Test();, possibly something like return; throw; etc.

So if you wish to insert a statement before or after an expression, you have to insert it before or after the containing statement.

However, this could create problems as you can have multiple expressions in the same Statement, e.g.

if(Test() && Test2()){

}

So in order to insert a new statement before or after the method invocation you could simply find the nearest Statement and insert it before or after said statement, e.g:

var statements = new List<StatementSyntax>();
var methodDeclarations = root.DescendantNodes().OfType<MethodDeclarationSyntax>();
foreach (var memmeth in methodDeclarations)
{
    var varInvocations = memmeth.DescendantNodes().OfType<InvocationExpressionSyntax>();
    foreach (InvocationExpressionSyntax invoc in varInvocations)
    {
        // Find the relevant node
        var statement = invoc.Ancestors().OfType<StatementSyntax>().FirstOrDefault();
        statements.Add(statement);
    }
}
// Track the nodes so you can change it in the tree even after modifying it
root = root.TrackNodes(statements.Distinct());
foreach(var statement in statements)
{
    var currentStatement = root.GetCurrentNode(statement);
    root = root.InsertNodesAfter(currentStatement,            
        new[] { SyntaxFactory.ExpressionStatement(
                    SyntaxFactory.InvocationExpression(
                        SyntaxFactory.MemberAccessExpression(
                            SyntaxKind.SimpleMemberAccessExpression, 
                            SyntaxFactory.IdentifierName("Console"), 
                            SyntaxFactory.IdentifierName("WriteLine"))
                        ))});
    currentStatement = root.GetCurrentNode(statement);
    root = root.InsertNodesBefore(currentStatement,
        new[] { SyntaxFactory.ExpressionStatement(
            SyntaxFactory.InvocationExpression(
                SyntaxFactory.MemberAccessExpression(
                    SyntaxKind.SimpleMemberAccessExpression,
                    SyntaxFactory.IdentifierName("Console"),
                    SyntaxFactory.IdentifierName("WriteLine"))
                ))});
}

Upvotes: 5

Related Questions