コード例 #1
0
        private bool TryGoToImplementations(SymbolMappingResult mapping, IList <ISymbol> implementations, CancellationToken cancellationToken, out string message)
        {
            if (implementations.Count == 0)
            {
                message = EditorFeaturesResources.SymbolHasNoImplementations;
                return(false);
            }
            else if (implementations.Count == 1)
            {
                GoToDefinition.GoToDefinitionHelpers.TryGoToDefinition(implementations.Single(), mapping.Project, _navigableItemPresenters, cancellationToken);
                message = null;
                return(true);
            }
            else
            {
                // We have multiple symbols, so we'll build a list of all preferred locations for all the symbols
                var navigableItems = implementations.SelectMany(
                    implementation => CreateItemsForImplementation(implementation, mapping.Solution));

                var presenter = _navigableItemPresenters.First();
                presenter.Value.DisplayResult(NavigableItemFactory.GetSymbolDisplayString(mapping.Project, mapping.Symbol), navigableItems);
                message = null;
                return(true);
            }
        }
コード例 #2
0
        private bool TryGoToImplementations(IEnumerable <ISymbol> candidateImplementations, SymbolMappingResult mapping, CancellationToken cancellationToken, out string message)
        {
            var implementations = candidateImplementations
                                  .Where(s => !s.IsAbstract && s.Locations.Any(l => l.IsInSource))
                                  .ToList();

            if (implementations.Count == 0)
            {
                message = EditorFeaturesResources.SymbolHasNoImplementations;
                return(false);
            }
            else if (implementations.Count == 1)
            {
                GoToDefinition.GoToDefinitionHelpers.TryGoToDefinition(implementations.Single(), mapping.Project, _externalDefinitionProviders, _navigableItemPresenters, cancellationToken);
                message = null;
                return(true);
            }
            else
            {
                // We have multiple symbols, so we'll build a list of all preferred locations for all the symbols
                var navigableItems = implementations.SelectMany(
                    implementation => CreateItemsForImplementation(implementation, mapping.Solution));

                var presenter = _navigableItemPresenters.First();
                presenter.Value.DisplayResult(NavigableItemFactory.GetSymbolDisplayString(mapping.Project, mapping.Symbol), navigableItems);
                message = null;
                return(true);
            }
        }
コード例 #3
0
        public async Task <ImmutableArray <INavigableItem> > FindDefinitionsAsync(
            Document document,
            int position,
            CancellationToken cancellationToken
            )
        {
            var symbolService = document.GetRequiredLanguageService <IGoToDefinitionSymbolService>();

            var(symbol, _) = await symbolService
                             .GetSymbolAndBoundSpanAsync(
                document,
                position,
                includeType : true,
                cancellationToken
                )
                             .ConfigureAwait(false);

            // Try to compute source definitions from symbol.
            return(symbol != null
              ? NavigableItemFactory.GetItemsFromPreferredSourceLocations(
                       document.Project.Solution,
                       symbol,
                       displayTaggedParts : null,
                       cancellationToken : cancellationToken
                       )
              : ImmutableArray <INavigableItem> .Empty);
        }
コード例 #4
0
        public async TPL.Task <IEnumerable <INavigableItem> > FindDefinitionsAsync(Document document, int position, CancellationToken cancellationToken)
        {
            var definitionItems = await GetDefinitionItemsAsync(document, position, cancellationToken).ConfigureAwait(false);

            if (definitionItems.IsDefaultOrEmpty)
            {
                return(ImmutableArray <INavigableItem> .Empty);
            }

            var navigableItems = ImmutableArray.CreateBuilder <INavigableItem>();

            foreach (var documentSpan in definitionItems.SelectMany(di => di.SourceSpans))
            {
                var declaredSymbolInfo = new DeclaredSymbolInfo(Roslyn.Utilities.StringTable.GetInstance(),
                                                                string.Empty,
                                                                string.Empty,
                                                                string.Empty,
                                                                string.Empty,
                                                                DeclaredSymbolInfoKind.Class,
                                                                Accessibility.NotApplicable,
                                                                documentSpan.SourceSpan,
                                                                ImmutableArray <string> .Empty);

                navigableItems.Add(NavigableItemFactory.GetItemFromDeclaredSymbolInfo(declaredSymbolInfo, documentSpan.Document));
            }

            return(navigableItems.ToArray());
        }
コード例 #5
0
        public async Task <IEnumerable <INavigableItem> > FindDefinitionsAsync(Document document, int position, CancellationToken cancellationToken)
        {
            var symbol = await FindSymbolAsync(document, position, cancellationToken).ConfigureAwait(false);

            // realize the list here so that the consumer await'ing the result doesn't lazily cause
            // them to be created on an inappropriate thread.
            return(NavigableItemFactory.GetItemsFromPreferredSourceLocations(document.Project.Solution, symbol).ToList());
        }
