Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add access modifier to method using Roslyn CodeFixProvider?

Tags:

c#

roslyn

I was at the TechEd a few days ago, and I saw this talk by Kevin Pilch-Bisson (relevent part starts at about 18 minutes) ... I thought is was pretty cool, so I decided to play around with Roslyn myself.

I'm trying to make a rule "Access Modifier Must Be Declared" (Stylecop SA1400) - meaning,

This violates the rule:

    static void Main(string[] args)
    {
    }

This is ok:

    public static void Main(string[] args)
    {
    }

It must have an explicit internal keyword, public keyword, private keyword, or protected keyword.

Detecting the violation was fairly easy, but now I'm trying to provide a fix. I've been trying things and searching everywhere, but I can't find out how to add access modifiers.

This is what I have so far:

public async Task<IEnumerable<CodeAction>> GetFixesAsync(Document document, TextSpan span, IEnumerable<Diagnostic> diagnostics, CancellationToken cancellationToken)
{
    var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
    var token = root.FindToken(span.Start);

    var methodDeclaration = token.Parent as MethodDeclarationSyntax;

    //var newModifiers = methodDeclaration.Modifiers.Add(SyntaxFactory.AccessorDeclaration(SyntaxKind.PublicKeyword));         
    //var newModifiers = new SyntaxTokenList() { new SyntaxToken() };

    MethodDeclarationSyntax newMethodDeclaration = methodDeclaration.WithModifiers(methodDeclaration.Modifiers);
    var newRoot = root.ReplaceNode(methodDeclaration, newMethodDeclaration);
    var newDocument = document.WithSyntaxRoot(newRoot);

    return new[] { CodeAction.Create("Add Public Keyword", newDocument) };
}

The WithModifiers needs a SyntaxTokenList, which I can New(), but I don't know how to make it of SyntaxKind.PublicKeyword. I'm also not sure if I'm even suppose to new it, or use the SyntaxFactory. However, when using the SyntaxFactory, I also can't figure out which method I need to create a SyntaxToken of SyntaxKind.PublicKeyword

I can post the entire thing, including the DiagnosticAnalyzer if there's interest...

like image 695
Ron Sijm Avatar asked Nov 02 '14 18:11

Ron Sijm


2 Answers

Glad you enjoyed the talk! We actually have some helpers in the syntax model to make it easier to add items to lists, so you should be able to do something like:

var newMethodDeclaration = methodDeclaration.AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword));

To get the new method declaration.

The expanded form of this would be something like:

var newModifiers = SyntaxFactory.TokenList(modifiers.Concat(new[] { SyntaxFactory.Token(SyntaxKind.PublicKeyword)}));
var newMethodDeclaration = methodDeclaration.WithModifiers(newModifiers);

Hope this helps

like image 80
Kevin Pilch Avatar answered Oct 05 '22 23:10

Kevin Pilch


What I actually needed was this:

var newModifiers = SyntaxFactory.TokenList(SyntaxFactory.Token(accessModifierToken))
    .AddRange(methodDeclaration.Modifiers);

It's almost what Chris Eelmaa suggested, but with that suggestion I ended up with static public void Main which is valid, but ugly.

Appending public adds it to the end of the list, and as far as I know, the access modifier should always be the first.

like image 35
Ron Sijm Avatar answered Oct 06 '22 00:10

Ron Sijm