From bf2789517e360bb7685e218433aca161287b620c Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 8 Nov 2022 16:00:34 -0800 Subject: [PATCH 1/9] Non document changes --- .../CodeActions/ParentInstallPackageCodeAction.cs | 2 +- .../AddPackage/InstallPackageParentCodeAction.cs | 2 +- .../Protocol/Handler}/CodeActions/CodeActionHelpers.cs | 9 ++------- .../Handler}/CodeActions/CodeActionResolveData.cs | 0 .../Handler}/CodeActions/CodeActionResolveHandler.cs | 2 -- .../Protocol/Handler}/CodeActions/CodeActionsCache.cs | 4 ---- .../Handler}/CodeActions/CodeActionsCacheFactory.cs | 0 .../Protocol/Handler}/CodeActions/CodeActionsHandler.cs | 0 .../Handler}/CodeActions/RunCodeActionHandler.cs | 1 - src/Workspaces/Core/Portable/CodeActions/CodeAction.cs | 3 +++ src/Workspaces/Core/Portable/Tags/WellKnownTags.cs | 1 - 11 files changed, 7 insertions(+), 17 deletions(-) rename src/{EditorFeatures/Core/LanguageServer/Handlers => Features/LanguageServer/Protocol/Handler}/CodeActions/CodeActionHelpers.cs (98%) rename src/{EditorFeatures/Core/LanguageServer/Handlers => Features/LanguageServer/Protocol/Handler}/CodeActions/CodeActionResolveData.cs (100%) rename src/{EditorFeatures/Core/LanguageServer/Handlers => Features/LanguageServer/Protocol/Handler}/CodeActions/CodeActionResolveHandler.cs (99%) rename src/{EditorFeatures/Core/LanguageServer/Handlers => Features/LanguageServer/Protocol/Handler}/CodeActions/CodeActionsCache.cs (97%) rename src/{EditorFeatures/Core/LanguageServer/Handlers => Features/LanguageServer/Protocol/Handler}/CodeActions/CodeActionsCacheFactory.cs (100%) rename src/{EditorFeatures/Core/LanguageServer/Handlers => Features/LanguageServer/Protocol/Handler}/CodeActions/CodeActionsHandler.cs (100%) rename src/{EditorFeatures/Core/LanguageServer/Handlers => Features/LanguageServer/Protocol/Handler}/CodeActions/RunCodeActionHandler.cs (98%) diff --git a/src/Features/Core/Portable/AddImport/CodeActions/ParentInstallPackageCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/ParentInstallPackageCodeAction.cs index 4884081c4131e..c74cee9bb09d9 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/ParentInstallPackageCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/ParentInstallPackageCodeAction.cs @@ -24,7 +24,7 @@ internal abstract partial class AbstractAddImportFeatureService private class ParentInstallPackageCodeAction : CodeAction.CodeActionWithNestedActions { - public override ImmutableArray Tags => WellKnownTagArrays.NuGet; + public override ImmutableArray Tags => MakesNonDocumentChangeTags; /// /// Even though we have child actions, we mark ourselves as explicitly non-inlinable. diff --git a/src/Features/Core/Portable/AddPackage/InstallPackageParentCodeAction.cs b/src/Features/Core/Portable/AddPackage/InstallPackageParentCodeAction.cs index 912d8989569c8..0b2c6c6a2c1d1 100644 --- a/src/Features/Core/Portable/AddPackage/InstallPackageParentCodeAction.cs +++ b/src/Features/Core/Portable/AddPackage/InstallPackageParentCodeAction.cs @@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.AddPackage /// internal class InstallPackageParentCodeAction : CodeAction.CodeActionWithNestedActions { - public override ImmutableArray Tags => WellKnownTagArrays.NuGet; + public override ImmutableArray Tags => MakesNonDocumentChangeTags; /// /// Even though we have child actions, we mark ourselves as explicitly non-inlinable. diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionHelpers.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs similarity index 98% rename from src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionHelpers.cs rename to src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs index 3a957e6848bea..c34409706b3d2 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionHelpers.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs @@ -18,7 +18,6 @@ using Roslyn.Utilities; using static Microsoft.CodeAnalysis.CodeActions.CodeAction; using CodeAction = Microsoft.CodeAnalysis.CodeActions.CodeAction; -using CodeActionOptions = Microsoft.CodeAnalysis.CodeActions.CodeActionOptions; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions @@ -59,16 +58,12 @@ public static async Task GetVSCodeActionsAsync( { // Filter out code actions with options since they'll show dialogs and we can't remote the UI and the options. if (suggestedAction.OriginalCodeAction is CodeActionWithOptions) - { continue; - } - // TO-DO: Re-enable code actions involving package manager once supported by LSP. + // Skip code actions that make non-document changes. We can't apply them in LSP currently. // https://github.com/dotnet/roslyn/issues/48698 - if (suggestedAction.OriginalCodeAction.Tags.Equals(WellKnownTagArrays.NuGet)) - { + if (suggestedAction.OriginalCodeAction.Tags.Contains(CodeAction.MakesNonDocumentChange)) continue; - } codeActions.Add(GenerateVSCodeAction( request, documentText, diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionResolveData.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveData.cs similarity index 100% rename from src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionResolveData.cs rename to src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveData.cs diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionResolveHandler.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs similarity index 99% rename from src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionResolveHandler.cs rename to src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs index b58aa7a27fc03..2e3613e22ab0a 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionResolveHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs @@ -85,9 +85,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(LSP.CodeAction request) var operations = await codeActionToResolve.GetOperationsAsync(cancellationToken).ConfigureAwait(false); if (operations.IsEmpty) - { return codeAction; - } // If we have all non-ApplyChangesOperations, set up to run as command on the server // instead of using WorkspaceEdits. diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionsCache.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionsCache.cs similarity index 97% rename from src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionsCache.cs rename to src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionsCache.cs index bd4bac23fac21..453a5e29cad2d 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionsCache.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionsCache.cs @@ -2,15 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.Composition; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServer.Handler.Completion; using Microsoft.CodeAnalysis.UnifiedSuggestions; using Roslyn.Utilities; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionsCacheFactory.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionsCacheFactory.cs similarity index 100% rename from src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionsCacheFactory.cs rename to src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionsCacheFactory.cs diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionsHandler.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs similarity index 100% rename from src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/CodeActionsHandler.cs rename to src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs diff --git a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/RunCodeActionHandler.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/RunCodeActionHandler.cs similarity index 98% rename from src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/RunCodeActionHandler.cs rename to src/Features/LanguageServer/Protocol/Handler/CodeActions/RunCodeActionHandler.cs index 9fb862ff58220..7c0c6a3fe7e43 100644 --- a/src/EditorFeatures/Core/LanguageServer/Handlers/CodeActions/RunCodeActionHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/RunCodeActionHandler.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions; using Microsoft.CodeAnalysis.LanguageServer.Handler.Commands; diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs b/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs index e3c3c6e1402e8..e06d2d43992ad 100644 --- a/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs +++ b/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs @@ -33,6 +33,9 @@ namespace Microsoft.CodeAnalysis.CodeActions /// public abstract class CodeAction { + internal const string MakesNonDocumentChange = nameof(MakesNonDocumentChange); + private protected ImmutableArray MakesNonDocumentChangeTags = ImmutableArray.Create(MakesNonDocumentChange); + /// /// A short title describing the action that may appear in a menu. /// diff --git a/src/Workspaces/Core/Portable/Tags/WellKnownTags.cs b/src/Workspaces/Core/Portable/Tags/WellKnownTags.cs index d17c2078e94da..b0e2e3957198b 100644 --- a/src/Workspaces/Core/Portable/Tags/WellKnownTags.cs +++ b/src/Workspaces/Core/Portable/Tags/WellKnownTags.cs @@ -130,7 +130,6 @@ internal static class WellKnownTagArrays internal static readonly ImmutableArray StatusInformation = ImmutableArray.Create(WellKnownTags.StatusInformation); internal static readonly ImmutableArray AddReference = ImmutableArray.Create(WellKnownTags.AddReference); - internal static readonly ImmutableArray NuGet = ImmutableArray.Create(WellKnownTags.NuGet); internal static readonly ImmutableArray TargetTypeMatch = ImmutableArray.Create(WellKnownTags.TargetTypeMatch); internal static readonly ImmutableArray CSharpFile = ImmutableArray.Create(WellKnownTags.File, LanguageNames.CSharp); From 4cccc6036bc1e5f77f7cb2deed6ca70c95f0f5fb Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 8 Nov 2022 16:09:37 -0800 Subject: [PATCH 2/9] note non document changes --- .../AddImport/CodeActions/AddImportCodeAction.cs | 5 +++-- .../CodeActions/AssemblyReferenceCodeAction.cs | 2 +- .../InstallPackageAndAddImportCodeAction.cs | 2 +- .../MetadataSymbolReferenceCodeAction.cs | 2 +- .../CodeActions/ProjectSymbolReferenceCodeAction.cs | 13 +++++++------ .../SymbolReference.SymbolReferenceCodeAction.cs | 6 ++++-- .../Core/Portable/CodeActions/CodeAction.cs | 2 +- 7 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/Features/Core/Portable/AddImport/CodeActions/AddImportCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/AddImportCodeAction.cs index b7d1135d61447..05234f52caad7 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/AddImportCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/AddImportCodeAction.cs @@ -43,13 +43,14 @@ private abstract class AddImportCodeAction : CodeAction protected AddImportCodeAction( Document originalDocument, - AddImportFixData fixData) + AddImportFixData fixData, + ImmutableArray additionalTags) { OriginalDocument = originalDocument; FixData = fixData; Title = fixData.Title; - Tags = fixData.Tags.ToImmutableArrayOrEmpty(); + Tags = fixData.Tags.ToImmutableArrayOrEmpty().AddRange(additionalTags); Priority = fixData.Priority; _textChanges = fixData.TextChanges.ToImmutableArrayOrEmpty(); } diff --git a/src/Features/Core/Portable/AddImport/CodeActions/AssemblyReferenceCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/AssemblyReferenceCodeAction.cs index ca2b0f94a064c..54de0a913b6ea 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/AssemblyReferenceCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/AssemblyReferenceCodeAction.cs @@ -19,7 +19,7 @@ private class AssemblyReferenceCodeAction : AddImportCodeAction public AssemblyReferenceCodeAction( Document originalDocument, AddImportFixData fixData) - : base(originalDocument, fixData) + : base(originalDocument, fixData, MakesNonDocumentChangeTags) { Contract.ThrowIfFalse(fixData.Kind == AddImportFixKind.ReferenceAssemblySymbol); } diff --git a/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs index 4ba21c98e321a..c03cc8086b9f6 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs @@ -33,7 +33,7 @@ public InstallPackageAndAddImportCodeAction( AddImportFixData fixData, string title, InstallPackageDirectlyCodeActionOperation installOperation) - : base(originalDocument, fixData) + : base(originalDocument, fixData, MakesNonDocumentChangeTags) { Contract.ThrowIfFalse(fixData.Kind == AddImportFixKind.PackageSymbol); Title = title; diff --git a/src/Features/Core/Portable/AddImport/CodeActions/MetadataSymbolReferenceCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/MetadataSymbolReferenceCodeAction.cs index 713dc90adaa54..364ab20c389e2 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/MetadataSymbolReferenceCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/MetadataSymbolReferenceCodeAction.cs @@ -16,7 +16,7 @@ internal abstract partial class AbstractAddImportFeatureService.Empty) { Contract.ThrowIfFalse(fixData.Kind == AddImportFixKind.ProjectSymbol); } - private bool ShouldAddProjectReference() - => FixData.ProjectReferenceToAdd != null && FixData.ProjectReferenceToAdd != OriginalDocument.Project.Id; + private static bool ShouldAddProjectReference(Document originalDocument, AddImportFixData fixData) + => fixData.ProjectReferenceToAdd != null && fixData.ProjectReferenceToAdd != originalDocument.Project.Id; protected override Task UpdateProjectAsync(Project project, bool isPreview, CancellationToken cancellationToken) { - if (!ShouldAddProjectReference()) - { + if (!ShouldAddProjectReference(this.OriginalDocument, this.FixData)) return SpecializedTasks.Null(); - } var projectWithAddedReference = project.AddProjectReference(new ProjectReference(FixData.ProjectReferenceToAdd)); var applyOperation = new ApplyChangesOperation(projectWithAddedReference.Solution); diff --git a/src/Features/Core/Portable/AddImport/CodeActions/SymbolReference.SymbolReferenceCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/SymbolReference.SymbolReferenceCodeAction.cs index 882aabe48023f..5e5a0fcb7a898 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/SymbolReference.SymbolReferenceCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/SymbolReference.SymbolReferenceCodeAction.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; @@ -23,8 +24,9 @@ private abstract class SymbolReferenceCodeAction : AddImportCodeAction { protected SymbolReferenceCodeAction( Document originalDocument, - AddImportFixData fixData) - : base(originalDocument, fixData) + AddImportFixData fixData, + ImmutableArray additionalTags) + : base(originalDocument, fixData, additionalTags) { } diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs b/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs index e06d2d43992ad..1cae227a6fe2a 100644 --- a/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs +++ b/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs @@ -34,7 +34,7 @@ namespace Microsoft.CodeAnalysis.CodeActions public abstract class CodeAction { internal const string MakesNonDocumentChange = nameof(MakesNonDocumentChange); - private protected ImmutableArray MakesNonDocumentChangeTags = ImmutableArray.Create(MakesNonDocumentChange); + private protected static ImmutableArray MakesNonDocumentChangeTags = ImmutableArray.Create(MakesNonDocumentChange); /// /// A short title describing the action that may appear in a menu. From 18644e73db5fecf7802cb4cc6cd397df96071d82 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 8 Nov 2022 16:30:24 -0800 Subject: [PATCH 3/9] Update handlers --- .../NamingStyle/NamingStyleCodeFixProvider.cs | 8 + .../AddMissingReferenceCodeAction.cs | 7 + .../ChangeSignatureCodeAction.cs | 7 + .../AbstractMoveToNamespaceCodeAction.cs | 29 ++- .../CodeActions/CodeActionResolveHandler.cs | 171 ++++++++---------- .../Handler/CodeActions/CodeActionsHandler.cs | 10 +- .../CodeActions/RunCodeActionHandler.cs | 102 ----------- ...eActionOperationFactoryWorkspaceService.cs | 4 +- 8 files changed, 130 insertions(+), 208 deletions(-) delete mode 100644 src/Features/LanguageServer/Protocol/Handler/CodeActions/RunCodeActionHandler.cs diff --git a/src/Analyzers/Core/CodeFixes/NamingStyle/NamingStyleCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/NamingStyle/NamingStyleCodeFixProvider.cs index e42d5924318ee..54942acef60c0 100644 --- a/src/Analyzers/Core/CodeFixes/NamingStyle/NamingStyleCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/NamingStyle/NamingStyleCodeFixProvider.cs @@ -121,6 +121,14 @@ private class FixNameCodeAction : CodeAction private readonly Func> _createChangedSolutionAsync; private readonly string _equivalenceKey; +#if !CODE_STYLE + /// + /// This code action invokes code on the UI thread to tell 3rd parties about the rename. As such, it does + /// more than make document changes (and is thus restricted in which hosts it can run). + /// + public override ImmutableArray Tags => MakesNonDocumentChangeTags; +#endif + public FixNameCodeAction( #if !CODE_STYLE Solution startingSolution, diff --git a/src/Features/Core/Portable/AddMissingReference/AddMissingReferenceCodeAction.cs b/src/Features/Core/Portable/AddMissingReference/AddMissingReferenceCodeAction.cs index c5c56dc004e12..e3ac42722c12b 100644 --- a/src/Features/Core/Portable/AddMissingReference/AddMissingReferenceCodeAction.cs +++ b/src/Features/Core/Portable/AddMissingReference/AddMissingReferenceCodeAction.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; @@ -21,6 +22,12 @@ internal class AddMissingReferenceCodeAction : CodeAction public override string Title { get; } + /// + /// This code action adds references, and thus definitely makes non-document changes. It cannot run in hosts + /// that only support text changes. + /// + public override ImmutableArray Tags => MakesNonDocumentChangeTags; + public AddMissingReferenceCodeAction(Project project, string title, ProjectReference? projectReferenceToAdd, AssemblyIdentity missingAssemblyIdentity) { _project = project; diff --git a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs index ed277bad0ab9f..f23c7814684c7 100644 --- a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs +++ b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CodeActions; @@ -18,6 +19,12 @@ internal class ChangeSignatureCodeAction : CodeActionWithOptions private readonly AbstractChangeSignatureService _changeSignatureService; private readonly ChangeSignatureAnalysisSucceededContext _context; + /// + /// This code action currently pops up a confirmation dialog to the user. As such, it does more than make + /// document changes (and is thus restricted in which hosts it can run). + /// + public override ImmutableArray Tags => MakesNonDocumentChangeTags; + public ChangeSignatureCodeAction(AbstractChangeSignatureService changeSignatureService, ChangeSignatureAnalysisSucceededContext context) { _changeSignatureService = changeSignatureService; diff --git a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs index 6d3cccd76b5fd..9f5d6d4f61a7f 100644 --- a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs +++ b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs @@ -21,13 +21,33 @@ internal abstract partial class AbstractMoveToNamespaceCodeAction : CodeActionWi private readonly MoveToNamespaceAnalysisResult _moveToNamespaceAnalysisResult; private readonly CodeCleanupOptionsProvider _cleanupOptions; - public AbstractMoveToNamespaceCodeAction(IMoveToNamespaceService moveToNamespaceService, MoveToNamespaceAnalysisResult analysisResult, CodeCleanupOptionsProvider cleanupOptions) + public AbstractMoveToNamespaceCodeAction( + IMoveToNamespaceService moveToNamespaceService, + MoveToNamespaceAnalysisResult analysisResult, + CodeCleanupOptionsProvider cleanupOptions) { _moveToNamespaceService = moveToNamespaceService; _moveToNamespaceAnalysisResult = analysisResult; _cleanupOptions = cleanupOptions; } + public override ImmutableArray Tags + { + get + { + var solution = _moveToNamespaceAnalysisResult.Document.Project.Solution; + var symbolRenameCodeActionOperationFactory = solution.Services.GetService(); + + // If we're in a host that supports the symbol rename code action, then this code action will do more + // than just move. It will also notify clients about the rename it does. As such, it does more than + // make / document changes (and is thus restricted in which hosts it can run). + if (symbolRenameCodeActionOperationFactory != null) + return MakesNonDocumentChangeTags; + + return ImmutableArray.Empty; + } + } + public override object GetOptions(CancellationToken cancellationToken) { return _moveToNamespaceService.GetChangeNamespaceOptions( @@ -67,10 +87,9 @@ private static ImmutableArray CreateRenameOperations(MoveTo var symbolRenameCodeActionOperationFactory = moveToNamespaceResult.UpdatedSolution.Services.GetService(); - // It's possible we're not in a host context providing this service, in which case - // just provide a code action that won't notify of the symbol rename. - // Without the symbol rename operation, code generators (like WPF) may not - // know to regenerate code correctly. + // It's possible we're not in a host context providing this service, in which case just provide a code + // action that won't notify of the symbol rename. Without the symbol rename operation, code generators (like + // WPF) may not know to regenerate code correctly. if (symbolRenameCodeActionOperationFactory != null) { foreach (var (newName, symbol) in moveToNamespaceResult.NewNameOriginalSymbolMapping) diff --git a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs index 2e3613e22ab0a..b348f039edc8d 100644 --- a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs @@ -24,15 +24,13 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler { /// - /// Resolves a code action by filling out its Edit and/or Command property. - /// The handler is triggered only when a user hovers over a code action. This - /// system allows the basic code action data to be computed quickly, and the - /// complex data, such as edits and commands, to be computed only when necessary - /// (i.e. when hovering/previewing a code action). - /// - /// TODO - This must be moved to the MS.CA.LanguageServer.Protocol project once the - /// EditorFeatures references in are removed. - /// See https://github.com/dotnet/roslyn/issues/55142 + /// Resolves a code action by filling out its Edit property. The handler is triggered only when a user hovers over a + /// code action. This system allows the basic code action data to be computed quickly, and the complex data, to be + /// computed only when necessary (i.e. when hovering/previewing a code action). + /// + /// This system only supports text edits to documents. In the future, supporting complex edits (including changes to + /// project files) would be desirable. + /// /// [ExportCSharpVisualBasicStatelessLspService(typeof(CodeActionResolveHandler)), Shared] [Method(LSP.Methods.CodeActionResolveName)] @@ -79,113 +77,102 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(LSP.CodeAction request) _codeRefactoringService, cancellationToken).ConfigureAwait(false); - var codeActionToResolve = CodeActionHelpers.GetCodeActionToResolve( - data.UniqueIdentifier, codeActions); + var codeActionToResolve = CodeActionHelpers.GetCodeActionToResolve(data.UniqueIdentifier, codeActions); Contract.ThrowIfNull(codeActionToResolve); var operations = await codeActionToResolve.GetOperationsAsync(cancellationToken).ConfigureAwait(false); - if (operations.IsEmpty) - return codeAction; - // If we have all non-ApplyChangesOperations, set up to run as command on the server - // instead of using WorkspaceEdits. - if (operations.All(operation => operation is not ApplyChangesOperation)) - { - codeAction.Command = SetCommand(codeAction.Title, data); - return codeAction; - } + // We only support making solution changing actions. We can also ignore DocumentNavigation as that is an + // additional suggestion a code action can make about what to do post edit. + var applicableActions = operations.Where(o => o is ApplyChangesOperation or DocumentNavigationOperation).ToArray(); // TO-DO: We currently must execute code actions which add new documents on the server as commands, // since there is no LSP support for adding documents yet. In the future, we should move these actions // to execute on the client. // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1147293/ - // Add workspace edits - var applyChangesOperations = operations.OfType(); - if (applyChangesOperations.Any()) - { - var solution = document.Project.Solution; - var textDiffService = solution.Services.GetService(); + var solution = document.Project.Solution; + var textDiffService = solution.Services.GetService(); - using var _ = ArrayBuilder.GetInstance(out var textDocumentEdits); - foreach (var applyChangesOperation in applyChangesOperations) - { - var changes = applyChangesOperation.ChangedSolution.GetChanges(solution); - var projectChanges = changes.GetProjectChanges(); - - // TO-DO: If the change involves adding or removing a document, execute via command instead of WorkspaceEdit - // until adding/removing documents is supported in LSP: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1147293/ - // After support is added, remove the below if-statement and add code to support adding/removing documents. - var addedDocuments = projectChanges.SelectMany( - pc => pc.GetAddedDocuments().Concat(pc.GetAddedAdditionalDocuments().Concat(pc.GetAddedAnalyzerConfigDocuments()))); - var removedDocuments = projectChanges.SelectMany( - pc => pc.GetRemovedDocuments().Concat(pc.GetRemovedAdditionalDocuments().Concat(pc.GetRemovedAnalyzerConfigDocuments()))); - if (addedDocuments.Any() || removedDocuments.Any()) - { - codeAction.Command = SetCommand(codeAction.Title, data); - return codeAction; - } + using var _ = ArrayBuilder.GetInstance(out var textDocumentEdits); - // TO-DO: If the change involves adding or removing a project reference, execute via command instead of - // WorkspaceEdit until adding/removing project references is supported in LSP: - // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1166040 - var projectReferences = projectChanges.SelectMany( - pc => pc.GetAddedProjectReferences().Concat(pc.GetRemovedProjectReferences())); - if (projectReferences.Any()) - { - codeAction.Command = SetCommand(codeAction.Title, data); - return codeAction; - } + foreach (var option in operations) + { + // We only support making solution-updating operations in LSP. And only ones that modify documents. 1st + // class code actions that do more than this are supposed to add the CodeAction.MakesNonDocumentChange + // in their Tags so we can filter them out before returning them to the client. + // + // However, we cannot enforce this as 3rd party fixers can still run. So we filter their results to + // only apply the portions of their work that updates documents, and nothing else. + if (option is not ApplyChangesOperation applyChangesOperation) + continue; + + var changes = applyChangesOperation.ChangedSolution.GetChanges(solution); + var projectChanges = changes.GetProjectChanges(); + + // ignore any non-document changes. In the future we could see if there is some mechanism by which we + // can make these changes safely in LSP. +#if false + + // TO-DO: If the change involves adding or removing a document, execute via command instead of WorkspaceEdit + // until adding/removing documents is supported in LSP: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1147293/ + // After support is added, remove the below if-statement and add code to support adding/removing documents. + var addedDocuments = projectChanges.SelectMany( + pc => pc.GetAddedDocuments().Concat(pc.GetAddedAdditionalDocuments().Concat(pc.GetAddedAnalyzerConfigDocuments()))); + var removedDocuments = projectChanges.SelectMany( + pc => pc.GetRemovedDocuments().Concat(pc.GetRemovedAdditionalDocuments().Concat(pc.GetRemovedAnalyzerConfigDocuments()))); + if (addedDocuments.Any() || removedDocuments.Any()) + { + codeAction.Command = SetCommand(codeAction.Title, data); + return codeAction; + } - var changedDocuments = projectChanges.SelectMany(pc => pc.GetChangedDocuments()); - var changedAnalyzerConfigDocuments = projectChanges.SelectMany(pc => pc.GetChangedAnalyzerConfigDocuments()); - var changedAdditionalDocuments = projectChanges.SelectMany(pc => pc.GetChangedAdditionalDocuments()); - - // Changed documents - await AddTextDocumentEditsAsync( - textDocumentEdits, changedDocuments, - applyChangesOperation.ChangedSolution.GetDocument, solution.GetDocument, textDiffService, - cancellationToken).ConfigureAwait(false); - - // Changed analyzer config documents - await AddTextDocumentEditsAsync( - textDocumentEdits, changedAnalyzerConfigDocuments, - applyChangesOperation.ChangedSolution.GetAnalyzerConfigDocument, solution.GetAnalyzerConfigDocument, - textDiffService: null, cancellationToken).ConfigureAwait(false); - - // Changed additional documents - await AddTextDocumentEditsAsync( - textDocumentEdits, changedAdditionalDocuments, - applyChangesOperation.ChangedSolution.GetAdditionalDocument, solution.GetAdditionalDocument, - textDiffService: null, cancellationToken).ConfigureAwait(false); + // TO-DO: If the change involves adding or removing a project reference, execute via command instead of + // WorkspaceEdit until adding/removing project references is supported in LSP: + // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1166040 + var projectReferences = projectChanges.SelectMany( + pc => pc.GetAddedProjectReferences().Concat(pc.GetRemovedProjectReferences())); + if (projectReferences.Any()) + { + codeAction.Command = SetCommand(codeAction.Title, data); + return codeAction; } - codeAction.Edit = new LSP.WorkspaceEdit { DocumentChanges = textDocumentEdits.ToArray() }; +#endif + + // Changed documents + await AddTextDocumentEditsAsync( + projectChanges.SelectMany(pc => pc.GetChangedDocuments()), + applyChangesOperation.ChangedSolution.GetDocument, + solution.GetDocument).ConfigureAwait(false); + + // Changed analyzer config documents + await AddTextDocumentEditsAsync( + projectChanges.SelectMany(pc => pc.GetChangedAnalyzerConfigDocuments()), + applyChangesOperation.ChangedSolution.GetAnalyzerConfigDocument, + solution.GetAnalyzerConfigDocument).ConfigureAwait(false); + + // Changed additional documents + await AddTextDocumentEditsAsync( + projectChanges.SelectMany(pc => pc.GetChangedAdditionalDocuments()), + applyChangesOperation.ChangedSolution.GetAdditionalDocument, + solution.GetAdditionalDocument).ConfigureAwait(false); } - return codeAction; + codeAction.Edit = new LSP.WorkspaceEdit { DocumentChanges = textDocumentEdits.ToArray() }; - // Local functions - static LSP.Command SetCommand(string title, CodeActionResolveData data) => new LSP.Command - { - CommandIdentifier = CodeActionsHandler.RunCodeActionCommandName, - Title = title, - Arguments = new object[] { data } - }; + return codeAction; - static async Task AddTextDocumentEditsAsync( - ArrayBuilder textDocumentEdits, + async Task AddTextDocumentEditsAsync( IEnumerable changedDocuments, - Func getNewDocumentFunc, - Func getOldDocumentFunc, - IDocumentTextDifferencingService? textDiffService, - CancellationToken cancellationToken) + Func getNewDocument, + Func getOldDocument) where T : TextDocument { foreach (var docId in changedDocuments) { - var newTextDoc = getNewDocumentFunc(docId); - var oldTextDoc = getOldDocumentFunc(docId); + var newTextDoc = getNewDocument(docId); + var oldTextDoc = getOldDocument(docId); Contract.ThrowIfNull(oldTextDoc); Contract.ThrowIfNull(newTextDoc); diff --git a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs index fb35d5dbf39fe..99f63c14f4ccf 100644 --- a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionsHandler.cs @@ -19,13 +19,9 @@ namespace Microsoft.CodeAnalysis.LanguageServer.Handler { /// - /// Handles the initial request for code actions. Leaves the Edit and Command properties - /// of the returned VSCodeActions blank, as these properties should be populated by the - /// CodeActionsResolveHandler only when the user requests them. - /// - /// TODO - This must be moved to the MS.CA.LanguageServer.Protocol project once the - /// EditorFeatures references in are removed. - /// See https://github.com/dotnet/roslyn/issues/55142 + /// Handles the initial request for code actions. Leaves the Edit and Command properties of the returned + /// VSCodeActions blank, as these properties should be populated by the CodeActionsResolveHandler only when the user + /// requests them. /// [ExportCSharpVisualBasicStatelessLspService(typeof(CodeActionsHandler)), Shared] [Method(LSP.Methods.TextDocumentCodeActionName)] diff --git a/src/Features/LanguageServer/Protocol/Handler/CodeActions/RunCodeActionHandler.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/RunCodeActionHandler.cs deleted file mode 100644 index 7c0c6a3fe7e43..0000000000000 --- a/src/Features/LanguageServer/Protocol/Handler/CodeActions/RunCodeActionHandler.cs +++ /dev/null @@ -1,102 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Composition; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.LanguageServer.Handler.CodeActions; -using Microsoft.CodeAnalysis.LanguageServer.Handler.Commands; -using Microsoft.CodeAnalysis.Options; -using Newtonsoft.Json.Linq; -using Roslyn.Utilities; -using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; - -namespace Microsoft.CodeAnalysis.LanguageServer.Handler -{ - /// - /// Runs a code action as a command on the server. - /// This is done when a code action cannot be applied as a WorkspaceEdit on the LSP client. - /// For example, all non-ApplyChangesOperations must be applied as a command. - /// TO-DO: Currently, any ApplyChangesOperation that adds or removes a document must also be - /// applied as a command due to an LSP bug (see https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1147293/). - /// Commands must be applied from the UI thread in VS. - /// - /// TODO - This must be moved to the MS.CA.LanguageServer.Protocol project once the - /// UI thread dependencies are resolved and references are removed. - /// See https://github.com/dotnet/roslyn/issues/55142 - /// - [ExportCSharpVisualBasicStatelessLspService(typeof(RunCodeActionHandler)), Shared] - [Command(CodeActionsHandler.RunCodeActionCommandName)] - internal class RunCodeActionHandler : AbstractExecuteWorkspaceCommandHandler - { - private readonly ICodeFixService _codeFixService; - private readonly ICodeRefactoringService _codeRefactoringService; - private readonly IGlobalOptionService _globalOptions; - private readonly IThreadingContext _threadingContext; - - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public RunCodeActionHandler( - ICodeFixService codeFixService, - ICodeRefactoringService codeRefactoringService, - IGlobalOptionService globalOptions, - IThreadingContext threadingContext) - { - _codeFixService = codeFixService; - _codeRefactoringService = codeRefactoringService; - _globalOptions = globalOptions; - _threadingContext = threadingContext; - } - - public override string Command => CodeActionsHandler.RunCodeActionCommandName; - - public override bool MutatesSolutionState => true; - public override bool RequiresLSPSolution => true; - - public override LSP.TextDocumentIdentifier GetTextDocumentIdentifier(LSP.ExecuteCommandParams request) - { - var runRequest = ((JToken)request.Arguments.Single()).ToObject(); - Assumes.Present(runRequest); - - return runRequest.TextDocument; - } - - public override async Task HandleRequestAsync(LSP.ExecuteCommandParams request, RequestContext context, CancellationToken cancellationToken) - { - var document = context.Document; - Contract.ThrowIfNull(document); - - var runRequest = ((JToken)request.Arguments.Single()).ToObject(); - Assumes.Present(runRequest); - - var options = _globalOptions.GetCodeActionOptionsProvider(); - - var codeActionsCache = context.GetRequiredLspService(); - var codeActions = await CodeActionHelpers.GetCodeActionsAsync( - codeActionsCache, document, runRequest.Range, options, _codeFixService, _codeRefactoringService, cancellationToken).ConfigureAwait(false); - - var actionToRun = CodeActionHelpers.GetCodeActionToResolve(runRequest.UniqueIdentifier, codeActions); - Contract.ThrowIfNull(actionToRun); - - var operations = await actionToRun.GetOperationsAsync(cancellationToken).ConfigureAwait(false); - - // TODO - This UI thread dependency should be removed. - // https://github.com/dotnet/roslyn/projects/45#card-20619668 - await _threadingContext.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); - - foreach (var operation in operations) - { - operation.Apply(document.Project.Solution.Workspace, cancellationToken); - } - - return true; - } - } -} diff --git a/src/VisualStudio/Core/Def/Workspace/VisualStudioAddMetadataReferenceCodeActionOperationFactoryWorkspaceService.cs b/src/VisualStudio/Core/Def/Workspace/VisualStudioAddMetadataReferenceCodeActionOperationFactoryWorkspaceService.cs index 3c215fe548bbd..c379352837f72 100644 --- a/src/VisualStudio/Core/Def/Workspace/VisualStudioAddMetadataReferenceCodeActionOperationFactoryWorkspaceService.cs +++ b/src/VisualStudio/Core/Def/Workspace/VisualStudioAddMetadataReferenceCodeActionOperationFactoryWorkspaceService.cs @@ -42,7 +42,7 @@ public CodeActionOperation CreateAddMetadataReferenceOperation(ProjectId project return new AddMetadataReferenceOperation(projectId, assemblyIdentity); } - private class AddMetadataReferenceOperation : Microsoft.CodeAnalysis.CodeActions.CodeActionOperation + private class AddMetadataReferenceOperation : CodeActionOperation { private readonly AssemblyIdentity _assemblyIdentity; private readonly ProjectId _projectId; @@ -53,7 +53,7 @@ public AddMetadataReferenceOperation(ProjectId projectId, AssemblyIdentity assem _assemblyIdentity = assemblyIdentity; } - public override void Apply(Microsoft.CodeAnalysis.Workspace workspace, CancellationToken cancellationToken = default) + public override void Apply(Workspace workspace, CancellationToken cancellationToken = default) { var visualStudioWorkspace = (VisualStudioWorkspaceImpl)workspace; if (!visualStudioWorkspace.TryAddReferenceToProject(_projectId, "*" + _assemblyIdentity.GetDisplayName())) From 6d57fd2c3499d943f1b63974f3e5ecacfc2ac698 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 8 Nov 2022 16:42:33 -0800 Subject: [PATCH 4/9] Simplify --- .../NamingStyle/NamingStyleCodeFixProvider.cs | 11 +++++----- .../AssemblyReferenceCodeAction.cs | 6 ++++- .../InstallPackageAndAddImportCodeAction.cs | 6 ++++- .../MetadataSymbolReferenceCodeAction.cs | 6 ++++- .../ParentInstallPackageCodeAction.cs | 7 ++++-- .../ProjectSymbolReferenceCodeAction.cs | 6 ++++- .../AddMissingReferenceCodeAction.cs | 6 ++--- .../InstallPackageParentCodeAction.cs | 6 ++++- .../ChangeSignatureCodeAction.cs | 2 +- .../AbstractMoveToNamespaceCodeAction.cs | 22 +++++-------------- .../Handler/CodeActions/CodeActionHelpers.cs | 7 +++--- .../CodeActions/CodeActionResolveHandler.cs | 10 ++++----- .../CodeActions/CodeActionsHandlerProvider.cs | 14 ------------ .../Core/Portable/CodeActions/CodeAction.cs | 4 ++-- 14 files changed, 55 insertions(+), 58 deletions(-) diff --git a/src/Analyzers/Core/CodeFixes/NamingStyle/NamingStyleCodeFixProvider.cs b/src/Analyzers/Core/CodeFixes/NamingStyle/NamingStyleCodeFixProvider.cs index 54942acef60c0..95e261d279c36 100644 --- a/src/Analyzers/Core/CodeFixes/NamingStyle/NamingStyleCodeFixProvider.cs +++ b/src/Analyzers/Core/CodeFixes/NamingStyle/NamingStyleCodeFixProvider.cs @@ -121,13 +121,12 @@ private class FixNameCodeAction : CodeAction private readonly Func> _createChangedSolutionAsync; private readonly string _equivalenceKey; -#if !CODE_STYLE /// - /// This code action invokes code on the UI thread to tell 3rd parties about the rename. As such, it does - /// more than make document changes (and is thus restricted in which hosts it can run). + /// This code action does produce non-text-edit operations (like notifying 3rd parties about a rename). But + /// it doesn't require this. As such, we can allow it to run in hosts that only allow document edits. Those + /// hosts will simply ignore the operations they don't understand. /// - public override ImmutableArray Tags => MakesNonDocumentChangeTags; -#endif + public override ImmutableArray Tags => ImmutableArray.Empty; public FixNameCodeAction( #if !CODE_STYLE @@ -167,7 +166,7 @@ protected override async Task> ComputeOperation { codeAction, factory.CreateSymbolRenamedOperation(_symbol, _newName, _startingSolution, newSolution) - }.AsEnumerable(); + }; #endif } diff --git a/src/Features/Core/Portable/AddImport/CodeActions/AssemblyReferenceCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/AssemblyReferenceCodeAction.cs index 54de0a913b6ea..a43865cbd7310 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/AssemblyReferenceCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/AssemblyReferenceCodeAction.cs @@ -16,10 +16,14 @@ internal abstract partial class AbstractAddImportFeatureService + /// This code action only works by adding a reference. As such, it requires a non document change (and is + /// thus restricted in which hosts it can run). + /// public AssemblyReferenceCodeAction( Document originalDocument, AddImportFixData fixData) - : base(originalDocument, fixData, MakesNonDocumentChangeTags) + : base(originalDocument, fixData, RequiresNonDocumentChangeTags) { Contract.ThrowIfFalse(fixData.Kind == AddImportFixKind.ReferenceAssemblySymbol); } diff --git a/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs index c03cc8086b9f6..4be859f664114 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/InstallPackageAndAddImportCodeAction.cs @@ -28,12 +28,16 @@ private class InstallPackageAndAddImportCodeAction : AddImportCodeAction /// private readonly InstallPackageDirectlyCodeActionOperation _installOperation; + /// + /// This code action only works by installing a package. As such, it requires a non document change (and is + /// thus restricted in which hosts it can run). + /// public InstallPackageAndAddImportCodeAction( Document originalDocument, AddImportFixData fixData, string title, InstallPackageDirectlyCodeActionOperation installOperation) - : base(originalDocument, fixData, MakesNonDocumentChangeTags) + : base(originalDocument, fixData, RequiresNonDocumentChangeTags) { Contract.ThrowIfFalse(fixData.Kind == AddImportFixKind.PackageSymbol); Title = title; diff --git a/src/Features/Core/Portable/AddImport/CodeActions/MetadataSymbolReferenceCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/MetadataSymbolReferenceCodeAction.cs index 364ab20c389e2..2b7848a5d5f39 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/MetadataSymbolReferenceCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/MetadataSymbolReferenceCodeAction.cs @@ -15,8 +15,12 @@ internal abstract partial class AbstractAddImportFeatureService + /// This code action only works by adding a reference to a metadata dll. As such, it requires a non + /// document change (and is thus restricted in which hosts it can run). + /// public MetadataSymbolReferenceCodeAction(Document originalDocument, AddImportFixData fixData) - : base(originalDocument, fixData, MakesNonDocumentChangeTags) + : base(originalDocument, fixData, RequiresNonDocumentChangeTags) { Contract.ThrowIfFalse(fixData.Kind == AddImportFixKind.MetadataSymbol); } diff --git a/src/Features/Core/Portable/AddImport/CodeActions/ParentInstallPackageCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/ParentInstallPackageCodeAction.cs index c74cee9bb09d9..66380dc60d477 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/ParentInstallPackageCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/ParentInstallPackageCodeAction.cs @@ -10,7 +10,6 @@ using Microsoft.CodeAnalysis.CodeActions; using Microsoft.CodeAnalysis.Packaging; using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.Tags; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.AddImport @@ -24,7 +23,11 @@ internal abstract partial class AbstractAddImportFeatureService private class ParentInstallPackageCodeAction : CodeAction.CodeActionWithNestedActions { - public override ImmutableArray Tags => MakesNonDocumentChangeTags; + /// + /// This code action only works by installing a package. As such, it requires a non document change (and is + /// thus restricted in which hosts it can run). + /// + public override ImmutableArray Tags => RequiresNonDocumentChangeTags; /// /// Even though we have child actions, we mark ourselves as explicitly non-inlinable. diff --git a/src/Features/Core/Portable/AddImport/CodeActions/ProjectSymbolReferenceCodeAction.cs b/src/Features/Core/Portable/AddImport/CodeActions/ProjectSymbolReferenceCodeAction.cs index f51841694c5ad..06b9606da80a1 100644 --- a/src/Features/Core/Portable/AddImport/CodeActions/ProjectSymbolReferenceCodeAction.cs +++ b/src/Features/Core/Portable/AddImport/CodeActions/ProjectSymbolReferenceCodeAction.cs @@ -21,12 +21,16 @@ internal abstract partial class AbstractAddImportFeatureService private class ProjectSymbolReferenceCodeAction : SymbolReferenceCodeAction { + /// + /// This code action may or may not add a project reference. If it does, it requires a non document change + /// (and is thus restricted in which hosts it can run). If it doesn't, it can run anywhere. + /// public ProjectSymbolReferenceCodeAction( Document originalDocument, AddImportFixData fixData) : base(originalDocument, fixData, - additionalTags: ShouldAddProjectReference(originalDocument, fixData) ? MakesNonDocumentChangeTags : ImmutableArray.Empty) + additionalTags: ShouldAddProjectReference(originalDocument, fixData) ? RequiresNonDocumentChangeTags : ImmutableArray.Empty) { Contract.ThrowIfFalse(fixData.Kind == AddImportFixKind.ProjectSymbol); } diff --git a/src/Features/Core/Portable/AddMissingReference/AddMissingReferenceCodeAction.cs b/src/Features/Core/Portable/AddMissingReference/AddMissingReferenceCodeAction.cs index e3ac42722c12b..fdeeb1df1095a 100644 --- a/src/Features/Core/Portable/AddMissingReference/AddMissingReferenceCodeAction.cs +++ b/src/Features/Core/Portable/AddMissingReference/AddMissingReferenceCodeAction.cs @@ -23,10 +23,10 @@ internal class AddMissingReferenceCodeAction : CodeAction public override string Title { get; } /// - /// This code action adds references, and thus definitely makes non-document changes. It cannot run in hosts - /// that only support text changes. + /// This code action only works by adding references. As such, it requires a non document change (and is + /// thus restricted in which hosts it can run). /// - public override ImmutableArray Tags => MakesNonDocumentChangeTags; + public override ImmutableArray Tags => RequiresNonDocumentChangeTags; public AddMissingReferenceCodeAction(Project project, string title, ProjectReference? projectReferenceToAdd, AssemblyIdentity missingAssemblyIdentity) { diff --git a/src/Features/Core/Portable/AddPackage/InstallPackageParentCodeAction.cs b/src/Features/Core/Portable/AddPackage/InstallPackageParentCodeAction.cs index 0b2c6c6a2c1d1..933b628839994 100644 --- a/src/Features/Core/Portable/AddPackage/InstallPackageParentCodeAction.cs +++ b/src/Features/Core/Portable/AddPackage/InstallPackageParentCodeAction.cs @@ -20,7 +20,11 @@ namespace Microsoft.CodeAnalysis.AddPackage /// internal class InstallPackageParentCodeAction : CodeAction.CodeActionWithNestedActions { - public override ImmutableArray Tags => MakesNonDocumentChangeTags; + /// + /// This code action only works by installing a package. As such, it requires a non document change (and is + /// thus restricted in which hosts it can run). + /// + public override ImmutableArray Tags => RequiresNonDocumentChangeTags; /// /// Even though we have child actions, we mark ourselves as explicitly non-inlinable. diff --git a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs index f23c7814684c7..9fe93598816dc 100644 --- a/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs +++ b/src/Features/Core/Portable/ChangeSignature/ChangeSignatureCodeAction.cs @@ -23,7 +23,7 @@ internal class ChangeSignatureCodeAction : CodeActionWithOptions /// This code action currently pops up a confirmation dialog to the user. As such, it does more than make /// document changes (and is thus restricted in which hosts it can run). /// - public override ImmutableArray Tags => MakesNonDocumentChangeTags; + public override ImmutableArray Tags => RequiresNonDocumentChangeTags; public ChangeSignatureCodeAction(AbstractChangeSignatureService changeSignatureService, ChangeSignatureAnalysisSucceededContext context) { diff --git a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs index 9f5d6d4f61a7f..189dd13e602c3 100644 --- a/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs +++ b/src/Features/Core/Portable/MoveToNamespace/AbstractMoveToNamespaceCodeAction.cs @@ -31,22 +31,12 @@ public AbstractMoveToNamespaceCodeAction( _cleanupOptions = cleanupOptions; } - public override ImmutableArray Tags - { - get - { - var solution = _moveToNamespaceAnalysisResult.Document.Project.Solution; - var symbolRenameCodeActionOperationFactory = solution.Services.GetService(); - - // If we're in a host that supports the symbol rename code action, then this code action will do more - // than just move. It will also notify clients about the rename it does. As such, it does more than - // make / document changes (and is thus restricted in which hosts it can run). - if (symbolRenameCodeActionOperationFactory != null) - return MakesNonDocumentChangeTags; - - return ImmutableArray.Empty; - } - } + /// + /// This code action does notify clients about the rename it performs. However, this is an optional part of + /// this work, that happens after the move has happened. As such, this does not require non document changes + /// and can run in all our hosts. + /// + public override ImmutableArray Tags => ImmutableArray.Empty; public override object GetOptions(CancellationToken cancellationToken) { diff --git a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs index c34409706b3d2..19534571877ee 100644 --- a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionHelpers.cs @@ -16,7 +16,6 @@ using Microsoft.CodeAnalysis.UnifiedSuggestions; using Microsoft.VisualStudio.LanguageServer.Protocol; using Roslyn.Utilities; -using static Microsoft.CodeAnalysis.CodeActions.CodeAction; using CodeAction = Microsoft.CodeAnalysis.CodeActions.CodeAction; using LSP = Microsoft.VisualStudio.LanguageServer.Protocol; @@ -60,9 +59,9 @@ public static async Task GetVSCodeActionsAsync( if (suggestedAction.OriginalCodeAction is CodeActionWithOptions) continue; - // Skip code actions that make non-document changes. We can't apply them in LSP currently. + // Skip code actions that requires non-document changes. We can't apply them in LSP currently. // https://github.com/dotnet/roslyn/issues/48698 - if (suggestedAction.OriginalCodeAction.Tags.Contains(CodeAction.MakesNonDocumentChange)) + if (suggestedAction.OriginalCodeAction.Tags.Contains(CodeAction.RequiresNonDocumentChange)) continue; codeActions.Add(GenerateVSCodeAction( @@ -231,7 +230,7 @@ private static CodeAction GetNestedActionsFromActionSet(IUnifiedSuggestedAction } } - return CodeActionWithNestedActions.Create( + return CodeAction.CodeActionWithNestedActions.Create( codeAction.Title, nestedActions.ToImmutable(), codeAction.IsInlinable, codeAction.Priority); } diff --git a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs index b348f039edc8d..6124bb43500aa 100644 --- a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs @@ -163,11 +163,11 @@ await AddTextDocumentEditsAsync( return codeAction; - async Task AddTextDocumentEditsAsync( + async Task AddTextDocumentEditsAsync( IEnumerable changedDocuments, - Func getNewDocument, - Func getOldDocument) - where T : TextDocument + Func getNewDocument, + Func getOldDocument) + where TTextDocument : TextDocument { foreach (var docId in changedDocuments) { @@ -196,7 +196,7 @@ async Task AddTextDocumentEditsAsync( var edits = textChanges.Select(tc => ProtocolConversions.TextChangeToTextEdit(tc, oldText)).ToArray(); var documentIdentifier = new OptionalVersionedTextDocumentIdentifier { Uri = newTextDoc.GetURI() }; - textDocumentEdits.Add(new TextDocumentEdit { TextDocument = documentIdentifier, Edits = edits.ToArray() }); + textDocumentEdits.Add(new TextDocumentEdit { TextDocument = documentIdentifier, Edits = edits }); } } } diff --git a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/CodeActions/CodeActionsHandlerProvider.cs b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/CodeActions/CodeActionsHandlerProvider.cs index 16128bb031d60..4c041562a38be 100644 --- a/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/CodeActions/CodeActionsHandlerProvider.cs +++ b/src/VisualStudio/Xaml/Impl/Implementation/LanguageServer/Handler/CodeActions/CodeActionsHandlerProvider.cs @@ -44,18 +44,4 @@ public XamlCodeActionResolveHandler( { } } - - [ExportStatelessXamlLspService(typeof(RunCodeActionHandler)), Shared] - internal class XamlRunCodeActionHandler : RunCodeActionHandler - { - [ImportingConstructor] - [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public XamlRunCodeActionHandler( - ICodeFixService codeFixService, - ICodeRefactoringService codeRefactoringService, - IGlobalOptionService globalOptions, - IThreadingContext threadingContext) : base(codeFixService, codeRefactoringService, globalOptions, threadingContext) - { - } - } } diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs b/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs index 1cae227a6fe2a..a3fbe7afca50f 100644 --- a/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs +++ b/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs @@ -33,8 +33,8 @@ namespace Microsoft.CodeAnalysis.CodeActions /// public abstract class CodeAction { - internal const string MakesNonDocumentChange = nameof(MakesNonDocumentChange); - private protected static ImmutableArray MakesNonDocumentChangeTags = ImmutableArray.Create(MakesNonDocumentChange); + internal const string RequiresNonDocumentChange = nameof(RequiresNonDocumentChange); + private protected static ImmutableArray RequiresNonDocumentChangeTags = ImmutableArray.Create(RequiresNonDocumentChange); /// /// A short title describing the action that may appear in a menu. From 9cc544ba9d6521e8fc2139567b04efe605c93c46 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 8 Nov 2022 16:46:29 -0800 Subject: [PATCH 5/9] Add docs --- .../Core/Portable/CodeActions/CodeAction.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs b/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs index a3fbe7afca50f..31b2bc798e1dc 100644 --- a/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs +++ b/src/Workspaces/Core/Portable/CodeActions/CodeAction.cs @@ -33,6 +33,20 @@ namespace Microsoft.CodeAnalysis.CodeActions /// public abstract class CodeAction { + /// + /// Tag we use to convey that this code action should only be shown if it's in a host that allows for + /// non-document changes. For example if it needs to make project changes, or if will show host-specific UI. + /// + /// Note: if the bulk of code action is just document changes, and it does some optional things beyond that + /// (like navigating the user somewhere) this should not be set. Such a code action is still usable in all + /// hosts and should be shown to the user. It's only if the code action can truly not function should this + /// tag be provided. + /// + /// + /// Currently, this also means that we presume that all 3rd party code actions do not require non-document + /// changes and we will show them all in all hosts. + /// + /// internal const string RequiresNonDocumentChange = nameof(RequiresNonDocumentChange); private protected static ImmutableArray RequiresNonDocumentChangeTags = ImmutableArray.Create(RequiresNonDocumentChange); From b52f2cfee03bb257e446892c13da1b7f6b9f4e2d Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 8 Nov 2022 18:10:59 -0800 Subject: [PATCH 6/9] Add doc link --- .../Handler/CodeActions/CodeActionResolveHandler.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs index 6124bb43500aa..7e04c6b9bd450 100644 --- a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs @@ -61,6 +61,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(LSP.CodeAction request) public async Task HandleRequestAsync(LSP.CodeAction codeAction, RequestContext context, CancellationToken cancellationToken) { var document = context.GetRequiredDocument(); + var solution = document.Project.Solution; var data = ((JToken)codeAction.Data!).ToObject(); Assumes.Present(data); @@ -82,16 +83,11 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(LSP.CodeAction request) var operations = await codeActionToResolve.GetOperationsAsync(cancellationToken).ConfigureAwait(false); - // We only support making solution changing actions. We can also ignore DocumentNavigation as that is an - // additional suggestion a code action can make about what to do post edit. - var applicableActions = operations.Where(o => o is ApplyChangesOperation or DocumentNavigationOperation).ToArray(); - // TO-DO: We currently must execute code actions which add new documents on the server as commands, // since there is no LSP support for adding documents yet. In the future, we should move these actions // to execute on the client. // https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1147293/ - var solution = document.Project.Solution; var textDiffService = solution.Services.GetService(); using var _ = ArrayBuilder.GetInstance(out var textDocumentEdits); @@ -110,8 +106,11 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(LSP.CodeAction request) var changes = applyChangesOperation.ChangedSolution.GetChanges(solution); var projectChanges = changes.GetProjectChanges(); - // ignore any non-document changes. In the future we could see if there is some mechanism by which we - // can make these changes safely in LSP. + // Ignore any non-document changes for now. Note though that LSP does support additional functionality + // (like create/rename/delete file). Once VS updates their LSP client impl to support this, we should + // add that support here. + // + // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspaceEdit #if false // TO-DO: If the change involves adding or removing a document, execute via command instead of WorkspaceEdit From 6464996686412c7c24ca53c3f5d04e14a93e0b63 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Tue, 8 Nov 2022 18:25:32 -0800 Subject: [PATCH 7/9] Log informatin --- .../Protocol/Handler/CodeActions/CodeActionResolveHandler.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs index 7e04c6b9bd450..9e8628f48d4ef 100644 --- a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs @@ -101,7 +101,10 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(LSP.CodeAction request) // However, we cannot enforce this as 3rd party fixers can still run. So we filter their results to // only apply the portions of their work that updates documents, and nothing else. if (option is not ApplyChangesOperation applyChangesOperation) + { + context.TraceInformation($"Skipping code action operation for '{data.UniqueIdentifier}'. It was a '{option.GetType().FullName}'"); continue; + } var changes = applyChangesOperation.ChangedSolution.GetChanges(solution); var projectChanges = changes.GetProjectChanges(); From 764227bcf93f4d2bfdd20ddd0a931faa63069289 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 9 Nov 2022 08:38:43 -0800 Subject: [PATCH 8/9] Fixup tests --- .../AbstractCrossLanguageUserDiagnosticTest.vb | 2 +- .../AddImport/AddImportCrossLanguageTests.vb | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/EditorFeatures/Test2/Diagnostics/AbstractCrossLanguageUserDiagnosticTest.vb b/src/EditorFeatures/Test2/Diagnostics/AbstractCrossLanguageUserDiagnosticTest.vb index beda37d80fb1d..62aab7c8b8d39 100644 --- a/src/EditorFeatures/Test2/Diagnostics/AbstractCrossLanguageUserDiagnosticTest.vb +++ b/src/EditorFeatures/Test2/Diagnostics/AbstractCrossLanguageUserDiagnosticTest.vb @@ -77,7 +77,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics Dim codeAction = codeActions(codeActionIndex) If Not glyphTags.IsDefault Then - Assert.Equal(glyphTags, codeAction.Tags) + AssertEx.SetEqual(glyphTags, codeAction.Tags) End If Dim oldSolution = workspace.CurrentSolution diff --git a/src/EditorFeatures/Test2/Diagnostics/AddImport/AddImportCrossLanguageTests.vb b/src/EditorFeatures/Test2/Diagnostics/AddImport/AddImportCrossLanguageTests.vb index 348eb6832d533..2f21f5d7e6895 100644 --- a/src/EditorFeatures/Test2/Diagnostics/AddImport/AddImportCrossLanguageTests.vb +++ b/src/EditorFeatures/Test2/Diagnostics/AddImport/AddImportCrossLanguageTests.vb @@ -13,6 +13,7 @@ Imports Microsoft.CodeAnalysis.SolutionCrawler Imports Microsoft.CodeAnalysis.Tags Imports Microsoft.CodeAnalysis.VisualBasic.AddImport Imports Roslyn.Utilities +Imports Microsoft.CodeAnalysis.CodeActions Namespace Microsoft.CodeAnalysis.Editor.UnitTests.Diagnostics.AddImport @@ -266,7 +267,8 @@ namespace CSAssembly2 Await TestAsync( input, expected, codeActionIndex:=0, addedReference:="CSAssembly1", - glyphTags:=WellKnownTagArrays.CSharpProject, onAfterWorkspaceCreated:=AddressOf WaitForSymbolTreeInfoCache) + glyphTags:=WellKnownTagArrays.CSharpProject.Add(CodeAction.RequiresNonDocumentChange), + onAfterWorkspaceCreated:=AddressOf WaitForSymbolTreeInfoCache) End Function @@ -353,7 +355,8 @@ namespace CSAssembly2 Await TestAsync( input, expected, codeActionIndex:=0, addedReference:="CSAssembly1", - glyphTags:=WellKnownTagArrays.CSharpProject, onAfterWorkspaceCreated:=AddressOf WaitForSymbolTreeInfoCache) + glyphTags:=WellKnownTagArrays.CSharpProject.Add(CodeAction.RequiresNonDocumentChange), + onAfterWorkspaceCreated:=AddressOf WaitForSymbolTreeInfoCache) End Function @@ -399,7 +402,7 @@ namespace CSAssembly2 .Value.Trim() Await TestAsync(input, expected, codeActionIndex:=0, addedReference:="NewName", - glyphTags:=WellKnownTagArrays.CSharpProject, + glyphTags:=WellKnownTagArrays.CSharpProject.Add(CodeAction.RequiresNonDocumentChange), onAfterWorkspaceCreated:= Async Function(workspace As TestWorkspace) Dim project = workspace.CurrentSolution.Projects.Single(Function(p) p.AssemblyName = "CSAssembly1") @@ -445,7 +448,8 @@ End Namespace Await TestAsync( input, expected, codeActionIndex:=0, addedReference:="VBAssembly1", - glyphTags:=WellKnownTagArrays.VisualBasicProject, onAfterWorkspaceCreated:=AddressOf WaitForSymbolTreeInfoCache) + glyphTags:=WellKnownTagArrays.VisualBasicProject.Add(CodeAction.RequiresNonDocumentChange), + onAfterWorkspaceCreated:=AddressOf WaitForSymbolTreeInfoCache) End Function Private Async Function WaitForSymbolTreeInfoCache(workspace As TestWorkspace) As Task @@ -522,7 +526,8 @@ namespace A - Await TestAsync(input, addedReference:="CSAssembly2", glyphTags:=WellKnownTagArrays.CSharpProject, + Await TestAsync(input, addedReference:="CSAssembly2", + glyphTags:=WellKnownTagArrays.CSharpProject.Add(CodeAction.RequiresNonDocumentChange), onAfterWorkspaceCreated:=AddressOf WaitForSymbolTreeInfoCache) End Function From 1eaa2918a32d5d1406399d93fc5a7b2237203efe Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Wed, 9 Nov 2022 08:42:33 -0800 Subject: [PATCH 9/9] Add comments --- .../Protocol/Handler/CodeActions/CodeActionResolveHandler.cs | 2 ++ .../ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs index 9e8628f48d4ef..97ce814f8f0ce 100644 --- a/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs +++ b/src/Features/LanguageServer/Protocol/Handler/CodeActions/CodeActionResolveHandler.cs @@ -114,6 +114,8 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(LSP.CodeAction request) // add that support here. // // https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspaceEdit + // + // Tracked with: https://github.com/dotnet/roslyn/issues/65303 #if false // TO-DO: If the change involves adding or removing a document, execute via command instead of WorkspaceEdit diff --git a/src/Features/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs b/src/Features/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs index d7d753843da1c..33aedb466d380 100644 --- a/src/Features/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs +++ b/src/Features/LanguageServer/ProtocolUnitTests/CodeActions/RunCodeActionsTests.cs @@ -24,7 +24,7 @@ public RunCodeActionsTests(ITestOutputHelper testOutputHelper) : base(testOutput { } - [WpfFact] + [WpfFact(Skip = "https://github.com/dotnet/roslyn/issues/65303")] public async Task TestRunCodeActions() { var markup =