2014-11-02 14 views
10

Ero al TechEd pochi giorni fa, e ho visto this talk by Kevin Pilch-Bisson (relevent part starts at about 18 minutes) ... Ho pensato che fosse abbastanza bello, così ho deciso di giocare con Roslyn me stesso.Aggiungi il modificatore di accesso al metodo utilizzando Roslyn CodeFixProvider?

Sto cercando di fare una regola "Accesso modificatore deve essere dichiarato" (StyleCop SA1400) - significato,

Questo viola la regola:

static void Main(string[] args) 
    { 
    } 

Questo è ok:

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

Deve avere una parola chiave interna, una parola chiave pubblica, una parola chiave privata o una parola chiave parola chiave tected.

Rilevare la violazione era abbastanza semplice, ma ora sto cercando di fornire una soluzione. Ho provato cose e cercato ovunque, ma non riesco a scoprire come aggiungere i modificatori di accesso.

Questo è quello che ho finora:

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

Il WithModifiers ha bisogno di un SyntaxTokenList, che posso New(), ma non so come fare di SyntaxKind.PublicKeyword. Non sono nemmeno sicuro di dover supporre che sia nuovo, o di usare lo SyntaxFactory. Tuttavia, quando si utilizza il SyntaxFactory, anche io non riesco a capire quale metodo che ho bisogno di creare un SyntaxToken di SyntaxKind.PublicKeyword

posso postare l'intera cosa, compreso il DiagnosticAnalyzer se c'è interesse ...

risposta

3

Quello che in realtà serviva era questo:

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

sua quasi quello che Chris Eelmaa suggerito, ma con quel suggerimento ho finito con static public void Main che è valido, ma brutto.

L'aggiunta di pubblico lo aggiunge alla fine dell'elenco e, per quanto ne so, il modificatore di accesso dovrebbe sempre essere il primo.

+1

Mi sembra buono, tranne che tu hai un "TokenList pubblico" locale inutilizzato.Il tuo Func verrà chiamato per creare l'anteprima e quando cliccato, ma dovrebbe andare bene –

+0

Ok grazie :). publicTokenList, di solito resharper mi dice di questi, ma dato che stavo lavorando su vs14 non ha avuto questo .. –

1

Beh, per creare un modificatori che indicano public static, è possibile utilizzare questo:

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

Ma nel tuo caso, non vedo il motivo per cui

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

methodDeclaration.WithModifiers(updatedModifiers); 

non funzionerebbe.

+0

Il primo suggerimento non funziona perché ovviamente non è sempre necessario il static, ma ho il suo solo scopo di spiegare la sintassi ... Tuttavia, anche il secondo suggerimento non funziona, risulta in 'static public void Main 'o publicvoid statico Main –

+0

@RonSijm, +1. Non ho alcun problema se ripulisci la tua risposta e metti solo materiale rilevante (ad esempio, sbarazzarsi di 'GetFixesAsync' e' CreateAction') e accettarlo. È una bella domanda –

6

Felice che ti sia piaciuto il discorso! Noi in realtà sono alcuni aiutanti nel modello di sintassi per rendere più facile per aggiungere elementi a liste, così si dovrebbe essere in grado di fare qualcosa di simile:

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

Per ottenere la nuova dichiarazione di metodo.

La forma estesa di questo sarebbe qualcosa di simile:

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

Spero che questo aiuti

+0

Mi è piaciuta molto la conversazione! A proposito del miglior talk che ho visto su teched, insieme a quello di Async :) - In ogni caso, il tuo suggerimento funziona in qualche modo, ma finisco con "static public void Main". Ho aggiunto la mia soluzione che sembra funzionare. Se potessi riesaminarlo, nel caso avessi fatto qualcosa di strano, sarebbe comunque grandioso. È la prima cosa che ho fatto per Roslyn, quindi ci sono probabilmente un sacco di cose da migliorare –

+0

Oh btw, perché la sintassi del AnalyzeNode è questa: 'public void AnalyzeNode (nodo SyntaxNode, SemanticModel semanticModel, Action addDiagnostic' e non questo : 'Azione pubblica AnalyzeNode (nodo SyntaxNode, SemanticModel semanticModel'? Sembra un po 'strano –

+1

Perché è possibile segnalare più diagnostiche. Inoltre, il loro essere un richiamo ci consente di evitare alcune allocazioni e di trasmettere in streaming i risultati quando vengono segnalati –

Problemi correlati