Ali Sepehri.Kh
Ali Sepehri.Kh

Reputation: 2508

Replacing the body of a method removes the following line break

I'm using the following code to replace the body of methods by Roslyn;

/* method is instance of MethodDeclarationSyntax */
BlockSyntax newBody = SyntaxFactory.Block(SyntaxFactory.ParseStatement("throw new NotImplementedException();"));
BlockSyntax body = method.Body;
var modifiedMethod = method.ReplaceNode(body, newBody);

But when I do this, line breaks after the methods are removed and if there is a #region or #endregion tag after the method an error will occur.

For example

    #region
    static void RemoveRegions(string str)
    {
        return;
    }
    #endregion

And after replacing the body

    #region
    static void RemoveRegions(string str)
    {
        throw new NotImplementedException();
    }        #endregion    // This cause to compiling error

Upvotes: 5

Views: 2935

Answers (2)

David Poeschl
David Poeschl

Reputation: 864

The original BlockSyntax body contained some "Trailing Trivia" in the form of whitespace (a newline) after the close curly brace. Your constructed BlockSyntax newBody will contain a close curly brace as well, but that curly brace doesn't know whether or not it should have any whitespace after it.

You could do one of three things. I think #1 is the best option but I'm listing the others for completeness:

  1. Reuse the trailing trivia from the original node. You can make use of the trailing trivia from the original node by using GetTrailingTrivia and WithTrailingTrivia:

    var originalTrailingTrivia = body.GetTrailingTrivia();
    newBody = newBody.WithTrailingTrivia(originalTrailingTrivia);
    

    In my opinion, this is your best bet. It will preserve the layout of the code by keeping around any trailing trivia (whether it be one blank line, five blank lines, zero blank lines and two spaces, one space and a comment, etc.) and will be more generally suited to other scenarios you haven't dreamed up yet.

  2. Format the new node. Let the built-in Formatter decide how to handle the whitespace by using WithAdditionalAnnotations to add the Formatter.Annotation and perform a Formatter.FormatAsync on the tree containing the newBody:

    newBody = newBody.WithAdditionalAnnotation(Formatter.Annotation)
    // Code that replaces this node back into the document
    var formattedDocument = Formatter.Format(document, Formatter.Annotation);
    

    Note that this will also format the contents of the method. You could format only the close curly brace and tokens around it by adding the Formatter.Annotation directly to the close curly brace itself instead of the entire BlockSyntax and following the same steps. This approach may lay things out in a reasonable way, but it will remove any comments or intentionally strange whitespace attached to the close curly brace.

  3. Add a trailing newline manually. Create a newline manually and add it to newBody with WithTrailingTrivia:

    newBody = newBody.WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed);
    

    This will also remove any comments or intentionally strange whitespace attached to the close curly brace. It also ignores all context and will not honor any user-specified formatting settings that might change the desired layout of method blocks.

Upvotes: 17

Kevin Pilch
Kevin Pilch

Reputation: 11615

Either Format the new node, or add SyntaxTrivia to it.

Upvotes: 1

Related Questions