File: CodeFixesAndRefactorings\AbstractFixAllCodeAction.cs
Web Access
Project: src\src\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj (Microsoft.CodeAnalysis.Features)
// 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 Roslyn.Utilities;
using FixAllScope = Microsoft.CodeAnalysis.CodeFixes.FixAllScope;
 
namespace Microsoft.CodeAnalysis.CodeFixesAndRefactorings;
 
/// <summary>
/// Fix all code action for a code action registered by
/// a <see cref="CodeFixes.CodeFixProvider"/> or a <see cref="CodeRefactorings.CodeRefactoringProvider"/>.
/// </summary>
internal abstract class AbstractFixAllCodeAction : CodeAction
{
    private bool _showPreviewChangesDialog;
 
    public IFixAllState FixAllState { get; }
 
    protected AbstractFixAllCodeAction(
        IFixAllState fixAllState, bool showPreviewChangesDialog)
    {
        FixAllState = fixAllState;
        _showPreviewChangesDialog = showPreviewChangesDialog;
    }
 
    /// <summary>
    /// Determine if the <see cref="IFixAllState.Provider"/> is an internal first-party provider or not.
    /// </summary>
    protected abstract bool IsInternalProvider(IFixAllState fixAllState);
 
    /// <summary>
    /// Creates a new <see cref="IFixAllContext"/> with the given parameters.
    /// </summary>
    protected abstract IFixAllContext CreateFixAllContext(IFixAllState fixAllState, IProgress<CodeAnalysisProgress> progressTracker, CancellationToken cancellationToken);
 
    public override string Title
        => this.FixAllState.Scope switch
        {
            FixAllScope.Document => FeaturesResources.Document,
            FixAllScope.Project => FeaturesResources.Project,
            FixAllScope.Solution => FeaturesResources.Solution,
            FixAllScope.ContainingMember => FeaturesResources.Containing_Member,
            FixAllScope.ContainingType => FeaturesResources.Containing_Type,
            _ => throw ExceptionUtilities.UnexpectedValue(this.FixAllState.Scope),
        };
 
    internal override string Message => FeaturesResources.Computing_fix_all_occurrences_code_fix;
 
    protected sealed override Task<ImmutableArray<CodeActionOperation>> ComputeOperationsAsync(
        IProgress<CodeAnalysisProgress> progressTracker, CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();
        FixAllLogger.LogState(FixAllState, IsInternalProvider(FixAllState));
 
        var service = FixAllState.Project.Solution.Services.GetRequiredService<IFixAllGetFixesService>();
 
        var fixAllContext = CreateFixAllContext(FixAllState, progressTracker, cancellationToken);
        progressTracker.Report(CodeAnalysisProgress.Description(fixAllContext.GetDefaultFixAllTitle()));
 
        return service.GetFixAllOperationsAsync(fixAllContext, _showPreviewChangesDialog);
    }
 
    protected sealed override Task<Solution?> GetChangedSolutionAsync(
        IProgress<CodeAnalysisProgress> progressTracker, CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();
        FixAllLogger.LogState(FixAllState, IsInternalProvider(FixAllState));
 
        var service = FixAllState.Project.Solution.Services.GetRequiredService<IFixAllGetFixesService>();
 
        var fixAllContext = CreateFixAllContext(FixAllState, progressTracker, cancellationToken);
        progressTracker.Report(CodeAnalysisProgress.Description(fixAllContext.GetDefaultFixAllTitle()));
 
        return service.GetFixAllChangedSolutionAsync(fixAllContext);
    }
 
    // internal for testing purposes.
    internal TestAccessor GetTestAccessor()
        => new(this);
 
    // internal for testing purposes.
    internal readonly struct TestAccessor
    {
        private readonly AbstractFixAllCodeAction _fixAllCodeAction;
 
        internal TestAccessor(AbstractFixAllCodeAction fixAllCodeAction)
            => _fixAllCodeAction = fixAllCodeAction;
 
        /// <summary>
        /// Gets a reference to <see cref="_showPreviewChangesDialog"/>, which can be read or written by test code.
        /// </summary>
        public ref bool ShowPreviewChangesDialog
            => ref _fixAllCodeAction._showPreviewChangesDialog;
    }
}