コード例 #6
0
        private static IEnumerable <INavigableItem> CreateItemsForImplementation(ISymbol implementation, Solution solution)
        {
            var symbolDisplayService = solution.Workspace.Services.GetLanguageServices(implementation.Language).GetRequiredService <ISymbolDisplayService>();

            return(NavigableItemFactory.GetItemsFromPreferredSourceLocations(
                       solution,
                       implementation,
                       displayString: symbolDisplayService.ToDisplayString(implementation)));
        }
コード例 #7
0
        public async Task <IEnumerable <INavigableItem> > FindDefinitionsAsync(
            Document document, int position, CancellationToken cancellationToken)
        {
            var symbol = await FindSymbolAsync(document, position, cancellationToken).ConfigureAwait(false);

            // Try to compute source definitions from symbol.
            var items = symbol != null
                ? NavigableItemFactory.GetItemsFromPreferredSourceLocations(document.Project.Solution, symbol, displayTaggedParts : null, cancellationToken : cancellationToken)
                : null;

            // realize the list here so that the consumer await'ing the result doesn't lazily cause
            // them to be created on an inappropriate thread.
            return(items?.ToList());
        }
コード例 #8
0
        private static INavigateToSearchResult ConvertResult(
            bool containsDots, DeclaredSymbolInfo declaredSymbolInfo, Document document,
            PatternMatches matches)
        {
            var matchKind = GetNavigateToMatchKind(containsDots, matches);

            // A match is considered to be case sensitive if all its constituent pattern matches are
            // case sensitive.
            var isCaseSensitive = matches.All(m => m.IsCaseSensitive);
            var kind            = GetItemKind(declaredSymbolInfo);
            var navigableItem   = NavigableItemFactory.GetItemFromDeclaredSymbolInfo(declaredSymbolInfo, document);

            return(new SearchResult(document, declaredSymbolInfo, kind, matchKind, isCaseSensitive, navigableItem));
        }
コード例 #9
0
        private bool TryPresentInNavigableItemsPresenter(
            SymbolMappingResult mapping, List <ISymbol> implementations, out string message)
        {
            // We have multiple symbols, so we'll build a list of all preferred locations for all the symbols
            var navigableItems = implementations.SelectMany(
                implementation => CreateItemsForImplementation(implementation, mapping.Solution));

            var presenter = _navigableItemPresenters.First();

            var taggedParts = NavigableItemFactory.GetSymbolDisplayTaggedParts(mapping.Project, mapping.Symbol);

            presenter.Value.DisplayResult(taggedParts.JoinText(), navigableItems);
            message = null;
            return(true);
        }
コード例 #10
0
        private INavigateToSearchResult ConvertResult(bool containsDots, ValueTuple <DeclaredSymbolInfo, Document, IEnumerable <PatternMatch> > result)
        {
            var declaredSymbolInfo = result.Item1;
            var document           = result.Item2;
            var matches            = result.Item3;
            var matchKind          = GetNavigateToMatchKind(containsDots, matches);

            // A match is considered to be case sensitive if all its constituent pattern matches are
            // case sensitive.
            var isCaseSensitive = matches.All(m => m.IsCaseSensitive);
            var kind            = GetItemKind(declaredSymbolInfo);
            var navigableItem   = NavigableItemFactory.GetItemFromDeclaredSymbolInfo(declaredSymbolInfo, document);

            return(new SearchResult(document, declaredSymbolInfo, kind, matchKind, isCaseSensitive, navigableItem));
        }
コード例 #11
0
        private INavigateToSearchResult ConvertResult(ValueTuple <DeclaredSymbolInfo, Document, IEnumerable <PatternMatch> > result, CancellationToken cancellationToken)
        {
            var declaredSymbolInfo = result.Item1;
            var document           = result.Item2;
            var matches            = result.Item3;
            var matchKind          = GetNavigateToMatchKind(matches);
            var kind          = GetItemKind(declaredSymbolInfo);
            var navigableItem = NavigableItemFactory.GetItemFromDeclaredSymbolInfo(declaredSymbolInfo, document, cancellationToken);

            return(new SearchResult(
                       document,
                       declaredSymbolInfo,
                       kind,
                       matchKind,
                       navigableItem));
        }
