private async Task <Tuple <IEnumerable <ReferencedSymbol>, Solution> > FindReferencedSymbolsAsync( Document document, int position, IWaitContext waitContext) { var cancellationToken = waitContext.CancellationToken; var symbolAndProject = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync( document, position, cancellationToken).ConfigureAwait(false); if (symbolAndProject == null) { return(null); } var symbol = symbolAndProject?.symbol; var project = symbolAndProject?.project; var displayName = FindUsagesHelpers.GetDisplayName(symbol); waitContext.Message = string.Format( EditorFeaturesResources.Finding_references_of_0, displayName); var result = await SymbolFinder.FindReferencesAsync(symbol, project.Solution, cancellationToken).ConfigureAwait(false); return(Tuple.Create(result, project.Solution)); }
public static bool TryGoToDefinition( ISymbol symbol, Solution solution, IThreadingContext threadingContext, IStreamingFindUsagesPresenter streamingPresenter, CancellationToken cancellationToken, bool thirdPartyNavigationAllowed = true ) { var definitions = GetDefinitions( symbol, solution, thirdPartyNavigationAllowed, cancellationToken ); var title = string.Format( EditorFeaturesResources._0_declarations, FindUsagesHelpers.GetDisplayName(symbol) ); return threadingContext.JoinableTaskFactory.Run( () => streamingPresenter.TryNavigateToOrPresentItemsAsync( threadingContext, solution.Workspace, title, definitions, cancellationToken ) ); }
public async Task FindBasesAsync(Document document, int position, IFindUsagesContext context) { var cancellationToken = context.CancellationToken; var symbolAndProjectOpt = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync( document, position, cancellationToken).ConfigureAwait(false); if (symbolAndProjectOpt == null) { await context.ReportMessageAsync( EditorFeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret).ConfigureAwait(false); return; } var(symbol, project) = symbolAndProjectOpt.Value; var bases = FindBaseHelpers.FindBases( symbol, project, cancellationToken); await context.SetSearchTitleAsync( string.Format(EditorFeaturesResources._0_bases, FindUsagesHelpers.GetDisplayName(symbol))).ConfigureAwait(false); var found = false; // For each potential base, try to find its definition in sources. // If found, add it's definitionItem to the context. // If not found but the symbol is from metadata, create it's definition item from metadata and add to the context. foreach (var baseSymbol in bases) { var sourceDefinition = await SymbolFinder.FindSourceDefinitionAsync( SymbolAndProjectId.Create(baseSymbol, project.Id), project.Solution, cancellationToken).ConfigureAwait(false); if (sourceDefinition.Symbol != null) { var definitionItem = await sourceDefinition.Symbol.ToClassifiedDefinitionItemAsync( project.Solution.GetProject(sourceDefinition.ProjectId), includeHiddenLocations : false, FindReferencesSearchOptions.Default, cancellationToken : cancellationToken) .ConfigureAwait(false); await context.OnDefinitionFoundAsync(definitionItem).ConfigureAwait(false); found = true; } else if (baseSymbol.Locations.Any(l => l.IsInMetadata)) { var definitionItem = baseSymbol.ToNonClassifiedDefinitionItem( project, includeHiddenLocations: true); await context.OnDefinitionFoundAsync(definitionItem).ConfigureAwait(false); found = true; } } if (!found) { await context.ReportMessageAsync(EditorFeaturesResources.The_symbol_has_no_base) .ConfigureAwait(false); } }
private async Task StreamingFindBaseSymbolsAsync( Document document, int caretPosition, IStreamingFindUsagesPresenter presenter) { try { using (var token = _asyncListener.BeginAsyncOperation(nameof(StreamingFindBaseSymbolsAsync))) { // Let the presented know we're starting a search. var context = presenter.StartSearch( EditorFeaturesResources.Navigating, supportsReferences: true); using (Logger.LogBlock( FunctionId.CommandHandler_FindAllReference, KeyValueLogMessage.Create(LogType.UserAction, m => m["type"] = "streaming"), context.CancellationToken)) { try { #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task var relevantSymbol = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(document, caretPosition, context.CancellationToken); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task var overriddenSymbol = relevantSymbol?.symbol.GetOverriddenMember(); while (overriddenSymbol != null) { if (context.CancellationToken.IsCancellationRequested) { return; } var definitionItem = overriddenSymbol.ToNonClassifiedDefinitionItem(document.Project.Solution, true); #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task await context.OnDefinitionFoundAsync(definitionItem); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task // try getting the next one overriddenSymbol = overriddenSymbol.GetOverriddenMember(); } } finally { await context.OnCompletedAsync().ConfigureAwait(false); } } } } catch (OperationCanceledException) { } catch (Exception e) when(FatalError.ReportAndCatch(e)) { } }
private async Task FindMemberOverloadsAsync( Document document, int caretPosition, IStreamingFindUsagesPresenter presenter) { try { using (var token = _asyncListener.BeginAsyncOperation(nameof(FindMemberOverloadsAsync))) { // Let the presented know we're starting a search. var context = presenter.StartSearch( EditorFeaturesResources.Navigating, supportsReferences: true); using (Logger.LogBlock( FunctionId.CommandHandler_FindAllReference, KeyValueLogMessage.Create(LogType.UserAction, m => m["type"] = "streaming"), context.CancellationToken)) { try { #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task var candidateSymbolProjectPair = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(document, caretPosition, context.CancellationToken); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task // we need to get the containing type (i.e. class) var symbol = candidateSymbolProjectPair?.symbol; // if we didn't get any symbol, that's it if (symbol == null || symbol.ContainingType == null) { return; } foreach (var curSymbol in symbol.ContainingType.GetMembers() .Where(m => m.Kind == symbol.Kind && m.Name == symbol.Name)) { var definitionItem = curSymbol.ToNonClassifiedDefinitionItem(document.Project.Solution, true); #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task await context.OnDefinitionFoundAsync(definitionItem); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task } } finally { await context.OnCompletedAsync().ConfigureAwait(false); } } } } catch (OperationCanceledException) { } catch (Exception e) when(FatalError.ReportAndCatch(e)) { } }
private async Task <INavigableLocation?> GetAlternativeLocationIfAlreadyOnDefinitionAsync( Document document, int position, ISymbol symbol, CancellationToken cancellationToken) { var project = document.Project; var solution = project.Solution; var sourceLocations = symbol.Locations.WhereAsArray(loc => loc.IsInSource); if (sourceLocations.Length != 1) { return(null); } var definitionLocation = sourceLocations[0]; if (!definitionLocation.SourceSpan.IntersectsWith(position)) { return(null); } var definitionTree = definitionLocation.SourceTree; var definitionDocument = solution.GetDocument(definitionTree); if (definitionDocument != document) { return(null); } // Ok, we were already on the definition. Look for better symbols we could show results // for instead. For now, just see if we're on an interface member impl. If so, we can // instead navigate to the actual interface member. // // In the future we can expand this with other mappings if appropriate. var interfaceImpls = symbol.ExplicitOrImplicitInterfaceImplementations(); if (interfaceImpls.Length == 0) { return(null); } var title = string.Format(EditorFeaturesResources._0_implemented_members, FindUsagesHelpers.GetDisplayName(symbol)); using var _ = ArrayBuilder <DefinitionItem> .GetInstance(out var builder); foreach (var impl in interfaceImpls) { builder.AddRange(await GoToDefinitionHelpers.GetDefinitionsAsync( impl, solution, thirdPartyNavigationAllowed: false, cancellationToken).ConfigureAwait(false)); } var definitions = builder.ToImmutable(); return(await _streamingPresenter.GetStreamingLocationAsync( _threadingContext, solution.Workspace, title, definitions, cancellationToken).ConfigureAwait(false)); }
private bool TryGoToAlternativeLocationIfAlreadyOnDefinition( Document document, int position, ISymbol symbol, CancellationToken cancellationToken) { var project = document.Project; var solution = project.Solution; var sourceLocations = symbol.Locations.WhereAsArray(loc => loc.IsInSource); if (sourceLocations.Length != 1) { return(false); } var definitionLocation = sourceLocations[0]; if (!definitionLocation.SourceSpan.IntersectsWith(position)) { return(false); } var definitionTree = definitionLocation.SourceTree; var definitionDocument = solution.GetDocument(definitionTree); if (definitionDocument != document) { return(false); } // Ok, we were already on the definition. Look for better symbols we could show results // for instead. For now, just see if we're on an interface member impl. If so, we can // instead navigate to the actual interface member. // // In the future we can expand this with other mappings if appropriate. var interfaceImpls = symbol.ExplicitOrImplicitInterfaceImplementations(); if (interfaceImpls.Length == 0) { return(false); } var definitions = interfaceImpls.SelectMany( i => GoToDefinitionHelpers.GetDefinitions( i, solution, thirdPartyNavigationAllowed: false, cancellationToken)).ToImmutableArray(); var title = string.Format(EditorFeaturesResources._0_implemented_members, FindUsagesHelpers.GetDisplayName(symbol)); return(_threadingContext.JoinableTaskFactory.Run(() => _streamingPresenter.TryNavigateToOrPresentItemsAsync( _threadingContext, solution.Workspace, title, definitions, cancellationToken))); }
public static bool TryGoToDefinition( ISymbol symbol, Solution solution, IStreamingFindUsagesPresenter streamingPresenter, CancellationToken cancellationToken, bool thirdPartyNavigationAllowed = true) { var definitions = GetDefinitions(symbol, solution, thirdPartyNavigationAllowed, cancellationToken); var title = string.Format(EditorFeaturesResources._0_declarations, FindUsagesHelpers.GetDisplayName(symbol)); return(streamingPresenter.TryNavigateToOrPresentItemsAsync( solution.Workspace, title, definitions).WaitAndGetResult(cancellationToken)); }
public static async Task <bool> TryGoToDefinitionAsync( ISymbol symbol, Solution solution, IThreadingContext threadingContext, IStreamingFindUsagesPresenter streamingPresenter, CancellationToken cancellationToken, bool thirdPartyNavigationAllowed = true) { var title = string.Format(EditorFeaturesResources._0_declarations, FindUsagesHelpers.GetDisplayName(symbol)); var definitions = await GetDefinitionsAsync(symbol, solution, thirdPartyNavigationAllowed, cancellationToken).ConfigureAwait(false); return(await streamingPresenter.TryNavigateToOrPresentItemsAsync( threadingContext, solution.Workspace, title, definitions, cancellationToken).ConfigureAwait(false)); }
internal static bool TryGoToDefinition( ISymbol symbol, Project project, IEnumerable <Lazy <IStreamingFindUsagesPresenter> > streamingPresenters, CancellationToken cancellationToken, bool thirdPartyNavigationAllowed = true, bool throwOnHiddenDefinition = false) { var definitions = GetDefinitions(symbol, project, thirdPartyNavigationAllowed, cancellationToken); var presenter = streamingPresenters.FirstOrDefault()?.Value; var title = string.Format("_0_declarations", FindUsagesHelpers.GetDisplayName(symbol)); return(presenter.TryNavigateToOrPresentItemsAsync( project.Solution.Workspace, title, definitions).WaitAndGetResult(cancellationToken)); }
public bool TryGoToImplementation(Document document, int position, CancellationToken cancellationToken, out string message) { var result = FindUsagesHelpers.FindImplementationsAsync(document, position, cancellationToken).WaitAndGetResult(cancellationToken); if (result == null) { message = EditorFeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret; return(false); } if (result.Value.message != null) { message = result.Value.message; return(false); } return(TryGoToImplementations( result.Value.symbol, result.Value.project, result.Value.implementations, cancellationToken, out message)); }
public static async Task <(ISymbol symbol, ImmutableArray <SymbolAndProjectId> implementations, string message)?> FindBasesAsync(Document document, int position, CancellationToken cancellationToken) { var symbolAndProject = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync( document, position, cancellationToken).ConfigureAwait(false); if (symbolAndProject == null) { return(null); } var symbol = symbolAndProject.Value.symbol; var project = symbolAndProject.Value.project; var bases = await FindBasesWorkerAsync(symbol, project, cancellationToken).ConfigureAwait(false); var filteredSymbols = bases.WhereAsArray(s => s.Symbol.Locations.Any(l => l.IsInSource)); return(filteredSymbols.Length == 0 ? (symbol, filteredSymbols, EditorFeaturesResources.The_symbol_has_no_base) : (symbol, filteredSymbols, null)); }
public async Task FindBasesAsync(Document document, int position, IFindUsagesContext context) { var cancellationToken = context.CancellationToken; var tuple = await FindBaseHelpers.FindBasesAsync(document, position, cancellationToken).ConfigureAwait(false); if (tuple == null) { await context.ReportMessageAsync( EditorFeaturesResources.Cannot_navigate_to_the_symbol_under_the_caret).ConfigureAwait(false); return; } var(symbol, implementations, message) = tuple.Value; if (message != null) { await context.ReportMessageAsync(message).ConfigureAwait(false); return; } await context.SetSearchTitleAsync( string.Format(EditorFeaturesResources._0_bases, FindUsagesHelpers.GetDisplayName(symbol))).ConfigureAwait(false); var solution = document.Project.Solution; foreach (var implementation in implementations) { var definitionItem = await implementation.Symbol.ToClassifiedDefinitionItemAsync( solution.GetProject(implementation.ProjectId), includeHiddenLocations : false, FindReferencesSearchOptions.Default, cancellationToken : cancellationToken).ConfigureAwait(false); await context.OnDefinitionFoundAsync(definitionItem).ConfigureAwait(false); } }
private async Task FindExtensionMethodsAsync( Document document, int caretPosition, IStreamingFindUsagesPresenter presenter, CancellationToken cancellationToken ) { try { using var token = _asyncListener.BeginAsyncOperation( nameof(FindExtensionMethodsAsync) ); var context = presenter.StartSearch( EditorFeaturesResources.Navigating, supportsReferences: true, cancellationToken ); using ( Logger.LogBlock( FunctionId.CommandHandler_FindAllReference, KeyValueLogMessage.Create(LogType.UserAction, m => m["type"] = "streaming"), context.CancellationToken ) ) { #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task var candidateSymbolProjectPair = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync( document, caretPosition, context.CancellationToken ); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task var symbol = candidateSymbolProjectPair?.symbol as INamedTypeSymbol; // if we didn't get the right symbol, just abort if (symbol == null) { await context.OnCompletedAsync().ConfigureAwait(false); return; } Compilation compilation; if (!document.Project.TryGetCompilation(out compilation)) { await context.OnCompletedAsync().ConfigureAwait(false); return; } var solution = document.Project.Solution; foreach ( var type in compilation.Assembly.GlobalNamespace.GetAllTypes( context.CancellationToken ) ) { if (!type.MightContainExtensionMethods) { continue; } foreach ( var extMethod in type.GetMembers() .OfType <IMethodSymbol>() .Where(method => method.IsExtensionMethod) ) { if (context.CancellationToken.IsCancellationRequested) { break; } var reducedMethod = extMethod.ReduceExtensionMethod(symbol); if (reducedMethod != null) { var loc = extMethod.Locations.First(); var sourceDefinition = await SymbolFinder .FindSourceDefinitionAsync( reducedMethod, solution, context.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, context.CancellationToken ); var definitionItem = reducedMethod.ToNonClassifiedDefinitionItem(solution, true); #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task await context.OnDefinitionFoundAsync(definitionItem); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task } } } } await context.OnCompletedAsync().ConfigureAwait(false); } } catch (OperationCanceledException) { } catch (Exception e) when(FatalError.ReportAndCatch(e)) { } }
private async Task FindImplementingMembersAsync( Document document, int caretPosition, IStreamingFindUsagesPresenter presenter, CancellationToken cancellationToken ) { try { using var token = _asyncListener.BeginAsyncOperation( nameof(FindImplementingMembersAsync) ); // Let the presented know we're starting a search. We pass in no cancellation token here as this // operation itself is fire-and-forget and the user won't cancel the operation through us (though // the window itself can cancel the operation if it is taken over for another find operation. var context = presenter.StartSearch( EditorFeaturesResources.Navigating, supportsReferences: true, cancellationToken ); using ( Logger.LogBlock( FunctionId.CommandHandler_FindAllReference, KeyValueLogMessage.Create(LogType.UserAction, m => m["type"] = "streaming"), context.CancellationToken ) ) { try { #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task var relevantSymbol = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync( document, caretPosition, context.CancellationToken ); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task var interfaceSymbol = relevantSymbol?.symbol as INamedTypeSymbol; if ( interfaceSymbol == null || interfaceSymbol.TypeKind != TypeKind.Interface ) { //looks like it's not a relevant symbol return; } // we now need to find the class that implements this particular interface, at the // caret position, or somewhere around it SyntaxNode nodeRoot; if (!document.TryGetSyntaxRoot(out nodeRoot)) { return; } #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task var documentToken = nodeRoot.FindToken(caretPosition); if (!documentToken.Span.IntersectsWith(caretPosition)) { return; // looks like it's not relevant } // the parents should bring us to the class definition var parentTypeNode = documentToken.Parent?.Parent?.Parent?.Parent; #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task var compilation = await document.Project.GetCompilationAsync( cancellationToken ); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task // let's finally get our implementing type var namedTypeSymbol = compilation .GetSemanticModel(syntaxTree) .GetDeclaredSymbol( parentTypeNode, cancellationToken: cancellationToken ) as INamedTypeSymbol; // unless something went wrong, and we got an empty symbol, if (namedTypeSymbol == null) { return; } // we can search for implementations of the interface, within this type #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task await InspectInterfaceAsync( context, interfaceSymbol, namedTypeSymbol, document.Project ); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task // now, we iterate on interfaces of our interfaces foreach (var iFace in interfaceSymbol.AllInterfaces) { #pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task await InspectInterfaceAsync( context, iFace, namedTypeSymbol, document.Project ); #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task } } finally { await context.OnCompletedAsync().ConfigureAwait(false); } } } catch (OperationCanceledException) { } catch (Exception e) when(FatalError.ReportAndCatch(e)) { } }
private bool TryGoToAlternativeLocationIfAlreadyOnDefinition( Document document, int position, ISymbol symbol, CancellationToken cancellationToken) { var project = document.Project; var solution = project.Solution; var sourceLocations = symbol.Locations.WhereAsArray(loc => loc.IsInSource); if (sourceLocations.Length != 1) { return(false); } var definitionLocation = sourceLocations[0]; if (!definitionLocation.SourceSpan.IntersectsWith(position)) { return(false); } var definitionTree = definitionLocation.SourceTree; var definitionDocument = solution.GetDocument(definitionTree); if (definitionDocument != document) { return(false); } // Ok, we were already on the definition. Look for better symbols we could show results // for instead. For now, just see if we're on an interface member impl. If so, we can // instead navigate to the actual interface member. // // In the future we can expand this with other mappings if appropriate. var interfaceImpls = symbol.ExplicitOrImplicitInterfaceImplementations(); if (interfaceImpls.Length == 0) { return(false); } var title = string.Format(EditorFeaturesResources._0_implemented_members, FindUsagesHelpers.GetDisplayName(symbol)); return(_threadingContext.JoinableTaskFactory.Run(async() => { using var _ = ArrayBuilder <DefinitionItem> .GetInstance(out var definitions); foreach (var impl in interfaceImpls) { // Use ConfigureAwait(true) here. Not for a correctness requirements, but because we're // already blocking the UI thread by being in a JTF.Run call. So we might as well try to // continue to use the blocking UI thread to do as much work as possible instead of making // it wait for threadpool threads to be available to process the work. definitions.AddRange(await GoToDefinitionHelpers.GetDefinitionsAsync( impl, solution, thirdPartyNavigationAllowed: false, cancellationToken).ConfigureAwait(true)); } return await _streamingPresenter.TryNavigateToOrPresentItemsAsync( _threadingContext, solution.Workspace, title, definitions.ToImmutable(), cancellationToken).ConfigureAwait(true); })); }
private async Task StreamingFindReferencesAsync( Document document, int caretPosition, IStreamingFindUsagesPresenter presenter) { try { // first, let's see if we even have a comment, otherwise there's no use in starting a search var relevantSymbol = await FindUsagesHelpers.GetRelevantSymbolAndProjectAtPositionAsync(document, caretPosition, new CancellationToken()).ConfigureAwait(false); var symbol = relevantSymbol?.symbol; if (symbol == null) return; // would be useful if we could notify the user why we didn't do anything // maybe using something like an info bar? var findUsagesService = document.GetLanguageService<IFindUsagesService>(); using var token = _asyncListener.BeginAsyncOperation(nameof(StreamingFindReferencesAsync)); var (context, cancellationToken) = presenter.StartSearch(EditorFeaturesResources.Find_References, supportsReferences: true); using (Logger.LogBlock( FunctionId.CommandHandler_FindAllReference, KeyValueLogMessage.Create(LogType.UserAction, m => m["type"] = "streaming"), cancellationToken)) { var symbolsToLookup = new List<ISymbol>(); foreach (var curSymbol in symbol.ContainingType.GetMembers() .Where(m => m.Kind == symbol.Kind && m.Name == symbol.Name)) { if (!document.Project.TryGetCompilation(out var compilation)) { // TODO: should we do anything more here? continue; } foreach (var sym in SymbolFinder.FindSimilarSymbols(curSymbol, compilation, cancellationToken)) { // assumption here is, that FindSimilarSymbols returns symbols inside same project var symbolsToAdd = await GatherSymbolsAsync(sym, document.Project.Solution, cancellationToken).ConfigureAwait(false); symbolsToLookup.AddRange(symbolsToAdd); } } foreach (var candidate in symbolsToLookup) { await AbstractFindUsagesService.FindSymbolReferencesAsync(context, candidate, document.Project, cancellationToken).ConfigureAwait(false); } // Note: we don't need to put this in a finally. The only time we might not hit // this is if cancellation or another error gets thrown. In the former case, // that means that a new search has started. We don't care about telling the // context it has completed. In the latter case something wrong has happened // and we don't want to run any more code in this particular context. await context.OnCompletedAsync(cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException) { } catch (Exception e) when (FatalError.ReportAndCatch(e)) { } }
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 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); symbol = await SymbolFinder.FindSourceDefinitionAsync(symbol, document.Project.Solution, cancellationToken).ConfigureAwait(false) ?? symbol; // Try to compute source definitions from symbol. return(symbol != null ? NavigableItemFactory.GetItemsFromPreferredSourceLocations(document.Project.Solution, symbol, displayTaggedParts : FindUsagesHelpers.GetDisplayParts(symbol), cancellationToken : cancellationToken) : ImmutableArray <INavigableItem> .Empty); }
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)); }