PeekableItemFactory.cs 3.6 KB
Newer Older
1 2 3 4 5 6 7 8
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
9
using Microsoft.CodeAnalysis.Editor.FindUsages;
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
using Microsoft.CodeAnalysis.Editor.Peek;
using Microsoft.CodeAnalysis.FindSymbols;
using Microsoft.CodeAnalysis.Navigation;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.Language.Intellisense;

namespace Microsoft.CodeAnalysis.Editor.Implementation.Peek
{
    [Export(typeof(IPeekableItemFactory))]
    internal class PeekableItemFactory : IPeekableItemFactory
    {
        private readonly IMetadataAsSourceFileService _metadataAsSourceFileService;

        [ImportingConstructor]
        private PeekableItemFactory(IMetadataAsSourceFileService metadataAsSourceFileService)
        {
            _metadataAsSourceFileService = metadataAsSourceFileService;
        }

29 30 31 32
        public async Task<IEnumerable<IPeekableItem>> GetPeekableItemsAsync(
            ISymbol symbol, Project project,
            IPeekResultFactory peekResultFactory, 
            CancellationToken cancellationToken)
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
        {
            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 results = new List<IPeekableItem>();

            var solution = project.Solution;
            var sourceDefinition = await SymbolFinder.FindSourceDefinitionAsync(symbol, solution, cancellationToken).ConfigureAwait(false);

            // And if our definition actually is from source, then let's re-figure out what project it came from
            if (sourceDefinition != null)
            {
                var originatingProject = solution.GetProject(sourceDefinition.ContainingAssembly, cancellationToken);

                project = originatingProject ?? project;
            }

            var symbolNavigationService = solution.Workspace.Services.GetService<ISymbolNavigationService>();
63 64
            var definitionItem = await symbol.ToDefinitionItemAsync(
                solution, includeHiddenLocations: true, cancellationToken: cancellationToken).ConfigureAwait(false);
65

66
            if (symbolNavigationService.WouldNavigateToSymbol(
67
                    definitionItem, solution, cancellationToken,
68
                    out var filePath, out var lineNumber, out var charOffset))
69 70 71 72 73 74
            {
                var position = new LinePosition(lineNumber, charOffset);
                results.Add(new ExternalFilePeekableItem(new FileLinePositionSpan(filePath, position, position), PredefinedPeekRelationships.Definitions, peekResultFactory));
            }
            else
            {
75
                var symbolKey = SymbolKey.Create(symbol, cancellationToken);
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90

                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));
                    }
                }
            }

            return results;
        }
    }
}