Why Roslyn is generating method code without spaces
Asked Answered
H

4

17

What am I doing wrong that Roslyn is generating code without any space between identifiers and keywords? It is also putting a semicolon at the end of the method block. Here is my code:

SeparatedSyntaxList<ParameterSyntax> parametersList = new SeparatedSyntaxList<ParameterSyntax>().AddRange
(new ParameterSyntax[]
    {
        SyntaxFactory.Parameter(SyntaxFactory.Identifier("sender")).WithType(SyntaxFactory.ParseTypeName("object")),
        SyntaxFactory.Parameter(SyntaxFactory.Identifier("args")).WithType(SyntaxFactory.ParseTypeName("EventArgs"))
    }
);

MethodDeclarationSyntax newMethod = SyntaxFactory.MethodDeclaration(
    SyntaxFactory.List<AttributeListSyntax>(),
    SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)),
    SyntaxFactory.ParseName("void"),
    null,
    SyntaxFactory.Identifier("simpleButton1_Click"),
    null,
    SyntaxFactory.ParameterList(parametersList),
    SyntaxFactory.List<TypeParameterConstraintClauseSyntax>(),
    SyntaxFactory.Block(),
    SyntaxFactory.Token(SyntaxKind.SemicolonToken)
);

And here is the result that I am having:

privatevoidsimpleButton1_Click(objectsender,EventArgse){};
Hunter answered 29/10, 2015 at 14:19 Comment(0)
D
5

I think it's putting the semicolon there because you are passing one to the method that creates the method declaration, I'm guessing this is used when declaring an abstract method without a body.

To correctly format the output you could use the Formatter class in the Microsoft.CodeAnalysis.Formatting namespace.

Workspace workspace = MSBuildWorkspace.Create();
SyntaxNode formattedNode = Microsoft.CodeAnalysis.Formatting.Formatter.Format(newMethod, workspace);

For the return type you could do the following

SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword));   

This will give you a TypeSyntax

Deeann answered 29/10, 2015 at 17:7 Comment(0)
A
14

To be even more comprehensive, NormalizeWhiteSpace should be mentioned. It applies default formatting to the given node:

MethodDeclarationSyntax newMethod = SyntaxFactory.MethodDeclaration(
    SyntaxFactory.List<AttributeListSyntax>(),
    SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)),
    SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword)),
    null,
    SyntaxFactory.Identifier("simpleButton1_Click"),
    null,
    SyntaxFactory.ParameterList(parametersList),
    SyntaxFactory.List<TypeParameterConstraintClauseSyntax>(),
    SyntaxFactory.Block(),
    null
  )

newMethod = newMethod.NormalizeWhitespace();

A ToString() on that will produce the expected output:

private void simpleButton1_Click(object sender, EventArgs args)
{
}
Antoniettaantonin answered 30/10, 2015 at 14:58 Comment(1)
NormalizeWhitespace works for me. It adds spaces (lots of them) but at least ensures a space between keywords and idsThimble
D
5

I think it's putting the semicolon there because you are passing one to the method that creates the method declaration, I'm guessing this is used when declaring an abstract method without a body.

To correctly format the output you could use the Formatter class in the Microsoft.CodeAnalysis.Formatting namespace.

Workspace workspace = MSBuildWorkspace.Create();
SyntaxNode formattedNode = Microsoft.CodeAnalysis.Formatting.Formatter.Format(newMethod, workspace);

For the return type you could do the following

SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.VoidKeyword));   

This will give you a TypeSyntax

Deeann answered 29/10, 2015 at 17:7 Comment(0)
C
3

You could use .WithAdditionalAnnotations(Formatter.Annotation) to format the syntax nodes that you generate.

Chesney answered 29/10, 2015 at 14:33 Comment(3)
Thanks @Chesney for the suggestion but it doesn't appear to work. What I got from this method is, it will add additional annotations on the method that I am not looking to insert. Instead I just want to create correct method syntax.Hunter
Where are you generating this code? Is this in a codefix provider and are you inside Visual Studio? If not, you'll need to use Formatter.Format() on the syntax node that you want to format.Chesney
Formatter.Format fixes parameters part but still the method declaration is like "privatevoidButton1_Click". Probably defined modifier by SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)) and returnType by SyntaxFactory.ParseName("void") is not the best way to go. Any idea how to improve it? BTW an ugly hack is to parse " void " instead of "void" to find desired resultsHunter
P
0

None of the above worked for me in a roslyn CodeFixProvider I'm working on.

I found on reliable solution was to change the method type name to " void " (Note the spaces).

It fixed it from privatevoidMethod() { to private void Method() {

MethodDeclarationSyntax method = SyntaxFactory.MethodDeclaration(
            SyntaxFactory.List<AttributeListSyntax>(),
            SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)),
            SyntaxFactory.ParseName(" void "), // <--------------!!!!
            null,
            SyntaxFactory.Identifier("Method"),
            null,
            SyntaxFactory.ParameterList(),
            SyntaxFactory.List<TypeParameterConstraintClauseSyntax>(),
            SyntaxFactory.Block(SyntaxFactory.ParseStatement(bodyText)),
            null)
            .WithAdditionalAnnotations(Formatter.Annotation);
        return method;

Then, I added the method to the classDeclarationSyntax, updated the root node with the new ClassDeclarationSyntax, and called:

await Formatter.FormatAsync(document)

This last bit made the correct indentation in the class etc.

For me using NormalizeWhiteSpace(); added 2 spaces instead of 1, even after calling format.

Perni answered 9/3 at 22:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.