File: Services\DiagnosticAnalyzer\RemoteDiagnosticAnalyzerService.cs
Web Access
Project: src\src\Workspaces\Remote\ServiceHub\Microsoft.CodeAnalysis.Remote.ServiceHub.csproj (Microsoft.CodeAnalysis.Remote.ServiceHub)
// 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.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Text;
using RoslynLogger = Microsoft.CodeAnalysis.Internal.Log.Logger;
 
namespace Microsoft.CodeAnalysis.Remote;
 
internal sealed class RemoteDiagnosticAnalyzerService(in BrokeredServiceBase.ServiceConstructionArguments arguments)
    : BrokeredServiceBase(arguments), IRemoteDiagnosticAnalyzerService
{
    internal sealed class Factory : FactoryBase<IRemoteDiagnosticAnalyzerService>
    {
        protected override IRemoteDiagnosticAnalyzerService CreateService(in ServiceConstructionArguments arguments)
            => new RemoteDiagnosticAnalyzerService(arguments);
    }
 
    public ValueTask<ImmutableArray<DiagnosticData>> ForceRunCodeAnalysisDiagnosticsAsync(
        Checksum solutionChecksum, ProjectId projectId, CancellationToken cancellationToken)
    {
        return RunWithSolutionAsync(
            solutionChecksum,
            async solution =>
            {
                var project = solution.GetRequiredProject(projectId);
                var service = solution.Services.GetRequiredService<IDiagnosticAnalyzerService>();
                return await service.ForceRunCodeAnalysisDiagnosticsAsync(
                    project, cancellationToken).ConfigureAwait(false);
            },
            cancellationToken);
    }
 
    public ValueTask<bool> IsAnyDiagnosticIdDeprioritizedAsync(
        Checksum solutionChecksum, ProjectId projectId, ImmutableArray<string> diagnosticIds, CancellationToken cancellationToken)
    {
        return RunWithSolutionAsync(
            solutionChecksum,
            async solution =>
            {
                var project = solution.GetRequiredProject(projectId);
                var service = solution.Services.GetRequiredService<IDiagnosticAnalyzerService>();
 
                return await service.IsAnyDiagnosticIdDeprioritizedAsync(
                    project, diagnosticIds, cancellationToken).ConfigureAwait(false);
            },
            cancellationToken);
    }
 
    public ValueTask<ImmutableArray<DiagnosticData>> GetDiagnosticsForIdsAsync(
        Checksum solutionChecksum, ProjectId projectId,
        ImmutableArray<DocumentId> documentIds,
        ImmutableHashSet<string>? diagnosticIds,
        AnalyzerFilter analyzerFilter,
        bool includeLocalDocumentDiagnostics,
        CancellationToken cancellationToken)
    {
        return RunWithSolutionAsync(
            solutionChecksum,
            async solution =>
            {
                var project = solution.GetRequiredProject(projectId);
                var service = solution.Services.GetRequiredService<IDiagnosticAnalyzerService>();
 
                return await service.GetDiagnosticsForIdsAsync(
                    project, documentIds, diagnosticIds, analyzerFilter,
                    includeLocalDocumentDiagnostics, cancellationToken).ConfigureAwait(false);
            },
            cancellationToken);
    }
 
    public ValueTask<ImmutableArray<DiagnosticData>> GetProjectDiagnosticsForIdsAsync(
        Checksum solutionChecksum, ProjectId projectId,
        ImmutableHashSet<string>? diagnosticIds,
        AnalyzerFilter analyzerFilter,
        CancellationToken cancellationToken)
    {
        return RunWithSolutionAsync(
            solutionChecksum,
            async solution =>
            {
                var project = solution.GetRequiredProject(projectId);
                var service = solution.Services.GetRequiredService<IDiagnosticAnalyzerService>();
 
                return await service.GetProjectDiagnosticsForIdsAsync(
                    project, diagnosticIds, analyzerFilter, cancellationToken).ConfigureAwait(false);
            },
            cancellationToken);
    }
 
    public ValueTask<ImmutableArray<DiagnosticData>> GetSourceGeneratorDiagnosticsAsync(Checksum solutionChecksum, ProjectId projectId, CancellationToken cancellationToken)
    {
        return RunWithSolutionAsync(
            solutionChecksum,
            async solution =>
            {
                var project = solution.GetRequiredProject(projectId);
                var diagnostics = await project.GetSourceGeneratorDiagnosticsAsync(cancellationToken).ConfigureAwait(false);
                using var builder = TemporaryArray<DiagnosticData>.Empty;
                foreach (var diagnostic in diagnostics)
                {
                    var document = solution.GetDocument(diagnostic.Location.SourceTree);
                    var data = document != null
                        ? DiagnosticData.Create(diagnostic, document)
                        : DiagnosticData.Create(diagnostic, project);
                    builder.Add(data);
                }
 
                return builder.ToImmutableAndClear();
            }, cancellationToken);
    }
 
    public ValueTask ReportAnalyzerPerformanceAsync(ImmutableArray<AnalyzerPerformanceInfo> snapshot, int unitCount, bool forSpanAnalysis, CancellationToken cancellationToken)
    {
        return RunServiceAsync(cancellationToken =>
        {
            using (RoslynLogger.LogBlock(FunctionId.CodeAnalysisService_ReportAnalyzerPerformance, cancellationToken))
            {
                cancellationToken.ThrowIfCancellationRequested();
 
                var service = GetWorkspace().Services.GetService<IPerformanceTrackerService>();
                if (service == null)
                {
                    return default;
                }
 
                service.AddSnapshot(snapshot, unitCount, forSpanAnalysis);
            }
 
            return default;
        }, cancellationToken);
    }
 
    public ValueTask<ImmutableArray<DiagnosticDescriptorData>> GetDiagnosticDescriptorsAsync(Checksum solutionChecksum, ProjectId projectId, string analyzerReferenceFullPath, CancellationToken cancellationToken)
    {
        return RunWithSolutionAsync(
            solutionChecksum,
            async solution =>
            {
                var project = solution.GetRequiredProject(projectId);
                var analyzerReference = project.AnalyzerReferences
                    .First(r => r.FullPath == analyzerReferenceFullPath);
 
                var descriptors = await project.GetDiagnosticDescriptorsAsync(analyzerReference, cancellationToken).ConfigureAwait(false);
                var descriptorData = descriptors.SelectAsArray(DiagnosticDescriptorData.Create);
 
                return descriptorData;
            },
            cancellationToken);
    }
 
    public ValueTask<ImmutableArray<string>> GetCompilationEndDiagnosticDescriptorIdsAsync(
        Checksum solutionChecksum, CancellationToken cancellationToken)
    {
        return RunWithSolutionAsync(
            solutionChecksum,
            async solution =>
            {
                var service = solution.Services.GetRequiredService<IDiagnosticAnalyzerService>();
                return await service.GetCompilationEndDiagnosticDescriptorIdsAsync(
                    solution, cancellationToken).ConfigureAwait(false);
            },
            cancellationToken);
    }
 
    public ValueTask<ImmutableArray<DiagnosticDescriptorData>> GetDiagnosticDescriptorsAsync(
        Checksum solutionChecksum,
        ProjectId projectId,
        string analyzerReferenceFullPath,
        string language,
        CancellationToken cancellationToken)
    {
        return RunWithSolutionAsync(
            solutionChecksum,
            async solution =>
            {
                var service = solution.Services.GetRequiredService<IDiagnosticAnalyzerService>();
                var project = solution.GetRequiredProject(projectId);
                var analyzerReference = project.AnalyzerReferences
                    .First(r => r.FullPath == analyzerReferenceFullPath);
 
                var descriptors = await service.GetDiagnosticDescriptorsAsync(
                    solution, projectId, analyzerReference, language, cancellationToken).ConfigureAwait(false);
                return descriptors.SelectAsArray(DiagnosticDescriptorData.Create);
            },
            cancellationToken);
    }
 
    public ValueTask<ImmutableDictionary<string, ImmutableArray<DiagnosticDescriptorData>>> GetDiagnosticDescriptorsPerReferenceAsync(
        Checksum solutionChecksum,
        ProjectId? projectId,
        CancellationToken cancellationToken)
    {
        return RunWithSolutionAsync(
            solutionChecksum,
            async solution =>
            {
                var service = solution.Services.GetRequiredService<IDiagnosticAnalyzerService>();
                var map = await service.GetDiagnosticDescriptorsPerReferenceAsync(solution, projectId, cancellationToken).ConfigureAwait(false);
                return map.ToImmutableDictionary(
                    kvp => kvp.Key,
                    kvp => kvp.Value.SelectAsArray(DiagnosticDescriptorData.Create));
 
            },
            cancellationToken);
    }
 
    public ValueTask<ImmutableArray<DiagnosticData>> GetDiagnosticsForSpanAsync(
        Checksum solutionChecksum,
        DocumentId documentId,
        TextSpan? range,
        DiagnosticIdFilter diagnosticIdFilter,
        CodeActionRequestPriority? priority,
        DiagnosticKind diagnosticKind,
        CancellationToken cancellationToken)
    {
        return RunWithSolutionAsync(
            solutionChecksum,
            async solution =>
            {
                var document = await solution.GetRequiredTextDocumentAsync(
                    documentId, cancellationToken).ConfigureAwait(false);
                var service = solution.Services.GetRequiredService<IDiagnosticAnalyzerService>();
 
                return await service.GetDiagnosticsForSpanAsync(
                    document, range, diagnosticIdFilter, priority, diagnosticKind, cancellationToken).ConfigureAwait(false);
            },
            cancellationToken);
    }
}