コード例 #12
0
        /// <summary>
        /// Finds references using <see cref="SymbolFinder.FindReferencesAsync(ISymbol, Solution, CancellationToken)"/>
        /// </summary>
        private async Task AddSymbolReferencesAsync(Document document, int position, ArrayBuilder <INavigableItem> builder, IWaitContext waitContext)
        {
            var result = await this.FindReferencedSymbolsAsync(document, position, waitContext).ConfigureAwait(false);

            if (result != null)
            {
                var referencedSymbols = result.Item1;
                var searchSolution    = result.Item2;

                var q = from r in referencedSymbols
                        from loc in r.Locations
                        select NavigableItemFactory.GetItemFromSymbolLocation(searchSolution, r.Definition, loc.Location);

                builder.AddRange(q);
            }
        }
コード例 #13
0
        private static INavigateToSearchResult ConvertResult(
            DeclaredSymbolInfo declaredSymbolInfo, Document document,
            ArrayBuilder <PatternMatch> nameMatches, ArrayBuilder <PatternMatch> containerMatches)
        {
            var matchKind = GetNavigateToMatchKind(nameMatches);

            // A match is considered to be case sensitive if all its constituent pattern matches are
            // case sensitive.
            var isCaseSensitive = nameMatches.All(m => m.IsCaseSensitive) && containerMatches.All(m => m.IsCaseSensitive);
            var kind            = GetItemKind(declaredSymbolInfo);
            var navigableItem   = NavigableItemFactory.GetItemFromDeclaredSymbolInfo(declaredSymbolInfo, document);

            return(new SearchResult(
                       document, declaredSymbolInfo, kind, matchKind, isCaseSensitive, navigableItem,
                       nameMatches.SelectMany(m => m.MatchedSpans).ToImmutableArray()));
        }
コード例 #14
0
        public async Task <IEnumerable <INavigableItem> > FindDefinitionsAsync(Document document, int position, CancellationToken cancellationToken)
        {
            var symbol = await FindSymbolAsync(document, position, cancellationToken).ConfigureAwait(false);

            // Try to compute source definitions from symbol.
            var items = symbol != null?NavigableItemFactory.GetItemsFromPreferredSourceLocations(document.Project.Solution, symbol) : null;

            if (items == null || items.IsEmpty())
            {
                // Fallback to asking the navigation definition providers for navigable definition locations.
                items = await GoToDefinitionHelpers.FindExternalDefinitionsAsync(document, position, _externalDefinitionProviders, cancellationToken).ConfigureAwait(false);
            }

            // realize the list here so that the consumer await'ing the result doesn't lazily cause
            // them to be created on an inappropriate thread.
            return(items?.ToList());
        }
コード例 #15
0
        public static async Task <IEnumerable <INavigableItem> > FindExternalDefinitionsAsync(ISymbol symbol, Project project, IEnumerable <Lazy <INavigableDefinitionProvider> > externalDefinitionProviders, CancellationToken cancellationToken)
        {
            foreach (var definitionProvider in externalDefinitionProviders)
            {
                var definitions = await definitionProvider.Value.FindDefinitionsAsync(project, symbol, cancellationToken).ConfigureAwait(false);

                if (definitions != null && definitions.Any())
                {
                    var preferredDefinitions = NavigableItemFactory.GetPreferredNavigableItems(project.Solution, definitions);
                    if (preferredDefinitions.Any())
                    {
                        return(preferredDefinitions);
                    }
                }
            }

            return(SpecializedCollections.EmptyEnumerable <INavigableItem>());
        }
コード例 #16
0
        private static async Task <LSP.Location[]> GetSymbolDefinitionLocationsAsync(XamlSymbolDefinition symbolDefinition, RequestContext context, IMetadataAsSourceFileService metadataAsSourceFileService, CancellationToken cancellationToken)
        {
            Contract.ThrowIfNull(symbolDefinition.Symbol);

            using var _ = ArrayBuilder <LSP.Location> .GetInstance(out var locations);

            var symbol = symbolDefinition.Symbol;

            var items = NavigableItemFactory.GetItemsFromPreferredSourceLocations(context.Solution, symbol, displayTaggedParts: null, cancellationToken);

            if (items.Any())
            {
                foreach (var item in items)
                {
                    var location = await ProtocolConversions.TextSpanToLocationAsync(
                        item.Document, item.SourceSpan, item.IsStale, cancellationToken).ConfigureAwait(false);

                    locations.AddIfNotNull(location);
                }
            }
            else
            {
                var metadataLocation = symbol.Locations.Where(loc => loc.IsInMetadata).FirstOrDefault();
                if (metadataLocation != null && metadataAsSourceFileService.IsNavigableMetadataSymbol(symbol))
                {
                    var project = context.Document?.GetCodeProject();
                    if (project != null)
                    {
                        var declarationFile = await metadataAsSourceFileService.GetGeneratedFileAsync(project, symbol, allowDecompilation : false, cancellationToken).ConfigureAwait(false);

                        var linePosSpan = declarationFile.IdentifierLocation.GetLineSpan().Span;
                        locations.Add(new LSP.Location
                        {
                            Uri   = new Uri(declarationFile.FilePath),
                            Range = ProtocolConversions.LinePositionToRange(linePosSpan),
                        });
                    }
                }
            }

            return(locations.ToArray());
        }
