File: CodeRefactorings\SyntaxEditorBasedCodeRefactoringProvider.cs
Web Access
Project: src\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using FixAllScope = Microsoft.CodeAnalysis.CodeFixes.FixAllScope;
 
namespace Microsoft.CodeAnalysis.CodeRefactorings;
 
internal abstract partial class SyntaxEditorBasedCodeRefactoringProvider : CodeRefactoringProvider
{
    protected static readonly ImmutableArray<FixAllScope> DefaultFixAllScopes = [FixAllScope.Document, FixAllScope.Project, FixAllScope.Solution];
    protected static readonly ImmutableArray<FixAllScope> AllFixAllScopes = [FixAllScope.Document, FixAllScope.Project, FixAllScope.Solution, FixAllScope.ContainingType, FixAllScope.ContainingMember];
 
    protected abstract ImmutableArray<FixAllScope> SupportedFixAllScopes { get; }
 
    internal sealed override FixAllProvider? GetFixAllProvider()
    {
        if (SupportedFixAllScopes.IsEmpty)
            return null;
 
        return FixAllProvider.Create(
            async (fixAllContext, document, fixAllSpans) =>
            {
                return await this.FixAllAsync(document, fixAllSpans, fixAllContext.CodeActionEquivalenceKey, fixAllContext.CancellationToken).ConfigureAwait(false);
            },
            SupportedFixAllScopes);
    }
 
    protected Task<Document> FixAsync(
        Document document,
        TextSpan fixAllSpan,
        string? equivalenceKey,
        CancellationToken cancellationToken)
    {
        return FixAllWithEditorAsync(document,
            editor => FixAllAsync(document, [fixAllSpan], editor, equivalenceKey, cancellationToken),
            cancellationToken);
    }
 
    protected Task<Document> FixAllAsync(
        Document document,
        Optional<ImmutableArray<TextSpan>> fixAllSpans,
        string? equivalenceKey,
        CancellationToken cancellationToken)
    {
        return FixAllWithEditorAsync(document, FixAllAsync, cancellationToken);
 
        // Local functions
        Task FixAllAsync(SyntaxEditor editor)
        {
            // Fix the entire document if there are no sub-spans to fix.
            var spans = fixAllSpans.HasValue ? fixAllSpans.Value : [editor.OriginalRoot.FullSpan];
            return this.FixAllAsync(document, spans, editor, equivalenceKey, cancellationToken);
        }
    }
 
    internal static async Task<Document> FixAllWithEditorAsync(
        Document document,
        Func<SyntaxEditor, Task> editAsync,
        CancellationToken cancellationToken)
    {
        var root = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
        var editor = new SyntaxEditor(root, document.Project.Solution.Services);
 
        await editAsync(editor).ConfigureAwait(false);
 
        var newRoot = editor.GetChangedRoot();
        return document.WithSyntaxRoot(newRoot);
    }
 
    protected abstract Task FixAllAsync(
        Document document,
        ImmutableArray<TextSpan> fixAllSpans,
        SyntaxEditor editor,
        string? equivalenceKey,
        CancellationToken cancellationToken);
}