diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs index cb5c4c6b189cc41e4ec6acee7ce74925019b3a7c..178fb727559bf57022cde8c113fd02d8dde18ae1 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs @@ -56,9 +56,6 @@ internal abstract class VisualStudioWorkspaceImpl : VisualStudioWorkspace private readonly ForegroundThreadAffinitizedObject _foregroundObject = new ForegroundThreadAffinitizedObject(); - private PackageInstallerService _packageInstallerService; - private SymbolSearchService _symbolSearchService; - public VisualStudioWorkspaceImpl( SVsServiceProvider serviceProvider, WorkspaceBackgroundWork backgroundWork) @@ -111,11 +108,6 @@ protected void InitializeStandardVisualStudioWorkspace(SVsServiceProvider servic // Ensure the options factory services are initialized on the UI thread this.Services.GetService(); - - // Ensure the nuget package services are initialized on the UI thread. - _symbolSearchService = this.Services.GetService() as SymbolSearchService; - _packageInstallerService = (PackageInstallerService)this.Services.GetService(); - _packageInstallerService.Connect(this); } /// NOTE: Call only from derived class constructor @@ -1011,9 +1003,6 @@ internal void StopSolutionCrawler() protected override void Dispose(bool finalize) { - _packageInstallerService?.Disconnect(this); - _symbolSearchService?.Dispose(); - // workspace is going away. unregister this workspace from work coordinator StopSolutionCrawler(); diff --git a/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs b/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs index 44b6323f74d1d002823784e55aa59e50f0564187..3f6537ed20c33b31eb5a395dbdf341a567648035 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs +++ b/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Notification; using Microsoft.CodeAnalysis.Packaging; @@ -41,13 +42,9 @@ namespace Microsoft.VisualStudio.LanguageServices.Packaging internal partial class PackageInstallerService : ForegroundThreadAffinitizedObject, IPackageInstallerService, IVsSearchProviderCallback { private readonly object _gate = new object(); + private readonly VisualStudioWorkspaceImpl _workspace; private readonly IVsEditorAdaptersFactoryService _editorAdaptersFactoryService; - /// - /// The workspace we're connected to. When we're disconnected this will become 'null'. - /// That's our signal to stop working. - /// - private VisualStudioWorkspaceImpl _workspace; private IVsPackageInstallerServices _packageInstallerServices; private IVsPackageInstaller _packageInstaller; private IVsPackageUninstaller _packageUninstaller; @@ -66,8 +63,10 @@ internal partial class PackageInstallerService : ForegroundThreadAffinitizedObje [ImportingConstructor] public PackageInstallerService( + VisualStudioWorkspaceImpl workspace, IVsEditorAdaptersFactoryService editorAdaptersFactoryService) { + _workspace = workspace; _editorAdaptersFactoryService = editorAdaptersFactoryService; } @@ -75,25 +74,25 @@ internal partial class PackageInstallerService : ForegroundThreadAffinitizedObje public event EventHandler PackageSourcesChanged; - internal void Connect(VisualStudioWorkspaceImpl workspace) + internal void Start() { this.AssertIsForeground(); - var options = workspace.Options; + var options = _workspace.Options; if (!options.GetOption(ServiceComponentOnOffOptions.SymbolSearch)) { return; } - ConnectWorker(workspace); + StartWorker(); } // Don't inline this method. The references to nuget types will cause the nuget packages // to load. [MethodImpl(MethodImplOptions.NoInlining)] - private void ConnectWorker(VisualStudioWorkspaceImpl workspace) + private void StartWorker() { - var componentModel = workspace.GetVsService(); + var componentModel = _workspace.GetVsService(); _packageInstallerServices = componentModel.GetExtensions().FirstOrDefault(); _packageInstaller = componentModel.GetExtensions().FirstOrDefault(); _packageUninstaller = componentModel.GetExtensions().FirstOrDefault(); @@ -105,7 +104,6 @@ private void ConnectWorker(VisualStudioWorkspaceImpl workspace) } // Start listening to workspace changes. - _workspace = workspace; _workspace.WorkspaceChanged += OnWorkspaceChanged; _packageSourceProvider.SourcesChanged += OnSourceProviderSourcesChanged; @@ -118,7 +116,7 @@ private void ConnectWorker(VisualStudioWorkspaceImpl workspace) _packageUninstaller != null && _packageSourceProvider != null; - internal void Disconnect(VisualStudioWorkspaceImpl workspace) + internal void Stop() { this.AssertIsForeground(); @@ -127,11 +125,8 @@ internal void Disconnect(VisualStudioWorkspaceImpl workspace) return; } - Debug.Assert(workspace == _workspace); _packageSourceProvider.SourcesChanged -= OnSourceProviderSourcesChanged; _workspace.WorkspaceChanged -= OnWorkspaceChanged; - - _workspace = null; } private void OnSourceProviderSourcesChanged(object sender, EventArgs e) diff --git a/src/VisualStudio/Core/Def/RoslynPackage.cs b/src/VisualStudio/Core/Def/RoslynPackage.cs index 899b202941682e8aeaa1ef8e4a8742b7bb745ddc..3d48714de1f9a41455a8c600f68245eef1c40d04 100644 --- a/src/VisualStudio/Core/Def/RoslynPackage.cs +++ b/src/VisualStudio/Core/Def/RoslynPackage.cs @@ -10,20 +10,24 @@ using Microsoft.CodeAnalysis.Editor.Host; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.Packaging; +using Microsoft.CodeAnalysis.SymbolSearch; using Microsoft.CodeAnalysis.Versions; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.LanguageServices.Implementation; +using Microsoft.VisualStudio.LanguageServices.Implementation.Interactive; using Microsoft.VisualStudio.LanguageServices.Implementation.Library.FindResults; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.RuleSets; using Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource; +using Microsoft.VisualStudio.LanguageServices.Packaging; +using Microsoft.VisualStudio.LanguageServices.SymbolSearch; using Microsoft.VisualStudio.LanguageServices.Utilities; using Microsoft.VisualStudio.PlatformUI; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; -using Task = System.Threading.Tasks.Task; -using Microsoft.VisualStudio.LanguageServices.Implementation.Interactive; using static Microsoft.CodeAnalysis.Utilities.ForegroundThreadDataKind; +using Task = System.Threading.Tasks.Task; namespace Microsoft.VisualStudio.LanguageServices.Setup { @@ -40,6 +44,9 @@ internal class RoslynPackage : Package private RuleSetEventHandler _ruleSetEventHandler; private IDisposable _solutionEventMonitor; + private PackageInstallerService _packageInstallerService; + private SymbolSearchService _symbolSearchService; + protected override void Initialize() { base.Initialize(); @@ -161,6 +168,14 @@ private void LoadComponents() LoadAnalyzerNodeComponents(); + // Ensure the nuget package services are initialized after we've loaded + // the solution. + _packageInstallerService = _workspace.Services.GetService() as PackageInstallerService; + _symbolSearchService = _workspace.Services.GetService() as SymbolSearchService; + + _packageInstallerService?.Start(); + _symbolSearchService?.Start(); + Task.Run(() => LoadComponentsBackground()); } @@ -202,6 +217,9 @@ internal IComponentModel ComponentModel protected override void Dispose(bool disposing) { + _packageInstallerService?.Stop(); + _symbolSearchService?.Stop(); + UnregisterFindResultsLibraryManager(); DisposeVisualStudioDocumentTrackingService(); diff --git a/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj b/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj index cfc34cd62512a071fa64c9d5d7967cb253608658..bfc7d2f8f338f234bb49abac4a1951b020e8c6d0 100644 --- a/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj +++ b/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj @@ -170,7 +170,6 @@ - diff --git a/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.Update.cs b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.Update.cs index 894bdef8002d19146ca3a24632969cbb3fc7406f..6318b250b2d042bed69648af7f0cd037673bbe90 100644 --- a/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.Update.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.Update.cs @@ -5,22 +5,21 @@ using System.Collections.Generic; using System.IO; using System.IO.Compression; +using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Xml; using System.Xml.Linq; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Elfie.Model; using Microsoft.CodeAnalysis.Packaging; +using Microsoft.CodeAnalysis.Shared.Options; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.Internal.VisualStudio.Shell.Interop; using Roslyn.Utilities; using static System.FormattableString; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Shared.Options; -using System.Linq; -using System.Collections.Immutable; namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { @@ -51,8 +50,6 @@ internal partial class SymbolSearchService private readonly CancellationTokenSource _cancellationTokenSource; private readonly CancellationToken _cancellationToken; - private readonly Workspace _workspace; - private readonly ConcurrentDictionary _sourceToUpdateSentinel = new ConcurrentDictionary(); @@ -68,12 +65,6 @@ internal partial class SymbolSearchService private readonly string _localSettingsDirectory; private readonly Func _reportAndSwallowException; - public void Dispose() - { - // Cancel any existing work. - _cancellationTokenSource.Cancel(); - } - private void LogInfo(string text) => _logService.LogInfo(text); private void LogException(Exception e, string text) => _logService.LogException(e, text); diff --git a/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.cs b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.cs index 1da89cb57f8520363cd88839f5541a52865b608f..e93058a99e2caca27c81377ff960624b185e64a6 100644 --- a/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.IO; +using System.Composition; using System.Linq; using System.Threading; using Microsoft.CodeAnalysis; @@ -12,14 +12,16 @@ using Microsoft.CodeAnalysis.Elfie.Model.Structures; using Microsoft.CodeAnalysis.Elfie.Model.Tree; using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Packaging; +using Microsoft.CodeAnalysis.Shared.Options; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.SymbolSearch; using Microsoft.Internal.VisualStudio.Shell.Interop; +using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.Settings; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Shell.Settings; -using static System.FormattableString; using VSShell = Microsoft.VisualStudio.Shell; namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch @@ -31,20 +33,22 @@ namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch /// This implementation also spawns a task which will attempt to keep that database up to /// date by downloading patches on a daily basis. /// - internal partial class SymbolSearchService : - ForegroundThreadAffinitizedObject, - ISymbolSearchService, - IDisposable + [ExportWorkspaceService(typeof(ISymbolSearchService)), Shared] + internal partial class SymbolSearchService : ForegroundThreadAffinitizedObject, ISymbolSearchService { + private readonly Workspace _workspace; + private ConcurrentDictionary _sourceToDatabase = new ConcurrentDictionary(); + private bool _started; + + [ImportingConstructor] public SymbolSearchService( - VSShell.SVsServiceProvider serviceProvider, - Workspace workspace, - IPackageInstallerService installerService) - : this(workspace, - installerService, + VisualStudioWorkspaceImpl workspace, + VSShell.SVsServiceProvider serviceProvider) + : this(workspace, + workspace.Services.GetService(), CreateRemoteControlService(serviceProvider), new LogService((IVsActivityLog)serviceProvider.GetService(typeof(SVsActivityLog))), new DelayService(), @@ -56,11 +60,6 @@ internal partial class SymbolSearchService : FatalError.ReportWithoutCrash, new CancellationTokenSource()) { - installerService.PackageSourcesChanged += OnOptionChanged; - var optionsService = workspace.Services.GetService(); - optionsService.OptionChanged += OnOptionChanged; - - OnOptionChanged(this, EventArgs.Empty); } private static IRemoteControlService CreateRemoteControlService(VSShell.SVsServiceProvider serviceProvider) @@ -112,6 +111,38 @@ private static IRemoteControlService CreateRemoteControlService(VSShell.SVsServi _cancellationToken = _cancellationTokenSource.Token; } + internal void Start() + { + var options = _workspace.Options; + if (!options.GetOption(ServiceComponentOnOffOptions.SymbolSearch)) + { + return; + } + + var optionsService = _workspace.Services.GetService(); + optionsService.OptionChanged += OnOptionChanged; + + // Start the whole process once we're connected + _installerService.PackageSourcesChanged += OnOptionChanged; + OnOptionChanged(this, EventArgs.Empty); + _started = true; + } + + internal void Stop() + { + if (!_started) + { + return; + } + + var optionsService = _workspace.Services.GetService(); + optionsService.OptionChanged -= OnOptionChanged; + + _installerService.PackageSourcesChanged -= OnOptionChanged; + // Cancel any existing work. + _cancellationTokenSource.Cancel(); + } + public IEnumerable FindPackagesWithType( string source, string name, int arity, CancellationToken cancellationToken) { diff --git a/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchServiceFactory.cs b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchServiceFactory.cs deleted file mode 100644 index 83a83207316bf06ba6132248b35480fade4e546f..0000000000000000000000000000000000000000 --- a/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchServiceFactory.cs +++ /dev/null @@ -1,61 +0,0 @@ -// 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.Generic; -using System.Composition; -using System.Threading; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Packaging; -using Microsoft.CodeAnalysis.Shared.Options; -using Microsoft.CodeAnalysis.SymbolSearch; -using Roslyn.Utilities; -using VSShell = Microsoft.VisualStudio.Shell; - -namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch -{ - [ExportWorkspaceServiceFactory(typeof(ISymbolSearchService), WorkspaceKind.Host), Shared] - internal class SymbolSearchServiceFactory : IWorkspaceServiceFactory - { - private readonly VSShell.SVsServiceProvider _serviceProvider; - - [ImportingConstructor] - public SymbolSearchServiceFactory( - VSShell.SVsServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - - public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) - { - var options = workspaceServices.Workspace.Options; - if (options.GetOption(ServiceComponentOnOffOptions.SymbolSearch)) - { - // Only support package search in vs workspace. - if (workspaceServices.Workspace is VisualStudioWorkspace) - { - return new SymbolSearchService( - _serviceProvider, workspaceServices.Workspace, - workspaceServices.GetService()); - } - } - - return new NullSymbolSearchService(); - } - - private class NullSymbolSearchService : ISymbolSearchService - { - public IEnumerable FindPackagesWithType( - string source, string name, int arity, CancellationToken cancellationToken) - { - return SpecializedCollections.EmptyEnumerable(); - } - - public IEnumerable FindReferenceAssembliesWithType( - string name, int arity, CancellationToken cancellationToken) - { - return SpecializedCollections.EmptyEnumerable(); - } - } - } -}