コード例 #17
0
        private static bool TryPresentInNavigableItemsPresenter(
            Solution solution, ISymbol symbol,
            IEnumerable <Lazy <INavigableItemsPresenter> > presenters,
            string title, Location[] locations)
        {
            var presenter = presenters.FirstOrDefault();

            if (presenter != null)
            {
                var navigableItems = locations.Select(location =>
                                                      NavigableItemFactory.GetItemFromSymbolLocation(
                                                          solution, symbol, location,
                                                          displayTaggedParts: null)).ToImmutableArray();

                presenter.Value.DisplayResult(title, navigableItems);
                return(true);
            }

            return(false);
        }
コード例 #18
0
        public async Task <IEnumerable <INavigableItem> > FindReferencesAsync(Document document, int position, IWaitContext waitContext)
        {
            var cancellationToken = waitContext.CancellationToken;
            var result            = await this.FindReferencedSymbolsAsync(document, position, waitContext).ConfigureAwait(false);

            if (result == null)
            {
                return(SpecializedCollections.EmptyEnumerable <INavigableItem>());
            }

            var referencedSymbols = result.Item1;
            var searchSolution    = result.Item2;

            var q = from r in referencedSymbols
                    from loc in r.Locations
                    select NavigableItemFactory.GetItemFromSymbolLocation(searchSolution, r.Definition, loc.Location);

            // realize the list here so that the consumer await'ing the result doesn't lazily cause
            // them to be created on an inapropriate thread.
            return(q.ToList());
        }
コード例 #19
0
        private static IEnumerable <INavigateToSearchResult> ConvertResult(
            ISymbol declaredSymbol, Document document, SyntaxTreeBase syntaxTree,
            NavigateToMatchKind matchKind)
        {
            var isCaseSensitive = false;
            var kind            = GetItemKind(declaredSymbol.Kind);

            foreach (var location in declaredSymbol.Locations)
            {
                var sourceFileSpan = syntaxTree.GetSourceFileSpan(location);

                if (sourceFileSpan.IsInRootFile)
                {
                    var navigableItem = NavigableItemFactory.GetItemFromDeclaredSymbol(
                        declaredSymbol, document, sourceFileSpan);

                    yield return(new SearchResult(
                                     document, declaredSymbol, kind, matchKind,
                                     isCaseSensitive, navigableItem));
                }
            }
        }
コード例 #20
0
        private static SearchResult ConvertResult(
            DeclaredSymbolInfo declaredSymbolInfo, Document document,
            ArrayBuilder <PatternMatch> nameMatches, ArrayBuilder <PatternMatch> containerMatches)
        {
            var matchKind = GetNavigateToMatchKind(nameMatches);

            // A match is considered to be case sensitive if all its constituent pattern matches are
            // case sensitive.
            var isCaseSensitive = nameMatches.All(m => m.IsCaseSensitive) && containerMatches.All(m => m.IsCaseSensitive);
            var kind            = GetItemKind(declaredSymbolInfo);
            var navigableItem   = NavigableItemFactory.GetItemFromDeclaredSymbolInfo(declaredSymbolInfo, document);

            var matchedSpans = ArrayBuilder <TextSpan> .GetInstance();

            foreach (var match in nameMatches)
            {
                matchedSpans.AddRange(match.MatchedSpans);
            }

            return(new SearchResult(
                       document, declaredSymbolInfo, kind, matchKind, isCaseSensitive, navigableItem,
                       matchedSpans.ToImmutableAndFree()));
        }
