diff --git a/src/EditorFeatures/CSharpTest/Diagnostics/AddUsing/AddUsingTests_NuGet.cs b/src/EditorFeatures/CSharpTest/Diagnostics/AddUsing/AddUsingTests_NuGet.cs index 65cb526457173..8d2fed741de6a 100644 --- a/src/EditorFeatures/CSharpTest/Diagnostics/AddUsing/AddUsingTests_NuGet.cs +++ b/src/EditorFeatures/CSharpTest/Diagnostics/AddUsing/AddUsingTests_NuGet.cs @@ -9,14 +9,17 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.CodeFixes.AddImport; using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Packaging; +using Microsoft.CodeAnalysis.Shared.Options; +using Microsoft.CodeAnalysis.SymbolSearch; using Moq; using Roslyn.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.AddUsing { - using FixProviderData = Tuple; + using FixProviderData = Tuple; public partial class AddUsingTests { @@ -27,6 +30,15 @@ public class NuGet : AddUsingTests private static readonly ImmutableArray NugetPackageSources = ImmutableArray.Create(new PackageSource(NugetOrgSource, "http://nuget.org/")); + protected override async Task CreateWorkspaceFromFileAsync(string definition, ParseOptions parseOptions, CompilationOptions compilationOptions) + { + var workspace = await base.CreateWorkspaceFromFileAsync(definition, parseOptions, compilationOptions); + workspace.Options = workspace.Options + .WithChangedOption(AddImportOptions.SuggestForTypesInNuGetPackages, LanguageNames.CSharp, true) + .WithChangedOption(AddImportOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.CSharp, true); + return workspace; + } + internal override Tuple CreateDiagnosticProviderAndFixer( Workspace workspace, object fixProviderData) { @@ -50,7 +62,7 @@ public async Task TestSearchPackageSingleName() installerServiceMock.SetupGet(i => i.IsEnabled).Returns(true); installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources); - var packageServiceMock = new Mock(); + var packageServiceMock = new Mock(); packageServiceMock.Setup(s => s.FindPackagesWithType( NugetOrgSource, "NuGetType", 0, It.IsAny())) .Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))); @@ -79,7 +91,7 @@ public async Task TestSearchPackageMultipleNames() installerServiceMock.SetupGet(i => i.IsEnabled).Returns(true); installerServiceMock.SetupGet(i => i.PackageSources).Returns(NugetPackageSources); - var packageServiceMock = new Mock(); + var packageServiceMock = new Mock(); packageServiceMock.Setup(s => s.FindPackagesWithType( NugetOrgSource, "NuGetType", 0, It.IsAny())) .Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2"))); @@ -110,7 +122,7 @@ public async Task TestMissingIfPackageAlreadyInstalled() installerServiceMock.Setup(s => s.IsInstalled(It.IsAny(), It.IsAny(), "NuGetPackage")) .Returns(true); - var packageServiceMock = new Mock(); + var packageServiceMock = new Mock(); packageServiceMock.Setup(s => s.FindPackagesWithType( NugetOrgSource, "NuGetType", 0, It.IsAny())) .Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2"))); @@ -134,7 +146,7 @@ public async Task TestOptionsOffered() installerServiceMock.Setup(s => s.GetInstalledVersions("NuGetPackage")) .Returns(new[] { "1.0", "2.0" }); - var packageServiceMock = new Mock(); + var packageServiceMock = new Mock(); packageServiceMock.Setup(s => s.FindPackagesWithType( NugetOrgSource, "NuGetType", 0, It.IsAny())) .Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2"))); @@ -180,7 +192,7 @@ public async Task TestInstallGetsCalledNoVersion() installerServiceMock.Setup(s => s.TryInstallPackage( It.IsAny(), It.IsAny(), It.IsAny(), "NuGetPackage", /*versionOpt*/ null, It.IsAny())); - var packageServiceMock = new Mock(); + var packageServiceMock = new Mock(); packageServiceMock.Setup(s => s.FindPackagesWithType( NugetOrgSource, "NuGetType", 0, It.IsAny())) .Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))); @@ -212,7 +224,7 @@ public async Task TestInstallGetsCalledWithVersion() installerServiceMock.Setup(s => s.TryInstallPackage( It.IsAny(), It.IsAny(), It.IsAny(), "NuGetPackage", "1.0", It.IsAny())); - var packageServiceMock = new Mock(); + var packageServiceMock = new Mock(); packageServiceMock.Setup(s => s.FindPackagesWithType(NugetOrgSource, "NuGetType", 0, It.IsAny())) .Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))); diff --git a/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb b/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb index 1eb51093550a3..ee7a97804ca58 100644 --- a/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb +++ b/src/EditorFeatures/VisualBasicTest/Diagnostics/AddImport/AddImportTests_NuGet.vb @@ -5,11 +5,14 @@ Imports System.Threading Imports Microsoft.CodeAnalysis.CodeActions Imports Microsoft.CodeAnalysis.CodeFixes Imports Microsoft.CodeAnalysis.Diagnostics +Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Packaging +Imports Microsoft.CodeAnalysis.Shared.Options +Imports Microsoft.CodeAnalysis.SymbolSearch Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.CodeFixes.AddImport Imports Moq -Imports ProviderData = System.Tuple(Of Microsoft.CodeAnalysis.Packaging.IPackageInstallerService, Microsoft.CodeAnalysis.Packaging.IPackageSearchService) +Imports ProviderData = System.Tuple(Of Microsoft.CodeAnalysis.Packaging.IPackageInstallerService, Microsoft.CodeAnalysis.SymbolSearch.ISymbolSearchService) Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeActions.AddImport Partial Public Class AddImportTests @@ -21,6 +24,14 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeActions.AddImp Private Shared ReadOnly NugetPackageSources As ImmutableArray(Of PackageSource) = ImmutableArray.Create(New PackageSource(NugetOrgSource, "http://nuget.org")) + Protected Overrides Async Function CreateWorkspaceFromFileAsync(definition As String, parseOptions As ParseOptions, compilationOptions As CompilationOptions) As Task(Of TestWorkspace) + Dim workspace = Await MyBase.CreateWorkspaceFromFileAsync(definition, parseOptions, compilationOptions) + workspace.Options = workspace.Options. + WithChangedOption(AddImportOptions.SuggestForTypesInNuGetPackages, LanguageNames.VisualBasic, True). + WithChangedOption(AddImportOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.VisualBasic, True) + Return workspace + End Function + Friend Overrides Function CreateDiagnosticProviderAndFixer(workspace As Workspace, fixProviderData As Object) As Tuple(Of DiagnosticAnalyzer, CodeFixProvider) Dim data = DirectCast(fixProviderData, ProviderData) Return Tuple.Create(Of DiagnosticAnalyzer, CodeFixProvider)( @@ -40,7 +51,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.CodeActions.AddImp installerServiceMock.SetupGet(Function(i) i.IsEnabled).Returns(True) installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources) - Dim packageServiceMock = New Mock(Of IPackageSearchService)() + Dim packageServiceMock = New Mock(Of ISymbolSearchService)() packageServiceMock.Setup(Function(s) s.FindPackagesWithType(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())). Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))) @@ -65,7 +76,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa installerServiceMock.SetupGet(Function(i) i.IsEnabled).Returns(True) installerServiceMock.SetupGet(Function(i) i.PackageSources).Returns(NugetPackageSources) - Dim packageServiceMock = New Mock(Of IPackageSearchService)() + Dim packageServiceMock = New Mock(Of ISymbolSearchService)() packageServiceMock.Setup(Function(s) s.FindPackagesWithType(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())). Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2"))) @@ -92,7 +103,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa installerServiceMock.Setup(Function(s) s.IsInstalled(It.IsAny(Of Workspace)(), It.IsAny(Of ProjectId)(), "NuGetPackage")). Returns(True) - Dim packageServiceMock = New Mock(Of IPackageSearchService)() + Dim packageServiceMock = New Mock(Of ISymbolSearchService)() packageServiceMock.Setup(Function(s) s.FindPackagesWithType(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())). Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2"))) @@ -114,7 +125,7 @@ fixProviderData:=New ProviderData(installerServiceMock.Object, packageServiceMoc installerServiceMock.Setup(Function(s) s.GetInstalledVersions("NuGetPackage")). Returns({"1.0", "2.0"}) - Dim packageServiceMock = New Mock(Of IPackageSearchService)() + Dim packageServiceMock = New Mock(Of ISymbolSearchService)() packageServiceMock.Setup(Function(s) s.FindPackagesWithType(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())). Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NS1", "NS2"))) @@ -155,7 +166,7 @@ fixProviderData:=data) installerServiceMock.Setup(Function(s) s.TryInstallPackage( It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", Nothing, It.IsAny(Of CancellationToken))) - Dim packageServiceMock = New Mock(Of IPackageSearchService)() + Dim packageServiceMock = New Mock(Of ISymbolSearchService)() packageServiceMock.Setup(Function(s) s.FindPackagesWithType(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())). Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))) @@ -183,7 +194,7 @@ End Class", fixProviderData:=New ProviderData(installerServiceMock.Object, packa installerServiceMock.Setup(Function(s) s.TryInstallPackage( It.IsAny(Of Workspace), It.IsAny(Of DocumentId), It.IsAny(Of String), "NuGetPackage", "1.0", It.IsAny(Of CancellationToken))) - Dim packageServiceMock = New Mock(Of IPackageSearchService)() + Dim packageServiceMock = New Mock(Of ISymbolSearchService)() packageServiceMock.Setup(Function(s) s.FindPackagesWithType(NugetOrgSource, "NuGetType", 0, It.IsAny(Of CancellationToken)())). Returns(CreateSearchResult("NuGetPackage", "NuGetType", CreateNameParts("NuGetNamespace"))) diff --git a/src/Features/CSharp/Portable/CodeFixes/AddImport/CSharpAddImportCodeFixProvider.cs b/src/Features/CSharp/Portable/CodeFixes/AddImport/CSharpAddImportCodeFixProvider.cs index 3a913c2dc1960..67799d084a315 100644 --- a/src/Features/CSharp/Portable/CodeFixes/AddImport/CSharpAddImportCodeFixProvider.cs +++ b/src/Features/CSharp/Portable/CodeFixes/AddImport/CSharpAddImportCodeFixProvider.cs @@ -19,6 +19,7 @@ using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Simplification; +using Microsoft.CodeAnalysis.SymbolSearch; using Roslyn.Utilities; using static Microsoft.CodeAnalysis.CSharp.CodeFixes.AddImport.AddImportDiagnosticIds; @@ -154,8 +155,8 @@ public CSharpAddImportCodeFixProvider() /// For testing purposes only (so that tests can pass in mock values) internal CSharpAddImportCodeFixProvider( IPackageInstallerService installerService, - IPackageSearchService packageSearchService) - : base(installerService, packageSearchService) + ISymbolSearchService symbolSearchService) + : base(installerService, symbolSearchService) { } diff --git a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.AssemblyReference.cs b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.AssemblyReference.cs index 896c8e07a70fa..3851fc1dd652d 100644 --- a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.AssemblyReference.cs +++ b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.AssemblyReference.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Packaging; +using Microsoft.CodeAnalysis.SymbolSearch; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeFixes.AddImport diff --git a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolReferenceFinder.cs b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolReferenceFinder.cs index 702af7f73b5ce..fd6b3894b8815 100644 --- a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolReferenceFinder.cs +++ b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.SymbolReferenceFinder.cs @@ -1,6 +1,5 @@ // 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.Concurrent; using System.Collections.Generic; using System.Linq; @@ -9,6 +8,8 @@ using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Shared.Options; +using Microsoft.CodeAnalysis.SymbolSearch; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeFixes.AddImport @@ -232,32 +233,41 @@ private async Task> GetMatchingTypesAsync(SearchScope sea { var workspaceServices = _document.Project.Solution.Workspace.Services; - var packageSearchService = _owner._packageSearchService ?? workspaceServices.GetService(); - var referenceAssemblySearchService = _owner._referenceAssemblySearchService ?? workspaceServices.GetService(); + var symbolSearchService = _owner._symbolSearchService ?? workspaceServices.GetService(); var installerService = _owner._packageInstallerService ?? workspaceServices.GetService(); - if (referenceAssemblySearchService != null) + var language = _document.Project.Language; + + var options = workspaceServices.Workspace.Options; + var searchReferenceAssemblies = options.GetOption( + AddImportOptions.SuggestForTypesInReferenceAssemblies, language); + var searchNugetPackages = options.GetOption( + AddImportOptions.SuggestForTypesInNuGetPackages, language); + + if (symbolSearchService != null && + searchReferenceAssemblies) { cancellationToken.ThrowIfCancellationRequested(); await FindReferenceAssemblyTypeReferencesAsync( - referenceAssemblySearchService, allReferences, nameNode, name, arity, isAttributeSearch, cancellationToken).ConfigureAwait(false); + symbolSearchService, allReferences, nameNode, name, arity, isAttributeSearch, cancellationToken).ConfigureAwait(false); } - if (packageSearchService != null && + if (symbolSearchService != null && + searchNugetPackages && installerService.IsEnabled) { foreach (var packageSource in installerService.PackageSources) { cancellationToken.ThrowIfCancellationRequested(); await FindNugetTypeReferencesAsync( - packageSource, packageSearchService, installerService, allReferences, + packageSource, symbolSearchService, installerService, allReferences, nameNode, name, arity, isAttributeSearch, cancellationToken).ConfigureAwait(false); } } } private async Task FindReferenceAssemblyTypeReferencesAsync( - IReferenceAssemblySearchService searchService, + ISymbolSearchService searchService, List allReferences, TSimpleNameSyntax nameNode, string name, @@ -283,7 +293,7 @@ private async Task> GetMatchingTypesAsync(SearchScope sea private async Task FindNugetTypeReferencesAsync( PackageSource source, - IPackageSearchService searchService, + ISymbolSearchService searchService, IPackageInstallerService installerService, List allReferences, TSimpleNameSyntax nameNode, diff --git a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.cs b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.cs index 226d9edf1e118..fb6a31b088a72 100644 --- a/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.cs +++ b/src/Features/Core/Portable/CodeFixes/AddImport/AbstractAddImportCodeFixProvider.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Options; +using Microsoft.CodeAnalysis.SymbolSearch; using Roslyn.Utilities; using static Roslyn.Utilities.PortableShim; @@ -25,18 +26,15 @@ internal abstract partial class AbstractAddImportCodeFixProviderValues for these parameters can be provided (during testing) for mocking purposes. protected AbstractAddImportCodeFixProvider( IPackageInstallerService packageInstallerService = null, - IPackageSearchService packageSearchService = null, - IReferenceAssemblySearchService referenceAssemblySearchService = null) + ISymbolSearchService symbolSearchService = null) { _packageInstallerService = packageInstallerService; - _packageSearchService = packageSearchService; - _referenceAssemblySearchService = referenceAssemblySearchService; + _symbolSearchService = symbolSearchService; } protected abstract bool CanAddImport(SyntaxNode node, CancellationToken cancellationToken); @@ -81,7 +79,8 @@ public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) return; } - var placeSystemNamespaceFirst = document.Project.Solution.Workspace.Options.GetOption( + var options = document.Project.Solution.Workspace.Options; + var placeSystemNamespaceFirst = options.GetOption( OrganizerOptions.PlaceSystemNamespaceFirst, document.Project.Language); using (Logger.LogBlock(FunctionId.Refactoring_AddImport, cancellationToken)) diff --git a/src/Features/Core/Portable/Features.csproj b/src/Features/Core/Portable/Features.csproj index c7d1ec8fd436a..bbd742099c6a2 100644 --- a/src/Features/Core/Portable/Features.csproj +++ b/src/Features/Core/Portable/Features.csproj @@ -281,8 +281,9 @@ + - + diff --git a/src/Features/Core/Portable/Shared/Options/AddImportOptions.cs b/src/Features/Core/Portable/Shared/Options/AddImportOptions.cs new file mode 100644 index 0000000000000..ad67c157a21ec --- /dev/null +++ b/src/Features/Core/Portable/Shared/Options/AddImportOptions.cs @@ -0,0 +1,15 @@ +using Microsoft.CodeAnalysis.Options; + +namespace Microsoft.CodeAnalysis.Shared.Options +{ + internal class AddImportOptions + { + public const string FeatureName = "AddImport"; + + public static PerLanguageOption SuggestForTypesInReferenceAssemblies = + new PerLanguageOption(FeatureName, nameof(SuggestForTypesInReferenceAssemblies), defaultValue: false); + + public static PerLanguageOption SuggestForTypesInNuGetPackages = + new PerLanguageOption(FeatureName, nameof(SuggestForTypesInNuGetPackages), defaultValue: false); + } +} diff --git a/src/Features/Core/Portable/Shared/Options/AddImportOptionsProvider.cs b/src/Features/Core/Portable/Shared/Options/AddImportOptionsProvider.cs new file mode 100644 index 0000000000000..34ab8010f6049 --- /dev/null +++ b/src/Features/Core/Portable/Shared/Options/AddImportOptionsProvider.cs @@ -0,0 +1,22 @@ +using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.Options.Providers; +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.Shared.Options +{ + [ExportOptionProvider, Shared] + internal class AddImportOptionsProvider : IOptionProvider + { + private readonly IEnumerable _options = ImmutableArray.Create( + AddImportOptions.SuggestForTypesInReferenceAssemblies, + AddImportOptions.SuggestForTypesInNuGetPackages); + + public IEnumerable GetOptions() => _options; + } +} diff --git a/src/Features/Core/Portable/Shared/Options/OrganizerOptions.cs b/src/Features/Core/Portable/Shared/Options/OrganizerOptions.cs index fa5cf5d16dc3b..8719bbefda316 100644 --- a/src/Features/Core/Portable/Shared/Options/OrganizerOptions.cs +++ b/src/Features/Core/Portable/Shared/Options/OrganizerOptions.cs @@ -13,13 +13,5 @@ public static PerLanguageOption PlaceSystemNamespaceFirst { get { return Editing.GenerationOptions.PlaceSystemNamespaceFirst; } } - - /// - /// This option is currently unused by Roslyn, but we might want to implement it in the - /// future. Keeping the option while it's unimplemented allows all upgrade paths to - /// maintain any customized value for this setting, even through versions that have not - /// implemented this feature yet. - /// - public static readonly PerLanguageOption WarnOnBuildErrors = new PerLanguageOption(FeatureName, "WarnOnBuildErrors", defaultValue: true); } } diff --git a/src/Features/Core/Portable/Shared/Options/OrganizerOptionsProvider.cs b/src/Features/Core/Portable/Shared/Options/OrganizerOptionsProvider.cs deleted file mode 100644 index cfb2137091033..0000000000000 --- a/src/Features/Core/Portable/Shared/Options/OrganizerOptionsProvider.cs +++ /dev/null @@ -1,24 +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.Collections.Immutable; -using System.Composition; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Options.Providers; - -namespace Microsoft.CodeAnalysis.Shared.Options -{ - [ExportOptionProvider, Shared] - internal class OrganizerOptionsProvider : IOptionProvider - { - private readonly IEnumerable _options = new List - { - OrganizerOptions.WarnOnBuildErrors - }.ToImmutableArray(); - - public IEnumerable GetOptions() - { - return _options; - } - } -} diff --git a/src/Features/Core/Portable/Shared/Options/ServiceComponentOnOffOptions.cs b/src/Features/Core/Portable/Shared/Options/ServiceComponentOnOffOptions.cs index 02fb6726a6d46..cb84736e3728b 100644 --- a/src/Features/Core/Portable/Shared/Options/ServiceComponentOnOffOptions.cs +++ b/src/Features/Core/Portable/Shared/Options/ServiceComponentOnOffOptions.cs @@ -13,6 +13,6 @@ internal static class ServiceComponentOnOffOptions public static readonly Option DiagnosticProvider = new Option(OptionName, "Diagnostic Provider", defaultValue: true); - public static readonly Option PackageSearch = new Option(OptionName, nameof(PackageSearch), defaultValue: false); + public static readonly Option SymbolSearch = new Option(OptionName, nameof(SymbolSearch), defaultValue: true); } } diff --git a/src/Features/Core/Portable/Shared/Options/ServiceComponentOnOffOptionsProvider.cs b/src/Features/Core/Portable/Shared/Options/ServiceComponentOnOffOptionsProvider.cs index 4055d0d29167a..7c3387f73c883 100644 --- a/src/Features/Core/Portable/Shared/Options/ServiceComponentOnOffOptionsProvider.cs +++ b/src/Features/Core/Portable/Shared/Options/ServiceComponentOnOffOptionsProvider.cs @@ -14,7 +14,7 @@ internal class ServiceComponentOnOffOptionsProvider : IOptionProvider { private readonly IEnumerable _options = ImmutableArray.Create( ServiceComponentOnOffOptions.DiagnosticProvider, - ServiceComponentOnOffOptions.PackageSearch); + ServiceComponentOnOffOptions.SymbolSearch); public IEnumerable GetOptions() => _options; } diff --git a/src/Features/VisualBasic/Portable/CodeFixes/AddImport/VisualBasicAddImportCodeFixProvider.vb b/src/Features/VisualBasic/Portable/CodeFixes/AddImport/VisualBasicAddImportCodeFixProvider.vb index c36cdb24e1d46..3668727e54b2d 100644 --- a/src/Features/VisualBasic/Portable/CodeFixes/AddImport/VisualBasicAddImportCodeFixProvider.vb +++ b/src/Features/VisualBasic/Portable/CodeFixes/AddImport/VisualBasicAddImportCodeFixProvider.vb @@ -11,6 +11,7 @@ Imports Microsoft.CodeAnalysis.Formatting Imports Microsoft.CodeAnalysis.LanguageServices Imports Microsoft.CodeAnalysis.Packaging Imports Microsoft.CodeAnalysis.Simplification +Imports Microsoft.CodeAnalysis.SymbolSearch Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.AddImport @@ -24,7 +25,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeFixes.AddImport ''' ''' For testing purposes so that tests can pass in mocks for these values. ''' - Friend Sub New(installerService As IPackageInstallerService, searchService As IPackageSearchService) + Friend Sub New(installerService As IPackageInstallerService, + searchService As ISymbolSearchService) MyBase.New(installerService, searchService) End Sub diff --git a/src/VisualStudio/CSharp/Impl/CSharpVSResources.Designer.cs b/src/VisualStudio/CSharp/Impl/CSharpVSResources.Designer.cs index 114fcf28a9130..84f50440e253f 100644 --- a/src/VisualStudio/CSharp/Impl/CSharpVSResources.Designer.cs +++ b/src/VisualStudio/CSharp/Impl/CSharpVSResources.Designer.cs @@ -537,15 +537,6 @@ internal class CSharpVSResources { } } - /// - /// Looks up a localized string similar to Organize Usings. - /// - internal static string Option_OrganizeUsings { - get { - return ResourceManager.GetString("Option_OrganizeUsings", resourceCulture); - } - } - /// /// Looks up a localized string similar to Outlining. /// @@ -574,7 +565,7 @@ internal class CSharpVSResources { } /// - /// Looks up a localized string similar to Show preview for _rename tracking. + /// Looks up a localized string similar to Show preview for rename _tracking. /// internal static string Option_RenameTrackingPreview { get { @@ -610,11 +601,29 @@ internal class CSharpVSResources { } /// - /// Looks up a localized string similar to Warn if _build errors exist when organizing usings. + /// Looks up a localized string similar to Suggest usings for types in _NuGet packages. + /// + internal static string Option_Suggest_usings_for_types_in_NuGet_packages { + get { + return ResourceManager.GetString("Option_Suggest_usings_for_types_in_NuGet_packages", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Suggest usings for types in _reference assemblies. + /// + internal static string Option_Suggest_usings_for_types_in_reference_assemblies { + get { + return ResourceManager.GetString("Option_Suggest_usings_for_types_in_reference_assemblies", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Using Directives. /// - internal static string Option_WarnOnBuildErrors { + internal static string Option_Using_Directives { get { - return ResourceManager.GetString("Option_WarnOnBuildErrors", resourceCulture); + return ResourceManager.GetString("Option_Using_Directives", resourceCulture); } } diff --git a/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx b/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx index ff977606cf486..a08ad0be05e02 100644 --- a/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx +++ b/src/VisualStudio/CSharp/Impl/CSharpVSResources.resx @@ -369,8 +369,8 @@ Small - - Organize Usings + + Using Directives Outlining @@ -381,9 +381,6 @@ _Place 'System' directives first when sorting usings - - Warn if _build errors exist when organizing usings - _Show completion list after a character is typed @@ -403,7 +400,7 @@ Selection In Completion List - Show preview for _rename tracking + Show preview for rename _tracking Place open brace on new line for property, indexer, and event accessors @@ -411,4 +408,10 @@ Place open brace on new line for properties, indexers, and events + + Suggest usings for types in _reference assemblies + + + Suggest usings for types in _NuGet packages + \ No newline at end of file diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml index ac8abb93bccf2..e81dc7cb0d85c 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml @@ -11,6 +11,20 @@ + + + + + + + @@ -42,17 +56,6 @@ Content="{x:Static local:AdvancedOptionPageStrings.Option_RenameTrackingPreview}" /> - - - - - - diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs index 02a60efb7fb63..3bca78cd47c76 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageControl.xaml.cs @@ -15,6 +15,10 @@ public AdvancedOptionPageControl(IServiceProvider serviceProvider) : base(servic { InitializeComponent(); + BindToOption(PlaceSystemNamespaceFirst, OrganizerOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp); + BindToOption(SuggestForTypesInReferenceAssemblies, AddImportOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.CSharp); + BindToOption(SuggestForTypesInNuGetPackages, AddImportOptions.SuggestForTypesInNuGetPackages, LanguageNames.CSharp); + BindToOption(EnterOutliningMode, FeatureOnOffOptions.Outlining, LanguageNames.CSharp); BindToOption(GenerateXmlDocCommentsForTripleSlash, FeatureOnOffOptions.AutoXmlDocCommentGeneration, LanguageNames.CSharp); BindToOption(InsertAsteriskAtTheStartOfNewLinesWhenWritingBlockComments, FeatureOnOffOptions.AutoInsertBlockCommentStartString, LanguageNames.CSharp); @@ -22,7 +26,6 @@ public AdvancedOptionPageControl(IServiceProvider serviceProvider) : base(servic BindToOption(EnableHighlightReferences, FeatureOnOffOptions.ReferenceHighlighting, LanguageNames.CSharp); BindToOption(EnableHighlightKeywords, FeatureOnOffOptions.KeywordHighlighting, LanguageNames.CSharp); BindToOption(RenameTrackingPreview, FeatureOnOffOptions.RenameTrackingPreview, LanguageNames.CSharp); - BindToOption(PlaceSystemNamespaceFirst, OrganizerOptions.PlaceSystemNamespaceFirst, LanguageNames.CSharp); BindToOption(DontPutOutOrRefOnStruct, ExtractMethodOptions.DontPutOutOrRefOnStruct, LanguageNames.CSharp); BindToOption(AllowMovingDeclaration, ExtractMethodOptions.AllowMovingDeclaration, LanguageNames.CSharp); BindToFullSolutionAnalysisOption(ClosedFileDiagnostics, LanguageNames.CSharp); diff --git a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs index 89c536d917e6b..3cc6fdff90eaa 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AdvancedOptionPageStrings.cs @@ -89,11 +89,6 @@ public static string Option_OptimizeForSolutionSize_Small get { return CSharpVSResources.Option_OptimizeForSolutionSize_Small; } } - public static string Option_OrganizeUsings - { - get { return CSharpVSResources.Option_OrganizeUsings; } - } - public static string Option_Outlining { get { return CSharpVSResources.Option_Outlining; } @@ -109,9 +104,13 @@ public static string Option_PlaceSystemNamespaceFirst get { return CSharpVSResources.Option_PlaceSystemNamespaceFirst; } } - public static string Option_WarnOnBuildErrors - { - get { return CSharpVSResources.Option_WarnOnBuildErrors; } - } + public static string Option_Using_Directives => + CSharpVSResources.Option_Using_Directives; + + public static string Option_Suggest_usings_for_types_in_reference_assemblies => + CSharpVSResources.Option_Suggest_usings_for_types_in_reference_assemblies; + + public static string Option_Suggest_usings_for_types_in_NuGet_packages => + CSharpVSResources.Option_Suggest_usings_for_types_in_NuGet_packages; } } diff --git a/src/VisualStudio/CSharp/Impl/Options/AutomationObject.cs b/src/VisualStudio/CSharp/Impl/Options/AutomationObject.cs index adeb8b09aac61..5fc0a872e33f1 100644 --- a/src/VisualStudio/CSharp/Impl/Options/AutomationObject.cs +++ b/src/VisualStudio/CSharp/Impl/Options/AutomationObject.cs @@ -300,6 +300,18 @@ public int SortUsings_PlaceSystemFirst set { SetBooleanOption(OrganizerOptions.PlaceSystemNamespaceFirst, value); } } + public int AddImport_SuggestForTypesInReferenceAssemblies + { + get { return GetBooleanOption(AddImportOptions.SuggestForTypesInReferenceAssemblies); } + set { SetBooleanOption(AddImportOptions.SuggestForTypesInReferenceAssemblies, value); } + } + + public int AddImport_SuggestForTypesInNuGetPackages + { + get { return GetBooleanOption(AddImportOptions.SuggestForTypesInNuGetPackages); } + set { SetBooleanOption(AddImportOptions.SuggestForTypesInNuGetPackages, value); } + } + public int Space_AfterBasesColon { get { return GetBooleanOption(CSharpFormattingOptions.SpaceAfterColonInBaseTypeDeclaration); } @@ -473,12 +485,6 @@ public int Style_UseVarWhenDeclaringLocals set { SetBooleanOption(CSharpCodeStyleOptions.UseVarWhenDeclaringLocals, value); } } - public int WarnOnBuildErrors - { - get { return GetBooleanOption(OrganizerOptions.WarnOnBuildErrors); } - set { SetBooleanOption(OrganizerOptions.WarnOnBuildErrors, value); } - } - public int Wrapping_IgnoreSpacesAroundBinaryOperators { get diff --git a/src/VisualStudio/CSharp/Impl/Options/CSharpSettingsManagerOptionSerializer.cs b/src/VisualStudio/CSharp/Impl/Options/CSharpSettingsManagerOptionSerializer.cs index 0c3a53cf24695..0e6767bb0a196 100644 --- a/src/VisualStudio/CSharp/Impl/Options/CSharpSettingsManagerOptionSerializer.cs +++ b/src/VisualStudio/CSharp/Impl/Options/CSharpSettingsManagerOptionSerializer.cs @@ -33,6 +33,7 @@ namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options [ExportLanguageSpecificOptionSerializer( LanguageNames.CSharp, OrganizerOptions.FeatureName, + AddImportOptions.FeatureName, CompletionOptions.FeatureName, CSharpCompletionOptions.FeatureName, CSharpCodeStyleOptions.FeatureName, @@ -82,6 +83,7 @@ private bool ShouldIncludeOnOffOption(FieldInfo fieldInfo) Type[] types = new[] { typeof(OrganizerOptions), + typeof(AddImportOptions), typeof(CSharpCompletionOptions), typeof(SimplificationOptions), typeof(CSharpCodeStyleOptions), @@ -120,7 +122,8 @@ protected override string GetStorageKeyForOption(IOption option) protected override bool SupportsOption(IOption option, string languageName) { if (option == OrganizerOptions.PlaceSystemNamespaceFirst || - option == OrganizerOptions.WarnOnBuildErrors || + option == AddImportOptions.SuggestForTypesInReferenceAssemblies || + option == AddImportOptions.SuggestForTypesInNuGetPackages || option == CSharpCompletionOptions.AddNewLineOnEnterAfterFullyTypedWord || option == CSharpCompletionOptions.IncludeSnippets || option.Feature == CSharpCodeStyleOptions.FeatureName || diff --git a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs index b93fb3a2895a6..cb5c4c6b189cc 100644 --- a/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs +++ b/src/VisualStudio/Core/Def/Implementation/ProjectSystem/VisualStudioWorkspaceImpl.cs @@ -16,11 +16,13 @@ using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.Shared.Utilities; using Microsoft.CodeAnalysis.SolutionCrawler; +using Microsoft.CodeAnalysis.SymbolSearch; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.ComponentModelHost; using Microsoft.VisualStudio.Feedback.Interop; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Extensions; using Microsoft.VisualStudio.LanguageServices.Packaging; +using Microsoft.VisualStudio.LanguageServices.SymbolSearch; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Text; @@ -55,7 +57,7 @@ internal abstract class VisualStudioWorkspaceImpl : VisualStudioWorkspace private readonly ForegroundThreadAffinitizedObject _foregroundObject = new ForegroundThreadAffinitizedObject(); private PackageInstallerService _packageInstallerService; - private PackageSearchService _packageSearchService; + private SymbolSearchService _symbolSearchService; public VisualStudioWorkspaceImpl( SVsServiceProvider serviceProvider, @@ -111,7 +113,7 @@ protected void InitializeStandardVisualStudioWorkspace(SVsServiceProvider servic this.Services.GetService(); // Ensure the nuget package services are initialized on the UI thread. - _packageSearchService = this.Services.GetService() as PackageSearchService; + _symbolSearchService = this.Services.GetService() as SymbolSearchService; _packageInstallerService = (PackageInstallerService)this.Services.GetService(); _packageInstallerService.Connect(this); } @@ -1010,7 +1012,7 @@ internal void StopSolutionCrawler() protected override void Dispose(bool finalize) { _packageInstallerService?.Disconnect(this); - _packageSearchService?.Dispose(); + _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 99905fd4c148e..44b6323f74d1d 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs +++ b/src/VisualStudio/Core/Def/Packaging/PackageInstallerServiceFactory.cs @@ -80,7 +80,7 @@ internal void Connect(VisualStudioWorkspaceImpl workspace) this.AssertIsForeground(); var options = workspace.Options; - if (!options.GetOption(ServiceComponentOnOffOptions.PackageSearch)) + if (!options.GetOption(ServiceComponentOnOffOptions.SymbolSearch)) { return; } diff --git a/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj b/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj index 11041d74c659e..986b62105d917 100644 --- a/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj +++ b/src/VisualStudio/Core/Def/ServicesVisualStudio.csproj @@ -156,23 +156,23 @@ - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + True @@ -743,7 +743,7 @@ - + diff --git a/src/VisualStudio/Core/Def/Packaging/IPackageSearchDatabaseFactoryService.cs b/src/VisualStudio/Core/Def/SymbolSearch/IDatabaseFactoryService.cs similarity index 70% rename from src/VisualStudio/Core/Def/Packaging/IPackageSearchDatabaseFactoryService.cs rename to src/VisualStudio/Core/Def/SymbolSearch/IDatabaseFactoryService.cs index ee77da2d80756..6f91494de4eae 100644 --- a/src/VisualStudio/Core/Def/Packaging/IPackageSearchDatabaseFactoryService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/IDatabaseFactoryService.cs @@ -2,9 +2,9 @@ using Microsoft.CodeAnalysis.Elfie.Model; -namespace Microsoft.VisualStudio.LanguageServices.Packaging +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { - internal interface IPackageSearchDatabaseFactoryService + internal interface IDatabaseFactoryService { AddReferenceDatabase CreateDatabaseFromBytes(byte[] bytes); } diff --git a/src/VisualStudio/Core/Def/Packaging/IPackageSearchDelayService.cs b/src/VisualStudio/Core/Def/SymbolSearch/IDelayService.cs similarity index 87% rename from src/VisualStudio/Core/Def/Packaging/IPackageSearchDelayService.cs rename to src/VisualStudio/Core/Def/SymbolSearch/IDelayService.cs index 5aeae668d8020..59952ddf12e03 100644 --- a/src/VisualStudio/Core/Def/Packaging/IPackageSearchDelayService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/IDelayService.cs @@ -1,17 +1,13 @@ // 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.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Microsoft.VisualStudio.LanguageServices.Packaging +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { /// /// Used so we can mock out how the search service delays work for testing purposes. /// - internal interface IPackageSearchDelayService + internal interface IDelayService { /// /// The time to wait after a successful update (default = 1 day). diff --git a/src/VisualStudio/Core/Def/Packaging/IPackageSearchIOService.cs b/src/VisualStudio/Core/Def/SymbolSearch/IIOService.cs similarity index 77% rename from src/VisualStudio/Core/Def/Packaging/IPackageSearchIOService.cs rename to src/VisualStudio/Core/Def/SymbolSearch/IIOService.cs index c1e024e6bfca5..2488ba9bd4d6c 100644 --- a/src/VisualStudio/Core/Def/Packaging/IPackageSearchIOService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/IIOService.cs @@ -1,18 +1,13 @@ // 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.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Microsoft.VisualStudio.LanguageServices.Packaging +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { /// /// Used so we can mock out how the search service does IO for testing purposes. /// - internal interface IPackageSearchIOService + internal interface IIOService { void Create(DirectoryInfo directory); void Delete(FileInfo file); diff --git a/src/VisualStudio/Core/Def/Packaging/IPackageSearchLogService.cs b/src/VisualStudio/Core/Def/SymbolSearch/ILogService.cs similarity index 64% rename from src/VisualStudio/Core/Def/Packaging/IPackageSearchLogService.cs rename to src/VisualStudio/Core/Def/SymbolSearch/ILogService.cs index c0403d77588d1..d528d52042b06 100644 --- a/src/VisualStudio/Core/Def/Packaging/IPackageSearchLogService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/ILogService.cs @@ -1,17 +1,13 @@ // 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.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Microsoft.VisualStudio.LanguageServices.Packaging +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { /// /// Used so we can mock out logging in unit tests. /// - internal interface IPackageSearchLogService + internal interface ILogService { void LogException(Exception e, string text); void LogInfo(string text); diff --git a/src/VisualStudio/Core/Def/Packaging/IPackageSearchPatchService.cs b/src/VisualStudio/Core/Def/SymbolSearch/IPatchService.cs similarity index 60% rename from src/VisualStudio/Core/Def/Packaging/IPackageSearchPatchService.cs rename to src/VisualStudio/Core/Def/SymbolSearch/IPatchService.cs index 4757e2cdabd88..867cc9baf7468 100644 --- a/src/VisualStudio/Core/Def/Packaging/IPackageSearchPatchService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/IPatchService.cs @@ -1,17 +1,11 @@ // 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.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Microsoft.VisualStudio.LanguageServices.Packaging +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { /// /// Used so we can mock out patching in unit tests. /// - internal interface IPackageSearchPatchService + internal interface IPatchService { byte[] ApplyPatch(byte[] databaseBytes, byte[] patchBytes); } diff --git a/src/VisualStudio/Core/Def/Packaging/IPackageSearchRemoteControlService.cs b/src/VisualStudio/Core/Def/SymbolSearch/IRemoteControlService.cs similarity index 66% rename from src/VisualStudio/Core/Def/Packaging/IPackageSearchRemoteControlService.cs rename to src/VisualStudio/Core/Def/SymbolSearch/IRemoteControlService.cs index 076a4672a6987..02cc22fbbaeaa 100644 --- a/src/VisualStudio/Core/Def/Packaging/IPackageSearchRemoteControlService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/IRemoteControlService.cs @@ -5,20 +5,20 @@ using System.Threading.Tasks; using Microsoft.Internal.VisualStudio.Shell.Interop; -namespace Microsoft.VisualStudio.LanguageServices.Packaging +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { /// /// Used so we can mock out the remote control service in unit tests. /// - internal interface IPackageSearchRemoteControlService + internal interface IRemoteControlService { - IPackageSearchRemoteControlClient CreateClient(string hostId, string serverPath, int pollingMinutes); + IRemoteControlClient CreateClient(string hostId, string serverPath, int pollingMinutes); } /// /// Used so we can mock out the client in unit tests. /// - internal interface IPackageSearchRemoteControlClient : IDisposable + internal interface IRemoteControlClient : IDisposable { Task ReadFileAsync(__VsRemoteControlBehaviorOnStale behavior); } diff --git a/src/VisualStudio/Core/Def/Packaging/Patching/Delta.cs b/src/VisualStudio/Core/Def/SymbolSearch/Patching/Delta.cs similarity index 97% rename from src/VisualStudio/Core/Def/Packaging/Patching/Delta.cs rename to src/VisualStudio/Core/Def/SymbolSearch/Patching/Delta.cs index 6705c804a1ef3..2e14fe31718c2 100644 --- a/src/VisualStudio/Core/Def/Packaging/Patching/Delta.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/Patching/Delta.cs @@ -8,7 +8,7 @@ using System.Text; using System.Threading.Tasks; -namespace Microsoft.VisualStudio.LanguageServices.Packaging.Patching +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch.Patching { /// /// Wrapper around the msdelta api so we can consume patches produced by the Elfie service. diff --git a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.DatabaseFactoryService.cs b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.DatabaseFactoryService.cs similarity index 78% rename from src/VisualStudio/Core/Def/Packaging/PackageSearchService.DatabaseFactoryService.cs rename to src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.DatabaseFactoryService.cs index f1cb0fd735f1f..005985f81e333 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.DatabaseFactoryService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.DatabaseFactoryService.cs @@ -3,11 +3,11 @@ using System.IO; using Microsoft.CodeAnalysis.Elfie.Model; -namespace Microsoft.VisualStudio.LanguageServices.Packaging +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { - internal partial class PackageSearchService + internal partial class SymbolSearchService { - private class DatabaseFactoryService : IPackageSearchDatabaseFactoryService + private class DatabaseFactoryService : IDatabaseFactoryService { public AddReferenceDatabase CreateDatabaseFromBytes(byte[] bytes) { diff --git a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.DelayService.cs b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.DelayService.cs similarity index 78% rename from src/VisualStudio/Core/Def/Packaging/PackageSearchService.DelayService.cs rename to src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.DelayService.cs index 395ae950d1bf4..50480d70db71f 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.DelayService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.DelayService.cs @@ -2,11 +2,11 @@ using System; -namespace Microsoft.VisualStudio.LanguageServices.Packaging +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { - internal partial class PackageSearchService + internal partial class SymbolSearchService { - private class DelayService : IPackageSearchDelayService + private class DelayService : IDelayService { public TimeSpan CachePollDelay { get; } = TimeSpan.FromMinutes(1); public TimeSpan FileWriteDelay { get; } = TimeSpan.FromSeconds(10); diff --git a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.IOService.cs b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.IOService.cs similarity index 88% rename from src/VisualStudio/Core/Def/Packaging/PackageSearchService.IOService.cs rename to src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.IOService.cs index 676c2cecc3448..57c160145dea6 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.IOService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.IOService.cs @@ -3,11 +3,11 @@ using System.Collections.Generic; using System.IO; -namespace Microsoft.VisualStudio.LanguageServices.Packaging +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { - internal partial class PackageSearchService + internal partial class SymbolSearchService { - private class IOService : IPackageSearchIOService + private class IOService : IIOService { public void Create(DirectoryInfo directory) => directory.Create(); diff --git a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.LogService.cs b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.LogService.cs similarity index 91% rename from src/VisualStudio/Core/Def/Packaging/PackageSearchService.LogService.cs rename to src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.LogService.cs index 592154a7cb91e..5cb2f7486e5fa 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.LogService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.LogService.cs @@ -4,11 +4,11 @@ using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.VisualStudio.Shell.Interop; -namespace Microsoft.VisualStudio.LanguageServices.Packaging +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { - internal partial class PackageSearchService + internal partial class SymbolSearchService { - private class LogService : ForegroundThreadAffinitizedObject, IPackageSearchLogService + private class LogService : ForegroundThreadAffinitizedObject, ILogService { private readonly IVsActivityLog _activityLog; diff --git a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.PatchService.cs b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.PatchService.cs similarity index 69% rename from src/VisualStudio/Core/Def/Packaging/PackageSearchService.PatchService.cs rename to src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.PatchService.cs index e37ccf1c20723..3e57e52c7f574 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.PatchService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.PatchService.cs @@ -1,10 +1,10 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -namespace Microsoft.VisualStudio.LanguageServices.Packaging +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { - internal partial class PackageSearchService + internal partial class SymbolSearchService { - private class PatchService : IPackageSearchPatchService + private class PatchService : IPatchService { public byte[] ApplyPatch(byte[] databaseBytes, byte[] patchBytes) { diff --git a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.RemoteControlService.cs b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.RemoteControlService.cs similarity index 85% rename from src/VisualStudio/Core/Def/Packaging/PackageSearchService.RemoteControlService.cs rename to src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.RemoteControlService.cs index be2320dfc186c..625c973758d20 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.RemoteControlService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.RemoteControlService.cs @@ -6,11 +6,11 @@ using System.Threading.Tasks; using Microsoft.Internal.VisualStudio.Shell.Interop; -namespace Microsoft.VisualStudio.LanguageServices.Packaging +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { - internal partial class PackageSearchService + internal partial class SymbolSearchService { - private class RemoteControlService : IPackageSearchRemoteControlService + private class RemoteControlService : IRemoteControlService { private readonly object _remoteControlService; @@ -19,7 +19,7 @@ public RemoteControlService(object remoteControlService) _remoteControlService = remoteControlService; } - public IPackageSearchRemoteControlClient CreateClient(string hostId, string serverPath, int pollingMinutes) + public IRemoteControlClient CreateClient(string hostId, string serverPath, int pollingMinutes) { var serviceType = _remoteControlService.GetType(); var serviceAssembly = serviceType.Assembly; @@ -39,7 +39,7 @@ public IPackageSearchRemoteControlClient CreateClient(string hostId, string serv } } - private class RemoteControlClient : IPackageSearchRemoteControlClient + private class RemoteControlClient : IRemoteControlClient { // Have to keep the vsClient around as it will try to dispose the underlying // client when it gets GC'ed diff --git a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.Update.cs b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.Update.cs similarity index 94% rename from src/VisualStudio/Core/Def/Packaging/PackageSearchService.Update.cs rename to src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.Update.cs index 9bbc1e62f16c5..e588990c77485 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.Update.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.Update.cs @@ -17,8 +17,12 @@ 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.Packaging +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { /// /// A service which enables searching for packages matching certain criteria. @@ -27,7 +31,7 @@ namespace Microsoft.VisualStudio.LanguageServices.Packaging /// 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 PackageSearchService + internal partial class SymbolSearchService { // Internal for testing purposes. internal const string ContentAttributeName = "content"; @@ -49,6 +53,8 @@ internal partial class PackageSearchService private readonly CancellationTokenSource _cancellationTokenSource; private readonly CancellationToken _cancellationToken; + private readonly Workspace _workspace; + private readonly ConcurrentDictionary _sourceToUpdateSentinel = new ConcurrentDictionary(); @@ -58,12 +64,12 @@ internal partial class PackageSearchService // Interfaces that abstract out the external functionality we need. Used so we can easily // mock behavior during tests. private readonly IPackageInstallerService _installerService; - private readonly IPackageSearchDelayService _delayService; - private readonly IPackageSearchIOService _ioService; - private readonly IPackageSearchLogService _logService; - private readonly IPackageSearchRemoteControlService _remoteControlService; - private readonly IPackageSearchPatchService _patchService; - private readonly IPackageSearchDatabaseFactoryService _databaseFactoryService; + private readonly IDelayService _delayService; + private readonly IIOService _ioService; + private readonly ILogService _logService; + private readonly IRemoteControlService _remoteControlService; + private readonly IPatchService _patchService; + private readonly IDatabaseFactoryService _databaseFactoryService; private readonly Func _reportAndSwallowException; public void Dispose() @@ -76,12 +82,27 @@ public void Dispose() private void LogException(Exception e, string text) => _logService.LogException(e, text); - private void OnPackageSourcesChanged(object sender, EventArgs e) + private void OnOptionChanged(object sender, EventArgs e) { + var options = _workspace.Options; + if (!options.GetOption(AddImportOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.CSharp) && + !options.GetOption(AddImportOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.VisualBasic) && + !options.GetOption(AddImportOptions.SuggestForTypesInNuGetPackages, LanguageNames.CSharp) && + !options.GetOption(AddImportOptions.SuggestForTypesInNuGetPackages, LanguageNames.VisualBasic)) + { + // If we don't have any add-import features that would use these indices, then + // don't bother creating them. + return; + } + // Kick off a database update. Wait a few seconds before starting so we don't // interfere too much with solution loading. var sources = _installerService.PackageSources; - foreach (var source in sources) + + // Always pull down the nuget.org index. It contains the MS reference assembly index + // inside of it. + var allSources = sources.Concat(new PackageSource(NugetOrgSource, source: null)); + foreach (var source in allSources) { Task.Delay(TimeSpan.FromSeconds(10)).ContinueWith(_ => UpdateSourceInBackgroundAsync(source.Name), TaskScheduler.Default); @@ -109,11 +130,11 @@ internal Task UpdateSourceInBackgroundAsync(string source) private class Updater { - private readonly PackageSearchService _service; + private readonly SymbolSearchService _service; private readonly string _source; private readonly FileInfo _databaseFileInfo; - public Updater(PackageSearchService service, string source) + public Updater(SymbolSearchService service, string source) { _service = service; _source = source; @@ -541,7 +562,7 @@ private async Task DownloadFileAsync(string serverPath) } /// Returns 'null' if download is not available and caller should keep polling. - private async Task TryDownloadFileAsync(IPackageSearchRemoteControlClient client) + private async Task TryDownloadFileAsync(IRemoteControlClient client) { _service.LogInfo("Read file from client"); diff --git a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.cs b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.cs similarity index 89% rename from src/VisualStudio/Core/Def/Packaging/PackageSearchService.cs rename to src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.cs index 795e7cb76bce3..f2a30c81729e6 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageSearchService.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchService.cs @@ -6,13 +6,15 @@ using System.IO; using System.Linq; using System.Threading; -using System.Threading.Tasks; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Elfie.Model; using Microsoft.CodeAnalysis.Elfie.Model.Structures; using Microsoft.CodeAnalysis.Elfie.Model.Tree; using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Packaging; +using Microsoft.CodeAnalysis.SymbolSearch; using Microsoft.Internal.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.Settings; using Microsoft.VisualStudio.Shell.Interop; @@ -20,7 +22,7 @@ using static System.FormattableString; using VSShell = Microsoft.VisualStudio.Shell; -namespace Microsoft.VisualStudio.LanguageServices.Packaging +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { /// /// A service which enables searching for packages matching certain criteria. @@ -29,16 +31,19 @@ namespace Microsoft.VisualStudio.LanguageServices.Packaging /// 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 PackageSearchService : + internal partial class SymbolSearchService : ForegroundThreadAffinitizedObject, - IPackageSearchService, - IReferenceAssemblySearchService, + ISymbolSearchService, IDisposable { private ConcurrentDictionary _sourceToDatabase = new ConcurrentDictionary(); - public PackageSearchService(VSShell.SVsServiceProvider serviceProvider, IPackageInstallerService installerService) - : this(installerService, + public SymbolSearchService( + VSShell.SVsServiceProvider serviceProvider, + Workspace workspace, + IPackageInstallerService installerService) + : this(workspace, + installerService, CreateRemoteControlService(serviceProvider), new LogService((IVsActivityLog)serviceProvider.GetService(typeof(SVsActivityLog))), new DelayService(), @@ -50,11 +55,14 @@ public PackageSearchService(VSShell.SVsServiceProvider serviceProvider, IPackage FatalError.ReportWithoutCrash, new CancellationTokenSource()) { - installerService.PackageSourcesChanged += OnPackageSourcesChanged; - OnPackageSourcesChanged(this, EventArgs.Empty); + installerService.PackageSourcesChanged += OnOptionChanged; + var optionsService = workspace.Services.GetService(); + optionsService.OptionChanged += OnOptionChanged; + + OnOptionChanged(this, EventArgs.Empty); } - private static IPackageSearchRemoteControlService CreateRemoteControlService(VSShell.SVsServiceProvider serviceProvider) + private static IRemoteControlService CreateRemoteControlService(VSShell.SVsServiceProvider serviceProvider) { var vsService = serviceProvider.GetService(typeof(SVsRemoteControlService)); if (vsService == null) @@ -69,14 +77,15 @@ private static IPackageSearchRemoteControlService CreateRemoteControlService(VSS /// /// For testing purposes only. /// - internal PackageSearchService( + internal SymbolSearchService( + Workspace workspace, IPackageInstallerService installerService, - IPackageSearchRemoteControlService remoteControlService, - IPackageSearchLogService logService, - IPackageSearchDelayService delayService, - IPackageSearchIOService ioService, - IPackageSearchPatchService patchService, - IPackageSearchDatabaseFactoryService databaseFactoryService, + IRemoteControlService remoteControlService, + ILogService logService, + IDelayService delayService, + IIOService ioService, + IPatchService patchService, + IDatabaseFactoryService databaseFactoryService, string localSettingsDirectory, Func reportAndSwallowException, CancellationTokenSource cancellationTokenSource) @@ -87,6 +96,7 @@ private static IPackageSearchRemoteControlService CreateRemoteControlService(VSS return; } + _workspace = workspace; _installerService = installerService; _delayService = delayService; _ioService = ioService; diff --git a/src/VisualStudio/Core/Def/Packaging/PackageSearchServiceFactory.cs b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchServiceFactory.cs similarity index 58% rename from src/VisualStudio/Core/Def/Packaging/PackageSearchServiceFactory.cs rename to src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchServiceFactory.cs index 4709041e9a75b..83a83207316bf 100644 --- a/src/VisualStudio/Core/Def/Packaging/PackageSearchServiceFactory.cs +++ b/src/VisualStudio/Core/Def/SymbolSearch/SymbolSearchServiceFactory.cs @@ -8,18 +8,19 @@ 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.Packaging +namespace Microsoft.VisualStudio.LanguageServices.SymbolSearch { - [ExportWorkspaceServiceFactory(typeof(IPackageSearchService), WorkspaceKind.Host), Shared] - internal class PackageSearchServiceFactory : IWorkspaceServiceFactory + [ExportWorkspaceServiceFactory(typeof(ISymbolSearchService), WorkspaceKind.Host), Shared] + internal class SymbolSearchServiceFactory : IWorkspaceServiceFactory { private readonly VSShell.SVsServiceProvider _serviceProvider; [ImportingConstructor] - public PackageSearchServiceFactory( + public SymbolSearchServiceFactory( VSShell.SVsServiceProvider serviceProvider) { _serviceProvider = serviceProvider; @@ -28,25 +29,33 @@ internal class PackageSearchServiceFactory : IWorkspaceServiceFactory public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) { var options = workspaceServices.Workspace.Options; - if (options.GetOption(ServiceComponentOnOffOptions.PackageSearch)) + if (options.GetOption(ServiceComponentOnOffOptions.SymbolSearch)) { // Only support package search in vs workspace. if (workspaceServices.Workspace is VisualStudioWorkspace) { - return new PackageSearchService(_serviceProvider, workspaceServices.GetService()); + return new SymbolSearchService( + _serviceProvider, workspaceServices.Workspace, + workspaceServices.GetService()); } } - return new NullPackageSearchService(); + return new NullSymbolSearchService(); } - private class NullPackageSearchService : IPackageSearchService + 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(); + } } } } diff --git a/src/VisualStudio/Core/Test/Packaging/PackageSearchServiceTests.vb b/src/VisualStudio/Core/Test/Packaging/PackageSearchServiceTests.vb deleted file mode 100644 index 616d990ca2542..0000000000000 --- a/src/VisualStudio/Core/Test/Packaging/PackageSearchServiceTests.vb +++ /dev/null @@ -1,787 +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. - -Imports System.Collections.Immutable -Imports System.IO -Imports System.IO.Compression -Imports System.Threading -Imports System.Threading.Tasks -Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Elfie.Model -Imports Microsoft.CodeAnalysis.Packaging -Imports Microsoft.Internal.VisualStudio.Shell.Interop -Imports Microsoft.VisualStudio.LanguageServices.Packaging -Imports Moq -Imports Roslyn.Test.Utilities - -Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Packaging - Public Class PackageSearchServiceTests - Private Shared ReadOnly s_allButMoqExceptions As Func(Of Exception, Boolean) = - Function(e) TypeOf e IsNot MockException - - - Public Async Function CreateCacheFolderIfMissing() As Task - Dim cancellationTokenSource = New CancellationTokenSource() - - Dim ioMock = New Mock(Of IPackageSearchIOService)(MockBehavior.Strict) - - ' Simulate the cache folder being missing. - ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) - - ' Expect that the cache directory is created. Cancel processing at that point so - ' the test can complete. - ioMock.Setup(Sub(s) s.Create(It.IsAny(Of DirectoryInfo))).Callback( - AddressOf cancellationTokenSource.Cancel) - - Dim remoteControlService = New Mock(Of IPackageSearchRemoteControlService) - - Dim service = New PackageSearchService( - installerService:=TestInstallerService.Instance, - remoteControlService:=remoteControlService.Object, - logService:=TestLogService.Instance, - delayService:=TestDelayService.Instance, - ioService:=ioMock.Object, - patchService:=Nothing, - databaseFactoryService:=Nothing, - localSettingsDirectory:="TestDirectory", - reportAndSwallowException:=s_allButMoqExceptions, - cancellationTokenSource:=cancellationTokenSource) - - Await service.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource) - ioMock.Verify() - remoteControlService.Verify() - End Function - - - Public Async Function DoNotCreateCacheFolderIfItIsThere() As Task - Dim cancellationTokenSource = New CancellationTokenSource() - - Dim ioMock = New Mock(Of IPackageSearchIOService)(MockBehavior.Strict) - - ' Simulate the cache folder being there. We use a 'strict' mock so that - ' we'll throw if we get the call to create the directory. - ioMock.Setup(Function(s) s.Exists(It.IsAny(Of DirectoryInfo))).Returns(True).Callback( - AddressOf cancellationTokenSource.Cancel) - - Dim remoteControlService = New Mock(Of IPackageSearchRemoteControlService) - - Dim service = New PackageSearchService( - installerService:=TestInstallerService.Instance, - remoteControlService:=remoteControlService.Object, - logService:=TestLogService.Instance, - delayService:=TestDelayService.Instance, - ioService:=ioMock.Object, - patchService:=Nothing, - databaseFactoryService:=Nothing, - localSettingsDirectory:="TestDirectory", - reportAndSwallowException:=s_allButMoqExceptions, - cancellationTokenSource:=cancellationTokenSource) - - Await service.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource) - ioMock.Verify() - remoteControlService.Verify() - End Function - - - Public Async Function DownloadFullDatabaseWhenLocalDatabaseIsMissing() As Task - Dim cancellationTokenSource = New CancellationTokenSource() - - Dim ioMock = New Mock(Of IPackageSearchIOService)() - - ' Simlute the local database being missing. - ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) - - Dim clientMock = New Mock(Of IPackageSearchRemoteControlClient) - - Dim serviceMock = New Mock(Of IPackageSearchRemoteControlService)(MockBehavior.Strict) - - ' The client should request the 'Latest' database from the server. - ' Cancel processing at that point so the test can complete. - serviceMock.Setup( - Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Latest.*"), It.IsAny(Of Integer))). - Returns(clientMock.Object). - Callback(AddressOf cancellationTokenSource.Cancel) - - Dim searchService = New PackageSearchService( - installerService:=TestInstallerService.Instance, - remoteControlService:=serviceMock.Object, - logService:=TestLogService.Instance, - delayService:=TestDelayService.Instance, - ioService:=ioMock.Object, - patchService:=Nothing, - databaseFactoryService:=Nothing, - localSettingsDirectory:="TestDirectory", - reportAndSwallowException:=s_allButMoqExceptions, - cancellationTokenSource:=cancellationTokenSource) - - Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource) - ioMock.Verify() - serviceMock.Verify() - clientMock.Verify() - End Function - - - Public Async Function FailureToParseFullDBAtXmlLevelTakesCatastrophicPath() As Task - Dim cancellationTokenSource = New CancellationTokenSource() - - Dim ioMock = New Mock(Of IPackageSearchIOService)() - - ' Simlute the local database being missing. - ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) - - Dim clientMock = CreateClientMock(CreateStream(New XElement("Database", - New XAttribute(PackageSearchService.ContentAttributeName, ""), - New XAttribute(PackageSearchService.ChecksumAttributeName, Convert.ToBase64String(New Byte() {0, 1, 2}))))) - - Dim serviceMock = New Mock(Of IPackageSearchRemoteControlService)(MockBehavior.Strict) - - ' The client should request the 'Latest' database from the server. - ' Cancel processing at that point so the test can complete. - serviceMock.Setup( - Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Latest.*"), It.IsAny(Of Integer))). - Returns(clientMock.Object) - - Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict) - delayMock.SetupGet(Function(s) s.CatastrophicFailureDelay).Returns(TimeSpan.Zero).Callback( - AddressOf cancellationTokenSource.Cancel) - - Dim searchService = New PackageSearchService( - installerService:=TestInstallerService.Instance, - remoteControlService:=serviceMock.Object, - logService:=TestLogService.Instance, - delayService:=delayMock.Object, - ioService:=ioMock.Object, - patchService:=Nothing, - databaseFactoryService:=Nothing, - localSettingsDirectory:="TestDirectory", - reportAndSwallowException:=s_allButMoqExceptions, - cancellationTokenSource:=cancellationTokenSource) - - Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource) - ioMock.Verify() - serviceMock.Verify() - clientMock.Verify() - delayMock.Verify() - End Function - - - Public Async Function TestClientDisposedAfterUse() As Task - Dim cancellationTokenSource = New CancellationTokenSource() - - Dim ioMock = New Mock(Of IPackageSearchIOService)() - ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) - - Dim clientMock = New Mock(Of IPackageSearchRemoteControlClient)(MockBehavior.Strict) - clientMock.Setup(Sub(c) c.Dispose()) - - Dim serviceMock = New Mock(Of IPackageSearchRemoteControlService)(MockBehavior.Strict) - serviceMock.Setup( - Function(s) s.CreateClient(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Integer))). - Returns(clientMock.Object). - Callback(AddressOf cancellationTokenSource.Cancel) - - Dim searchService = New PackageSearchService( - installerService:=TestInstallerService.Instance, - remoteControlService:=serviceMock.Object, - logService:=TestLogService.Instance, - delayService:=TestDelayService.Instance, - ioService:=ioMock.Object, - patchService:=Nothing, - databaseFactoryService:=Nothing, - localSettingsDirectory:="TestDirectory", - reportAndSwallowException:=s_allButMoqExceptions, - cancellationTokenSource:=cancellationTokenSource) - - Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource) - ioMock.Verify() - serviceMock.Verify() - clientMock.Verify() - End Function - - - Public Async Function CrashInClientRunsFailureLoopPath() As Task - Dim cancellationTokenSource = New CancellationTokenSource() - - Dim ioMock = New Mock(Of IPackageSearchIOService)() - - ' Simulate the database not being there. - ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) - - Dim clientMock = New Mock(Of IPackageSearchRemoteControlClient)(MockBehavior.Strict) - - ' We should get a call to try to read the file. Simulate a crash in the client. - clientMock.Setup(Sub(c) c.ReadFileAsync(It.IsAny(Of __VsRemoteControlBehaviorOnStale))). - Throws(New NotImplementedException()) - - ' Client should be disposed. - clientMock.Setup(Sub(c) c.Dispose()) - - Dim remoteControlMock = New Mock(Of IPackageSearchRemoteControlService)(MockBehavior.Strict) - remoteControlMock.Setup( - Function(s) s.CreateClient(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Integer))). - Returns(clientMock.Object) - - ' Because the client failed we will expect to call into the 'UpdateFailedDelay' to - ' control when we do our next loop. - ' Cancel processing at that point so the test can complete. - Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict) - delayMock.SetupGet(Function(s) s.ExpectedFailureDelay).Returns(TimeSpan.Zero).Callback( - AddressOf cancellationTokenSource.Cancel) - - Dim searchService = New PackageSearchService( - installerService:=TestInstallerService.Instance, - remoteControlService:=remoteControlMock.Object, - logService:=TestLogService.Instance, - delayService:=delayMock.Object, - ioService:=ioMock.Object, - patchService:=Nothing, - databaseFactoryService:=Nothing, - localSettingsDirectory:="TestDirectory", - reportAndSwallowException:=s_allButMoqExceptions, - cancellationTokenSource:=cancellationTokenSource) - - Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource) - ioMock.Verify() - remoteControlMock.Verify() - clientMock.Verify() - delayMock.Verify() - End Function - - - Public Async Function FailureToParseFullDBAtElfieLevelTakesCatastrophicPath() As Task - Dim cancellationTokenSource = New CancellationTokenSource() - - Dim ioMock = New Mock(Of IPackageSearchIOService)() - 'Simulate the database file not existing. - ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) - - ' Get a client that will download the latest database. - Dim clientMock = CreateFullDatabaseClientMock() - Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=True) - - Dim factoryMock = New Mock(Of IPackageSearchDatabaseFactoryService)(MockBehavior.Strict) - ' Simulate Elfie throwing when trying to make a database from the contents of that response - factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). - Throws(New NotImplementedException()) - - ' Because the parsing failed we will expect to call into the 'UpdateFailedDelay' to - ' control when we do our next loop. - ' Cancel processing at that point so the test can complete. - Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict) - delayMock.SetupGet(Function(s) s.CatastrophicFailureDelay).Returns(TimeSpan.Zero).Callback( - AddressOf cancellationTokenSource.Cancel) - - Dim searchService = New PackageSearchService( - installerService:=TestInstallerService.Instance, - remoteControlService:=remoteControlMock.Object, - logService:=TestLogService.Instance, - delayService:=delayMock.Object, - ioService:=ioMock.Object, - patchService:=Nothing, - databaseFactoryService:=factoryMock.Object, - localSettingsDirectory:="TestDirectory", - reportAndSwallowException:=s_allButMoqExceptions, - cancellationTokenSource:=cancellationTokenSource) - - Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource) - ioMock.Verify() - remoteControlMock.Verify() - clientMock.Verify() - delayMock.Verify() - factoryMock.Verify() - End Function - - - Public Async Function SuccessParsingDBWritesToDisk() As Task - Dim cancellationTokenSource = New CancellationTokenSource() - - Dim ioMock = New Mock(Of IPackageSearchIOService)() - ' Simulate the local database not being there. - ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) - - ' Create a client that will download the latest database. - Dim clientMock = CreateFullDatabaseClientMock() - Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=True) - - ' Successfully create a database from that response. - Dim factoryMock = New Mock(Of IPackageSearchDatabaseFactoryService)(MockBehavior.Strict) - factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). - Returns(New AddReferenceDatabase()) - - ' Expect that we'll write the database to disk successfully. - SetupWritesDatabaseSuccessfullyToDisk(ioMock) - - Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict) - - ' Because writing to disk succeeded, we expect we'll loop on the 'UpdateSucceededDelay'. - ' Cancel processing at that point so the test can complete. - delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero). - Callback(AddressOf cancellationTokenSource.Cancel) - - Dim searchService = New PackageSearchService( - installerService:=TestInstallerService.Instance, - remoteControlService:=remoteControlMock.Object, - logService:=TestLogService.Instance, - delayService:=delayMock.Object, - ioService:=ioMock.Object, - patchService:=Nothing, - databaseFactoryService:=factoryMock.Object, - localSettingsDirectory:="TestDirectory", - reportAndSwallowException:=s_allButMoqExceptions, - cancellationTokenSource:=cancellationTokenSource) - - Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource) - ioMock.Verify() - remoteControlMock.Verify() - clientMock.Verify() - delayMock.Verify() - factoryMock.Verify() - End Function - - - Public Async Function WriteAgainOnIOFailure() As Task - Dim cancellationTokenSource = New CancellationTokenSource() - - Dim ioMock = New Mock(Of IPackageSearchIOService)() - - ' Simulate the database being missing. - ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) - - ' Create a client that will download the latest databsae - Dim clientMock = CreateFullDatabaseClientMock() - Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=True) - - ' Create a database from the client response. - Dim factoryMock = New Mock(Of IPackageSearchDatabaseFactoryService)(MockBehavior.Strict) - factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). - Returns(New AddReferenceDatabase()) - - Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict) - - ' Write the temp file out to disk. - ioMock.Setup(Sub(s) s.WriteAndFlushAllBytes(It.IsAny(Of String), It.IsAny(Of Byte()))) - - ' Simulate a failure doing the first 'replace' of the database file. - ioMock.Setup(Sub(s) s.Replace(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Boolean))). - Throws(New IOException()) - - ' We'll expect to have to replay the write. So we should get a call to 'FileWriteDelay' - delayMock.SetupGet(Function(s) s.FileWriteDelay).Returns(TimeSpan.Zero) - - ' Succeed on the second write attempt. - ioMock.Setup(Sub(s) s.Replace(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Boolean))) - - ' Because writing to disk succeeded, we expect we'll loop on the 'UpdateSucceededDelay'. - ' Cancel processing at that point so the test can complete. - delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero). - Callback(AddressOf cancellationTokenSource.Cancel) - - Dim searchService = New PackageSearchService( - installerService:=TestInstallerService.Instance, - remoteControlService:=remoteControlMock.Object, - logService:=TestLogService.Instance, - delayService:=delayMock.Object, - ioService:=ioMock.Object, - patchService:=Nothing, - databaseFactoryService:=factoryMock.Object, - localSettingsDirectory:="TestDirectory", - reportAndSwallowException:=s_allButMoqExceptions, - cancellationTokenSource:=cancellationTokenSource) - - Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource) - ioMock.Verify() - remoteControlMock.Verify() - clientMock.Verify() - delayMock.Verify() - factoryMock.Verify() - End Function - - - Public Async Function LocalDatabaseExistingCausesPatchToDownload_UpToDate_DoesNothing() As Task - Dim cancellationTokenSource = New CancellationTokenSource() - - Dim ioMock = New Mock(Of IPackageSearchIOService)() - - ' Simulate the database being there. - ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True) - - ' We'll successfully read in the local database. - Dim databaseFactoryMock = New Mock(Of IPackageSearchDatabaseFactoryService)(MockBehavior.Strict) - databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). - Returns(New AddReferenceDatabase()) - - ' Create a client that will return a patch that says things are up to date. - Dim clientMock = CreatePatchClientMock(isUpToDate:=True) - Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False) - - Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict) - - ' Because everything is up to date, we expect we'll loop on the 'UpdateSucceededDelay'. - ' Cancel processing at that point so the test can complete. - delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero). - Callback(AddressOf cancellationTokenSource.Cancel) - - Dim searchService = New PackageSearchService( - installerService:=TestInstallerService.Instance, - remoteControlService:=remoteControlMock.Object, - logService:=TestLogService.Instance, - delayService:=delayMock.Object, - ioService:=ioMock.Object, - patchService:=Nothing, - databaseFactoryService:=databaseFactoryMock.Object, - localSettingsDirectory:="TestDirectory", - reportAndSwallowException:=s_allButMoqExceptions, - cancellationTokenSource:=cancellationTokenSource) - - Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource) - ioMock.Verify() - remoteControlMock.Verify() - clientMock.Verify() - delayMock.Verify() - databaseFactoryMock.Verify() - End Function - - - Public Async Function LocalDatabaseExistingCausesPatchToDownload_IsTooOldCausesFullDownload() As Task - Dim cancellationTokenSource = New CancellationTokenSource() - - Dim ioMock = New Mock(Of IPackageSearchIOService)() - - ' Simulate the database being there. - ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True) - - ' We'll successfully read in the local database. - Dim databaseFactoryMock = New Mock(Of IPackageSearchDatabaseFactoryService)(MockBehavior.Strict) - databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). - Returns(New AddReferenceDatabase()) - - ' Create a client that will return a patch that says things are too old. - Dim clientMock = CreatePatchClientMock(isTooOld:=True) - Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False) - - ' This should cause us to want to then download the full db. So now - ' setup an expectation that we'll download the latest. - Dim clientMock2 = CreateFullDatabaseClientMock() - SetupDownloadLatest(remoteControlMock, clientMock2) - - ' Expect that we'll write the database to disk successfully. - SetupWritesDatabaseSuccessfullyToDisk(ioMock) - - Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict) - - ' Because we got the full database, we expect we'll loop on the 'UpdateSucceededDelay'. - ' Cancel processing at that point so the test can complete. - delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero). - Callback(AddressOf cancellationTokenSource.Cancel) - - Dim searchService = New PackageSearchService( - installerService:=TestInstallerService.Instance, - remoteControlService:=remoteControlMock.Object, - logService:=TestLogService.Instance, - delayService:=delayMock.Object, - ioService:=ioMock.Object, - patchService:=Nothing, - databaseFactoryService:=databaseFactoryMock.Object, - localSettingsDirectory:="TestDirectory", - reportAndSwallowException:=s_allButMoqExceptions, - cancellationTokenSource:=cancellationTokenSource) - - Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource) - ioMock.Verify() - remoteControlMock.Verify() - clientMock.Verify() - clientMock2.Verify() - delayMock.Verify() - databaseFactoryMock.Verify() - End Function - - - Public Async Function LocalDatabaseExistingCausesPatchToDownload_ContentsCausesPatching_FailureToPatchCausesFullDownload() As Task - Dim cancellationTokenSource = New CancellationTokenSource() - - Dim ioMock = New Mock(Of IPackageSearchIOService)() - - ' Simulate the database being there. - ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True) - - ' We'll successfully read in the local database. - Dim databaseFactoryMock = New Mock(Of IPackageSearchDatabaseFactoryService)(MockBehavior.Strict) - databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). - Returns(New AddReferenceDatabase()) - - ' Create a client that will return a patch with contents. - Dim clientMock = CreatePatchClientMock(contents:="") - Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False) - - ' Simulate a crash in the patching process. - Dim patchService = New Mock(Of IPackageSearchPatchService)(MockBehavior.Strict) - patchService.Setup(Sub(s) s.ApplyPatch(It.IsAny(Of Byte()), It.IsAny(Of Byte()))). - Throws(New NotImplementedException()) - - ' This should cause us to want to then download the full db. So now - ' setup an expectation that we'll download the latest. - Dim clientMock2 = CreateFullDatabaseClientMock() - SetupDownloadLatest(remoteControlMock, clientMock2) - - ' Expect that we'll write the database to disk successfully. - SetupWritesDatabaseSuccessfullyToDisk(ioMock) - - Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict) - - ' Because we wrote the full database, we expect we'll loop on the 'UpdateSucceededDelay'. - ' Cancel processing at that point so the test can complete. - delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero). - Callback(AddressOf cancellationTokenSource.Cancel) - - Dim searchService = New PackageSearchService( - installerService:=TestInstallerService.Instance, - remoteControlService:=remoteControlMock.Object, - logService:=TestLogService.Instance, - delayService:=delayMock.Object, - ioService:=ioMock.Object, - patchService:=Nothing, - databaseFactoryService:=databaseFactoryMock.Object, - localSettingsDirectory:="TestDirectory", - reportAndSwallowException:=s_allButMoqExceptions, - cancellationTokenSource:=cancellationTokenSource) - - Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource) - ioMock.Verify() - remoteControlMock.Verify() - clientMock.Verify() - clientMock2.Verify() - patchService.Verify() - delayMock.Verify() - databaseFactoryMock.Verify() - End Function - - - Public Async Function LocalDatabaseExistingCausesPatchToDownload_ContentsCausesPatching_SuccessfulPatchWritesToDisk() As Task - Dim cancellationTokenSource = New CancellationTokenSource() - - Dim ioMock = New Mock(Of IPackageSearchIOService)() - - ' Simulate the database being there. - ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True) - - ' We'll successfully read in the local database. - Dim databaseFactoryMock = New Mock(Of IPackageSearchDatabaseFactoryService)(MockBehavior.Strict) - databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). - Returns(New AddReferenceDatabase()) - - ' Create a client that will return a patch with contents. - Dim clientMock = CreatePatchClientMock(contents:="") - Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False) - - ' Simulate a crash in the patching process. - Dim patchMock = New Mock(Of IPackageSearchPatchService)(MockBehavior.Strict) - patchMock.Setup(Function(s) s.ApplyPatch(It.IsAny(Of Byte()), It.IsAny(Of Byte()))). - Returns(New Byte() {0}) - - ' Expect that we'll write the database to disk successfully. - SetupWritesDatabaseSuccessfullyToDisk(ioMock) - - Dim delayMock = New Mock(Of IPackageSearchDelayService)(MockBehavior.Strict) - - ' Because we wrote the full database, we expect we'll loop on the 'UpdateSucceededDelay'. - ' Cancel processing at that point so the test can complete. - delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero). - Callback(AddressOf cancellationTokenSource.Cancel) - - Dim searchService = New PackageSearchService( - installerService:=TestInstallerService.Instance, - remoteControlService:=remoteControlMock.Object, - logService:=TestLogService.Instance, - delayService:=delayMock.Object, - ioService:=ioMock.Object, - patchService:=patchMock.Object, - databaseFactoryService:=databaseFactoryMock.Object, - localSettingsDirectory:="TestDirectory", - reportAndSwallowException:=s_allButMoqExceptions, - cancellationTokenSource:=cancellationTokenSource) - - Await searchService.UpdateSourceInBackgroundAsync(PackageSearchService.NugetOrgSource) - ioMock.Verify() - remoteControlMock.Verify() - clientMock.Verify() - patchMock.Verify() - delayMock.Verify() - databaseFactoryMock.Verify() - End Function - - Private Shared Sub SetupWritesDatabaseSuccessfullyToDisk(ioMock As Mock(Of IPackageSearchIOService)) - ' Expect that we'll write out the temp file. - ioMock.Setup(Sub(s) s.WriteAndFlushAllBytes(It.IsRegex(".*tmp"), It.IsAny(Of Byte()))) - - ' Expect that we'll replace the existing file with the temp file. - ioMock.Setup(Sub(s) s.Replace(It.IsRegex(".*tmp"), It.IsRegex(".*txt"), Nothing, It.IsAny(Of Boolean))) - End Sub - - Private Shared Function CreateRemoteControlServiceMock( - clientMock As Mock(Of IPackageSearchRemoteControlClient), - latest As Boolean) As Mock(Of IPackageSearchRemoteControlService) - Dim remoteControlMock = New Mock(Of IPackageSearchRemoteControlService)(MockBehavior.Strict) - - If latest Then - SetupDownloadLatest(remoteControlMock, clientMock) - Else - SetupDownloadPatch(clientMock, remoteControlMock) - End If - Return remoteControlMock - End Function - - Private Shared Sub SetupDownloadPatch(clientMock As Mock(Of IPackageSearchRemoteControlClient), remoteControlMock As Mock(Of IPackageSearchRemoteControlService)) - remoteControlMock.Setup( - Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Patch.*"), It.IsAny(Of Integer))). - Returns(clientMock.Object) - End Sub - - Private Shared Sub SetupDownloadLatest(remoteControlMock As Mock(Of IPackageSearchRemoteControlService), clientMock As Mock(Of IPackageSearchRemoteControlClient)) - remoteControlMock.Setup( - Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Latest.*"), It.IsAny(Of Integer))). - Returns(clientMock.Object) - End Sub - - Private Function CreateFullDatabaseClientMock() As Mock(Of IPackageSearchRemoteControlClient) - Return CreateClientMock(CreateFullDownloadElementStream()) - End Function - - Private Function CreateClientMock(stream As Stream) As Mock(Of IPackageSearchRemoteControlClient) - Dim clientMock = New Mock(Of IPackageSearchRemoteControlClient)(MockBehavior.Strict) - - ' Return a full database element when the service asks for it. - clientMock.Setup(Function(c) c.ReadFileAsync(It.IsAny(Of __VsRemoteControlBehaviorOnStale))). - Returns(Task.FromResult(stream)) - ' Always dispose the client when we get a response. - clientMock.Setup(Sub(c) c.Dispose()) - Return clientMock - End Function - - Private Function CreatePatchClientMock(Optional isUpToDate As Boolean = False, - Optional isTooOld As Boolean = False, - Optional contents As String = Nothing) As Mock(Of IPackageSearchRemoteControlClient) - Return CreateClientMock(CreatePatchElementStream(isUpToDate, isTooOld, contents)) - End Function - - Private Function CreatePatchElementStream(Optional isUpToDate As Boolean = False, - Optional isTooOld As Boolean = False, - Optional contents As String = Nothing) As Stream - Dim element = New XElement("Patch", - If(isUpToDate, New XAttribute(PackageSearchService.UpToDateAttributeName, True), Nothing), - If(isTooOld, New XAttribute(PackageSearchService.TooOldAttributeName, True), Nothing), - If(contents IsNot Nothing, New XAttribute(PackageSearchService.ContentAttributeName, contents), Nothing)) - - Return CreateStream(element) - End Function - - Private Function CreateFullDownloadElementStream() As Stream - Dim saveStream = New MemoryStream() - Dim zipStream = New DeflateStream(saveStream, CompressionMode.Compress) - zipStream.Write(New Byte() {0}, 0, 1) - zipStream.Flush() - Dim contents = Convert.ToBase64String(saveStream.ToArray()) - - Return CreateStream(New XElement("Database", - New XAttribute(PackageSearchService.ContentAttributeName, contents))) - End Function - - Private Function CreateStream(element As XElement) As Stream - Dim stream = New MemoryStream() - element.Save(stream) - stream.Position = 0 - Return stream - End Function - - Private Class TestDelayService - Implements IPackageSearchDelayService - - Public Shared ReadOnly Instance As TestDelayService = New TestDelayService() - - Private Sub New() - End Sub - - Public ReadOnly Property CachePollDelay As TimeSpan Implements IPackageSearchDelayService.CachePollDelay - Get - Return TimeSpan.Zero - End Get - End Property - - Public ReadOnly Property FileWriteDelay As TimeSpan Implements IPackageSearchDelayService.FileWriteDelay - Get - Return TimeSpan.Zero - End Get - End Property - - Public ReadOnly Property ExpectedFailureDelay As TimeSpan Implements IPackageSearchDelayService.ExpectedFailureDelay - Get - Return TimeSpan.Zero - End Get - End Property - - Public ReadOnly Property UpdateSucceededDelay As TimeSpan Implements IPackageSearchDelayService.UpdateSucceededDelay - Get - Return TimeSpan.Zero - End Get - End Property - - Public ReadOnly Property CatastrophicFailureDelay As TimeSpan Implements IPackageSearchDelayService.CatastrophicFailureDelay - Get - Return TimeSpan.Zero - End Get - End Property - End Class - - Private Class TestInstallerService - Implements IPackageInstallerService - - Public Shared ReadOnly Instance As IPackageInstallerService = New TestInstallerService() - - Public ReadOnly Property IsEnabled As Boolean Implements IPackageInstallerService.IsEnabled - Get - Return True - End Get - End Property - - Public ReadOnly Property PackageSources As ImmutableArray(Of PackageSource) Implements IPackageInstallerService.PackageSources - Get - Throw New NotImplementedException() - End Get - End Property - - Public Event PackageSourcesChanged As EventHandler Implements IPackageInstallerService.PackageSourcesChanged - - Public Sub ShowManagePackagesDialog(packageName As String) Implements IPackageInstallerService.ShowManagePackagesDialog - Throw New NotImplementedException() - End Sub - - Public Iterator Function GetInstalledVersions(packageName As String) As IEnumerable(Of String) Implements IPackageInstallerService.GetInstalledVersions - End Function - - Public Function GetProjectsWithInstalledPackage(solution As Solution, packageName As String, version As String) As IEnumerable(Of Project) Implements IPackageInstallerService.GetProjectsWithInstalledPackage - Throw New NotImplementedException() - End Function - - Public Function IsInstalled(workspace As Workspace, projectId As ProjectId, packageName As String) As Boolean Implements IPackageInstallerService.IsInstalled - Throw New NotImplementedException() - End Function - - Public Function TryInstallPackage(workspace As Workspace, documentId As DocumentId, source As String, packageName As String, versionOpt As String, cancellationToken As CancellationToken) As Boolean Implements IPackageInstallerService.TryInstallPackage - Throw New NotImplementedException() - End Function - End Class - - Private Class TestLogService - Implements IPackageSearchLogService - - Public Shared ReadOnly Instance As TestLogService = New TestLogService() - - Private Sub New() - End Sub - - Public Sub LogException(e As Exception, text As String) Implements IPackageSearchLogService.LogException - End Sub - - Public Sub LogInfo(text As String) Implements IPackageSearchLogService.LogInfo - End Sub - End Class - End Class -End Namespace \ No newline at end of file diff --git a/src/VisualStudio/Core/Test/ServicesVisualStudioTest.vbproj b/src/VisualStudio/Core/Test/ServicesVisualStudioTest.vbproj index 8cd097525b73c..6da6ba87523cc 100644 --- a/src/VisualStudio/Core/Test/ServicesVisualStudioTest.vbproj +++ b/src/VisualStudio/Core/Test/ServicesVisualStudioTest.vbproj @@ -310,7 +310,7 @@ - + diff --git a/src/VisualStudio/Core/Test/SymbolSearch/SymbolSearchServiceTests.vb b/src/VisualStudio/Core/Test/SymbolSearch/SymbolSearchServiceTests.vb new file mode 100644 index 0000000000000..800e2a4207c46 --- /dev/null +++ b/src/VisualStudio/Core/Test/SymbolSearch/SymbolSearchServiceTests.vb @@ -0,0 +1,827 @@ +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports System.Collections.Immutable +Imports System.IO +Imports System.IO.Compression +Imports System.Threading +Imports System.Threading.Tasks +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces +Imports Microsoft.CodeAnalysis.Elfie.Model +Imports Microsoft.CodeAnalysis.Packaging +Imports Microsoft.Internal.VisualStudio.Shell.Interop +Imports Microsoft.VisualStudio.LanguageServices.SymbolSearch +Imports Moq +Imports Roslyn.Test.Utilities + +Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.SymbolSearch + Public Class SymbolSearchServiceTests + Private Shared ReadOnly s_allButMoqExceptions As Func(Of Exception, Boolean) = + Function(e) TypeOf e IsNot MockException + + + Public Async Function CreateCacheFolderIfMissing() As Task + Using workspace = Await TestWorkspace.CreateCSharpAsync("") + Dim cancellationTokenSource = New CancellationTokenSource() + + Dim ioMock = New Mock(Of IIOService)(MockBehavior.Strict) + + ' Simulate the cache folder being missing. + ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) + + ' Expect that the cache directory is created. Cancel processing at that point so + ' the test can complete. + ioMock.Setup(Sub(s) s.Create(It.IsAny(Of DirectoryInfo))).Callback( + AddressOf cancellationTokenSource.Cancel) + + Dim remoteControlService = New Mock(Of IRemoteControlService) + + Dim service = New SymbolSearchService( + workspace, + installerService:=TestInstallerService.Instance, + remoteControlService:=remoteControlService.Object, + logService:=TestLogService.Instance, + delayService:=TestDelayService.Instance, + ioService:=ioMock.Object, + patchService:=Nothing, + databaseFactoryService:=Nothing, + localSettingsDirectory:="TestDirectory", + reportAndSwallowException:=s_allButMoqExceptions, + cancellationTokenSource:=cancellationTokenSource) + + Await service.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource) + ioMock.Verify() + remoteControlService.Verify() + End Using + End Function + + + Public Async Function DoNotCreateCacheFolderIfItIsThere() As Task + Using workspace = Await TestWorkspace.CreateCSharpAsync("") + Dim cancellationTokenSource = New CancellationTokenSource() + + Dim ioMock = New Mock(Of IIOService)(MockBehavior.Strict) + + ' Simulate the cache folder being there. We use a 'strict' mock so that + ' we'll throw if we get the call to create the directory. + ioMock.Setup(Function(s) s.Exists(It.IsAny(Of DirectoryInfo))).Returns(True).Callback( + AddressOf cancellationTokenSource.Cancel) + + Dim remoteControlService = New Mock(Of IRemoteControlService) + + Dim service = New SymbolSearchService( + workspace, + installerService:=TestInstallerService.Instance, + remoteControlService:=remoteControlService.Object, + logService:=TestLogService.Instance, + delayService:=TestDelayService.Instance, + ioService:=ioMock.Object, + patchService:=Nothing, + databaseFactoryService:=Nothing, + localSettingsDirectory:="TestDirectory", + reportAndSwallowException:=s_allButMoqExceptions, + cancellationTokenSource:=cancellationTokenSource) + + Await service.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource) + ioMock.Verify() + remoteControlService.Verify() + End Using + End Function + + + Public Async Function DownloadFullDatabaseWhenLocalDatabaseIsMissing() As Task + Using workspace = Await TestWorkspace.CreateCSharpAsync("") + Dim cancellationTokenSource = New CancellationTokenSource() + + Dim ioMock = New Mock(Of IIOService)() + + ' Simlute the local database being missing. + ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) + + Dim clientMock = New Mock(Of IRemoteControlClient) + + Dim serviceMock = New Mock(Of IRemoteControlService)(MockBehavior.Strict) + + ' The client should request the 'Latest' database from the server. + ' Cancel processing at that point so the test can complete. + serviceMock.Setup( + Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Latest.*"), It.IsAny(Of Integer))). + Returns(clientMock.Object). + Callback(AddressOf cancellationTokenSource.Cancel) + + Dim searchService = New SymbolSearchService( + workspace, + installerService:=TestInstallerService.Instance, + remoteControlService:=serviceMock.Object, + logService:=TestLogService.Instance, + delayService:=TestDelayService.Instance, + ioService:=ioMock.Object, + patchService:=Nothing, + databaseFactoryService:=Nothing, + localSettingsDirectory:="TestDirectory", + reportAndSwallowException:=s_allButMoqExceptions, + cancellationTokenSource:=cancellationTokenSource) + + Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource) + ioMock.Verify() + serviceMock.Verify() + clientMock.Verify() + End Using + End Function + + + Public Async Function FailureToParseFullDBAtXmlLevelTakesCatastrophicPath() As Task + Using workspace = Await TestWorkspace.CreateCSharpAsync("") + Dim cancellationTokenSource = New CancellationTokenSource() + + Dim ioMock = New Mock(Of IIOService)() + + ' Simlute the local database being missing. + ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) + + Dim clientMock = CreateClientMock(CreateStream(New XElement("Database", + New XAttribute(SymbolSearchService.ContentAttributeName, ""), + New XAttribute(SymbolSearchService.ChecksumAttributeName, Convert.ToBase64String(New Byte() {0, 1, 2}))))) + + Dim serviceMock = New Mock(Of IRemoteControlService)(MockBehavior.Strict) + + ' The client should request the 'Latest' database from the server. + ' Cancel processing at that point so the test can complete. + serviceMock.Setup( + Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Latest.*"), It.IsAny(Of Integer))). + Returns(clientMock.Object) + + Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict) + delayMock.SetupGet(Function(s) s.CatastrophicFailureDelay).Returns(TimeSpan.Zero).Callback( + AddressOf cancellationTokenSource.Cancel) + + Dim searchService = New SymbolSearchService( + workspace, + installerService:=TestInstallerService.Instance, + remoteControlService:=serviceMock.Object, + logService:=TestLogService.Instance, + delayService:=delayMock.Object, + ioService:=ioMock.Object, + patchService:=Nothing, + databaseFactoryService:=Nothing, + localSettingsDirectory:="TestDirectory", + reportAndSwallowException:=s_allButMoqExceptions, + cancellationTokenSource:=cancellationTokenSource) + + Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource) + ioMock.Verify() + serviceMock.Verify() + clientMock.Verify() + delayMock.Verify() + End Using + End Function + + + Public Async Function TestClientDisposedAfterUse() As Task + Using workspace = Await TestWorkspace.CreateCSharpAsync("") + Dim cancellationTokenSource = New CancellationTokenSource() + + Dim ioMock = New Mock(Of IIOService)() + ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) + + Dim clientMock = New Mock(Of IRemoteControlClient)(MockBehavior.Strict) + clientMock.Setup(Sub(c) c.Dispose()) + + Dim serviceMock = New Mock(Of IRemoteControlService)(MockBehavior.Strict) + serviceMock.Setup( + Function(s) s.CreateClient(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Integer))). + Returns(clientMock.Object). + Callback(AddressOf cancellationTokenSource.Cancel) + + Dim searchService = New SymbolSearchService( + workspace, + installerService:=TestInstallerService.Instance, + remoteControlService:=serviceMock.Object, + logService:=TestLogService.Instance, + delayService:=TestDelayService.Instance, + ioService:=ioMock.Object, + patchService:=Nothing, + databaseFactoryService:=Nothing, + localSettingsDirectory:="TestDirectory", + reportAndSwallowException:=s_allButMoqExceptions, + cancellationTokenSource:=cancellationTokenSource) + + Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource) + ioMock.Verify() + serviceMock.Verify() + clientMock.Verify() + End Using + End Function + + + Public Async Function CrashInClientRunsFailureLoopPath() As Task + Using workspace = Await TestWorkspace.CreateCSharpAsync("") + Dim cancellationTokenSource = New CancellationTokenSource() + + Dim ioMock = New Mock(Of IIOService)() + + ' Simulate the database not being there. + ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) + + Dim clientMock = New Mock(Of IRemoteControlClient)(MockBehavior.Strict) + + ' We should get a call to try to read the file. Simulate a crash in the client. + clientMock.Setup(Sub(c) c.ReadFileAsync(It.IsAny(Of __VsRemoteControlBehaviorOnStale))). + Throws(New NotImplementedException()) + + ' Client should be disposed. + clientMock.Setup(Sub(c) c.Dispose()) + + Dim remoteControlMock = New Mock(Of IRemoteControlService)(MockBehavior.Strict) + remoteControlMock.Setup( + Function(s) s.CreateClient(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Integer))). + Returns(clientMock.Object) + + ' Because the client failed we will expect to call into the 'UpdateFailedDelay' to + ' control when we do our next loop. + ' Cancel processing at that point so the test can complete. + Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict) + delayMock.SetupGet(Function(s) s.ExpectedFailureDelay).Returns(TimeSpan.Zero).Callback( + AddressOf cancellationTokenSource.Cancel) + + Dim searchService = New SymbolSearchService( + workspace, + installerService:=TestInstallerService.Instance, + remoteControlService:=remoteControlMock.Object, + logService:=TestLogService.Instance, + delayService:=delayMock.Object, + ioService:=ioMock.Object, + patchService:=Nothing, + databaseFactoryService:=Nothing, + localSettingsDirectory:="TestDirectory", + reportAndSwallowException:=s_allButMoqExceptions, + cancellationTokenSource:=cancellationTokenSource) + + Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource) + ioMock.Verify() + remoteControlMock.Verify() + clientMock.Verify() + delayMock.Verify() + End Using + End Function + + + Public Async Function FailureToParseFullDBAtElfieLevelTakesCatastrophicPath() As Task + Using workspace = Await TestWorkspace.CreateCSharpAsync("") + Dim cancellationTokenSource = New CancellationTokenSource() + + Dim ioMock = New Mock(Of IIOService)() + 'Simulate the database file not existing. + ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) + + ' Get a client that will download the latest database. + Dim clientMock = CreateFullDatabaseClientMock() + Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=True) + + Dim factoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict) + ' Simulate Elfie throwing when trying to make a database from the contents of that response + factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). + Throws(New NotImplementedException()) + + ' Because the parsing failed we will expect to call into the 'UpdateFailedDelay' to + ' control when we do our next loop. + ' Cancel processing at that point so the test can complete. + Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict) + delayMock.SetupGet(Function(s) s.CatastrophicFailureDelay).Returns(TimeSpan.Zero).Callback( + AddressOf cancellationTokenSource.Cancel) + + Dim searchService = New SymbolSearchService( + workspace, + installerService:=TestInstallerService.Instance, + remoteControlService:=remoteControlMock.Object, + logService:=TestLogService.Instance, + delayService:=delayMock.Object, + ioService:=ioMock.Object, + patchService:=Nothing, + databaseFactoryService:=factoryMock.Object, + localSettingsDirectory:="TestDirectory", + reportAndSwallowException:=s_allButMoqExceptions, + cancellationTokenSource:=cancellationTokenSource) + + Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource) + ioMock.Verify() + remoteControlMock.Verify() + clientMock.Verify() + delayMock.Verify() + factoryMock.Verify() + End Using + End Function + + + Public Async Function SuccessParsingDBWritesToDisk() As Task + Using workspace = Await TestWorkspace.CreateCSharpAsync("") + Dim cancellationTokenSource = New CancellationTokenSource() + + Dim ioMock = New Mock(Of IIOService)() + ' Simulate the local database not being there. + ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) + + ' Create a client that will download the latest database. + Dim clientMock = CreateFullDatabaseClientMock() + Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=True) + + ' Successfully create a database from that response. + Dim factoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict) + factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). + Returns(New AddReferenceDatabase()) + + ' Expect that we'll write the database to disk successfully. + SetupWritesDatabaseSuccessfullyToDisk(ioMock) + + Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict) + + ' Because writing to disk succeeded, we expect we'll loop on the 'UpdateSucceededDelay'. + ' Cancel processing at that point so the test can complete. + delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero). + Callback(AddressOf cancellationTokenSource.Cancel) + + Dim searchService = New SymbolSearchService( + workspace, + installerService:=TestInstallerService.Instance, + remoteControlService:=remoteControlMock.Object, + logService:=TestLogService.Instance, + delayService:=delayMock.Object, + ioService:=ioMock.Object, + patchService:=Nothing, + databaseFactoryService:=factoryMock.Object, + localSettingsDirectory:="TestDirectory", + reportAndSwallowException:=s_allButMoqExceptions, + cancellationTokenSource:=cancellationTokenSource) + + Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource) + ioMock.Verify() + remoteControlMock.Verify() + clientMock.Verify() + delayMock.Verify() + factoryMock.Verify() + End Using + End Function + + + Public Async Function WriteAgainOnIOFailure() As Task + Using workspace = Await TestWorkspace.CreateCSharpAsync("") + Dim cancellationTokenSource = New CancellationTokenSource() + + Dim ioMock = New Mock(Of IIOService)() + + ' Simulate the database being missing. + ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(False) + + ' Create a client that will download the latest databsae + Dim clientMock = CreateFullDatabaseClientMock() + Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=True) + + ' Create a database from the client response. + Dim factoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict) + factoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). + Returns(New AddReferenceDatabase()) + + Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict) + + ' Write the temp file out to disk. + ioMock.Setup(Sub(s) s.WriteAndFlushAllBytes(It.IsAny(Of String), It.IsAny(Of Byte()))) + + ' Simulate a failure doing the first 'replace' of the database file. + ioMock.Setup(Sub(s) s.Replace(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Boolean))). + Throws(New IOException()) + + ' We'll expect to have to replay the write. So we should get a call to 'FileWriteDelay' + delayMock.SetupGet(Function(s) s.FileWriteDelay).Returns(TimeSpan.Zero) + + ' Succeed on the second write attempt. + ioMock.Setup(Sub(s) s.Replace(It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of String), It.IsAny(Of Boolean))) + + ' Because writing to disk succeeded, we expect we'll loop on the 'UpdateSucceededDelay'. + ' Cancel processing at that point so the test can complete. + delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero). + Callback(AddressOf cancellationTokenSource.Cancel) + + Dim searchService = New SymbolSearchService( + workspace, + installerService:=TestInstallerService.Instance, + remoteControlService:=remoteControlMock.Object, + logService:=TestLogService.Instance, + delayService:=delayMock.Object, + ioService:=ioMock.Object, + patchService:=Nothing, + databaseFactoryService:=factoryMock.Object, + localSettingsDirectory:="TestDirectory", + reportAndSwallowException:=s_allButMoqExceptions, + cancellationTokenSource:=cancellationTokenSource) + + Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource) + ioMock.Verify() + remoteControlMock.Verify() + clientMock.Verify() + delayMock.Verify() + factoryMock.Verify() + End Using + End Function + + + Public Async Function LocalDatabaseExistingCausesPatchToDownload_UpToDate_DoesNothing() As Task + Using workspace = Await TestWorkspace.CreateCSharpAsync("") + Dim cancellationTokenSource = New CancellationTokenSource() + + Dim ioMock = New Mock(Of IIOService)() + + ' Simulate the database being there. + ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True) + + ' We'll successfully read in the local database. + Dim databaseFactoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict) + databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). + Returns(New AddReferenceDatabase()) + + ' Create a client that will return a patch that says things are up to date. + Dim clientMock = CreatePatchClientMock(isUpToDate:=True) + Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False) + + Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict) + + ' Because everything is up to date, we expect we'll loop on the 'UpdateSucceededDelay'. + ' Cancel processing at that point so the test can complete. + delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero). + Callback(AddressOf cancellationTokenSource.Cancel) + + Dim searchService = New SymbolSearchService( + workspace, + installerService:=TestInstallerService.Instance, + remoteControlService:=remoteControlMock.Object, + logService:=TestLogService.Instance, + delayService:=delayMock.Object, + ioService:=ioMock.Object, + patchService:=Nothing, + databaseFactoryService:=databaseFactoryMock.Object, + localSettingsDirectory:="TestDirectory", + reportAndSwallowException:=s_allButMoqExceptions, + cancellationTokenSource:=cancellationTokenSource) + + Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource) + ioMock.Verify() + remoteControlMock.Verify() + clientMock.Verify() + delayMock.Verify() + databaseFactoryMock.Verify() + End Using + End Function + + + Public Async Function LocalDatabaseExistingCausesPatchToDownload_IsTooOldCausesFullDownload() As Task + Using workspace = Await TestWorkspace.CreateCSharpAsync("") + Dim cancellationTokenSource = New CancellationTokenSource() + + Dim ioMock = New Mock(Of IIOService)() + + ' Simulate the database being there. + ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True) + + ' We'll successfully read in the local database. + Dim databaseFactoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict) + databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). + Returns(New AddReferenceDatabase()) + + ' Create a client that will return a patch that says things are too old. + Dim clientMock = CreatePatchClientMock(isTooOld:=True) + Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False) + + ' This should cause us to want to then download the full db. So now + ' setup an expectation that we'll download the latest. + Dim clientMock2 = CreateFullDatabaseClientMock() + SetupDownloadLatest(remoteControlMock, clientMock2) + + ' Expect that we'll write the database to disk successfully. + SetupWritesDatabaseSuccessfullyToDisk(ioMock) + + Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict) + + ' Because we got the full database, we expect we'll loop on the 'UpdateSucceededDelay'. + ' Cancel processing at that point so the test can complete. + delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero). + Callback(AddressOf cancellationTokenSource.Cancel) + + Dim searchService = New SymbolSearchService( + workspace, + installerService:=TestInstallerService.Instance, + remoteControlService:=remoteControlMock.Object, + logService:=TestLogService.Instance, + delayService:=delayMock.Object, + ioService:=ioMock.Object, + patchService:=Nothing, + databaseFactoryService:=databaseFactoryMock.Object, + localSettingsDirectory:="TestDirectory", + reportAndSwallowException:=s_allButMoqExceptions, + cancellationTokenSource:=cancellationTokenSource) + + Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource) + ioMock.Verify() + remoteControlMock.Verify() + clientMock.Verify() + clientMock2.Verify() + delayMock.Verify() + databaseFactoryMock.Verify() + End Using + End Function + + + Public Async Function LocalDatabaseExistingCausesPatchToDownload_ContentsCausesPatching_FailureToPatchCausesFullDownload() As Task + Using workspace = Await TestWorkspace.CreateCSharpAsync("") + Dim cancellationTokenSource = New CancellationTokenSource() + + Dim ioMock = New Mock(Of IIOService)() + + ' Simulate the database being there. + ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True) + + ' We'll successfully read in the local database. + Dim databaseFactoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict) + databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). + Returns(New AddReferenceDatabase()) + + ' Create a client that will return a patch with contents. + Dim clientMock = CreatePatchClientMock(contents:="") + Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False) + + ' Simulate a crash in the patching process. + Dim patchService = New Mock(Of IPatchService)(MockBehavior.Strict) + patchService.Setup(Sub(s) s.ApplyPatch(It.IsAny(Of Byte()), It.IsAny(Of Byte()))). + Throws(New NotImplementedException()) + + ' This should cause us to want to then download the full db. So now + ' setup an expectation that we'll download the latest. + Dim clientMock2 = CreateFullDatabaseClientMock() + SetupDownloadLatest(remoteControlMock, clientMock2) + + ' Expect that we'll write the database to disk successfully. + SetupWritesDatabaseSuccessfullyToDisk(ioMock) + + Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict) + + ' Because we wrote the full database, we expect we'll loop on the 'UpdateSucceededDelay'. + ' Cancel processing at that point so the test can complete. + delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero). + Callback(AddressOf cancellationTokenSource.Cancel) + + Dim searchService = New SymbolSearchService( + workspace, + installerService:=TestInstallerService.Instance, + remoteControlService:=remoteControlMock.Object, + logService:=TestLogService.Instance, + delayService:=delayMock.Object, + ioService:=ioMock.Object, + patchService:=Nothing, + databaseFactoryService:=databaseFactoryMock.Object, + localSettingsDirectory:="TestDirectory", + reportAndSwallowException:=s_allButMoqExceptions, + cancellationTokenSource:=cancellationTokenSource) + + Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource) + ioMock.Verify() + remoteControlMock.Verify() + clientMock.Verify() + clientMock2.Verify() + patchService.Verify() + delayMock.Verify() + databaseFactoryMock.Verify() + End Using + End Function + + + Public Async Function LocalDatabaseExistingCausesPatchToDownload_ContentsCausesPatching_SuccessfulPatchWritesToDisk() As Task + Using workspace = Await TestWorkspace.CreateCSharpAsync("") + Dim cancellationTokenSource = New CancellationTokenSource() + + Dim ioMock = New Mock(Of IIOService)() + + ' Simulate the database being there. + ioMock.Setup(Function(s) s.Exists(It.IsAny(Of FileSystemInfo))).Returns(True) + + ' We'll successfully read in the local database. + Dim databaseFactoryMock = New Mock(Of IDatabaseFactoryService)(MockBehavior.Strict) + databaseFactoryMock.Setup(Function(f) f.CreateDatabaseFromBytes(It.IsAny(Of Byte()))). + Returns(New AddReferenceDatabase()) + + ' Create a client that will return a patch with contents. + Dim clientMock = CreatePatchClientMock(contents:="") + Dim remoteControlMock = CreateRemoteControlServiceMock(clientMock, latest:=False) + + ' Simulate a crash in the patching process. + Dim patchMock = New Mock(Of IPatchService)(MockBehavior.Strict) + patchMock.Setup(Function(s) s.ApplyPatch(It.IsAny(Of Byte()), It.IsAny(Of Byte()))). + Returns(New Byte() {0}) + + ' Expect that we'll write the database to disk successfully. + SetupWritesDatabaseSuccessfullyToDisk(ioMock) + + Dim delayMock = New Mock(Of IDelayService)(MockBehavior.Strict) + + ' Because we wrote the full database, we expect we'll loop on the 'UpdateSucceededDelay'. + ' Cancel processing at that point so the test can complete. + delayMock.SetupGet(Function(s) s.UpdateSucceededDelay).Returns(TimeSpan.Zero). + Callback(AddressOf cancellationTokenSource.Cancel) + + Dim searchService = New SymbolSearchService( + workspace, + installerService:=TestInstallerService.Instance, + remoteControlService:=remoteControlMock.Object, + logService:=TestLogService.Instance, + delayService:=delayMock.Object, + ioService:=ioMock.Object, + patchService:=patchMock.Object, + databaseFactoryService:=databaseFactoryMock.Object, + localSettingsDirectory:="TestDirectory", + reportAndSwallowException:=s_allButMoqExceptions, + cancellationTokenSource:=cancellationTokenSource) + + Await searchService.UpdateSourceInBackgroundAsync(SymbolSearchService.NugetOrgSource) + ioMock.Verify() + remoteControlMock.Verify() + clientMock.Verify() + patchMock.Verify() + delayMock.Verify() + databaseFactoryMock.Verify() + End Using + End Function + + Private Shared Sub SetupWritesDatabaseSuccessfullyToDisk(ioMock As Mock(Of IIOService)) + ' Expect that we'll write out the temp file. + ioMock.Setup(Sub(s) s.WriteAndFlushAllBytes(It.IsRegex(".*tmp"), It.IsAny(Of Byte()))) + + ' Expect that we'll replace the existing file with the temp file. + ioMock.Setup(Sub(s) s.Replace(It.IsRegex(".*tmp"), It.IsRegex(".*txt"), Nothing, It.IsAny(Of Boolean))) + End Sub + + Private Shared Function CreateRemoteControlServiceMock( + clientMock As Mock(Of IRemoteControlClient), + latest As Boolean) As Mock(Of IRemoteControlService) + Dim remoteControlMock = New Mock(Of IRemoteControlService)(MockBehavior.Strict) + + If latest Then + SetupDownloadLatest(remoteControlMock, clientMock) + Else + SetupDownloadPatch(clientMock, remoteControlMock) + End If + Return remoteControlMock + End Function + + Private Shared Sub SetupDownloadPatch(clientMock As Mock(Of IRemoteControlClient), remoteControlMock As Mock(Of IRemoteControlService)) + remoteControlMock.Setup( + Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Patch.*"), It.IsAny(Of Integer))). + Returns(clientMock.Object) + End Sub + + Private Shared Sub SetupDownloadLatest(remoteControlMock As Mock(Of IRemoteControlService), clientMock As Mock(Of IRemoteControlClient)) + remoteControlMock.Setup( + Function(s) s.CreateClient(It.IsAny(Of String), It.IsRegex(".*Latest.*"), It.IsAny(Of Integer))). + Returns(clientMock.Object) + End Sub + + Private Function CreateFullDatabaseClientMock() As Mock(Of IRemoteControlClient) + Return CreateClientMock(CreateFullDownloadElementStream()) + End Function + + Private Function CreateClientMock(stream As Stream) As Mock(Of IRemoteControlClient) + Dim clientMock = New Mock(Of IRemoteControlClient)(MockBehavior.Strict) + + ' Return a full database element when the service asks for it. + clientMock.Setup(Function(c) c.ReadFileAsync(It.IsAny(Of __VsRemoteControlBehaviorOnStale))). + Returns(Task.FromResult(stream)) + ' Always dispose the client when we get a response. + clientMock.Setup(Sub(c) c.Dispose()) + Return clientMock + End Function + + Private Function CreatePatchClientMock(Optional isUpToDate As Boolean = False, + Optional isTooOld As Boolean = False, + Optional contents As String = Nothing) As Mock(Of IRemoteControlClient) + Return CreateClientMock(CreatePatchElementStream(isUpToDate, isTooOld, contents)) + End Function + + Private Function CreatePatchElementStream(Optional isUpToDate As Boolean = False, + Optional isTooOld As Boolean = False, + Optional contents As String = Nothing) As Stream + Dim element = New XElement("Patch", + If(isUpToDate, New XAttribute(SymbolSearchService.UpToDateAttributeName, True), Nothing), + If(isTooOld, New XAttribute(SymbolSearchService.TooOldAttributeName, True), Nothing), + If(contents IsNot Nothing, New XAttribute(SymbolSearchService.ContentAttributeName, contents), Nothing)) + + Return CreateStream(element) + End Function + + Private Function CreateFullDownloadElementStream() As Stream + Dim saveStream = New MemoryStream() + Dim zipStream = New DeflateStream(saveStream, CompressionMode.Compress) + zipStream.Write(New Byte() {0}, 0, 1) + zipStream.Flush() + Dim contents = Convert.ToBase64String(saveStream.ToArray()) + + Return CreateStream(New XElement("Database", + New XAttribute(SymbolSearchService.ContentAttributeName, contents))) + End Function + + Private Function CreateStream(element As XElement) As Stream + Dim stream = New MemoryStream() + element.Save(stream) + stream.Position = 0 + Return stream + End Function + + Private Class TestDelayService + Implements IDelayService + + Public Shared ReadOnly Instance As TestDelayService = New TestDelayService() + + Private Sub New() + End Sub + + Public ReadOnly Property CachePollDelay As TimeSpan Implements IDelayService.CachePollDelay + Get + Return TimeSpan.Zero + End Get + End Property + + Public ReadOnly Property FileWriteDelay As TimeSpan Implements IDelayService.FileWriteDelay + Get + Return TimeSpan.Zero + End Get + End Property + + Public ReadOnly Property ExpectedFailureDelay As TimeSpan Implements IDelayService.ExpectedFailureDelay + Get + Return TimeSpan.Zero + End Get + End Property + + Public ReadOnly Property UpdateSucceededDelay As TimeSpan Implements IDelayService.UpdateSucceededDelay + Get + Return TimeSpan.Zero + End Get + End Property + + Public ReadOnly Property CatastrophicFailureDelay As TimeSpan Implements IDelayService.CatastrophicFailureDelay + Get + Return TimeSpan.Zero + End Get + End Property + End Class + + Private Class TestInstallerService + Implements IPackageInstallerService + + Public Shared ReadOnly Instance As IPackageInstallerService = New TestInstallerService() + + Public ReadOnly Property IsEnabled As Boolean Implements IPackageInstallerService.IsEnabled + Get + Return True + End Get + End Property + + Public ReadOnly Property PackageSources As ImmutableArray(Of PackageSource) Implements IPackageInstallerService.PackageSources + Get + Throw New NotImplementedException() + End Get + End Property + + Public Event PackageSourcesChanged As EventHandler Implements IPackageInstallerService.PackageSourcesChanged + + Public Sub ShowManagePackagesDialog(packageName As String) Implements IPackageInstallerService.ShowManagePackagesDialog + Throw New NotImplementedException() + End Sub + + Public Iterator Function GetInstalledVersions(packageName As String) As IEnumerable(Of String) Implements IPackageInstallerService.GetInstalledVersions + End Function + + Public Function GetProjectsWithInstalledPackage(solution As Solution, packageName As String, version As String) As IEnumerable(Of Project) Implements IPackageInstallerService.GetProjectsWithInstalledPackage + Throw New NotImplementedException() + End Function + + Public Function IsInstalled(workspace As Workspace, projectId As ProjectId, packageName As String) As Boolean Implements IPackageInstallerService.IsInstalled + Throw New NotImplementedException() + End Function + + Public Function TryInstallPackage(workspace As Workspace, documentId As DocumentId, source As String, packageName As String, versionOpt As String, cancellationToken As CancellationToken) As Boolean Implements IPackageInstallerService.TryInstallPackage + Throw New NotImplementedException() + End Function + End Class + + Private Class TestLogService + Implements ILogService + + Public Shared ReadOnly Instance As TestLogService = New TestLogService() + + Private Sub New() + End Sub + + Public Sub LogException(e As Exception, text As String) Implements ILogService.LogException + End Sub + + Public Sub LogInfo(text As String) Implements ILogService.LogInfo + End Sub + End Class + End Class +End Namespace \ No newline at end of file diff --git a/src/VisualStudio/VisualBasic/Impl/BasicVSResources.Designer.vb b/src/VisualStudio/VisualBasic/Impl/BasicVSResources.Designer.vb index ba63f54099d9d..e52118374852f 100644 --- a/src/VisualStudio/VisualBasic/Impl/BasicVSResources.Designer.vb +++ b/src/VisualStudio/VisualBasic/Impl/BasicVSResources.Designer.vb @@ -226,6 +226,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic End Get End Property + ''' + ''' Looks up a localized string similar to Import Directives. + ''' + Friend Shared ReadOnly Property Option_Import_Directives() As String + Get + Return ResourceManager.GetString("Option_Import_Directives", resourceCulture) + End Get + End Property + ''' ''' Looks up a localized string similar to _Navigate to Object Browser for symbols defined in metadata. ''' @@ -290,7 +299,16 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic End Property ''' - ''' Looks up a localized string similar to Show preview for _rename tracking. + ''' Looks up a localized string similar to _Place 'System' directives first when sorting imports. + ''' + Friend Shared ReadOnly Property Option_PlaceSystemNamespaceFirst() As String + Get + Return ResourceManager.GetString("Option_PlaceSystemNamespaceFirst", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Show preview for rename _tracking. ''' Friend Shared ReadOnly Property Option_RenameTrackingPreview() As String Get @@ -298,6 +316,24 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic End Get End Property + ''' + ''' Looks up a localized string similar to Suggest imports for types in _NuGet packages. + ''' + Friend Shared ReadOnly Property Option_Suggest_imports_for_types_in_NuGet_packages() As String + Get + Return ResourceManager.GetString("Option_Suggest_imports_for_types_in_NuGet_packages", resourceCulture) + End Get + End Property + + ''' + ''' Looks up a localized string similar to Suggest imports for types in _reference assemblies. + ''' + Friend Shared ReadOnly Property Option_Suggest_imports_for_types_in_reference_assemblies() As String + Get + Return ResourceManager.GetString("Option_Suggest_imports_for_types_in_reference_assemblies", resourceCulture) + End Get + End Property + ''' ''' Looks up a localized string similar to Prefer intrinsic predefined type keyword when declaring locals, parameters and members. ''' diff --git a/src/VisualStudio/VisualBasic/Impl/BasicVSResources.resx b/src/VisualStudio/VisualBasic/Impl/BasicVSResources.resx index c2a4b9bba5601..22cd2cc8cef36 100644 --- a/src/VisualStudio/VisualBasic/Impl/BasicVSResources.resx +++ b/src/VisualStudio/VisualBasic/Impl/BasicVSResources.resx @@ -196,7 +196,7 @@ Performance - Show preview for _rename tracking + Show preview for rename _tracking _Navigate to Object Browser for symbols defined in metadata @@ -204,4 +204,16 @@ Go to Definition + + Import Directives + + + Suggest imports for types in _NuGet packages + + + Suggest imports for types in _reference assemblies + + + _Place 'System' directives first when sorting imports + \ No newline at end of file diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml index f1e1d4d10840d..de39cd91beb85 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml +++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml @@ -11,6 +11,21 @@ + + + + + + + + diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb index 0c42f0489df28..ac5e7e4e9c2b6 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageControl.xaml.vb @@ -13,6 +13,10 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options InitializeComponent() + BindToOption(PlaceSystemNamespaceFirst, OrganizerOptions.PlaceSystemNamespaceFirst, LanguageNames.VisualBasic) + BindToOption(SuggestForTypesInReferenceAssemblies, AddImportOptions.SuggestForTypesInReferenceAssemblies, LanguageNames.VisualBasic) + BindToOption(SuggestForTypesInNuGetPackages, AddImportOptions.SuggestForTypesInNuGetPackages, LanguageNames.VisualBasic) + BindToOption(EnableEndConstruct, FeatureOnOffOptions.EndConstruct, LanguageNames.VisualBasic) BindToOption(EnableOutlining, FeatureOnOffOptions.Outlining, LanguageNames.VisualBasic) BindToOption(EnableLineCommit, FeatureOnOffOptions.PrettyListing, LanguageNames.VisualBasic) diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb index 059cbe36dc87f..615d8768c642f 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/AdvancedOptionPageStrings.vb @@ -141,5 +141,28 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options End Get End Property + Public ReadOnly Property Option_Import_Directives As String + Get + Return BasicVSResources.Option_Import_Directives + End Get + End Property + + Public ReadOnly Property Option_PlaceSystemNamespaceFirst As String + Get + Return BasicVSResources.Option_PlaceSystemNamespaceFirst + End Get + End Property + + Public ReadOnly Property Option_Suggest_imports_for_types_in_reference_assemblies As String + Get + Return BasicVSResources.Option_Suggest_imports_for_types_in_reference_assemblies + End Get + End Property + + Public ReadOnly Property Option_Suggest_imports_for_types_in_NuGet_packages As String + Get + Return BasicVSResources.Option_Suggest_imports_for_types_in_NuGet_packages + End Get + End Property End Module -End Namespace +End Namespace \ No newline at end of file diff --git a/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject.vb b/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject.vb index 21018ded2105e..6b6a21f168638 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/AutomationObject.vb @@ -166,6 +166,33 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options End Set End Property + Public Property Option_PlaceSystemNamespaceFirst As Boolean + Get + Return GetBooleanOption(OrganizerOptions.PlaceSystemNamespaceFirst) + End Get + Set(value As Boolean) + SetBooleanOption(OrganizerOptions.PlaceSystemNamespaceFirst, value) + End Set + End Property + + Public Property Option_Suggest_imports_for_types_in_reference_assemblies As Boolean + Get + Return GetBooleanOption(AddImportOptions.SuggestForTypesInReferenceAssemblies) + End Get + Set(value As Boolean) + SetBooleanOption(AddImportOptions.SuggestForTypesInReferenceAssemblies, value) + End Set + End Property + + Public Property Option_Suggest_imports_for_types_in_NuGet_packages As Boolean + Get + Return GetBooleanOption(AddImportOptions.SuggestForTypesInNuGetPackages) + End Get + Set(value As Boolean) + SetBooleanOption(AddImportOptions.SuggestForTypesInNuGetPackages, value) + End Set + End Property + Private Function GetBooleanOption(key As [Option](Of Boolean)) As Boolean Return _optionService.GetOption(key) End Function diff --git a/src/VisualStudio/VisualBasic/Impl/Options/VisualBasicLanguageSettingsSerializer.vb b/src/VisualStudio/VisualBasic/Impl/Options/VisualBasicLanguageSettingsSerializer.vb index 2ba1cc53e1307..2ef7f16d2cc0b 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/VisualBasicLanguageSettingsSerializer.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/VisualBasicLanguageSettingsSerializer.vb @@ -8,9 +8,16 @@ Imports Microsoft.VisualStudio.Shell Imports Microsoft.VisualStudio.LanguageServices.Implementation.Options Imports Microsoft.CodeAnalysis.Options Imports System.Composition +Imports Microsoft.CodeAnalysis.Shared.Options Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options - + Friend NotInheritable Class VisualBasicLanguageSettingsSerializer Inherits AbstractLanguageSettingsSerializer diff --git a/src/VisualStudio/VisualBasic/Impl/Options/VisualBasicSettingsManagerOptionSerializer.vb b/src/VisualStudio/VisualBasic/Impl/Options/VisualBasicSettingsManagerOptionSerializer.vb index 629b66e2abc73..637e30c727827 100644 --- a/src/VisualStudio/VisualBasic/Impl/Options/VisualBasicSettingsManagerOptionSerializer.vb +++ b/src/VisualStudio/VisualBasic/Impl/Options/VisualBasicSettingsManagerOptionSerializer.vb @@ -17,6 +17,7 @@ Imports Microsoft.VisualStudio.Shell Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options - /// Searches for reference assemblies that contain a type with the provided name and arity. - /// Note: Implementations are free to return the results they feel best for the - /// given data. Specifically, they can do exact or fuzzy matching on the name. - /// They can use or ignore the arity depending on their capabilities. - /// - /// Implementations should return results in order from best to worst (from their - /// perspective). - /// - IEnumerable FindReferenceAssembliesWithType( - string name, int arity, CancellationToken cancellationToken); - } - - internal class ReferenceAssemblyWithTypeResult - { - public readonly IReadOnlyList ContainingNamespaceNames; - public readonly string AssemblyName; - public readonly string TypeName; - - public ReferenceAssemblyWithTypeResult( - string assemblyName, - string typeName, - IReadOnlyList containingNamespaceNames) - { - AssemblyName = assemblyName; - TypeName = typeName; - ContainingNamespaceNames = containingNamespaceNames; - } - } -} diff --git a/src/Workspaces/Core/Portable/Packaging/IPackageSearchService.cs b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchService.cs similarity index 54% rename from src/Workspaces/Core/Portable/Packaging/IPackageSearchService.cs rename to src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchService.cs index b882f0a25bc84..d753279dd8129 100644 --- a/src/Workspaces/Core/Portable/Packaging/IPackageSearchService.cs +++ b/src/Workspaces/Core/Portable/SymbolSearch/ISymbolSearchService.cs @@ -4,9 +4,9 @@ using System.Threading; using Microsoft.CodeAnalysis.Host; -namespace Microsoft.CodeAnalysis.Packaging +namespace Microsoft.CodeAnalysis.SymbolSearch { - internal interface IPackageSearchService : IWorkspaceService + internal interface ISymbolSearchService : IWorkspaceService { /// /// Searches for packages that contain a type with the provided name and arity. @@ -19,6 +19,18 @@ internal interface IPackageSearchService : IWorkspaceService /// IEnumerable FindPackagesWithType( string source, string name, int arity, CancellationToken cancellationToken); + + /// + /// Searches for reference assemblies that contain a type with the provided name and arity. + /// Note: Implementations are free to return the results they feel best for the + /// given data. Specifically, they can do exact or fuzzy matching on the name. + /// They can use or ignore the arity depending on their capabilities. + /// + /// Implementations should return results in order from best to worst (from their + /// perspective). + /// + IEnumerable FindReferenceAssembliesWithType( + string name, int arity, CancellationToken cancellationToken); } internal class PackageWithTypeResult @@ -40,4 +52,21 @@ internal class PackageWithTypeResult ContainingNamespaceNames = containingNamespaceNames; } } + + internal class ReferenceAssemblyWithTypeResult + { + public readonly IReadOnlyList ContainingNamespaceNames; + public readonly string AssemblyName; + public readonly string TypeName; + + public ReferenceAssemblyWithTypeResult( + string assemblyName, + string typeName, + IReadOnlyList containingNamespaceNames) + { + AssemblyName = assemblyName; + TypeName = typeName; + ContainingNamespaceNames = containingNamespaceNames; + } + } } diff --git a/src/Workspaces/Core/Portable/Workspaces.csproj b/src/Workspaces/Core/Portable/Workspaces.csproj index 10cb22dfc939b..9b6791a195209 100644 --- a/src/Workspaces/Core/Portable/Workspaces.csproj +++ b/src/Workspaces/Core/Portable/Workspaces.csproj @@ -396,11 +396,10 @@ - + - @@ -981,4 +980,4 @@ - + \ No newline at end of file