1

I'm writing an analyzer and codefix for an API migration (AutoMapper V5 Profiles), converting a protected override Configure method to a constructor:

from:

public class MappingProfile : Profile
{
    protected override Configure()
    {
        CreateMap<Foo, Bar>();
        RecognizePrefix("m_");
    }
}

to

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Foo, Bar>();
        RecognizePrefix("m_");
    }
}

I've found a way to convert the method node into a constructor, but I've been struggling a lot to get the whitespace right. This begs the question if I'm not overlooking a simpler way of converting a method to constructor.

So my question is: does Roslyn already give you a refactoring to convert a MethodDeclarationSyntax to a ConstructorDeclarationSyntax? Or an easier way than this LINQPad script.

Ties
  • 1,205
  • 2
  • 15
  • 28
  • Can't you just take the body of the method and create a constructor with that as body? Then format the entire constructor and whitespace will be pretty. – Jeroen Vannevel Nov 14 '16 at 12:03
  • No, since the existing formatting of the method body will be wiped out by `NormalizeWhiteSpace()`, which we want to keep – Ties Nov 14 '16 at 13:39
  • @Ties format the constructor with an empty/dummy body first, then add the old body, which is already formatted – m0sa Nov 15 '16 at 00:02
  • I tried that, but then the indentation level is off: NormalizeWhitespace will put the constructor at indentation level 0... – Ties Nov 15 '16 at 14:45
  • Have you tried `.WithAdditionalAnnotations(Formatter.Annotation)` ? – Kris Vandermotten Nov 16 '16 at 00:28
  • That's a really good idea, I'll give that a try. I have played around with that previously, but couldn't get it to work in an expected way. Do you have some links to blogs for examples where it is being used? – Ties Nov 16 '16 at 09:29
  • 1
    In your CodeFix, use `SyntaxFactory.ConstructorDeclaration(constructorIdentifier).WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword))).WithAttributeLists(oldMethodNode.AttributeLists).WithParameterList(newParameterList).WithBody(newBody).WithTriviaFrom(oldMethodNode).WithAdditionalAnnotations(Formatter.Annotation)`. It really should be as simple as that. Note that this may not work outside the CodeFix. Somebody has to process the annotation, and code fixes do that. – Kris Vandermotten Nov 16 '16 at 14:46
  • Outside of a CodeFix, you can use `Formatter.Format()` from `Microsoft.CodeAnalysis.Formatting`. See also http://stackoverflow.com/questions/19711218/how-to-add-white-space-and-or-format-code – Kris Vandermotten Nov 16 '16 at 14:55
  • Thanks Kris, I'll give that a try, when I'm all better (unfortunately, I'm stuck at the moment :() – Ties Nov 17 '16 at 11:57
  • @KrisVandermotten Thanks. I tried the Formatter annotation, and that worked like a charm! I knew it existed, but didn't really understand it, but now I do :) If you convert your comment into an answer, then I'll accept it ;) – Ties Nov 24 '16 at 16:32

1 Answers1

2

In a CodeFix, just add the formatter annotation:

SyntaxFactory
    .ConstructorDeclaration(constructorIdentifier)
    .‌​WithModifiers(Syntax‌​Factory.TokenList(Sy‌​ntaxFactory.Token(Sy‌​ntaxKind.PublicKeywo‌​rd)))
    .WithAttributeL‌​ists(oldMethodNode.A‌​ttributeLists)
    .WithP‌​arameterList(newPara‌​meterList)
    .WithBody(‌​newBody)
    .WithTriviaF‌​rom(oldMethodNode)
    .W‌​ithAdditionalAnnotat‌​ions(Formatter.Annot‌​ation)

That's enough to do the trick in a code fix, because the code fix infrastructure will process the annotation.

Outside of a CodeFix, you can use Formatter.Format() from Microsoft.CodeAnalysis.Formatting to process the annotation explicitely.

Kris Vandermotten
  • 10,111
  • 38
  • 49