コード例 #21
0
ファイル: GoToDefinitionHelpers.cs プロジェクト: taori/roslyn
        public static async Task <ImmutableArray <DefinitionItem> > GetDefinitionsAsync(
            ISymbol symbol,
            Solution solution,
            bool thirdPartyNavigationAllowed,
            CancellationToken cancellationToken)
        {
            var alias = symbol as IAliasSymbol;

            if (alias != null)
            {
                if (alias.Target is INamespaceSymbol ns && ns.IsGlobalNamespace)
                {
                    return(ImmutableArray.Create <DefinitionItem>());
                }
            }

            // VB global import aliases have a synthesized SyntaxTree.
            // We can't go to the definition of the alias, so use the target type.

            if (alias != null)
            {
                var sourceLocations = NavigableItemFactory.GetPreferredSourceLocations(
                    solution, symbol, cancellationToken);

                if (sourceLocations.All(l => solution.GetDocument(l.SourceTree) == null))
                {
                    symbol = alias.Target;
                }
            }

            var definition = await SymbolFinder.FindSourceDefinitionAsync(symbol, solution, cancellationToken).ConfigureAwait(false);

            cancellationToken.ThrowIfCancellationRequested();

            symbol = definition ?? symbol;

            // If it is a partial method declaration with no body, choose to go to the implementation
            // that has a method body.
            if (symbol is IMethodSymbol method)
            {
                symbol = method.PartialImplementationPart ?? symbol;
            }

            using var definitionsDisposer = ArrayBuilder <DefinitionItem> .GetInstance(out var definitions);

            // Going to a symbol may end up actually showing the symbol in the Find-Usages window.
            // This happens when there is more than one location for the symbol (i.e. for partial
            // symbols) and we don't know the best place to take you to.
            //
            // The FindUsages window supports showing the classified text for an item.  It does this
            // in two ways.  Either the item can pass along its classified text (and the window will
            // defer to that), or the item will have no classified text, and the window will compute
            // it in the BG.
            //
            // Passing along the classified information is valuable for OOP scenarios where we want
            // all that expensive computation done on the OOP side and not in the VS side.
            //
            // However, Go To Definition is all in-process, and is also synchronous.  So we do not
            // want to fetch the classifications here.  It slows down the command and leads to a
            // measurable delay in our perf tests.
            //
            // So, if we only have a single location to go to, this does no unnecessary work.  And,
            // if we do have multiple locations to show, it will just be done in the BG, unblocking
            // this command thread so it can return the user faster.
            var definitionItem = symbol.ToNonClassifiedDefinitionItem(solution, includeHiddenLocations: true);

            if (thirdPartyNavigationAllowed)
            {
                var factory = solution.Workspace.Services.GetService <IDefinitionsAndReferencesFactory>();
                if (factory != null)
                {
                    var thirdPartyItem = await factory.GetThirdPartyDefinitionItemAsync(solution, definitionItem, cancellationToken).ConfigureAwait(false);

                    definitions.AddIfNotNull(thirdPartyItem);
                }
            }

            definitions.Add(definitionItem);
            return(definitions.ToImmutable());
        }
コード例 #22
0
        public static bool TryGoToDefinition(
            ISymbol symbol,
            Project project,
            IEnumerable <Lazy <INavigableDefinitionProvider> > externalDefinitionProviders,
            IEnumerable <Lazy <INavigableItemsPresenter> > presenters,
            CancellationToken cancellationToken,
            bool thirdPartyNavigationAllowed = true,
            bool throwOnHiddenDefinition     = false)
        {
            var alias = symbol as IAliasSymbol;

            if (alias != null)
            {
                var ns = alias.Target as INamespaceSymbol;
                if (ns != null && ns.IsGlobalNamespace)
                {
                    return(false);
                }
            }

            // VB global import aliases have a synthesized SyntaxTree.
            // We can't go to the definition of the alias, so use the target type.

            var solution = project.Solution;

            if (symbol is IAliasSymbol &&
                NavigableItemFactory.GetPreferredSourceLocations(solution, symbol).All(l => project.Solution.GetDocument(l.SourceTree) == null))
            {
                symbol = ((IAliasSymbol)symbol).Target;
            }

            var definition = SymbolFinder.FindSourceDefinitionAsync(symbol, solution, cancellationToken).WaitAndGetResult(cancellationToken);

            cancellationToken.ThrowIfCancellationRequested();

            symbol = definition ?? symbol;

            if (thirdPartyNavigationAllowed && TryThirdPartyNavigation(symbol, solution))
            {
                return(true);
            }

            // If it is a partial method declaration with no body, choose to go to the implementation
            // that has a method body.
            if (symbol is IMethodSymbol)
            {
                symbol = ((IMethodSymbol)symbol).PartialImplementationPart ?? symbol;
            }

            var options = project.Solution.Options;

            var preferredSourceLocations = NavigableItemFactory.GetPreferredSourceLocations(solution, symbol).ToArray();
            var title = NavigableItemFactory.GetSymbolDisplayString(project, symbol);

            if (!preferredSourceLocations.Any())
            {
                // Attempt to find source locations from external definition providers.
                if (thirdPartyNavigationAllowed && externalDefinitionProviders.Any())
                {
                    var externalSourceDefinitions = FindExternalDefinitionsAsync(symbol, project, externalDefinitionProviders, cancellationToken).WaitAndGetResult(cancellationToken).ToImmutableArray();
                    if (externalSourceDefinitions.Length > 0)
                    {
                        return(TryGoToDefinition(externalSourceDefinitions, title, options, presenters, throwOnHiddenDefinition));
                    }
                }

                // If there are no visible source locations, then tell the host about the symbol and
                // allow it to navigate to it.  This will either navigate to any non-visible source
                // locations, or it can appropriately deal with metadata symbols for hosts that can go
                // to a metadata-as-source view.

                var symbolNavigationService = solution.Workspace.Services.GetService <ISymbolNavigationService>();
                return(symbolNavigationService.TryNavigateToSymbol(
                           symbol, project,
                           options: options.WithChangedOption(NavigationOptions.PreferProvisionalTab, true),
                           cancellationToken: cancellationToken));
            }

            var navigableItems = preferredSourceLocations.Select(location => NavigableItemFactory.GetItemFromSymbolLocation(solution, symbol, location)).ToImmutableArray();

            return(TryGoToDefinition(navigableItems, title, options, presenters, throwOnHiddenDefinition));
        }
