File: Peek\PeekableItemFactory.cs
Web Access
Project: src\src\EditorFeatures\Core.Wpf\Microsoft.CodeAnalysis.EditorFeatures.Wpf_bcxirj4e_wpftmp.csproj (Microsoft.CodeAnalysis.EditorFeatures.Wpf)
// 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;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.Peek;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.FindUsages;
using Microsoft.CodeAnalysis.GoToDefinition;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.MetadataAsSource;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.VisualStudio.Language.Intellisense;
 
namespace Microsoft.CodeAnalysis.Editor.Implementation.Peek;
 
[Export(typeof(IPeekableItemFactory))]
internal sealed class PeekableItemFactory : IPeekableItemFactory
{
    private readonly IMetadataAsSourceFileService _metadataAsSourceFileService;
    private readonly IGlobalOptionService _globalOptions;
    private readonly IThreadingContext _threadingContext;
 
    [ImportingConstructor]
    [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
    public PeekableItemFactory(
        IMetadataAsSourceFileService metadataAsSourceFileService,
        IGlobalOptionService globalOptions,
        IThreadingContext threadingContext)
    {
        _metadataAsSourceFileService = metadataAsSourceFileService;
        _globalOptions = globalOptions;
        _threadingContext = threadingContext;
    }
 
    public async Task<IEnumerable<IPeekableItem>> GetPeekableItemsAsync(
        ISymbol symbol,
        Project project,
        IPeekResultFactory peekResultFactory,
        CancellationToken cancellationToken)
    {
        if (symbol == null)
            throw new ArgumentNullException(nameof(symbol));
 
        if (project == null)
            throw new ArgumentNullException(nameof(project));
 
        if (peekResultFactory == null)
            throw new ArgumentNullException(nameof(peekResultFactory));
 
        var solution = project.Solution;
        symbol = SymbolFinder.FindSourceDefinition(symbol, solution, cancellationToken) ?? symbol;
        symbol = GoToDefinitionFeatureHelpers.TryGetPreferredSymbol(solution, symbol, cancellationToken);
        if (symbol is null)
            return [];
 
        // if we mapped the symbol, then get the new project it is contained in.
        var originatingProject = solution.GetProject(symbol.ContainingAssembly, cancellationToken);
        project = originatingProject ?? project;
 
        var definitionItem = symbol.ToNonClassifiedDefinitionItem(solution, includeHiddenLocations: true);
 
        var symbolNavigationService = solution.Services.GetService<ISymbolNavigationService>();
        var result = await symbolNavigationService.GetExternalNavigationSymbolLocationAsync(definitionItem, cancellationToken).ConfigureAwait(false);
 
        using var _ = ArrayBuilder<IPeekableItem>.GetInstance(out var results);
        if (result is var (filePath, linePosition))
        {
            results.Add(new ExternalFilePeekableItem(new FileLinePositionSpan(filePath, linePosition, linePosition), PredefinedPeekRelationships.Definitions, peekResultFactory));
        }
        else
        {
            var symbolKey = SymbolKey.Create(symbol, cancellationToken);
 
            var firstLocation = symbol.Locations.FirstOrDefault();
            if (firstLocation != null)
            {
                if (firstLocation.IsInSource || _metadataAsSourceFileService.IsNavigableMetadataSymbol(symbol))
                {
                    results.Add(new DefinitionPeekableItem(
                        solution.Workspace, project.Id, symbolKey, peekResultFactory, _metadataAsSourceFileService, _globalOptions, _threadingContext));
                }
            }
        }
 
        return results.ToImmutableAndClear();
    }
}