File: Handler\Diagnostics\DiagnosticSources\TaskListDiagnosticSource.cs
Web Access
Project: src\src\LanguageServer\Protocol\Microsoft.CodeAnalysis.LanguageServer.Protocol.csproj (Microsoft.CodeAnalysis.LanguageServer.Protocol)
// 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.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.TaskList;
 
namespace Microsoft.CodeAnalysis.LanguageServer.Handler.Diagnostics;
 
using static PullDiagnosticConstants;
 
internal sealed class TaskListDiagnosticSource(Document document, IGlobalOptionService globalOptions) : AbstractDocumentDiagnosticSource<Document>(document)
{
    private static readonly ImmutableArray<string> s_todoCommentCustomTags = [TaskItemCustomTag];
 
    private static readonly ImmutableDictionary<string, string?> s_lowPriorityProperties = ImmutableDictionary<string, string?>.Empty.Add(Priority, Low);
    private static readonly ImmutableDictionary<string, string?> s_mediumPriorityProperties = ImmutableDictionary<string, string?>.Empty.Add(Priority, Medium);
    private static readonly ImmutableDictionary<string, string?> s_highPriorityProperties = ImmutableDictionary<string, string?>.Empty.Add(Priority, High);
 
    private static Tuple<ImmutableArray<string>, ImmutableArray<TaskListItemDescriptor>> s_lastRequestedTokens =
        Tuple.Create(ImmutableArray<string>.Empty, ImmutableArray<TaskListItemDescriptor>.Empty);
 
    private readonly IGlobalOptionService _globalOptions = globalOptions;
 
    public override bool IsLiveSource()
        => true;
 
    public override async Task<ImmutableArray<DiagnosticData>> GetDiagnosticsAsync(
        RequestContext context, CancellationToken cancellationToken)
    {
        var service = this.Document.GetLanguageService<ITaskListService>();
        if (service == null)
            return [];
 
        var options = _globalOptions.GetTaskListOptions();
        var descriptors = GetAndCacheDescriptors(options.Descriptors);
 
        var items = await service.GetTaskListItemsAsync(this.Document, descriptors, cancellationToken).ConfigureAwait(false);
        if (items.Length == 0)
            return [];
 
        return items.SelectAsArray(i => new DiagnosticData(
            id: "TODO",
            category: "TODO",
            message: i.Message,
            severity: DiagnosticSeverity.Info,
            defaultSeverity: DiagnosticSeverity.Info,
            isEnabledByDefault: true,
            warningLevel: 0,
            customTags: s_todoCommentCustomTags,
            properties: GetProperties(i.Priority),
            projectId: this.Document.Project.Id,
            language: this.Document.Project.Language,
            location: new DiagnosticDataLocation(i.Span, this.Document.Id, mappedFileSpan: i.MappedSpan)));
    }
 
    private static ImmutableDictionary<string, string?> GetProperties(TaskListItemPriority priority)
        => priority switch
        {
            TaskListItemPriority.Low => s_lowPriorityProperties,
            TaskListItemPriority.Medium => s_mediumPriorityProperties,
            TaskListItemPriority.High => s_highPriorityProperties,
            _ => s_mediumPriorityProperties,
        };
 
    private static ImmutableArray<TaskListItemDescriptor> GetAndCacheDescriptors(ImmutableArray<string> tokenList)
    {
        var lastRequested = s_lastRequestedTokens;
        if (!lastRequested.Item1.SequenceEqual(tokenList))
        {
            var descriptors = TaskListItemDescriptor.Parse(tokenList);
            lastRequested = Tuple.Create(tokenList, descriptors);
            s_lastRequestedTokens = lastRequested;
        }
 
        return lastRequested.Item2;
    }
}