diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs index 382406b5cd96ce04f682c85226bbe23e5d58bdf6..fafe045f07ce0c04a5b2a149cdda2699d9360133 100644 --- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs +++ b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.ProgressAdapter.cs @@ -38,7 +38,7 @@ public Task ReportProgressAsync(int current, int maximum) /// /// Forwards IFindReferencesProgress calls to an IFindUsagesContext instance. /// - private class FindReferencesProgressAdapter : ForegroundThreadAffinitizedObject, IStreamingFindReferencesProgress + internal class FindReferencesProgressAdapter : ForegroundThreadAffinitizedObject, IStreamingFindReferencesProgress { private readonly Solution _solution; private readonly IFindUsagesContext _context; diff --git a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs index 3b5f5877f5192a7c3f0362f028ee45cef166002f..3f38e7adea255bbc61927073c1b54dc92dd5fa7c 100644 --- a/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs +++ b/src/EditorFeatures/Core/FindUsages/AbstractFindUsagesService.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Immutable; +using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.FindUsages; @@ -87,9 +88,13 @@ public async Task FindImplementationsAsync(Document document, int position, IFin return null; } - var symbol = symbolAndProject?.symbol; - var project = symbolAndProject?.project; + return await FindSymbolReferencesAsync( + context, symbolAndProject?.symbol, symbolAndProject?.project, cancellationToken).ConfigureAwait(false); + } + public static async Task FindSymbolReferencesAsync( + IFindUsagesContext context, ISymbol symbol, Project project, CancellationToken cancellationToken) + { context.SetSearchTitle(string.Format(EditorFeaturesResources._0_references, FindUsagesHelpers.GetDisplayName(symbol))); diff --git a/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs b/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs index a5a42da3000ceeb391d65aedd30e5531c23bce5b..0bd8ba4eec26adf88f498b35e5f1e54d34ade1c9 100644 --- a/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs +++ b/src/VisualStudio/Core/Def/Implementation/Library/ObjectBrowser/AbstractObjectBrowserLibraryManager.cs @@ -1,10 +1,15 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Text; using System.Threading; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor; +using Microsoft.CodeAnalysis.Editor.FindUsages; +using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser.Lists; @@ -33,7 +38,13 @@ internal abstract partial class AbstractObjectBrowserLibraryManager : AbstractLi private AbstractListItemFactory _listItemFactory; private object _classMemberGate = new object(); - protected AbstractObjectBrowserLibraryManager(string languageName, Guid libraryGuid, __SymbolToolLanguage preferredLanguage, IServiceProvider serviceProvider) + private readonly IEnumerable> _streamingPresenters; + + protected AbstractObjectBrowserLibraryManager( + string languageName, + Guid libraryGuid, + __SymbolToolLanguage preferredLanguage, + IServiceProvider serviceProvider) : base(libraryGuid, serviceProvider) { _languageName = languageName; @@ -43,6 +54,8 @@ protected AbstractObjectBrowserLibraryManager(string languageName, Guid libraryG this.Workspace = componentModel.GetService(); this.LibraryService = this.Workspace.Services.GetLanguageServices(languageName).GetService(); this.Workspace.WorkspaceChanged += OnWorkspaceChanged; + + this._streamingPresenters = componentModel.DefaultExportProvider.GetExports(); } internal abstract AbstractDescriptionBuilder CreateDescriptionBuilder( @@ -481,24 +494,15 @@ protected override bool TryExec(Guid commandGroup, uint commandId) switch (commandId) { case (uint)VSConstants.VSStd97CmdID.FindReferences: + var streamingPresenter = GetStreamingPresenter(); var symbolListItem = _activeListItem as SymbolListItem; - if (symbolListItem != null) + if (streamingPresenter != null && symbolListItem?.ProjectId != null) { - var projectId = symbolListItem.ProjectId; - if (projectId != null) + var project = this.Workspace.CurrentSolution.GetProject(symbolListItem.ProjectId); + if (project != null) { - var project = this.Workspace.CurrentSolution.GetProject(projectId); - if (project != null) - { - var compilation = project - .GetCompilationAsync(CancellationToken.None) - .WaitAndGetResult(CancellationToken.None); - - var symbol = symbolListItem.ResolveSymbol(compilation); - - this.Workspace.TryFindAllReferences(symbol, project, CancellationToken.None); - return true; - } + FindReferences(streamingPresenter, symbolListItem, project); + return true; } } @@ -508,5 +512,51 @@ protected override bool TryExec(Guid commandGroup, uint commandId) return false; } + + private IStreamingFindUsagesPresenter GetStreamingPresenter() + { + try + { + return _streamingPresenters.FirstOrDefault()?.Value; + } + catch + { + return null; + } + } + + private async void FindReferences( + IStreamingFindUsagesPresenter presenter, SymbolListItem symbolListItem, Project project) + { + try + { + // Let the presented know we're starting a search. It will give us back + // the context object that the FAR service will push results into. + var context = presenter.StartSearch( + EditorFeaturesResources.Find_References, supportsReferences: true); + + var cancellationToken = context.CancellationToken; + + // Fire and forget the work to go get references. + var compilation = await project.GetCompilationAsync(cancellationToken).ConfigureAwait(false); + var symbol = symbolListItem.ResolveSymbol(compilation); + + await AbstractFindUsagesService.FindSymbolReferencesAsync( + context, symbol, 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().ConfigureAwait(false); + } + catch (OperationCanceledException) + { + } + catch (Exception e) when (FatalError.ReportWithoutCrash(e)) + { + } + } } -} +} \ No newline at end of file diff --git a/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs b/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs index 1c800c54b925b4bbe88a06a6ca6d06bbeda9d334..671b0ff846c71dfb32d1d410c8bb723524c2042a 100644 --- a/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs +++ b/src/VisualStudio/Core/Impl/RoslynVisualStudioWorkspace.cs @@ -6,23 +6,17 @@ using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Editor.FindUsages; using Microsoft.CodeAnalysis.Editor.GoToDefinition; using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Undo; using Microsoft.CodeAnalysis.FindSymbols; -using Microsoft.CodeAnalysis.FindUsages; -using Microsoft.CodeAnalysis.GeneratedCodeRecognition; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Composition; -using Microsoft.VisualStudio.LanguageServices.Implementation; using Microsoft.VisualStudio.LanguageServices.Implementation.CodeModel; using Microsoft.VisualStudio.LanguageServices.Implementation.Interop; using Microsoft.VisualStudio.LanguageServices.Implementation.Library.ObjectBrowser.Lists; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; -using Microsoft.VisualStudio.Shell; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices @@ -32,18 +26,15 @@ namespace Microsoft.VisualStudio.LanguageServices internal class RoslynVisualStudioWorkspace : VisualStudioWorkspaceImpl { private readonly IEnumerable> _streamingPresenters; - private readonly IEnumerable> _referencedSymbolsPresenters; [ImportingConstructor] private RoslynVisualStudioWorkspace( ExportProvider exportProvider, [ImportMany] IEnumerable> streamingPresenters, - [ImportMany] IEnumerable> referencedSymbolsPresenters, [ImportMany] IEnumerable documentOptionsProviderFactories) : base(exportProvider.AsExportProvider()) { _streamingPresenters = streamingPresenters; - _referencedSymbolsPresenters = referencedSymbolsPresenters; foreach (var providerFactory in documentOptionsProviderFactories) { @@ -203,44 +194,15 @@ private static bool TryResolveSymbol(ISymbol symbol, Project project, Cancellati public override bool TryFindAllReferences(ISymbol symbol, Project project, CancellationToken cancellationToken) { - if (!_referencedSymbolsPresenters.Any()) - { - return false; - } - - if (!TryResolveSymbol(symbol, project, cancellationToken, out var searchSymbol, out var searchProject)) - { - return false; - } - - var searchSolution = searchProject.Solution; - - var result = SymbolFinder - .FindReferencesAsync(searchSymbol, searchSolution, cancellationToken) - .WaitAndGetResult(cancellationToken).ToList(); - - if (result != null) - { - DisplayReferencedSymbols(searchSolution, result); - return true; - } - + // Legacy API. Previously used by ObjectBrowser to support 'FindRefs' off of an + // object browser item. Now ObjectBrowser goes through the streaming-FindRefs system. return false; } - public override void DisplayReferencedSymbols( - Solution solution, IEnumerable referencedSymbols) + public override void DisplayReferencedSymbols(Solution solution, IEnumerable referencedSymbols) { - var service = this.Services.GetService(); - var definitionsAndReferences = service.CreateDefinitionsAndReferences( - solution, referencedSymbols, - includeHiddenLocations: false, cancellationToken: CancellationToken.None); - - foreach (var presenter in _referencedSymbolsPresenters) - { - presenter.Value.DisplayResult(definitionsAndReferences); - return; - } + // Legacy API. Previously used by ObjectBrowser to support 'FindRefs' off of an + // object browser item. Now ObjectBrowser goes through the streaming-FindRefs system. } internal override object GetBrowseObject(SymbolListItem symbolListItem)