简体   繁体   中英

Add access modifier to method using Roslyn CodeFixProvider?

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...

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

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.

Well, to create modifiers that indicate public static , you can use this:

var modifiers = SyntaxFactory.TokenList(
    new SyntaxToken[] { 
        SyntaxFactory.Token(SyntaxKind.PublicKeyword), 
        SyntaxFactory.Token(SyntaxKind.StaticKeyword) 
    }),

But in your case, I don't see why

var updatedModifiers = methodDeclaration
                .Modifiers
                .Add(SyntaxFactory.Token(SyntaxKind.PublicKeyword));

methodDeclaration.WithModifiers(updatedModifiers);

wouldn't work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM