Location>code7788 >text

Canonicalizing Asynchronous Methods to Return Async Endings with the `Roslyn` Parser and Fixer

Popularity:208 ℃/2024-09-19 11:40:08

Having previously written aUse the Fixer to help add header annotation text, today using Roslyn's code fixer for the asynchronous return method normalization feature

Implementation Analyzer

First you need to implement the analyzer, using theRegisterSyntaxNodeAction, analyze allThe syntactic type of the

[DiagnosticAnalyzer()]
public class AsyncMethodNameAnalyzer : DiagnosticAnalyzer
{
    public const string DiagnosticId = "GEN051";
    private static readonly LocalizableString Title = "Change the asynchronous method name to start withAsyncwind up";
    private static readonly LocalizableString MessageFormat = "Change the asynchronous method name to start withAsyncwind up";
    private static readonly LocalizableString Description = "Change the asynchronous method name to start withAsyncwind up.";
    private const string Category = "Documentation";

    private static readonly DiagnosticDescriptor Rule = new(
    DiagnosticId, Title, MessageFormat, Category,
    , isEnabledByDefault: true, description: Description);

    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Rule];


    public override void Initialize(AnalysisContext context)
    {
        if (context is null)
            return;
        ();
        ();
        (AnalyzeNode, );
    }

    // Asynchronous method names should begin withAsyncwind up
    private const string AsyncSuffix = "Async";

    private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
    {
        var methodDeclaration = (MethodDeclarationSyntax);

        //If the method containsasyncThe case for modification
        if (())
        {
            if (!(AsyncSuffix, ))
            {
                var diagnostic = (Rule, (), );
                (diagnostic);
            }
        }

        var returnType = ;

        //If the return type isTaskorTask<T>,orValueTask<T>,ValueTask then the method name should start withAsyncwind up
        // Determine if the return type is Task maybe ValueTask
        if (returnType is IdentifierNameSyntax identifierName)
        {
            if ( == "Task" || == "ValueTask")
            {
                if (!(AsyncSuffix, ))
                {
                    var diagnostic = (Rule, (), );
                    (diagnostic);
                }
            }
        }
        else if (returnType is GenericNameSyntax genericName && ( == "Task" || == "ValueTask"))
        {
            if (!(AsyncSuffix, ))
            {
                var diagnostic = (Rule, (), );
                (diagnostic);
            }
        }
    }
}

existInitialize method, a syntax node operation is registered to handle theMethodDeclarationSyntax nodes, the main consideration is whether the methodasynckeyword annotation, or whether the returned type is aTaskorValueTaskIf these conditions are met then the method name is determined.whether or notAsyncEnd. If such a problem exists then create a diagnostic and report it.

Implementing the Fixer

[ExportCodeFixProvider(, Name = nameof(AsyncMethodNameCodeFixProvider))]
[Shared]
internal class AsyncMethodNameCodeFixProvider : CodeFixProvider
{
    public override ImmutableArray<string> FixableDiagnosticIds => [];

    public sealed override FixAllProvider GetFixAllProvider() =>
        ;

    private const string Title = "Change the asynchronous method name to start withAsyncwind up";


    public override Task RegisterCodeFixesAsync(CodeFixContext context)
    {
        var diagnostic = [0];
        var diagnosticSpan = ;

        (
            (
                title: Title,
                createChangedDocument:
                c =>
                FixDocumentAsync(, diagnostic, c),
                equivalenceKey: Title),
            diagnostic);

        return ;

    }

    private const string AsyncSuffix = "Async";

    private static async Task<Document> FixDocumentAsync(Document document, Diagnostic diagnostic, CancellationToken c)
    {
        var root = await (c).ConfigureAwait(false);

        if (root == null)
            return document;

        var node = ();
        var methodDeclaration = (MethodDeclarationSyntax)node;
        var newName = $"{}{AsyncSuffix}";
        var newRoot = (methodDeclaration, ((newName)));
        return (newRoot);
    }
}

The implementation of the restorer is much simpler, and we use the diagnostic information and theDocumentYou can then locate the problematic method itself, and use theWithIdentifier cap (a poem)Just fix the method name to the correct value and return the fixed Document!

Preview effect

Finally, let's take a look at the results

Warning messages returned at compile time
image
Prompts generated when editing a document
image
Click on the tip to fix the code problem
image

ultimate

In fact, this belongs to the code habits or code style issues, personally recommended asynchronous methods or add a suffix, after all, with this specification we look at the method will be able to know that this is an asynchronous method 😃

Finally you can use the nuget package I posted to experience.

dotnet add package 

I posted the source code to GitHub, welcome to star!/vipwan/