diff --git a/src/EditorFeatures/CSharpTest/Interactive/NavigateTo/InteractiveNavigateToTests.cs b/src/EditorFeatures/CSharpTest/Interactive/NavigateTo/InteractiveNavigateToTests.cs index e11b0d3566e69d8387bcf0fe309d5cc477459953..7c0ee62c312b8555d0caccd59b3b72c5ad1e00db 100644 --- a/src/EditorFeatures/CSharpTest/Interactive/NavigateTo/InteractiveNavigateToTests.cs +++ b/src/EditorFeatures/CSharpTest/Interactive/NavigateTo/InteractiveNavigateToTests.cs @@ -12,7 +12,6 @@ using Roslyn.Test.Utilities; using Xunit; -#pragma warning disable CS0618 // MatchKind is obsolete namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.NavigateTo { public class InteractiveNavigateToTests : AbstractNavigateToTests @@ -20,7 +19,7 @@ public class InteractiveNavigateToTests : AbstractNavigateToTests protected override string Language => "csharp"; protected override TestWorkspace CreateWorkspace(string content, ExportProvider exportProvider) - => TestWorkspace.CreateCSharp(content, parseOptions: Options.Script); + => TestWorkspace.CreateCSharp(content, parseOptions: Options.Script, exportProvider: exportProvider); [WpfFact, Trait(Traits.Feature, Traits.Features.NavigateTo)] public async Task NoItemsForEmptyFile() @@ -641,4 +640,3 @@ public async Task TermSplittingTest8() } } } -#pragma warning restore CS0618 // MatchKind is obsolete diff --git a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs index 1ef00fafcf95967cfce969385058cd6265465bc2..1c764636c7c1c028e14bff6636fd0280b6f0ff75 100644 --- a/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs +++ b/src/EditorFeatures/CSharpTest/NavigateTo/NavigateToTests.cs @@ -1021,8 +1021,7 @@ public partial class C ", exportProvider: TestExportProvider.ExportProviderWithCSharpAndVisualBasic)) { - _provider = new NavigateToItemProvider( - workspace, AsynchronousOperationListenerProvider.NullListener, documentTrackingService: null); + _provider = new NavigateToItemProvider(workspace, AsynchronousOperationListenerProvider.NullListener); _aggregator = new NavigateToTestAggregator(_provider); var items = await _aggregator.GetItemsAsync("VisibleMethod"); diff --git a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.Searcher.cs b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.Searcher.cs index e575a1537e329d60c3e7c3f70756d1bf5fea595a..c5757d889a93b30e9decbd7ecdc36e041d80f48a 100644 --- a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.Searcher.cs +++ b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.Searcher.cs @@ -24,7 +24,6 @@ private class Searcher { private readonly Solution _solution; private readonly IAsynchronousOperationListener _asyncListener; - private readonly IDocumentTrackingService _documentTrackingService; private readonly INavigateToItemDisplayFactory _displayFactory; private readonly INavigateToCallback _callback; private readonly string _searchPattern; @@ -37,7 +36,6 @@ private class Searcher public Searcher( Solution solution, IAsynchronousOperationListener asyncListener, - IDocumentTrackingService documentTrackingService, INavigateToItemDisplayFactory displayFactory, INavigateToCallback callback, string searchPattern, @@ -47,7 +45,6 @@ private class Searcher { _solution = solution; _asyncListener = asyncListener; - _documentTrackingService = documentTrackingService; _displayFactory = displayFactory; _callback = callback; _searchPattern = searchPattern; @@ -78,7 +75,7 @@ internal async Task SearchAsync() // If the workspace is tracking documents, use that to prioritize our search // order. That way we provide results for the documents the user is working // on faster than the rest of the solution. - var docTrackingService = _documentTrackingService ?? workspace.Services.GetService(); + var docTrackingService = workspace.Services.GetService(); if (docTrackingService != null) { await SearchProjectsInPriorityOrder(docTrackingService).ConfigureAwait(false); diff --git a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.cs b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.cs index fc938b40b9fd5b4347188ce2769920ad03252032..862f13c309cc95a5580e2f3e549ec864a664337b 100644 --- a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.cs +++ b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProvider.cs @@ -18,22 +18,19 @@ internal partial class NavigateToItemProvider : INavigateToItemProvider2 { private readonly Workspace _workspace; private readonly IAsynchronousOperationListener _asyncListener; - private readonly IDocumentTrackingService _documentTrackingService; private readonly INavigateToItemDisplayFactory _displayFactory; private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); public NavigateToItemProvider( Workspace workspace, - IAsynchronousOperationListener asyncListener, - IDocumentTrackingService documentTrackingService) + IAsynchronousOperationListener asyncListener) { Contract.ThrowIfNull(workspace); Contract.ThrowIfNull(asyncListener); _workspace = workspace; _asyncListener = asyncListener; - _documentTrackingService = documentTrackingService; _displayFactory = new NavigateToItemDisplayFactory(); } @@ -123,7 +120,6 @@ private void StartSearch(INavigateToCallback callback, string searchValue, IImmu var searcher = new Searcher( _workspace.CurrentSolution, _asyncListener, - _documentTrackingService, _displayFactory, callback, searchValue, diff --git a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProviderFactory.cs b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProviderFactory.cs index 24176216a27c99c3ba3fab0e46e0f3a26c16194d..2204eb64f09ffb44fe1daaaffedd97060279bb5f 100644 --- a/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProviderFactory.cs +++ b/src/EditorFeatures/Core.Wpf/NavigateTo/NavigateToItemProviderFactory.cs @@ -36,8 +36,7 @@ public bool TryCreateNavigateToItemProvider(IServiceProvider serviceProvider, ou return false; } - provider = new NavigateToItemProvider( - workspace, _asyncListener, documentTrackingService: null); + provider = new NavigateToItemProvider(workspace, _asyncListener); return true; } } diff --git a/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs b/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs index 2d10464d536d08b223f3ea0fcf1732b6cb9a6c80..2e05d24aea4a7662e05c51e064b2fcb634f9a054 100644 --- a/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs +++ b/src/EditorFeatures/TestUtilities/NavigateTo/AbstractNavigateToTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Composition; using System.Linq; using System.Threading.Tasks; using System.Windows.Media; @@ -12,7 +13,8 @@ using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Editor.Wpf; -using Microsoft.CodeAnalysis.Remote; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities.RemoteHost; @@ -30,6 +32,13 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.NavigateTo [UseExportProvider] public abstract class AbstractNavigateToTests { + private static readonly Lazy s_exportProviderFactory = + new Lazy(() => + { + var catalog = TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithPart(typeof(DocumentTrackingServiceFactory)); + return ExportProviderCache.GetOrCreateExportProviderFactory(catalog); + }); + protected INavigateToItemProvider _provider; protected NavigateToTestAggregator _aggregator; @@ -58,23 +67,47 @@ public abstract class AbstractNavigateToTests protected async Task TestAsync(string content, Func body) { - await TestAsync(content, body, outOfProcess: true); - await TestAsync(content, body, outOfProcess: false); + // Keep track of tested combinations to ensure all expected tests run + var testedCombinations = new HashSet<(bool outOfProcess, Type documentTrackingServiceType)>(); + + await TestAsync(content, BodyWrapper, outOfProcess: true); + await TestAsync(content, BodyWrapper, outOfProcess: false); + + Assert.Contains((true, null), testedCombinations); + Assert.Contains((true, typeof(FirstDocIsVisibleDocumentTrackingService)), testedCombinations); + Assert.Contains((true, typeof(FirstDocIsActiveAndVisibleDocumentTrackingService)), testedCombinations); + + Assert.Contains((false, null), testedCombinations); + Assert.Contains((false, typeof(FirstDocIsVisibleDocumentTrackingService)), testedCombinations); + Assert.Contains((false, typeof(FirstDocIsActiveAndVisibleDocumentTrackingService)), testedCombinations); + + return; + + // Local function + Task BodyWrapper(TestWorkspace workspace) + { + // Track the current test setup + var outOfProcess = workspace.Options.GetOption(RemoteHostOptions.RemoteHostTest); + var documentTrackingServiceType = workspace.Services.GetService()?.GetType(); + testedCombinations.Add((outOfProcess, documentTrackingServiceType)); + + // Run the test itself + return body(workspace); + } } - internal async Task TestAsync(string content, Func body, bool outOfProcess) + private async Task TestAsync(string content, Func body, bool outOfProcess) { await TestAsync(content, body, outOfProcess, null); - await TestAsync(content, body, outOfProcess, w => new FirstDocIsVisibleDocumentTrackingService(w)); - await TestAsync(content, body, outOfProcess, w => new FirstDocIsActiveAndVisibleDocumentTrackingService(w)); + await TestAsync(content, body, outOfProcess, w => new FirstDocIsVisibleDocumentTrackingService(w.Workspace)); + await TestAsync(content, body, outOfProcess, w => new FirstDocIsActiveAndVisibleDocumentTrackingService(w.Workspace)); } - internal async Task TestAsync( + private async Task TestAsync( string content, Func body, bool outOfProcess, - Func createTrackingService) + Func createTrackingService) { - using (var workspace = SetupWorkspace( - content, TestExportProvider.ExportProviderWithCSharpAndVisualBasic, createTrackingService)) + using (var workspace = SetupWorkspace(content, createTrackingService)) { workspace.Options = workspace.Options.WithChangedOption(RemoteHostOptions.RemoteHostTest, outOfProcess); await body(workspace); @@ -82,33 +115,37 @@ internal async Task TestAsync(string content, Func body, bo } private protected TestWorkspace SetupWorkspace( - XElement workspaceElement, ExportProvider exportProvider, - Func createTrackingService) + XElement workspaceElement, + Func createTrackingService) { + var exportProvider = s_exportProviderFactory.Value.CreateExportProvider(); + var documentTrackingServiceFactory = exportProvider.GetExportedValue(); + documentTrackingServiceFactory.FactoryMethod = createTrackingService; + var workspace = TestWorkspace.Create(workspaceElement, exportProvider: exportProvider); - var trackingService = createTrackingService?.Invoke(workspace); - InitializeWorkspace(workspace, trackingService); + InitializeWorkspace(workspace); return workspace; } private protected TestWorkspace SetupWorkspace( - string content, ExportProvider exportProvider, - Func createTrackingService) + string content, + Func createTrackingService) { + var exportProvider = s_exportProviderFactory.Value.CreateExportProvider(); + var documentTrackingServiceFactory = exportProvider.GetExportedValue(); + documentTrackingServiceFactory.FactoryMethod = createTrackingService; + var workspace = CreateWorkspace(content, exportProvider); - var trackingService = createTrackingService?.Invoke(workspace); - InitializeWorkspace(workspace, trackingService); + InitializeWorkspace(workspace); return workspace; } - internal void InitializeWorkspace( - TestWorkspace workspace, IDocumentTrackingService documentTrackingService) + internal void InitializeWorkspace(TestWorkspace workspace) { - _provider = new NavigateToItemProvider(workspace, AsynchronousOperationListenerProvider.NullListener, documentTrackingService); + _provider = new NavigateToItemProvider(workspace, AsynchronousOperationListenerProvider.NullListener); _aggregator = new NavigateToTestAggregator(_provider); } -#pragma warning disable CS0618 // MatchKind is obsolete protected void VerifyNavigateToResultItems( List expecteditems, IEnumerable items) { @@ -193,47 +230,69 @@ protected static int CompareNavigateToItems(NavigateToItem a, NavigateToItem b) result = a.SecondarySort.CompareTo(b.SecondarySort); return result; } -#pragma warning restore CS0618 // MatchKind is obsolete - } -#pragma warning disable CS0067 + private class FirstDocIsVisibleDocumentTrackingService : IDocumentTrackingService + { + private readonly Workspace _workspace; - public class FirstDocIsVisibleDocumentTrackingService : IDocumentTrackingService - { - private readonly Workspace _workspace; + public FirstDocIsVisibleDocumentTrackingService(Workspace workspace) + { + _workspace = workspace; + } - public FirstDocIsVisibleDocumentTrackingService(Workspace workspace) - { - _workspace = workspace; + public event EventHandler ActiveDocumentChanged { add { } remove { } } + public event EventHandler NonRoslynBufferTextChanged { add { } remove { } } + + public DocumentId TryGetActiveDocument() + => null; + + public ImmutableArray GetVisibleDocuments() + => ImmutableArray.Create(_workspace.CurrentSolution.Projects.First().DocumentIds.First()); } - public event EventHandler ActiveDocumentChanged; - public event EventHandler NonRoslynBufferTextChanged; + private class FirstDocIsActiveAndVisibleDocumentTrackingService : IDocumentTrackingService + { + private readonly Workspace _workspace; - public DocumentId TryGetActiveDocument() - => null; + public FirstDocIsActiveAndVisibleDocumentTrackingService(Workspace workspace) + { + _workspace = workspace; + } - public ImmutableArray GetVisibleDocuments() - => ImmutableArray.Create(_workspace.CurrentSolution.Projects.First().DocumentIds.First()); - } + public event EventHandler ActiveDocumentChanged { add { } remove { } } + public event EventHandler NonRoslynBufferTextChanged { add { } remove { } } - public class FirstDocIsActiveAndVisibleDocumentTrackingService : IDocumentTrackingService - { - private readonly Workspace _workspace; + public DocumentId TryGetActiveDocument() + => _workspace.CurrentSolution.Projects.First().DocumentIds.First(); - public FirstDocIsActiveAndVisibleDocumentTrackingService(Workspace workspace) - { - _workspace = workspace; + public ImmutableArray GetVisibleDocuments() + => ImmutableArray.Create(_workspace.CurrentSolution.Projects.First().DocumentIds.First()); } - public event EventHandler ActiveDocumentChanged; - public event EventHandler NonRoslynBufferTextChanged; + [Export] + [ExportWorkspaceServiceFactory(typeof(IDocumentTrackingService), ServiceLayer.Host)] + [Shared] + [PartNotDiscoverable] + public sealed class DocumentTrackingServiceFactory : IWorkspaceServiceFactory + { + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public DocumentTrackingServiceFactory() + { + FactoryMethod = null; + } - public DocumentId TryGetActiveDocument() - => _workspace.CurrentSolution.Projects.First().DocumentIds.First(); + internal Func FactoryMethod + { + get; + set; + } - public ImmutableArray GetVisibleDocuments() - => ImmutableArray.Create(_workspace.CurrentSolution.Projects.First().DocumentIds.First()); + [Obsolete(MefConstruction.FactoryMethodMessage, error: true)] + public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) + { + return FactoryMethod?.Invoke(workspaceServices); + } + } } -#pragma warning restore } diff --git a/src/EditorFeatures/VisualBasicTest/NavigateTo/NavigateToTests.vb b/src/EditorFeatures/VisualBasicTest/NavigateTo/NavigateToTests.vb index 4139a5cadbca133f9c7932c93f50dd821285c93e..a920c8b751557e8f4b06bfab8979a2186e49a66c 100644 --- a/src/EditorFeatures/VisualBasicTest/NavigateTo/NavigateToTests.vb +++ b/src/EditorFeatures/VisualBasicTest/NavigateTo/NavigateToTests.vb @@ -739,7 +739,7 @@ Public Class Goo End Class - , exportProvider:=Nothing, createTrackingService:=Nothing) + , createTrackingService:=Nothing) Dim item As NavigateToItem = (Await _aggregator.GetItemsAsync("G")).Single() Dim itemDisplay As INavigateToItemDisplay = item.DisplayFactory.CreateItemDisplay(item)