From f30babb4cfec0c23b92ca9b7b43ee7f5ee375b2c Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Tue, 23 Apr 2019 14:42:16 -0700 Subject: [PATCH 1/7] Add IDocumentSupportsFeatureService --- ...ractiveTextBufferSupportsFeatureService.cs | 25 ++++++- .../ITextBufferSupportsFeatureService.cs | 1 + .../Shared/IDocumentSupportsFeatureService.cs | 33 +++++++++ ...lStudioTextBufferSupportsFeatureService.cs | 67 +++++++++++++++---- .../Mef/ExportWorkspaceServiceAttribute.cs | 2 +- 5 files changed, 111 insertions(+), 17 deletions(-) create mode 100644 src/Features/Core/Portable/Shared/IDocumentSupportsFeatureService.cs diff --git a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveTextBufferSupportsFeatureService.cs b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveTextBufferSupportsFeatureService.cs index 75bcb6c7bc582..a5d3c8d3d0527 100644 --- a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveTextBufferSupportsFeatureService.cs +++ b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveTextBufferSupportsFeatureService.cs @@ -3,14 +3,14 @@ using System.Composition; using Microsoft.CodeAnalysis.Editor.Shared; using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.InteractiveWindow; +using Microsoft.CodeAnalysis.Shared; namespace Microsoft.CodeAnalysis.Editor.Implementation.Interactive { [ExportWorkspaceService(typeof(ITextBufferSupportsFeatureService), WorkspaceKind.Interactive), Shared] - internal sealed class InteractiveTextBufferSupportsFeatureService : ITextBufferSupportsFeatureService + internal sealed class InteractiveTextBufferSupportsFeatureService : ITextBufferSupportsFeatureService, IDocumentSupportsFeatureService { public bool SupportsCodeFixes(ITextBuffer textBuffer) { @@ -45,5 +45,26 @@ public bool SupportsNavigationToAnyPosition(ITextBuffer textBuffer) { return true; } + + public bool SupportsCodeFixes(Document document) + { + // TODO: Implement this. + return false; + } + + public bool SupportsRefactorings(Document document) + { + return false; + } + + public bool SupportsRename(Document document) + { + return false; + } + + public bool SupportsNavigationToAnyPosition(Document document) + { + return true; + } } } diff --git a/src/EditorFeatures/Core/Shared/ITextBufferSupportsFeatureService.cs b/src/EditorFeatures/Core/Shared/ITextBufferSupportsFeatureService.cs index 35828e076cdd0..2777f21c0a263 100644 --- a/src/EditorFeatures/Core/Shared/ITextBufferSupportsFeatureService.cs +++ b/src/EditorFeatures/Core/Shared/ITextBufferSupportsFeatureService.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Shared; using Microsoft.VisualStudio.Text; namespace Microsoft.CodeAnalysis.Editor.Shared diff --git a/src/Features/Core/Portable/Shared/IDocumentSupportsFeatureService.cs b/src/Features/Core/Portable/Shared/IDocumentSupportsFeatureService.cs new file mode 100644 index 0000000000000..8141ed1a9d0f4 --- /dev/null +++ b/src/Features/Core/Portable/Shared/IDocumentSupportsFeatureService.cs @@ -0,0 +1,33 @@ +// 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.Composition; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; + +namespace Microsoft.CodeAnalysis.Shared +{ + internal interface IDocumentSupportsFeatureService : IWorkspaceService + { + bool SupportsCodeFixes(Document document); + bool SupportsRefactorings(Document document); + bool SupportsRename(Document document); + bool SupportsNavigationToAnyPosition(Document document); + } + + + [ExportWorkspaceService(typeof(IDocumentSupportsFeatureService), ServiceLayer.Default), Shared] + internal class DefaultDocumentSupportsFeatureService : IDocumentSupportsFeatureService + { + public bool SupportsCodeFixes(Document document) + => true; + + public bool SupportsNavigationToAnyPosition(Document document) + => true; + + public bool SupportsRefactorings(Document document) + => true; + + public bool SupportsRename(Document document) + => true; + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/VisualStudioTextBufferSupportsFeatureService.cs b/src/VisualStudio/Core/Def/Implementation/VisualStudioTextBufferSupportsFeatureService.cs index 6de3b3ab38d28..4877626eaa584 100644 --- a/src/VisualStudio/Core/Def/Implementation/VisualStudioTextBufferSupportsFeatureService.cs +++ b/src/VisualStudio/Core/Def/Implementation/VisualStudioTextBufferSupportsFeatureService.cs @@ -1,10 +1,12 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Collections.Immutable; using System.Composition; using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor.Shared; using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Microsoft.VisualStudio.LanguageServices.Implementation.Venus; @@ -12,17 +14,19 @@ namespace Microsoft.VisualStudio.LanguageServices.Implementation.SuggestionService { - [ExportWorkspaceService(typeof(ITextBufferSupportsFeatureService), ServiceLayer.Host), Shared] - internal sealed class VisualStudioTextBufferSupportsFeatureService : ITextBufferSupportsFeatureService + [Shared] + [ExportWorkspaceService(typeof(IDocumentSupportsFeatureService), ServiceLayer.Host)] + [ExportWorkspaceService(typeof(ITextBufferSupportsFeatureService), ServiceLayer.Host)] + internal sealed class VisualStudioTextBufferSupportsFeatureService : ITextBufferSupportsFeatureService, IDocumentSupportsFeatureService { public bool SupportsCodeFixes(ITextBuffer textBuffer) { - return GetContainedDocument(textBuffer) == null; + return SupportsCodeFixesWorker(GetContainedDocumentId(textBuffer)); } public bool SupportsRefactorings(ITextBuffer textBuffer) { - return GetContainedDocument(textBuffer) == null; + return SupportsRefactoringsWorker(GetContainedDocumentId(textBuffer)); } public bool SupportsRename(ITextBuffer textBuffer) @@ -30,9 +34,7 @@ public bool SupportsRename(ITextBuffer textBuffer) var sourceTextContainer = textBuffer.AsTextContainer(); if (Workspace.TryGetWorkspace(sourceTextContainer, out var workspace)) { - return workspace.GetRelatedDocumentIds(sourceTextContainer) - .Select(id => ContainedDocument.TryGetContainedDocument(id)) - .All(cd => cd == null || cd.SupportsRename); + return SupportsRenameWorker(workspace.GetRelatedDocumentIds(sourceTextContainer).ToImmutableArray()); } return false; @@ -40,23 +42,60 @@ public bool SupportsRename(ITextBuffer textBuffer) public bool SupportsNavigationToAnyPosition(ITextBuffer textBuffer) { - return GetContainedDocument(textBuffer) == null; + return SupportsNavigationToAnyPositionWorker(GetContainedDocumentId(textBuffer)); + } + + public bool SupportsCodeFixes(Document document) + { + return SupportsCodeFixesWorker(document.Id); + } + + public bool SupportsRefactorings(Document document) + { + return SupportsRefactoringsWorker(document.Id); + } + + public bool SupportsRename(Document document) + { + return SupportsRenameWorker(document.Project.Solution.GetRelatedDocumentIds(document.Id)); + } + + public bool SupportsNavigationToAnyPosition(Document document) + { + return SupportsNavigationToAnyPositionWorker(document.Id); } - private static ContainedDocument GetContainedDocument(ITextBuffer textBuffer) + private static DocumentId GetContainedDocumentId(ITextBuffer textBuffer) { var sourceTextContainer = textBuffer.AsTextContainer(); if (Workspace.TryGetWorkspace(sourceTextContainer, out var workspace) && workspace is VisualStudioWorkspaceImpl vsWorkspace) { - var id = vsWorkspace.GetDocumentIdInCurrentContext(sourceTextContainer); - if (id != null) - { - return ContainedDocument.TryGetContainedDocument(id); - } + return vsWorkspace.GetDocumentIdInCurrentContext(sourceTextContainer); } return null; } + + private static bool SupportsCodeFixesWorker(DocumentId id) + { + return ContainedDocument.TryGetContainedDocument(id) == null; + } + + private static bool SupportsRefactoringsWorker(DocumentId id) + { + return ContainedDocument.TryGetContainedDocument(id) == null; + } + + private static bool SupportsRenameWorker(ImmutableArray ids) + { + return ids.Select(id => ContainedDocument.TryGetContainedDocument(id)) + .All(cd => cd == null || cd.SupportsRename); + } + + private static bool SupportsNavigationToAnyPositionWorker(DocumentId id) + { + return ContainedDocument.TryGetContainedDocument(id) == null; + } } } diff --git a/src/Workspaces/Core/Portable/Workspace/Host/Mef/ExportWorkspaceServiceAttribute.cs b/src/Workspaces/Core/Portable/Workspace/Host/Mef/ExportWorkspaceServiceAttribute.cs index c59ea87475016..fd1e84d98acbf 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/Mef/ExportWorkspaceServiceAttribute.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/Mef/ExportWorkspaceServiceAttribute.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Host.Mef /// Use this attribute to declare a implementation for inclusion in a MEF-based workspace. /// [MetadataAttribute] - [AttributeUsage(AttributeTargets.Class)] + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class ExportWorkspaceServiceAttribute : ExportAttribute { /// From 4a6c40ca4a203ce8eb6b7753e79f79423ab49a58 Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Mon, 22 Apr 2019 17:40:51 -0700 Subject: [PATCH 2/7] Using FQN instead of adding import during ENC session --- .../AbstractTypeImportCompletionProvider.cs | 33 +++++++++++++++---- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractTypeImportCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractTypeImportCompletionProvider.cs index 06478a58dea31..d0c0070e8d81a 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractTypeImportCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractTypeImportCompletionProvider.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.AddImports; +using Microsoft.CodeAnalysis.Debugging; using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.Experiments; using Microsoft.CodeAnalysis.Formatting; @@ -179,7 +180,14 @@ internal override async Task GetChangeAsync(Document document, var containingNamespace = TypeImportCompletionItem.GetContainingNamespace(completionItem); Debug.Assert(containingNamespace != null); - if (document.Project.Solution.Workspace.CanApplyChange(ApplyChangesKind.ChangeDocument)) + if (ShouldCompleteWithFullyQualifyTypeName(document)) + { + var fullyQualifiedName = $"{containingNamespace}.{completionItem.DisplayText}"; + var change = new TextChange(completionListSpan, fullyQualifiedName); + + return CompletionChange.Create(change); + } + else { // Find context node so we can use it to decide where to insert using/imports. var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); @@ -223,14 +231,25 @@ internal override async Task GetChangeAsync(Document document, return CompletionChange.Create(Utilities.Collapse(newText, builder.ToImmutableAndFree())); } - else + + static bool ShouldCompleteWithFullyQualifyTypeName(Document document) { - // For workspace that doesn't support document change, e.g. DebuggerIntellisense - // we complete the type name in its fully qualified form instead. - var fullyQualifiedName = $"{containingNamespace}.{completionItem.DisplayText}"; - var change = new TextChange(completionListSpan, fullyQualifiedName); + var workspace = document.Project.Solution.Workspace; - return CompletionChange.Create(change); + // Certain types of workspace don't support document change, e.g. DebuggerIntellisense + if (!workspace.CanApplyChange(ApplyChangesKind.ChangeDocument)) + { + return true; + } + + // During an EnC session, adding import is not supported. + var encService = workspace.Services.GetService()?.EditAndContinueServiceOpt; + if (encService?.EditSession != null) + { + return true; + } + + return false; } } From 52e76c2bcc75653188fe688ec63c78ce5aaf75e4 Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Tue, 23 Apr 2019 15:24:49 -0700 Subject: [PATCH 3/7] Fix WorksspaceService exprot --- .../ChangeSignature/RemoveParametersTests.cs | 2 +- .../EncapsulateFieldCommandHandlerTests.cs | 2 +- .../ExtractInterface/ExtractInterfaceTests.cs | 2 +- .../ExtractMethod/ExtractMethodTests.cs | 2 +- .../OrganizeTypeDeclarationTests.cs | 2 +- .../InteractiveSupportsFeatureService.cs | 77 +++++++++++++ ...ractiveTextBufferSupportsFeatureService.cs | 70 ------------ .../Test2/Rename/RenameCommandHandlerTests.vb | 2 +- .../ChangeSignature/RemoveParametersTests.vb | 2 +- .../EncapsulateFieldCommandHandlerTests.vb | 2 +- .../ExtractInterface/ExtractInterfaceTests.vb | 2 +- .../ExtractMethodTests.LanguageInteraction.vb | 2 +- .../OrganizeTypeDeclarationTests.vb | 2 +- .../VisualStudioSupportsFeatureService.cs | 106 ++++++++++++++++++ ...lStudioTextBufferSupportsFeatureService.cs | 101 ----------------- .../Mef/ExportWorkspaceServiceAttribute.cs | 2 +- 16 files changed, 195 insertions(+), 183 deletions(-) create mode 100644 src/EditorFeatures/Core.Wpf/Interactive/InteractiveSupportsFeatureService.cs delete mode 100644 src/EditorFeatures/Core.Wpf/Interactive/InteractiveTextBufferSupportsFeatureService.cs create mode 100644 src/VisualStudio/Core/Def/Implementation/VisualStudioSupportsFeatureService.cs delete mode 100644 src/VisualStudio/Core/Def/Implementation/VisualStudioTextBufferSupportsFeatureService.cs diff --git a/src/EditorFeatures/CSharpTest/ChangeSignature/RemoveParametersTests.cs b/src/EditorFeatures/CSharpTest/ChangeSignature/RemoveParametersTests.cs index f101486d3128d..a31aaa839bb59 100644 --- a/src/EditorFeatures/CSharpTest/ChangeSignature/RemoveParametersTests.cs +++ b/src/EditorFeatures/CSharpTest/ChangeSignature/RemoveParametersTests.cs @@ -273,7 +273,7 @@ public void ChangeSignatureCommandDisabledInSubmission() { var exportProvider = ExportProviderCache .GetOrCreateExportProviderFactory( - TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(typeof(InteractiveTextBufferSupportsFeatureService))) + TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(typeof(InteractiveSupportsFeatureService.InteractiveTextBufferSupportsFeatureService))) .CreateExportProvider(); using (var workspace = TestWorkspace.Create(XElement.Parse(@" diff --git a/src/EditorFeatures/CSharpTest/EncapsulateField/EncapsulateFieldCommandHandlerTests.cs b/src/EditorFeatures/CSharpTest/EncapsulateField/EncapsulateFieldCommandHandlerTests.cs index 6210d0ff43720..8872340539e70 100644 --- a/src/EditorFeatures/CSharpTest/EncapsulateField/EncapsulateFieldCommandHandlerTests.cs +++ b/src/EditorFeatures/CSharpTest/EncapsulateField/EncapsulateFieldCommandHandlerTests.cs @@ -194,7 +194,7 @@ public void EncapsulateFieldCommandDisabledInSubmission() { var exportProvider = ExportProviderCache .GetOrCreateExportProviderFactory( - TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(typeof(InteractiveTextBufferSupportsFeatureService))) + TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(typeof(InteractiveSupportsFeatureService.InteractiveTextBufferSupportsFeatureService))) .CreateExportProvider(); using (var workspace = TestWorkspace.Create(XElement.Parse(@" diff --git a/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs b/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs index f1dcdb71fc33e..6af42860e96c5 100644 --- a/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs @@ -1062,7 +1062,7 @@ public void M(T a, U b) { } public void ExtractInterfaceCommandDisabledInSubmission() { var exportProvider = ExportProviderCache - .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(typeof(InteractiveTextBufferSupportsFeatureService))) + .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(typeof(InteractiveSupportsFeatureService.InteractiveTextBufferSupportsFeatureService))) .CreateExportProvider(); using (var workspace = TestWorkspace.Create(XElement.Parse(@" diff --git a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs index 4f5f1d5f46620..7f46bcd38f3b6 100644 --- a/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractMethod/ExtractMethodTests.cs @@ -10353,7 +10353,7 @@ public async Task ExtractMethod_Argument2() public void ExtractMethodCommandDisabledInSubmission() { var exportProvider = ExportProviderCache - .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(typeof(InteractiveTextBufferSupportsFeatureService))) + .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(typeof(InteractiveSupportsFeatureService.InteractiveTextBufferSupportsFeatureService))) .CreateExportProvider(); using (var workspace = TestWorkspace.Create(XElement.Parse(@" diff --git a/src/EditorFeatures/CSharpTest/Organizing/OrganizeTypeDeclarationTests.cs b/src/EditorFeatures/CSharpTest/Organizing/OrganizeTypeDeclarationTests.cs index bfc202df3b0d6..8b56e0bff0a58 100644 --- a/src/EditorFeatures/CSharpTest/Organizing/OrganizeTypeDeclarationTests.cs +++ b/src/EditorFeatures/CSharpTest/Organizing/OrganizeTypeDeclarationTests.cs @@ -1077,7 +1077,7 @@ void B() public void OrganizingCommandsDisabledInSubmission() { var exportProvider = ExportProviderCache - .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(typeof(InteractiveTextBufferSupportsFeatureService))) + .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(typeof(InteractiveSupportsFeatureService.InteractiveTextBufferSupportsFeatureService))) .CreateExportProvider(); using (var workspace = TestWorkspace.Create(XElement.Parse(@" diff --git a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveSupportsFeatureService.cs b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveSupportsFeatureService.cs new file mode 100644 index 0000000000000..d13cc6debe73c --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveSupportsFeatureService.cs @@ -0,0 +1,77 @@ +// 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.Composition; +using Microsoft.CodeAnalysis.Editor.Shared; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.InteractiveWindow; +using Microsoft.CodeAnalysis.Shared; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.Interactive +{ + internal sealed class InteractiveSupportsFeatureService + { + [ExportWorkspaceService(typeof(ITextBufferSupportsFeatureService), WorkspaceKind.Interactive), Shared] + internal class InteractiveTextBufferSupportsFeatureService : ITextBufferSupportsFeatureService + { + public bool SupportsCodeFixes(ITextBuffer textBuffer) + { + if (textBuffer != null) + { + var evaluator = (IInteractiveEvaluator)textBuffer.Properties[typeof(IInteractiveEvaluator)]; + var window = evaluator?.CurrentWindow; + if (window?.CurrentLanguageBuffer == textBuffer) + { + // These are only correct if we're on the UI thread. + // Otherwise, they're guesses and they might change immediately even if they're correct. + // If we return true and the buffer later becomes readonly, it appears that the + // the code fix simply has no effect. + return !window.IsResetting && !window.IsRunning; + } + } + + return false; + } + + public bool SupportsRefactorings(ITextBuffer textBuffer) + { + return false; + } + + public bool SupportsRename(ITextBuffer textBuffer) + { + return false; + } + + public bool SupportsNavigationToAnyPosition(ITextBuffer textBuffer) + { + return true; + } + } + + [ExportWorkspaceService(typeof(IDocumentSupportsFeatureService), WorkspaceKind.Interactive), Shared] + internal class InteractiveDocumentSupportsFeatureService : IDocumentSupportsFeatureService + { + public bool SupportsCodeFixes(Document document) + { + // TODO: Implement this. + return false; + } + + public bool SupportsRefactorings(Document document) + { + return false; + } + + public bool SupportsRename(Document document) + { + return false; + } + + public bool SupportsNavigationToAnyPosition(Document document) + { + return true; + } + } + } +} diff --git a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveTextBufferSupportsFeatureService.cs b/src/EditorFeatures/Core.Wpf/Interactive/InteractiveTextBufferSupportsFeatureService.cs deleted file mode 100644 index a5d3c8d3d0527..0000000000000 --- a/src/EditorFeatures/Core.Wpf/Interactive/InteractiveTextBufferSupportsFeatureService.cs +++ /dev/null @@ -1,70 +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.Composition; -using Microsoft.CodeAnalysis.Editor.Shared; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.InteractiveWindow; -using Microsoft.CodeAnalysis.Shared; - -namespace Microsoft.CodeAnalysis.Editor.Implementation.Interactive -{ - [ExportWorkspaceService(typeof(ITextBufferSupportsFeatureService), WorkspaceKind.Interactive), Shared] - internal sealed class InteractiveTextBufferSupportsFeatureService : ITextBufferSupportsFeatureService, IDocumentSupportsFeatureService - { - public bool SupportsCodeFixes(ITextBuffer textBuffer) - { - if (textBuffer != null) - { - var evaluator = (IInteractiveEvaluator)textBuffer.Properties[typeof(IInteractiveEvaluator)]; - var window = evaluator?.CurrentWindow; - if (window?.CurrentLanguageBuffer == textBuffer) - { - // These are only correct if we're on the UI thread. - // Otherwise, they're guesses and they might change immediately even if they're correct. - // If we return true and the buffer later becomes readonly, it appears that the - // the code fix simply has no effect. - return !window.IsResetting && !window.IsRunning; - } - } - - return false; - } - - public bool SupportsRefactorings(ITextBuffer textBuffer) - { - return false; - } - - public bool SupportsRename(ITextBuffer textBuffer) - { - return false; - } - - public bool SupportsNavigationToAnyPosition(ITextBuffer textBuffer) - { - return true; - } - - public bool SupportsCodeFixes(Document document) - { - // TODO: Implement this. - return false; - } - - public bool SupportsRefactorings(Document document) - { - return false; - } - - public bool SupportsRename(Document document) - { - return false; - } - - public bool SupportsNavigationToAnyPosition(Document document) - { - return true; - } - } -} diff --git a/src/EditorFeatures/Test2/Rename/RenameCommandHandlerTests.vb b/src/EditorFeatures/Test2/Rename/RenameCommandHandlerTests.vb index 60c6c832eed88..fbef73e975de8 100644 --- a/src/EditorFeatures/Test2/Rename/RenameCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/Rename/RenameCommandHandlerTests.vb @@ -51,7 +51,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Rename Public Sub RenameCommandDisabledInSubmission() Dim exportProvider = ExportProviderCache _ - .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(GetType(InteractiveTextBufferSupportsFeatureService))) _ + .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(GetType(InteractiveSupportsFeatureService.InteractiveTextBufferSupportsFeatureService))) _ .CreateExportProvider() Using workspace = TestWorkspace.Create( diff --git a/src/EditorFeatures/VisualBasicTest/ChangeSignature/RemoveParametersTests.vb b/src/EditorFeatures/VisualBasicTest/ChangeSignature/RemoveParametersTests.vb index f20d4bcaaf6f5..26b4631b0debf 100644 --- a/src/EditorFeatures/VisualBasicTest/ChangeSignature/RemoveParametersTests.vb +++ b/src/EditorFeatures/VisualBasicTest/ChangeSignature/RemoveParametersTests.vb @@ -96,7 +96,7 @@ End Module Public Sub TestChangeSignatureCommandDisabledInSubmission() Dim exportProvider = ExportProviderCache _ - .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(GetType(InteractiveTextBufferSupportsFeatureService))) _ + .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(GetType(InteractiveSupportsFeatureService.InteractiveTextBufferSupportsFeatureService))) _ .CreateExportProvider() Using workspace = TestWorkspace.Create( diff --git a/src/EditorFeatures/VisualBasicTest/EncapsulateField/EncapsulateFieldCommandHandlerTests.vb b/src/EditorFeatures/VisualBasicTest/EncapsulateField/EncapsulateFieldCommandHandlerTests.vb index ef07e4121b707..2d328bbc93ef7 100644 --- a/src/EditorFeatures/VisualBasicTest/EncapsulateField/EncapsulateFieldCommandHandlerTests.vb +++ b/src/EditorFeatures/VisualBasicTest/EncapsulateField/EncapsulateFieldCommandHandlerTests.vb @@ -134,7 +134,7 @@ End Class Public Sub EncapsulateFieldCommandDisabledInSubmission() Dim exportProvider = ExportProviderCache _ - .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(GetType(InteractiveTextBufferSupportsFeatureService))) _ + .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(GetType(InteractiveSupportsFeatureService.InteractiveTextBufferSupportsFeatureService))) _ .CreateExportProvider() Using workspace = TestWorkspace.Create( diff --git a/src/EditorFeatures/VisualBasicTest/ExtractInterface/ExtractInterfaceTests.vb b/src/EditorFeatures/VisualBasicTest/ExtractInterface/ExtractInterfaceTests.vb index dc7338eddfaee..4f0df28563f2e 100644 --- a/src/EditorFeatures/VisualBasicTest/ExtractInterface/ExtractInterfaceTests.vb +++ b/src/EditorFeatures/VisualBasicTest/ExtractInterface/ExtractInterfaceTests.vb @@ -1270,7 +1270,7 @@ End Namespace Public Sub TestExtractInterfaceCommandDisabledInSubmission() Dim exportProvider = ExportProviderCache _ - .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(GetType(InteractiveTextBufferSupportsFeatureService))) _ + .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(GetType(InteractiveSupportsFeatureService.InteractiveTextBufferSupportsFeatureService))) _ .CreateExportProvider() Using workspace = TestWorkspace.Create( diff --git a/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.LanguageInteraction.vb b/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.LanguageInteraction.vb index ba6934b5c540a..a43670469f6dd 100644 --- a/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.LanguageInteraction.vb +++ b/src/EditorFeatures/VisualBasicTest/ExtractMethod/ExtractMethodTests.LanguageInteraction.vb @@ -3367,7 +3367,7 @@ End Namespace" Public Sub TestExtractMethodCommandDisabledInSubmission() Dim exportProvider = ExportProviderCache _ - .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(GetType(InteractiveTextBufferSupportsFeatureService))) _ + .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(GetType(InteractiveSupportsFeatureService.InteractiveTextBufferSupportsFeatureService))) _ .CreateExportProvider() Using workspace = TestWorkspace.Create( diff --git a/src/EditorFeatures/VisualBasicTest/Organizing/OrganizeTypeDeclarationTests.vb b/src/EditorFeatures/VisualBasicTest/Organizing/OrganizeTypeDeclarationTests.vb index 987eaee9beada..8e439587d5677 100644 --- a/src/EditorFeatures/VisualBasicTest/Organizing/OrganizeTypeDeclarationTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Organizing/OrganizeTypeDeclarationTests.vb @@ -939,7 +939,7 @@ End Namespace Public Sub TestOrganizingCommandsDisabledInSubmission() Dim exportProvider = ExportProviderCache _ - .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(GetType(InteractiveTextBufferSupportsFeatureService))) _ + .GetOrCreateExportProviderFactory(TestExportProvider.EntireAssemblyCatalogWithCSharpAndVisualBasic.WithParts(GetType(InteractiveSupportsFeatureService.InteractiveTextBufferSupportsFeatureService))) _ .CreateExportProvider() Using workspace = TestWorkspace.Create( diff --git a/src/VisualStudio/Core/Def/Implementation/VisualStudioSupportsFeatureService.cs b/src/VisualStudio/Core/Def/Implementation/VisualStudioSupportsFeatureService.cs new file mode 100644 index 0000000000000..e3b72bd90fcb3 --- /dev/null +++ b/src/VisualStudio/Core/Def/Implementation/VisualStudioSupportsFeatureService.cs @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Immutable; +using System.Composition; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Editor.Shared; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; +using Microsoft.VisualStudio.LanguageServices.Implementation.Venus; +using Microsoft.VisualStudio.Text; + +namespace Microsoft.VisualStudio.LanguageServices.Implementation.SuggestionService +{ + internal sealed class VisualStudioSupportsFeatureService + { + [ExportWorkspaceService(typeof(ITextBufferSupportsFeatureService), ServiceLayer.Host), Shared] + private class VisualStudioTextBufferSupportsFeatureService : ITextBufferSupportsFeatureService + { + public bool SupportsCodeFixes(ITextBuffer textBuffer) + { + return SupportsCodeFixesWorker(GetContainedDocumentId(textBuffer)); + } + + public bool SupportsRefactorings(ITextBuffer textBuffer) + { + return SupportsRefactoringsWorker(GetContainedDocumentId(textBuffer)); + } + + public bool SupportsRename(ITextBuffer textBuffer) + { + var sourceTextContainer = textBuffer.AsTextContainer(); + if (Workspace.TryGetWorkspace(sourceTextContainer, out var workspace)) + { + return SupportsRenameWorker(workspace.GetRelatedDocumentIds(sourceTextContainer).ToImmutableArray()); + } + + return false; + } + + public bool SupportsNavigationToAnyPosition(ITextBuffer textBuffer) + { + return SupportsNavigationToAnyPositionWorker(GetContainedDocumentId(textBuffer)); + } + + private static DocumentId GetContainedDocumentId(ITextBuffer textBuffer) + { + var sourceTextContainer = textBuffer.AsTextContainer(); + if (Workspace.TryGetWorkspace(sourceTextContainer, out var workspace) + && workspace is VisualStudioWorkspaceImpl vsWorkspace) + { + return vsWorkspace.GetDocumentIdInCurrentContext(sourceTextContainer); + } + + return null; + } + } + + [ExportWorkspaceService(typeof(IDocumentSupportsFeatureService), ServiceLayer.Host), Shared] + private class VisualStudioDocumentSupportsFeatureService : IDocumentSupportsFeatureService + { + public bool SupportsCodeFixes(Document document) + { + return SupportsCodeFixesWorker(document.Id); + } + + public bool SupportsRefactorings(Document document) + { + return SupportsRefactoringsWorker(document.Id); + } + + public bool SupportsRename(Document document) + { + return SupportsRenameWorker(document.Project.Solution.GetRelatedDocumentIds(document.Id)); + } + + public bool SupportsNavigationToAnyPosition(Document document) + { + return SupportsNavigationToAnyPositionWorker(document.Id); + } + } + + private static bool SupportsCodeFixesWorker(DocumentId id) + { + return ContainedDocument.TryGetContainedDocument(id) == null; + } + + private static bool SupportsRefactoringsWorker(DocumentId id) + { + return ContainedDocument.TryGetContainedDocument(id) == null; + } + + private static bool SupportsRenameWorker(ImmutableArray ids) + { + return ids.Select(id => ContainedDocument.TryGetContainedDocument(id)) + .All(cd => cd == null || cd.SupportsRename); + } + + private static bool SupportsNavigationToAnyPositionWorker(DocumentId id) + { + return ContainedDocument.TryGetContainedDocument(id) == null; + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/VisualStudioTextBufferSupportsFeatureService.cs b/src/VisualStudio/Core/Def/Implementation/VisualStudioTextBufferSupportsFeatureService.cs deleted file mode 100644 index 4877626eaa584..0000000000000 --- a/src/VisualStudio/Core/Def/Implementation/VisualStudioTextBufferSupportsFeatureService.cs +++ /dev/null @@ -1,101 +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.Immutable; -using System.Composition; -using System.Linq; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Editor.Shared; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Shared; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; -using Microsoft.VisualStudio.LanguageServices.Implementation.Venus; -using Microsoft.VisualStudio.Text; - -namespace Microsoft.VisualStudio.LanguageServices.Implementation.SuggestionService -{ - [Shared] - [ExportWorkspaceService(typeof(IDocumentSupportsFeatureService), ServiceLayer.Host)] - [ExportWorkspaceService(typeof(ITextBufferSupportsFeatureService), ServiceLayer.Host)] - internal sealed class VisualStudioTextBufferSupportsFeatureService : ITextBufferSupportsFeatureService, IDocumentSupportsFeatureService - { - public bool SupportsCodeFixes(ITextBuffer textBuffer) - { - return SupportsCodeFixesWorker(GetContainedDocumentId(textBuffer)); - } - - public bool SupportsRefactorings(ITextBuffer textBuffer) - { - return SupportsRefactoringsWorker(GetContainedDocumentId(textBuffer)); - } - - public bool SupportsRename(ITextBuffer textBuffer) - { - var sourceTextContainer = textBuffer.AsTextContainer(); - if (Workspace.TryGetWorkspace(sourceTextContainer, out var workspace)) - { - return SupportsRenameWorker(workspace.GetRelatedDocumentIds(sourceTextContainer).ToImmutableArray()); - } - - return false; - } - - public bool SupportsNavigationToAnyPosition(ITextBuffer textBuffer) - { - return SupportsNavigationToAnyPositionWorker(GetContainedDocumentId(textBuffer)); - } - - public bool SupportsCodeFixes(Document document) - { - return SupportsCodeFixesWorker(document.Id); - } - - public bool SupportsRefactorings(Document document) - { - return SupportsRefactoringsWorker(document.Id); - } - - public bool SupportsRename(Document document) - { - return SupportsRenameWorker(document.Project.Solution.GetRelatedDocumentIds(document.Id)); - } - - public bool SupportsNavigationToAnyPosition(Document document) - { - return SupportsNavigationToAnyPositionWorker(document.Id); - } - - private static DocumentId GetContainedDocumentId(ITextBuffer textBuffer) - { - var sourceTextContainer = textBuffer.AsTextContainer(); - if (Workspace.TryGetWorkspace(sourceTextContainer, out var workspace) - && workspace is VisualStudioWorkspaceImpl vsWorkspace) - { - return vsWorkspace.GetDocumentIdInCurrentContext(sourceTextContainer); - } - - return null; - } - - private static bool SupportsCodeFixesWorker(DocumentId id) - { - return ContainedDocument.TryGetContainedDocument(id) == null; - } - - private static bool SupportsRefactoringsWorker(DocumentId id) - { - return ContainedDocument.TryGetContainedDocument(id) == null; - } - - private static bool SupportsRenameWorker(ImmutableArray ids) - { - return ids.Select(id => ContainedDocument.TryGetContainedDocument(id)) - .All(cd => cd == null || cd.SupportsRename); - } - - private static bool SupportsNavigationToAnyPositionWorker(DocumentId id) - { - return ContainedDocument.TryGetContainedDocument(id) == null; - } - } -} diff --git a/src/Workspaces/Core/Portable/Workspace/Host/Mef/ExportWorkspaceServiceAttribute.cs b/src/Workspaces/Core/Portable/Workspace/Host/Mef/ExportWorkspaceServiceAttribute.cs index fd1e84d98acbf..c59ea87475016 100644 --- a/src/Workspaces/Core/Portable/Workspace/Host/Mef/ExportWorkspaceServiceAttribute.cs +++ b/src/Workspaces/Core/Portable/Workspace/Host/Mef/ExportWorkspaceServiceAttribute.cs @@ -9,7 +9,7 @@ namespace Microsoft.CodeAnalysis.Host.Mef /// Use this attribute to declare a implementation for inclusion in a MEF-based workspace. /// [MetadataAttribute] - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + [AttributeUsage(AttributeTargets.Class)] public class ExportWorkspaceServiceAttribute : ExportAttribute { /// From d1b15fc152ebb292b61fcffe92b256df26e2fb1a Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Tue, 23 Apr 2019 15:25:20 -0700 Subject: [PATCH 4/7] Add check in import completion --- .../Providers/AbstractTypeImportCompletionProvider.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractTypeImportCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractTypeImportCompletionProvider.cs index d0c0070e8d81a..1299a8b6d9244 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractTypeImportCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractTypeImportCompletionProvider.cs @@ -15,6 +15,7 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Shared; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Extensions.ContextQuery; using Microsoft.CodeAnalysis.Text; @@ -249,6 +250,13 @@ static bool ShouldCompleteWithFullyQualifyTypeName(Document document) return true; } + // Certain documents, e.g. Razor document, don't support adding imports + var documentSupportsFeatureService = workspace.Services.GetService(); + if (!documentSupportsFeatureService.SupportsRefactorings(document)) + { + return true; + } + return false; } } From 1c1760549468bb5240285bbabd52578f7741a7f8 Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Tue, 23 Apr 2019 15:25:34 -0700 Subject: [PATCH 5/7] Fix formatting --- .../Core/Portable/MoveToNamespace/MoveToNamespaceResult.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceResult.cs b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceResult.cs index 8078bf142ee15..aa6752a74610b 100644 --- a/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceResult.cs +++ b/src/Features/Core/Portable/MoveToNamespace/MoveToNamespaceResult.cs @@ -18,7 +18,7 @@ internal class MoveToNamespaceResult public MoveToNamespaceResult( Solution originalSolution, - Solution updatedSolution, + Solution updatedSolution, DocumentId updatedDocumentId, ImmutableDictionary newNameOriginalSymbolMapping) { From 47138ad51f879106b9530238ea4066cecb8e6a37 Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Thu, 25 Apr 2019 13:04:01 -0700 Subject: [PATCH 6/7] Fix change namespace service to deal with referencing in Razor document w/o crashing --- .../SyncNamespace/AbstractChangeNamespaceService.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs index f1d91c38e899b..5df6e22ab296c 100644 --- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractChangeNamespaceService.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.Editing; using Microsoft.CodeAnalysis.FindSymbols; using Microsoft.CodeAnalysis.Formatting; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.RemoveUnnecessaryImports; @@ -588,6 +589,13 @@ private async Task FixReferencingDocumentAsync( string newNamespace, CancellationToken cancellationToken) { + // Can't apply change to certain document, simply return unchanged. + // e.g. Razor document (*.g.cs file, not *.cshtml) + if (!document.CanApplyChange()) + { + return document; + } + // 1. Fully qualify all simple references (i.e. not via an alias) with new namespace. // 2. Add using of new namespace (for each reference's container). // 3. Try to simplify qualified names introduced from step(1). From ae12b5e88c4bf487f32f380024dd66db54664794 Mon Sep 17 00:00:00 2001 From: Gen Lu Date: Thu, 25 Apr 2019 13:06:54 -0700 Subject: [PATCH 7/7] Remove unnecessary local --- .../AbstractSyncNamespaceCodeRefactoringProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs index 328dad996efdd..f80744b60160d 100644 --- a/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/CodeRefactorings/SyncNamespace/AbstractSyncNamespaceCodeRefactoringProvider.cs @@ -22,8 +22,8 @@ public override async Task ComputeRefactoringsAsync(CodeRefactoringContext conte var textSpan = context.Span; var cancellationToken = context.CancellationToken; - var workspace = document.Project.Solution.Workspace; - if (workspace.Kind == WorkspaceKind.MiscellaneousFiles || document.IsGeneratedCode(cancellationToken)) + if (document.Project.Solution.Workspace.Kind == WorkspaceKind.MiscellaneousFiles || + document.IsGeneratedCode(cancellationToken)) { return; }