File: FindUsages\FindUsagesHelpers.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.
 
#nullable disable
 
using System.Collections.Immutable;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.SymbolMapping;
 
namespace Microsoft.CodeAnalysis.FindUsages;
 
internal static class FindUsagesHelpers
{
    public static string GetDisplayName(ISymbol symbol)
        => symbol.IsConstructor() ? symbol.ContainingType.Name : symbol.Name;
 
    /// <summary>
    /// Common helper for both the synchronous and streaming versions of FAR. 
    /// It returns the symbol we want to search for and the solution we should
    /// be searching.
    /// 
    /// Note that the <see cref="Solution"/> returned may absolutely *not* be
    /// the same as <c>document.Project.Solution</c>.  This is because 
    /// there may be symbol mapping involved (for example in Metadata-As-Source
    /// scenarios).
    /// </summary>
    public static async Task<(ISymbol symbol, Project project)?> GetRelevantSymbolAndProjectAtPositionAsync(
        Document document, int position, CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();
 
        var symbol = await SymbolFinder.FindSymbolAtPositionAsync(document, position, cancellationToken: cancellationToken).ConfigureAwait(false);
        if (symbol == null)
            return null;
 
        // If this document is not in the primary workspace, we may want to search for results
        // in a solution different from the one we started in. Use the starting workspace's
        // ISymbolMappingService to get a context for searching in the proper solution.
        var mappingService = document.Project.Solution.Services.GetService<ISymbolMappingService>();
 
        var mapping = await mappingService.MapSymbolAsync(document, symbol, cancellationToken).ConfigureAwait(false);
        if (mapping == null)
            return null;
 
        return (mapping.Symbol, mapping.Project);
    }
 
    private static SymbolDisplayFormat GetFormat(ISymbol definition)
    {
        return definition.Kind == SymbolKind.Parameter
            ? s_parameterDefinitionFormat
            : s_definitionFormat;
    }
 
    private static readonly SymbolDisplayFormat s_definitionFormat =
        new(
            typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes,
            genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters,
            parameterOptions: SymbolDisplayParameterOptions.IncludeType,
            propertyStyle: SymbolDisplayPropertyStyle.ShowReadWriteDescriptor,
            delegateStyle: SymbolDisplayDelegateStyle.NameAndSignature,
            kindOptions: SymbolDisplayKindOptions.IncludeMemberKeyword | SymbolDisplayKindOptions.IncludeNamespaceKeyword | SymbolDisplayKindOptions.IncludeTypeKeyword,
            localOptions: SymbolDisplayLocalOptions.IncludeType,
            memberOptions:
                SymbolDisplayMemberOptions.IncludeContainingType |
                SymbolDisplayMemberOptions.IncludeExplicitInterface |
                SymbolDisplayMemberOptions.IncludeModifiers |
                SymbolDisplayMemberOptions.IncludeParameters |
                SymbolDisplayMemberOptions.IncludeType,
            globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.OmittedAsContaining,
            miscellaneousOptions:
                SymbolDisplayMiscellaneousOptions.EscapeKeywordIdentifiers |
                SymbolDisplayMiscellaneousOptions.UseSpecialTypes);
 
    private static readonly SymbolDisplayFormat s_parameterDefinitionFormat = s_definitionFormat
        .AddParameterOptions(SymbolDisplayParameterOptions.IncludeName);
 
    public static ImmutableArray<TaggedText> GetDisplayParts(ISymbol definition)
        => definition.ToDisplayParts(GetFormat(definition)).ToTaggedText();
}