Skip to content

Instantly share code, notes, and snippets.

@Schandlich
Last active August 29, 2015 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Schandlich/6cefe55a4fc61f9867f6 to your computer and use it in GitHub Desktop.
Save Schandlich/6cefe55a4fc61f9867f6 to your computer and use it in GitHub Desktop.
Async Method Name Checker
[ExportCodeFixProvider(DiagnosticAnalyzer.DiagnosticId, LanguageNames.CSharp)]
internal class CodeFixProvider : ICodeFixProvider
{
public IEnumerable<string> GetFixableDiagnosticIds()
{
return new[] { DiagnosticAnalyzer.DiagnosticId };
}
public async Task<IEnumerable<CodeAction>> GetFixesAsync(Document document, TextSpan span, IEnumerable<Diagnostic> diagnostics, CancellationToken cancellationToken)
{
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var diagnosticSpan = diagnostics.First().Location.SourceSpan;
var declaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<MethodDeclarationSyntax>().First();
return new[] { CodeAction.Create("Fix async naming convention error.", c => ChangeNameAsync(document, declaration, c)) };
}
private async Task<Solution> ChangeNameAsync(Document document, MethodDeclarationSyntax methodDeclaration, CancellationToken cancellationToken)
{
var identifierToken = methodDeclaration.Identifier;
var newName = identifierToken.Text + "Async";
var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
var typeSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration, cancellationToken);
var originalSolution = document.Project.Solution;
var optionSet = originalSolution.Workspace.GetOptions();
var newSolution = await Renamer.RenameSymbolAsync(document.Project.Solution, typeSymbol, newName, optionSet, cancellationToken).ConfigureAwait(false);
return newSolution;
}
}
[DiagnosticAnalyzer]
[ExportDiagnosticAnalyzer(DiagnosticId, LanguageNames.CSharp)]
public class DiagnosticAnalyzer : ISyntaxNodeAnalyzer<SyntaxKind>
{
internal const string DiagnosticId = "AsyncMethodNotNamedCorrectly";
internal const string Description = "A method with an async modifier needs to end with \"Async\"";
internal static readonly string MessageFormat = "Make sure the name of this method ends with \"Async\".";
internal const string Category = "Async";
internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Description, MessageFormat, Category, DiagnosticSeverity.Warning);
public ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
get { return ImmutableArray.Create(Rule); }
}
public ImmutableArray<SyntaxKind> SyntaxKindsOfInterest
{
get { return ImmutableArray.Create(SyntaxKind.MethodDeclaration); }
}
public void AnalyzeNode(SyntaxNode node, SemanticModel semanticModel, Action<Diagnostic> addDiagnostic, CancellationToken cancellationToken)
{
var method = (MethodDeclarationSyntax)node;
if (method.Modifiers.Any(SyntaxKind.AsyncKeyword)
&& method.ReturnType as GenericNameSyntax != null
&& !method.Identifier.Text.EndsWith("Async")
&& method.DescendantNodes().OfType<PrefixUnaryExpressionSyntax>().Any(x => x.IsKind(SyntaxKind.AwaitExpression)))
{
addDiagnostic(Diagnostic.Create(Rule, method.Identifier.GetLocation()));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment