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