WellKnownFixAllProviders.BatchFixer如何工作?

时间:2016-02-24 04:33:51

标签: c# roslyn

您可能知道,我们可以根据Roslyn和Visual Studio Integration提供的工具为我们的CSharp项目开发一些分析器和代码修复程序。 当我开发代码修补程序以更改代码语法树时,它适用于WellKnownFixAllProviders.BatchFixer。例如,将所有TypeDeclaration名称更改为大写。

public class MyClassCodeFixProvider : CodeFixProvider
{
    private const string title = "MyClassCodeFix";

    public sealed override ImmutableArray<string> FixableDiagnosticIds
    {
        get { return ImmutableArray.Create("MyClassCodeFix"); }
    }

    public sealed override FixAllProvider GetFixAllProvider()
    {
        return WellKnownFixAllProviders.BatchFixer;
    }
    public async sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
    {
        var document = context.Document;
        var span = context.Span;
        var cancellationToken = context.CancellationToken;

        var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

        var token = root.FindToken(span.Start);
        if (!token.Span.IntersectsWith(span))
        {
            return;
        }
        Diagnostic diagnostic = context.Diagnostics.First();
        TextSpan diagnosticSpan = diagnostic.Location.SourceSpan;
        TypeDeclarationSyntax declaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<TypeDeclarationSyntax>().First();

        var codeChangeForDocument = CodeAction.Create(
                            title: title,
                            //this code works fine
                            createChangedSolution: c => MakeUppercaseAsync(context, declaration, c),
                            equivalenceKey: title);
        context.RegisterCodeFix(codeChangeForDocument, context.Diagnostics);

    }
    private async Task<Solution> MakeUppercaseAsync(CodeFixContext context, TypeDeclarationSyntax typeDecl, CancellationToken cancellationToken)
    {
        var identifierToken = typeDecl.Identifier;
        var newName = identifierToken.Text.ToUpperInvariant();

        var semanticModel = await context.Document.GetSemanticModelAsync(cancellationToken);
        var typeSymbol = semanticModel.GetDeclaredSymbol(typeDecl, cancellationToken);

        var originalSolution = context.Document.Project.Solution;
        var optionSet = originalSolution.Workspace.Options;
        var newSolution = await Renamer.RenameSymbolAsync(context.Document.Project.Solution, typeSymbol, newName, optionSet, cancellationToken).ConfigureAwait(false);

        return newSolution;
    }
}

但是,当我们在代码修复中添加一些新文档,然后我们在文档或项目或解决方案中使用代码修复时,它根本不起作用(WellKnownFixAllProviders.BatchFixer窗口无法打开)。但是当我们在一个诊断上调用我们的代码修复时,它就完美了。

    public sealed override FixAllProvider GetFixAllProvider()
    {
        return WellKnownFixAllProviders.BatchFixer;
    }

    public async sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
    {
        var document = context.Document;
        var span = context.Span;
        var cancellationToken = context.CancellationToken;

        var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

        var token = root.FindToken(span.Start);
        if (!token.Span.IntersectsWith(span))
        {
            return;
        }
        Diagnostic diagnostic = context.Diagnostics.First();
        TextSpan diagnosticSpan = diagnostic.Location.SourceSpan;
        TypeDeclarationSyntax declaration = root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf().OfType<TypeDeclarationSyntax>().First();

        var codeChangeForDocument = CodeAction.Create(
                            title: title,
                            //createChangedSolution: c => MakeUppercaseAsync(context.Document, declaration, c),
                            //this code does not work
                            createChangedSolution : c => GenerateDocForSolution(context, declaration, c),
                            equivalenceKey: title);
        context.RegisterCodeFix(codeChangeForDocument, context.Diagnostics);

    }

    private async Task<Solution> GenerateDocForSolution(CodeFixContext context, TypeDeclarationSyntax declaration, CancellationToken cancellationToken)
    {
        var model = await context.Document.GetSemanticModelAsync(cancellationToken);
        ExtractPropFromEntitySyntaxWalker extractor = new ExtractPropFromEntitySyntaxWalker(model);
        extractor.Visit(declaration);

        var currentDoc = context.Document.Project.Documents.SingleOrDefault(doc => doc.Name == string.Format("{0}Auto", declaration.Identifier.Text));
        Document newDoc = null;
        if (currentDoc != null)
        {
            newDoc = currentDoc.WithSyntaxRoot(extractor.NewSyntax);
        }
        else
        {
            newDoc = context.Document.Project.AddDocument(string.Format("{0}Auto", declaration.Identifier.Text),
                                                            extractor.NewSyntax.GetText()
                                                            );
        }

        return newDoc.Project.Solution;
    }

据我所知,WellKnownFixAllProviders.BatchFixer合并了解决方案,项目或文档中所有诊断的所有代码修复所做的所有更改。 WellKnownFixAllProviders.BatchFixer是否支持此类方案?

0 个答案:

没有答案