File: SemanticSearch\SemanticSearchDefinitionItemFactory.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;
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.Text;
 
namespace Microsoft.CodeAnalysis.SemanticSearch;
 
internal static class SemanticSearchDefinitionItemFactory
{
    private static readonly FindReferencesSearchOptions s_findReferencesSearchOptions = new()
    {
        DisplayAllDefinitions = true,
    };
 
    public static DefinitionItem Create(string text)
    {
        var displayStr = Clip(text, maxLength: 100);
        var displayText = new TaggedText(TextTags.Text, displayStr);
 
        return DefinitionItem.CreateNonNavigableItem(
            tags: [],
            displayParts: text.Length == displayStr.Length ? [displayText] : [displayText, new TaggedText(TextTags.Punctuation, "…")]);
    }
 
    public static ValueTask<DefinitionItem> CreateAsync(Solution solution, ISymbol symbol, OptionsProvider<ClassificationOptions> classificationOptions, CancellationToken cancellationToken)
        => symbol.ToClassifiedDefinitionItemAsync(
            classificationOptions, solution, s_findReferencesSearchOptions, isPrimary: true, includeHiddenLocations: false, cancellationToken);
 
    public static ValueTask<DefinitionItem> CreateAsync(Document document, SyntaxNode node, CancellationToken cancellationToken)
        => CreateItemAsync(document, node.FullSpan, cancellationToken);
 
    public static async ValueTask<DefinitionItem?> CreateAsync(Solution solution, Location location, CancellationToken cancellationToken)
    {
        if (location.MetadataModule is { } module)
        {
            var metadataLocation = DefinitionItemFactory.GetMetadataLocation(module.ContainingAssembly, solution, out var originatingProjectId);
 
            return DefinitionItem.Create(
                tags: [],
                displayParts: [],
                sourceSpans: [],
                classifiedSpans: [],
                metadataLocations: [metadataLocation],
                properties: ImmutableDictionary<string, string>.Empty.WithMetadataSymbolProperties(module.ContainingAssembly, originatingProjectId));
        }
 
        if (solution.GetDocument(location.SourceTree) is { } document)
        {
            return await CreateItemAsync(document, location.SourceSpan, cancellationToken).ConfigureAwait(false);
        }
 
        return null;
    }
 
    private static async ValueTask<DefinitionItem> CreateItemAsync(Document document, TextSpan span, CancellationToken cancellationToken)
    {
        var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false);
        var displaySpan = Clip(span, maxLength: 100);
        var displayText = new TaggedText(TextTags.Text, text.ToString(displaySpan));
 
        return DefinitionItem.Create(
            tags: [],
            displayParts: displaySpan.Length == span.Length ? [displayText] : [displayText, new TaggedText(TextTags.Punctuation, "…")],
            sourceSpans: [new DocumentSpan(document, span)],
            classifiedSpans: [],
            metadataLocations: []);
    }
 
    private static TextSpan Clip(TextSpan span, int maxLength)
        => new(span.Start, Math.Min(span.Length, maxLength));
 
    private static string Clip(string str, int maxLength)
        => str[0..Math.Min(str.Length, maxLength)];
}