コード例 #23
0
ファイル: GoToDefinitionHelpers.cs プロジェクト: znatz/roslyn
        public static bool TryGoToDefinition(
            ISymbol symbol,
            Project project,
            IEnumerable <Lazy <IStreamingFindUsagesPresenter> > streamingPresenters,
            CancellationToken cancellationToken,
            bool thirdPartyNavigationAllowed = true,
            bool throwOnHiddenDefinition     = false)
        {
            var alias = symbol as IAliasSymbol;

            if (alias != null)
            {
                var ns = alias.Target as INamespaceSymbol;
                if (ns != null && ns.IsGlobalNamespace)
                {
                    return(false);
                }
            }

            // VB global import aliases have a synthesized SyntaxTree.
            // We can't go to the definition of the alias, so use the target type.

            var solution = project.Solution;

            if (alias != null)
            {
                var sourceLocations = NavigableItemFactory.GetPreferredSourceLocations(
                    solution, symbol, cancellationToken);

                if (sourceLocations.All(l => project.Solution.GetDocument(l.SourceTree) == null))
                {
                    symbol = alias.Target;
                }
            }

            var definition = SymbolFinder.FindSourceDefinitionAsync(symbol, solution, cancellationToken).WaitAndGetResult(cancellationToken);

            cancellationToken.ThrowIfCancellationRequested();

            symbol = definition ?? symbol;

            // If it is a partial method declaration with no body, choose to go to the implementation
            // that has a method body.
            if (symbol is IMethodSymbol method)
            {
                symbol = method.PartialImplementationPart ?? symbol;
            }

            var definitions = ArrayBuilder <DefinitionItem> .GetInstance();

            // Going to a symbol may end up actually showing the symbol in the Find-Usages window.
            // This happens when there is more than one location for the symbol (i.e. for partial
            // symbols) and we don't know the best place to take you to.
            //
            // The FindUsages window supports showing the classified text for an item.  It does this
            // in two ways.  Either the item can pass along its classified text (and the window will
            // defer to that), or the item will have no classified text, and the window will compute
            // it in the BG.
            //
            // Passing along the classified information is valuable for OOP scenarios where we want
            // all that expensive computation done on the OOP side and not in the VS side.
            //
            // However, Go To Definition is all in-process, and is also synchronous.  So we do not
            // want to fetch the classifications here.  It slows down the command and leads to a
            // measurable delay in our perf tests.
            //
            // So, if we only have a single location to go to, this does no unnecessary work.  And,
            // if we do have multiple locations to show, it will just be done in the BG, unblocking
            // this command thread so it can return the user faster.
            var definitionItem = symbol.ToNonClassifiedDefinitionItem(solution, includeHiddenLocations: true);

            if (thirdPartyNavigationAllowed)
            {
                var factory        = solution.Workspace.Services.GetService <IDefinitionsAndReferencesFactory>();
                var thirdPartyItem = factory?.GetThirdPartyDefinitionItem(solution, definitionItem, cancellationToken);
                definitions.AddIfNotNull(thirdPartyItem);
            }

            definitions.Add(definitionItem);

            var presenter = streamingPresenters.FirstOrDefault()?.Value;
            var title     = string.Format(EditorFeaturesResources._0_declarations,
                                          FindUsagesHelpers.GetDisplayName(symbol));

            return(presenter.TryNavigateToOrPresentItemsAsync(
                       project.Solution.Workspace, title, definitions.ToImmutableAndFree()).WaitAndGetResult(cancellationToken));
        }
