diff --git a/src/Features/Core/Portable/Features.csproj b/src/Features/Core/Portable/Features.csproj index f3a305c1f9d3de6e76f4a8cb1de26ae84c8ac450..df851812afa1f44b93de300859b88b99d6592712 100644 --- a/src/Features/Core/Portable/Features.csproj +++ b/src/Features/Core/Portable/Features.csproj @@ -103,6 +103,7 @@ + diff --git a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.Remote.cs b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.Remote.cs index e17452d8317f3f1a770688ee2adbcfa85f6d8459..b15fcae7cf486d6d84dc697a01886c2725ed77e5 100644 --- a/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.Remote.cs +++ b/src/Features/Core/Portable/NavigateTo/AbstractNavigateToSearchService.Remote.cs @@ -44,7 +44,15 @@ internal abstract partial class AbstractNavigateToSearchService } } - private static Task GetRemoteHostClientAsync(Project project, CancellationToken cancellationToken) - => project.Solution.Workspace.GetRemoteHostClientAsync(cancellationToken); + private static async Task GetRemoteHostClientAsync(Project project, CancellationToken cancellationToken) + { + var outOfProcessAllowed = project.Solution.Workspace.Options.GetOption(NavigateToOptions.OutOfProcessAllowed); + if (!outOfProcessAllowed) + { + return null; + } + + return await project.Solution.Workspace.GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false); + } } } \ No newline at end of file diff --git a/src/Features/Core/Portable/NavigateTo/NavigateToOptions.cs b/src/Features/Core/Portable/NavigateTo/NavigateToOptions.cs new file mode 100644 index 0000000000000000000000000000000000000000..629b947242ca6a2951d34a0b5ae70d37050ec9b1 --- /dev/null +++ b/src/Features/Core/Portable/NavigateTo/NavigateToOptions.cs @@ -0,0 +1,14 @@ +// 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 Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.NavigateTo +{ + internal static class NavigateToOptions + { + private const string LocalRegistryPath = @"Roslyn\Features\NavigateTo\"; + + public static readonly Option OutOfProcessAllowed = new Option(nameof(NavigateToOptions), nameof(OutOfProcessAllowed), defaultValue: true, + storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(OutOfProcessAllowed))); + } +} \ No newline at end of file diff --git a/src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostOptions.cs b/src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostOptions.cs index 43b04f6c23bfaa262c745551dcb2150816a43eb0..23d8efbefe3fb924335950c95835f99d08e41d5b 100644 --- a/src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostOptions.cs +++ b/src/VisualStudio/Core/Def/Implementation/Remote/RemoteHostOptions.cs @@ -8,7 +8,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Remote internal static class RemoteHostOptions { [ExportOption] - public static readonly Option RemoteHost = new Option(nameof(InternalFeatureOnOffOptions), nameof(RemoteHost), defaultValue: true, + public static readonly Option RemoteHost = new Option(nameof(InternalFeatureOnOffOptions), nameof(RemoteHost), defaultValue: false, storageLocations: new LocalUserProfileStorageLocation(InternalFeatureOnOffOptions.LocalRegistryPath + nameof(RemoteHost))); [ExportOption] diff --git a/src/Workspaces/Core/Desktop/SymbolSearch/SymbolSearchUpdateEngineFactory.cs b/src/Workspaces/Core/Desktop/SymbolSearch/SymbolSearchUpdateEngineFactory.cs index 12217e4288995e7a8c4b3797597a32490d5fa155..815067846c7405077bf9751da3ba6f6cd8e5f6ae 100644 --- a/src/Workspaces/Core/Desktop/SymbolSearch/SymbolSearchUpdateEngineFactory.cs +++ b/src/Workspaces/Core/Desktop/SymbolSearch/SymbolSearchUpdateEngineFactory.cs @@ -18,25 +18,30 @@ internal static class SymbolSearchUpdateEngineFactory public static async Task CreateEngineAsync( Workspace workspace, ISymbolSearchLogService logService, CancellationToken cancellationToken) { - var client = await workspace.GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false); - if (client == null) + var outOfProcessAllowed = workspace.Options.GetOption(SymbolSearchOptions.OutOfProcessAllowed); + if (outOfProcessAllowed) { - return new SymbolSearchUpdateEngine(logService); - } + var client = await workspace.GetRemoteHostClientAsync(cancellationToken).ConfigureAwait(false); + if (client != null) + { + var emptySolution = workspace.CreateSolution(workspace.CurrentSolution.Id); - var emptySolution = workspace.CreateSolution(workspace.CurrentSolution.Id); + // We create a single session and use it for the entire lifetime of this process. + // That single session will be used to do all communication with the remote process. + // This is because each session will cause a new instance of the RemoteSymbolSearchUpdateEngine + // to be created on the remote side. We only want one instance of that type. The + // alternative is to make that type static variable on the remote side. But that's + // much less clean and would make some of the state management much more complex. + var session = await client.CreateServiceSessionAsync( + WellKnownServiceHubServices.RemoteSymbolSearchUpdateEngine, + emptySolution, logService, cancellationToken).ConfigureAwait(false); - // We create a single session and use it for the entire lifetime of this process. - // That single session will be used to do all communication with the remote process. - // This is because each session will cause a new instance of the RemoteSymbolSearchUpdateEngine - // to be created on the remote side. We only want one instance of that type. The - // alternative is to make that type static variable on the remote side. But that's - // much less clean and would make some of the state management much more complex. - var session = await client.CreateServiceSessionAsync( - WellKnownServiceHubServices.RemoteSymbolSearchUpdateEngine, - emptySolution, logService, cancellationToken).ConfigureAwait(false); + return new RemoteUpdateEngine(session); + } + } - return new RemoteUpdateEngine(session); + // Couldn't go out of proc. Just do everything inside the current process. + return new SymbolSearchUpdateEngine(logService); } private class RemoteUpdateEngine : ISymbolSearchUpdateEngine diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinderOptions.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinderOptions.cs new file mode 100644 index 0000000000000000000000000000000000000000..afa4ebb0437175b445f49b2c0b14ab9678bcdcf2 --- /dev/null +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinderOptions.cs @@ -0,0 +1,14 @@ +// 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 Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.FindSymbols +{ + internal static class SymbolFinderOptions + { + private const string LocalRegistryPath = @"Roslyn\Features\SymbolFinder\"; + + public static readonly Option OutOfProcessAllowed = new Option(nameof(SymbolFinderOptions), nameof(OutOfProcessAllowed), defaultValue: true, + storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(OutOfProcessAllowed))); + } +} \ No newline at end of file diff --git a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Remote.cs b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Remote.cs index a452f414eda8701118e22ba7cce3e7113752158b..92f795f7475471e58d64a281c8c2a2fff176f0eb 100644 --- a/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Remote.cs +++ b/src/Workspaces/Core/Portable/FindSymbols/SymbolFinder_Remote.cs @@ -17,11 +17,12 @@ public static partial class SymbolFinder Solution solution, IStreamingFindReferencesProgress progress, IImmutableSet documents, - CancellationToken cancellationToken = default(CancellationToken)) + CancellationToken cancellationToken) { using (Logger.LogBlock(FunctionId.FindReference, cancellationToken)) { - if (symbolAndProjectId.ProjectId == null) + var outOfProcessAllowed = solution.Workspace.Options.GetOption(SymbolFinderOptions.OutOfProcessAllowed); + if (symbolAndProjectId.ProjectId == null || !outOfProcessAllowed) { // This is a call through our old public API. We don't have the necessary // data to effectively run the call out of proc. diff --git a/src/Workspaces/Core/Portable/SymbolSearch/SymbolSearchOptions.cs b/src/Workspaces/Core/Portable/SymbolSearch/SymbolSearchOptions.cs index 753438afb9acdf1fe024437f8b14dd25126e1a76..a7b1aa6577790fffebcab5d35df9a36c6059aa1f 100644 --- a/src/Workspaces/Core/Portable/SymbolSearch/SymbolSearchOptions.cs +++ b/src/Workspaces/Core/Portable/SymbolSearch/SymbolSearchOptions.cs @@ -6,7 +6,15 @@ namespace Microsoft.CodeAnalysis.SymbolSearch { internal static class SymbolSearchOptions { - public static readonly Option Enabled = new Option(nameof(SymbolSearchOptions), nameof(Enabled), defaultValue: true); + private const string LocalRegistryPath = @"Roslyn\Features\SymbolSearch\"; + + public static readonly Option Enabled = new Option( + nameof(SymbolSearchOptions), nameof(Enabled), defaultValue: true, + storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(Enabled))); + + public static readonly Option OutOfProcessAllowed = new Option( + nameof(SymbolSearchOptions), nameof(OutOfProcessAllowed), defaultValue: true, + storageLocations: new LocalUserProfileStorageLocation(LocalRegistryPath + nameof(OutOfProcessAllowed))); public static PerLanguageOption SuggestForTypesInReferenceAssemblies = new PerLanguageOption(nameof(SymbolSearchOptions), nameof(SuggestForTypesInReferenceAssemblies), defaultValue: false, diff --git a/src/Workspaces/Core/Portable/Workspaces.csproj b/src/Workspaces/Core/Portable/Workspaces.csproj index 7fe788286098ddba3e8fd45497934a69ab371722..257f17e70f4de07d83dc9d62f5e185e0cee77128 100644 --- a/src/Workspaces/Core/Portable/Workspaces.csproj +++ b/src/Workspaces/Core/Portable/Workspaces.csproj @@ -386,6 +386,7 @@ +