File: AddImport\AbstractAddImportCodeFixProvider.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.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeCleanup;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.Packaging;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.SymbolSearch;
 
namespace Microsoft.CodeAnalysis.AddImport;
 
internal abstract partial class AbstractAddImportCodeFixProvider : CodeFixProvider
{
    private const int MaxResults = 5;
 
    private readonly IPackageInstallerService? _packageInstallerService;
    private readonly ISymbolSearchService? _symbolSearchService;
 
    /// <summary>
    /// Values for these parameters can be provided (during testing) for mocking purposes.
    /// </summary> 
    protected AbstractAddImportCodeFixProvider(
        IPackageInstallerService? packageInstallerService = null,
        ISymbolSearchService? symbolSearchService = null)
    {
        _packageInstallerService = packageInstallerService;
        _symbolSearchService = symbolSearchService;
 
        // Backdoor that allows this provider to use the high-priority bucket.
        this.CustomTags = this.CustomTags.Add(CodeAction.CanBeHighPriorityTag);
    }
 
    /// <summary>
    /// Add-using gets special privileges as being the most used code-action, along with being a core
    /// 'smart tag' feature in VS prior to us even having 'light bulbs'.  We want them to be computed
    /// first, ahead of everything else, and the main results should show up at the top of the list.
    /// </summary>
    protected override CodeActionRequestPriority ComputeRequestPriority()
        => CodeActionRequestPriority.High;
 
    public sealed override FixAllProvider? GetFixAllProvider()
    {
        // Currently Fix All is not supported for this provider
        // https://github.com/dotnet/roslyn/issues/34457
        return null;
    }
 
    public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
    {
        var document = context.Document;
        var span = context.Span;
        var cancellationToken = context.CancellationToken;
        var diagnostics = context.Diagnostics;
 
        var addImportService = document.GetRequiredLanguageService<IAddImportFeatureService>();
        var services = document.Project.Solution.Services;
        var searchOptions = await document.GetSymbolSearchOptionsAsync(cancellationToken).ConfigureAwait(false);
 
        var symbolSearchService = _symbolSearchService ?? services.GetRequiredService<ISymbolSearchService>();
 
        var installerService = searchOptions.SearchNuGetPackages ?
            _packageInstallerService ?? services.GetService<IPackageInstallerService>() : null;
 
        var packageSources = installerService?.IsEnabled(document.Project.Id) == true
            ? installerService.TryGetPackageSources()
            : [];
 
        if (packageSources.IsEmpty)
        {
            searchOptions = searchOptions with { SearchNuGetPackages = false };
        }
 
        var addImportOptions = await document.GetAddImportOptionsAsync(searchOptions, cancellationToken).ConfigureAwait(false);
 
        var fixesForDiagnostic = await addImportService.GetFixesForDiagnosticsAsync(
            document, span, diagnostics, MaxResults, symbolSearchService, addImportOptions, packageSources, cancellationToken).ConfigureAwait(false);
 
        foreach (var (diagnostic, fixes) in fixesForDiagnostic)
        {
            // Limit the results returned since this will be displayed to the user
            var codeActions = addImportService.GetCodeActionsForFixes(document, fixes, installerService, MaxResults);
            context.RegisterFixes(codeActions, diagnostic);
        }
    }
}