<commit_before>﻿// 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.

#nullable enable

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CaseCorrection;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.CodeAnalysis.Tags;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CodeActions
{
    /// <summary>
    /// An action produced by a <see cref="CodeFixProvider"/> or a <see cref="CodeRefactoringProvider"/>.
    /// </summary>
    public abstract class CodeAction
    {
        /// <summary>
        /// A short title describing the action that may appear in a menu.
        /// </summary>
        public abstract string Title { get; }

        internal virtual string Message => Title;

        /// <summary>
        /// Two code actions are treated as equivalent if they have equal non-null <see cref="EquivalenceKey"/> values and were generated
        /// by the same <see cref="CodeFixProvider"/> or <see cref="CodeRefactoringProvider"/>.
        /// </summary>
        /// <remarks>
        /// Equivalence of code actions affects some Visual Studio behavior. For example, if multiple equivalent
        /// code actions result from code fixes or refactorings for a single Visual Studio light bulb instance,
        /// the light bulb UI will present only one code action from each set of equivalent code actions.
        /// Additionally, a Fix All operation will apply only code actions that are equivalent to the original code action.
        ///
        /// If two code actions that could be treated as equivalent do not have equal <see cref="EquivalenceKey"/> values, Visual Studio behavior
        /// may be less helpful than would be optimal. If two code actions that should be treated as distinct have
        /// equal <see cref="EquivalenceKey"/> values, Visual Studio behavior may appear incorrect.
        /// </remarks>
        public virtual string? EquivalenceKey => null;

        internal virtual bool IsInlinable => false;

        internal virtual CodeActionPriority Priority => CodeActionPriority.Medium;

        /// <summary>
        /// Descriptive tags from <see cref="WellKnownTags"/>.
        /// These tags may influence how the item is displayed.
        /// </summary>
        public virtual ImmutableArray<string> Tags => ImmutableArray<string>.Empty;

        internal virtual ImmutableArray<CodeAction> NestedCodeActions
            => ImmutableArray<CodeAction>.Empty;

        /// <summary>
        /// The sequence of operations that define the code action.
        /// </summary>
        public Task<ImmutableArray<CodeActionOperation>> GetOperationsAsync(CancellationToken cancellationToken)
        {
            return GetOperationsAsync(new ProgressTracker(), cancellationToken);
        }

        internal Task<ImmutableArray<CodeActionOperation>> GetOperationsAsync(
            IProgressTracker progressTracker, CancellationToken cancellationToken)
        {
            return GetOperationsCoreAsync(progressTracker, cancellationToken);
        }

        /// <summary>
        /// The sequence of operations that define the code action.
        /// </summary>
        internal virtual async Task<ImmutableArray<CodeActionOperation>> GetOperationsCoreAsync(
            IProgressTracker progressTracker, CancellationToken cancellationToken)
        {
            var operations = await this.ComputeOperationsAsync(progressTracker, cancellationToken).ConfigureAwait(false);

            if (operations != null)
            {
                return await this.PostProcessAsync(operations, cancellationToken).ConfigureAwait(false);
            }

            return ImmutableArray<CodeActionOperation>.Empty;
        }

        /// <summary>
        /// The sequence of operations used to construct a preview.
        /// </summary>
        public async Task<ImmutableArray<CodeActionOperation>> GetPreviewOperationsAsync(CancellationToken cancellationToken)
        {
            var operations = await this.ComputePreviewOperationsAsync(cancellationToken).ConfigureAwait(false);

            if (operations != null)
            {
                return await this.PostProcessAsync(operations, cancellationToken).ConfigureAwait(false);
            }

            return ImmutableArray<CodeActionOperation>.Empty;
        }

        /// <summary>
        /// Override this method if you want to implement a <see cref="CodeAction"/> subclass that includes custom <see cref="CodeActionOperation"/>'s.
        /// </summary>
        protected virtual async Task<IEnumerable<CodeActionOperation>> ComputeOperationsAsync(CancellationToken cancellationToken)
        {
            var changedSolution = await GetChangedSolutionAsync(cancellationToken).ConfigureAwait(false);
            if (changedSolution == null)
            {
                return Array.Empty<CodeActionOperation>();
            }

            return new CodeActionOperation[] { new ApplyChangesOperation(changedSolution) };
        }

        internal virtual async Task<ImmutableArray<CodeActionOperation>> ComputeOperationsAsync(
            IProgressTracker progressTracker, CancellationToken cancellationToken)
        {
            var operations = await ComputeOperationsAsync(cancellationToken).ConfigureAwait(false);
            return operations.ToImmutableArrayOrEmpty();
        }

        /// <summary>
        /// Override this method if you want to implement a <see cref="CodeAction"/> that has a set of preview operations that are different
        /// than the operations produced by <see cref="ComputeOperationsAsync(CancellationToken)"/>.
        /// </summary>
        protected virtual Task<IEnumerable<CodeActionOperation>> ComputePreviewOperationsAsync(CancellationToken cancellationToken)
        {
            return ComputeOperationsAsync(cancellationToken);
        }

        /// <summary>
        /// Computes all changes for an entire solution.
        /// Override this method if you want to implement a <see cref="CodeAction"/> subclass that changes more than one document.
        /// </summary>
        protected async virtual Task<Solution?> GetChangedSolutionAsync(CancellationToken cancellationToken)
        {
            var changedDocument = await GetChangedDocumentAsync(cancellationToken).ConfigureAwait(false);
            if (changedDocument == null)
            {
                return null;
            }

            return changedDocument.Project.Solution;
        }

        internal virtual Task<Solution?> GetChangedSolutionAsync(
            IProgressTracker progressTracker, CancellationToken cancellationToken)
        {
            return GetChangedSolutionAsync(cancellationToken);
        }

        /// <summary>
        /// Computes changes for a single document. Override this method if you want to implement a
        /// <see cref="CodeAction"/> subclass that changes a single document.
        /// </summary>
        /// <remarks>
        /// All code actions are expected to operate on solutions. This method is a helper to simplify the
        /// implementation of <see cref="GetChangedSolutionAsync(CancellationToken)"/> for code actions that only need
        /// to change one document.
        /// </remarks>
        /// <exception cref="NotImplementedException">If this code action does not support changing a single document.</exception>
        protected virtual Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// used by batch fixer engine to get new solution
        /// </summary>
        internal async Task<Solution?> GetChangedSolutionInternalAsync(bool postProcessChanges = true, CancellationToken cancellationToken = default)
        {
            var solution = await GetChangedSolutionAsync(new ProgressTracker(), cancellationToken).ConfigureAwait(false);
            if (solution == null || !postProcessChanges)
            {
                return solution;
            }

            return await this.PostProcessChangesAsync(solution, cancellationToken).ConfigureAwait(false);
        }

        internal Task<Document> GetChangedDocumentInternalAsync(CancellationToken cancellation)
        {<commit_msg>Throw more appropriate exception<commit_after>﻿// 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.

#nullable enable

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CaseCorrection;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Shared.Utilities;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.CodeAnalysis.Tags;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CodeActions
{
    /// <summary>
    /// An action produced by a <see cref="CodeFixProvider"/> or a <see cref="CodeRefactoringProvider"/>.
    /// </summary>
    public abstract class CodeAction
    {
        /// <summary>
        /// A short title describing the action that may appear in a menu.
        /// </summary>
        public abstract string Title { get; }

        internal virtual string Message => Title;

        /// <summary>
        /// Two code actions are treated as equivalent if they have equal non-null <see cref="EquivalenceKey"/> values and were generated
        /// by the same <see cref="CodeFixProvider"/> or <see cref="CodeRefactoringProvider"/>.
        /// </summary>
        /// <remarks>
        /// Equivalence of code actions affects some Visual Studio behavior. For example, if multiple equivalent
        /// code actions result from code fixes or refactorings for a single Visual Studio light bulb instance,
        /// the light bulb UI will present only one code action from each set of equivalent code actions.
        /// Additionally, a Fix All operation will apply only code actions that are equivalent to the original code action.
        ///
        /// If two code actions that could be treated as equivalent do not have equal <see cref="EquivalenceKey"/> values, Visual Studio behavior
        /// may be less helpful than would be optimal. If two code actions that should be treated as distinct have
        /// equal <see cref="EquivalenceKey"/> values, Visual Studio behavior may appear incorrect.
        /// </remarks>
        public virtual string? EquivalenceKey => null;

        internal virtual bool IsInlinable => false;

        internal virtual CodeActionPriority Priority => CodeActionPriority.Medium;

        /// <summary>
        /// Descriptive tags from <see cref="WellKnownTags"/>.
        /// These tags may influence how the item is displayed.
        /// </summary>
        public virtual ImmutableArray<string> Tags => ImmutableArray<string>.Empty;

        internal virtual ImmutableArray<CodeAction> NestedCodeActions
            => ImmutableArray<CodeAction>.Empty;

        /// <summary>
        /// The sequence of operations that define the code action.
        /// </summary>
        public Task<ImmutableArray<CodeActionOperation>> GetOperationsAsync(CancellationToken cancellationToken)
        {
            return GetOperationsAsync(new ProgressTracker(), cancellationToken);
        }

        internal Task<ImmutableArray<CodeActionOperation>> GetOperationsAsync(
            IProgressTracker progressTracker, CancellationToken cancellationToken)
        {
            return GetOperationsCoreAsync(progressTracker, cancellationToken);
        }

        /// <summary>
        /// The sequence of operations that define the code action.
        /// </summary>
        internal virtual async Task<ImmutableArray<CodeActionOperation>> GetOperationsCoreAsync(
            IProgressTracker progressTracker, CancellationToken cancellationToken)
        {
            var operations = await this.ComputeOperationsAsync(progressTracker, cancellationToken).ConfigureAwait(false);

            if (operations != null)
            {
                return await this.PostProcessAsync(operations, cancellationToken).ConfigureAwait(false);
            }

            return ImmutableArray<CodeActionOperation>.Empty;
        }

        /// <summary>
        /// The sequence of operations used to construct a preview.
        /// </summary>
        public async Task<ImmutableArray<CodeActionOperation>> GetPreviewOperationsAsync(CancellationToken cancellationToken)
        {
            var operations = await this.ComputePreviewOperationsAsync(cancellationToken).ConfigureAwait(false);

            if (operations != null)
            {
                return await this.PostProcessAsync(operations, cancellationToken).ConfigureAwait(false);
            }

            return ImmutableArray<CodeActionOperation>.Empty;
        }

        /// <summary>
        /// Override this method if you want to implement a <see cref="CodeAction"/> subclass that includes custom <see cref="CodeActionOperation"/>'s.
        /// </summary>
        protected virtual async Task<IEnumerable<CodeActionOperation>> ComputeOperationsAsync(CancellationToken cancellationToken)
        {
            var changedSolution = await GetChangedSolutionAsync(cancellationToken).ConfigureAwait(false);
            if (changedSolution == null)
            {
                return Array.Empty<CodeActionOperation>();
            }

            return new CodeActionOperation[] { new ApplyChangesOperation(changedSolution) };
        }

        internal virtual async Task<ImmutableArray<CodeActionOperation>> ComputeOperationsAsync(
            IProgressTracker progressTracker, CancellationToken cancellationToken)
        {
            var operations = await ComputeOperationsAsync(cancellationToken).ConfigureAwait(false);
            return operations.ToImmutableArrayOrEmpty();
        }

        /// <summary>
        /// Override this method if you want to implement a <see cref="CodeAction"/> that has a set of preview operations that are different
        /// than the operations produced by <see cref="ComputeOperationsAsync(CancellationToken)"/>.
        /// </summary>
        protected virtual Task<IEnumerable<CodeActionOperation>> ComputePreviewOperationsAsync(CancellationToken cancellationToken)
        {
            return ComputeOperationsAsync(cancellationToken);
        }

        /// <summary>
        /// Computes all changes for an entire solution.
        /// Override this method if you want to implement a <see cref="CodeAction"/> subclass that changes more than one document.
        /// </summary>
        protected async virtual Task<Solution?> GetChangedSolutionAsync(CancellationToken cancellationToken)
        {
            var changedDocument = await GetChangedDocumentAsync(cancellationToken).ConfigureAwait(false);
            if (changedDocument == null)
            {
                return null;
            }

            return changedDocument.Project.Solution;
        }

        internal virtual Task<Solution?> GetChangedSolutionAsync(
            IProgressTracker progressTracker, CancellationToken cancellationToken)
        {
            return GetChangedSolutionAsync(cancellationToken);
        }

        /// <summary>
        /// Computes changes for a single document. Override this method if you want to implement a
        /// <see cref="CodeAction"/> subclass that changes a single document.
        /// </summary>
        /// <remarks>
        /// All code actions are expected to operate on solutions. This method is a helper to simplify the
        /// implementation of <see cref="GetChangedSolutionAsync(CancellationToken)"/> for code actions that only need
        /// to change one document.
        /// </remarks>
        /// <exception cref="NotSupportedException">If this code action does not support changing a single document.</exception>
        protected virtual Task<Document> GetChangedDocumentAsync(CancellationToken cancellationToken)
        {
            throw new NotSupportedException();
        }

        /// <summary>
        /// used by batch fixer engine to get new solution
        /// </summary>
        internal async Task<Solution?> GetChangedSolutionInternalAsync(bool postProcessChanges = true, CancellationToken cancellationToken = default)
        {
            var solution = await GetChangedSolutionAsync(new ProgressTracker(), cancellationToken).ConfigureAwait(false);
            if (solution == null || !postProcessChanges)
            {
                return solution;
            }

            return await this.PostProcessChangesAsync(solution, cancellationToken).ConfigureAwait(false);
        }

        internal Task<Document> GetChangedDocumentInternalAsync(CancellationToken cancellation)
        {
{'fraction_non_alphanumeric': 0.08147940599607734, 'fraction_numerical': 0.0, 'mean_word_length': 2.7024896265560168, 'pattern_counts': {'":': 0, '<': 145, '<?xml version=': 0, '>': 157, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1688554', 'n_tokens_mistral': 3938, 'n_tokens_neox': 3941, 'n_words': 1317}