Добавить модификатор доступа к методу с использованием Roslyn CodeFixProvider?

Я был в TechEd несколько дней назад, и я увидел этот разговор Кевина Пильча-Биссона (значительная часть начинается примерно через 18 минут)... я мысль была довольно крутой, поэтому я решил поиграть с Рослином.

Я пытаюсь сделать правило "Модификатор доступа должен быть объявлен" (Stylecop SA1400) - значение,

Это нарушает правило:

    static void Main(string[] args)
    {
    }

Это нормально:

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

Он должен иметь явное внутреннее ключевое слово, ключевое слово public, ключевое слово private или защищенное ключевое слово.

Обнаружение нарушения было довольно простым, но теперь я пытаюсь обеспечить исправление. Я пробовал вещи и искал везде, но я не могу узнать, как добавлять модификаторы доступа.

Это то, что у меня есть до сих пор:

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) };
}

Для WithModifiers требуется SyntaxTokenList, для которого я могу использовать New(), но я не знаю, как сделать его SyntaxKind.PublicKeyword. Я также не уверен, что я даже предполагаю, что это новое, или используйте SyntaxFactory. Однако при использовании SyntaxFactory я также не могу понять, какой метод мне нужен, чтобы создать SyntaxToken из SyntaxKind.PublicKeyword

Я могу опубликовать все, включая DiagnosticAnalyzer, если есть интерес...

Ответ 1

Я действительно нуждался в этом:

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

Его почти то, что предложил Крис Элмаа, но с этим предложением я закончил с static public void Main, который действителен, но уродлив.

Добавление публики добавляет его в конец списка, и, насколько я знаю, модификатор доступа всегда должен быть первым.

Ответ 2

Рад, что вам понравилось! На самом деле у нас есть некоторые помощники в синтаксической модели, чтобы упростить добавление элементов в списки, поэтому вы должны иметь возможность сделать что-то вроде:

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

Чтобы получить новое объявление метода.

Развернутая форма этого будет выглядеть примерно так:

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

Надеюсь, что это поможет

Ответ 3

Ну, чтобы создать модификаторы, указывающие public static, вы можете использовать это:

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

Но в вашем случае я не понимаю, почему

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

methodDeclaration.WithModifiers(updatedModifiers);

не будет работать.