File: FileBasedPrograms\VirtualProjectXmlDiagnosticSourceProvider.cs
Web Access
Project: src\src\LanguageServer\Microsoft.CodeAnalysis.LanguageServer\Microsoft.CodeAnalysis.LanguageServer.csproj (Microsoft.CodeAnalysis.LanguageServer)
// 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.Composition;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.LanguageServer.Handler;
using Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using Roslyn.LanguageServer.Protocol;
 
namespace Microsoft.CodeAnalysis.LanguageServer.FileBasedPrograms;
 
[Export(typeof(IDiagnosticSourceProvider)), Shared]
[method: ImportingConstructor]
[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
internal sealed class VirtualProjectXmlDiagnosticSourceProvider(VirtualProjectXmlProvider virtualProjectXmlProvider) : IDiagnosticSourceProvider
{
    public const string FileBasedPrograms = nameof(FileBasedPrograms);
 
    public bool IsDocument => true;
    public string Name => FileBasedPrograms;
 
    public bool IsEnabled(ClientCapabilities clientCapabilities) => true;
 
    public ValueTask<ImmutableArray<IDiagnosticSource>> CreateDiagnosticSourcesAsync(RequestContext context, CancellationToken cancellationToken)
    {
        ImmutableArray<IDiagnosticSource> sources = context.Document is null
            ? []
            : [new VirtualProjectXmlDiagnosticSource(context.Document, virtualProjectXmlProvider)];
 
        return ValueTask.FromResult(sources);
    }
 
    private sealed class VirtualProjectXmlDiagnosticSource(Document document, VirtualProjectXmlProvider virtualProjectXmlProvider) : IDiagnosticSource
    {
        public async Task<ImmutableArray<DiagnosticData>> GetDiagnosticsAsync(RequestContext context, CancellationToken cancellationToken)
        {
            if (string.IsNullOrEmpty(document.FilePath))
                return [];
 
            var simpleDiagnostics = await virtualProjectXmlProvider.GetCachedDiagnosticsAsync(document.FilePath, cancellationToken);
            if (simpleDiagnostics.IsDefaultOrEmpty)
                return [];
 
            var diagnosticDatas = new FixedSizeArrayBuilder<DiagnosticData>(simpleDiagnostics.Length);
            foreach (var simpleDiagnostic in simpleDiagnostics)
            {
                var location = new FileLinePositionSpan(simpleDiagnostic.Location.Path, simpleDiagnostic.Location.Span.ToLinePositionSpan());
                var diagnosticData = new DiagnosticData(
                    id: FileBasedPrograms,
                    category: FileBasedPrograms,
                    message: simpleDiagnostic.Message,
                    severity: DiagnosticSeverity.Error,
                    defaultSeverity: DiagnosticSeverity.Error,
                    isEnabledByDefault: true,
                    // Warning level 0 is used as a placeholder when the diagnostic has error severity
                    warningLevel: 0,
                    customTags: ImmutableArray<string>.Empty,
                    properties: ImmutableDictionary<string, string?>.Empty,
                    projectId: document.Project.Id,
                    location: new DiagnosticDataLocation(location, document.Id)
                );
                diagnosticDatas.Add(diagnosticData);
            }
            return diagnosticDatas.MoveToImmutable();
        }
 
        public TextDocumentIdentifier? GetDocumentIdentifier()
        {
            return !string.IsNullOrEmpty(document.FilePath)
            ? new VSTextDocumentIdentifier { ProjectContext = ProtocolConversions.ProjectToProjectContext(document.Project), DocumentUri = document.GetURI() }
            : null;
        }
 
        public ProjectOrDocumentId GetId()
        {
            return new ProjectOrDocumentId(document.Id);
        }
 
        public Project GetProject()
        {
            return document.Project;
        }
 
        /// <summary>
        /// These diagnostics are from the last time 'dotnet run-api' was invoked, which only occurs when a design time build is performed.
        /// <seealso cref="IDiagnosticSource.IsLiveSource"/>.
        /// </summary>
        /// <returns></returns>
        public bool IsLiveSource() => false;
 
        public string ToDisplayString() => nameof(VirtualProjectXmlDiagnosticSource);
    }
}