コード例 #24
0
        public static bool TryGoToDefinition(
            ISymbol symbol,
            Project project,
            IEnumerable <Lazy <INavigableItemsPresenter> > presenters,
            IEnumerable <Lazy <IStreamingFindUsagesPresenter> > streamingPresenters,
            CancellationToken cancellationToken,
            bool thirdPartyNavigationAllowed = true,
            bool throwOnHiddenDefinition     = false)
        {
            var alias = symbol as IAliasSymbol;

            if (alias != null)
            {
                var ns = alias.Target as INamespaceSymbol;
                if (ns != null && ns.IsGlobalNamespace)
                {
                    return(false);
                }
            }

            // VB global import aliases have a synthesized SyntaxTree.
            // We can't go to the definition of the alias, so use the target type.

            var solution = project.Solution;

            if (symbol is IAliasSymbol &&
                NavigableItemFactory.GetPreferredSourceLocations(solution, symbol).All(l => project.Solution.GetDocument(l.SourceTree) == null))
            {
                symbol = ((IAliasSymbol)symbol).Target;
            }

            var definition = SymbolFinder.FindSourceDefinitionAsync(symbol, solution, cancellationToken).WaitAndGetResult(cancellationToken);

            cancellationToken.ThrowIfCancellationRequested();

            symbol = definition ?? symbol;

            if (thirdPartyNavigationAllowed && TryThirdPartyNavigation(symbol, solution))
            {
                return(true);
            }

            // If it is a partial method declaration with no body, choose to go to the implementation
            // that has a method body.
            if (symbol is IMethodSymbol)
            {
                symbol = ((IMethodSymbol)symbol).PartialImplementationPart ?? symbol;
            }

            var options = project.Solution.Options;

            var preferredSourceLocations = NavigableItemFactory.GetPreferredSourceLocations(solution, symbol).ToArray();
            var displayParts             = NavigableItemFactory.GetSymbolDisplayTaggedParts(project, symbol);
            var title = displayParts.JoinText();

            if (preferredSourceLocations.Length == 0)
            {
                // If there are no visible source locations, then tell the host about the symbol and
                // allow it to navigate to it.  This will either navigate to any non-visible source
                // locations, or it can appropriately deal with metadata symbols for hosts that can go
                // to a metadata-as-source view.

                var symbolNavigationService = solution.Workspace.Services.GetService <ISymbolNavigationService>();
                return(symbolNavigationService.TryNavigateToSymbol(
                           symbol, project,
                           options: options.WithChangedOption(NavigationOptions.PreferProvisionalTab, true),
                           cancellationToken: cancellationToken));
            }
            else if (preferredSourceLocations.Length == 1)
            {
                var item = NavigableItemFactory.GetItemFromSymbolLocation(
                    solution, symbol, preferredSourceLocations[0],
                    displayTaggedParts: null);
                return(TryGoToSingleLocation(item, options, throwOnHiddenDefinition));
            }
            else
            {
                // We have multiple viable source locations, so ask the host what to do. Most hosts
                // will simply display the results to the user and allow them to choose where to
                // go.

                return(TryPresentInFindUsagesPresenter(solution, symbol, streamingPresenters, cancellationToken) ||
                       TryPresentInNavigableItemsPresenter(solution, symbol, presenters, title, preferredSourceLocations));
            }
        }
コード例 #25
0
        public static bool TryGoToDefinition(
            ISymbol symbol,
            Project project,
            IEnumerable <Lazy <IStreamingFindUsagesPresenter> > streamingPresenters,
            CancellationToken cancellationToken,
            bool thirdPartyNavigationAllowed = true,
            bool throwOnHiddenDefinition     = false)
        {
            var alias = symbol as IAliasSymbol;

            if (alias != null)
            {
                var ns = alias.Target as INamespaceSymbol;
                if (ns != null && ns.IsGlobalNamespace)
                {
                    return(false);
                }
            }

            // VB global import aliases have a synthesized SyntaxTree.
            // We can't go to the definition of the alias, so use the target type.

            var solution = project.Solution;

            if (alias != null)
            {
                var sourceLocations = NavigableItemFactory.GetPreferredSourceLocations(
                    solution, symbol, cancellationToken);

                if (sourceLocations.All(l => project.Solution.GetDocument(l.SourceTree) == null))
                {
                    symbol = alias.Target;
                }
            }

            var definition = SymbolFinder.FindSourceDefinitionAsync(symbol, solution, cancellationToken).WaitAndGetResult(cancellationToken);

            cancellationToken.ThrowIfCancellationRequested();

            symbol = definition ?? symbol;

            var definitions = ArrayBuilder <DefinitionItem> .GetInstance();

            if (thirdPartyNavigationAllowed)
            {
                var factory        = solution.Workspace.Services.GetService <IDefinitionsAndReferencesFactory>();
                var thirdPartyItem = factory?.GetThirdPartyDefinitionItem(solution, symbol, cancellationToken);
                definitions.AddIfNotNull(thirdPartyItem);
            }

            // If it is a partial method declaration with no body, choose to go to the implementation
            // that has a method body.
            if (symbol is IMethodSymbol method)
            {
                symbol = method.PartialImplementationPart ?? symbol;
            }

            var options = project.Solution.Options;

            definitions.Add(symbol.ToDefinitionItem(solution, includeHiddenLocations: true));

            var presenter = GetFindUsagesPresenter(streamingPresenters);
            var title     = string.Format(EditorFeaturesResources._0_declarations,
                                          FindUsagesHelpers.GetDisplayName(symbol));

            return(presenter.TryNavigateToOrPresentItemsAsync(
                       title, definitions.ToImmutableAndFree()).WaitAndGetResult(cancellationToken));
        }
コード例 #26
0
        public static bool TryGoToDefinition(
            ISymbol symbol,
            Project project,
            IEnumerable <Lazy <INavigableItemsPresenter> > presenters,
            CancellationToken cancellationToken,
            bool thirdPartyNavigationAllowed = true,
            bool throwOnHiddenDefinition     = false)
        {
            var alias = symbol as IAliasSymbol;

            if (alias != null)
            {
                var ns = alias.Target as INamespaceSymbol;
                if (ns != null && ns.IsGlobalNamespace)
                {
                    return(false);
                }
            }

            // VB global import aliases have a synthesized SyntaxTree.
            // We can't go to the definition of the alias, so use the target type.

            var solution = project.Solution;

            if (symbol is IAliasSymbol &&
                NavigableItemFactory.GetPreferredSourceLocations(solution, symbol).All(l => project.Solution.GetDocument(l.SourceTree) == null))
            {
                symbol = ((IAliasSymbol)symbol).Target;
            }

            var definition = SymbolFinder.FindSourceDefinitionAsync(symbol, solution, cancellationToken).WaitAndGetResult(cancellationToken);

            cancellationToken.ThrowIfCancellationRequested();

            symbol = definition ?? symbol;

            if (thirdPartyNavigationAllowed && TryThirdPartyNavigation(symbol, solution))
            {
                return(true);
            }

            // If it is a partial method declaration with no body, choose to go to the implementation
            // that has a method body.
            if (symbol is IMethodSymbol)
            {
                symbol = ((IMethodSymbol)symbol).PartialImplementationPart ?? symbol;
            }

            var preferredSourceLocations = NavigableItemFactory.GetPreferredSourceLocations(solution, symbol).ToArray();

            if (!preferredSourceLocations.Any())
            {
                // If there are no visible source locations, then tell the host about the symbol and
                // allow it to navigate to it.  THis will either navigate to any non-visible source
                // locations, or it can appropriately deal with metadata symbols for hosts that can go
                // to a metadata-as-source view.

                var symbolNavigationService = solution.Workspace.Services.GetService <ISymbolNavigationService>();
                return(symbolNavigationService.TryNavigateToSymbol(symbol, project, cancellationToken: cancellationToken, usePreviewTab: true));
            }

            // If we have a single location, then just navigate to it.
            if (preferredSourceLocations.Length == 1)
            {
                var firstItem         = preferredSourceLocations[0];
                var workspace         = project.Solution.Workspace;
                var navigationService = workspace.Services.GetService <IDocumentNavigationService>();

                if (navigationService.CanNavigateToSpan(workspace, solution.GetDocument(firstItem.SourceTree).Id, firstItem.SourceSpan))
                {
                    return(navigationService.TryNavigateToSpan(workspace, solution.GetDocument(firstItem.SourceTree).Id, firstItem.SourceSpan, usePreviewTab: true));
                }
                else
                {
                    if (throwOnHiddenDefinition)
                    {
                        const int E_FAIL = -2147467259;
                        throw new COMException(EditorFeaturesResources.TheDefinitionOfTheObjectIsHidden, E_FAIL);
                    }
                    else
                    {
                        return(false);
                    }
                }
            }
            else
            {
                // We have multiple viable source locations, so ask the host what to do. Most hosts
                // will simply display the results to the user and allow them to choose where to
                // go.

                if (presenters.Any())
                {
                    presenters.First().Value.DisplayResult(NavigableItemFactory.GetSymbolDisplayString(project, symbol),
                                                           preferredSourceLocations.Select(location => NavigableItemFactory.GetItemFromSymbolLocation(solution, symbol, location)).ToList());

                    return(true);
                }

                return(false);
            }
        }