From a4c4fdf5cb19244c026dff9753becae361d284d6 Mon Sep 17 00:00:00 2001 From: Christoph Bergmeister Date: Fri, 18 Feb 2022 15:55:03 -0800 Subject: [PATCH 1/2] Return a code action for each diagnostic record Currently, PSSA's `SuggestCorrections` property of the `DiagnosticRecord` object already is an array, but no built-in rules return more than one suggested correction, which led to `PowerShellEditorServices` not correctly translating this array before returning it as an code action as it only ever displayed one. This fixes it by making it generic again so it returns a code action for each suggest correction. It's basically just performing a `foreach` loop and calling `ToTextEdit` just once. This is a pre-requisite for an implementation of this, where a built-in rule will return multiple suggest corrections: https://github.com/PowerShell/PSScriptAnalyzer/issues/1767 I've manually tested this with a modified version of PSScriptAnalyzer where I return two suggested corrections. The extension's UI now shows me the two different suggested code actions and also applies them correctly. --- .../Handlers/CodeActionHandler.cs | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs index 062a312ff..24df42fe2 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs @@ -81,24 +81,27 @@ public override async Task Handle(CodeActionParams string diagnosticId = AnalysisService.GetUniqueIdFromDiagnostic(diagnostic); if (corrections.TryGetValue(diagnosticId, out MarkerCorrection correction)) { - codeActions.Add(new CodeAction + foreach (ScriptRegion edit in correction.Edits) { - Title = correction.Name, - Kind = CodeActionKind.QuickFix, - Edit = new WorkspaceEdit + codeActions.Add(new CodeAction { - DocumentChanges = new Container( - new WorkspaceEditDocumentChange( - new TextDocumentEdit - { - TextDocument = new OptionalVersionedTextDocumentIdentifier + Title = correction.Name, + Kind = CodeActionKind.QuickFix, + Edit = new WorkspaceEdit + { + DocumentChanges = new Container( + new WorkspaceEditDocumentChange( + new TextDocumentEdit { - Uri = request.TextDocument.Uri - }, - Edits = new TextEditContainer(correction.Edits.Select(ScriptRegion.ToTextEdit)) - })) - } - }); + TextDocument = new OptionalVersionedTextDocumentIdentifier + { + Uri = request.TextDocument.Uri + }, + Edits = new TextEditContainer(ScriptRegion.ToTextEdit(edit)) + })) + } + }); + } } } From f853cee2b0e01e39f1dfa0e49b82afd532c2ad42 Mon Sep 17 00:00:00 2001 From: Andrew Schwartzmeyer Date: Fri, 18 Feb 2022 16:54:42 -0800 Subject: [PATCH 2/2] Apply Roslyn analyzer fixes to `CodeActionHandler.cs` --- .../Handlers/CodeActionHandler.cs | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs index 24df42fe2..bc3e0a746 100644 --- a/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs +++ b/src/PowerShellEditorServices/Services/TextDocument/Handlers/CodeActionHandler.cs @@ -3,14 +3,12 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.PowerShell.EditorServices.Services; using Microsoft.PowerShell.EditorServices.Services.TextDocument; using Microsoft.PowerShell.EditorServices.Utility; -using Newtonsoft.Json.Linq; using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities; using OmniSharp.Extensions.LanguageServer.Protocol.Document; using OmniSharp.Extensions.LanguageServer.Protocol.Models; @@ -21,21 +19,22 @@ internal class PsesCodeActionHandler : CodeActionHandlerBase { private readonly ILogger _logger; private readonly AnalysisService _analysisService; - private readonly WorkspaceService _workspaceService; - public PsesCodeActionHandler(ILoggerFactory factory, AnalysisService analysisService, WorkspaceService workspaceService) + public PsesCodeActionHandler(ILoggerFactory factory, AnalysisService analysisService) { _logger = factory.CreateLogger(); _analysisService = analysisService; - _workspaceService = workspaceService; } - protected override CodeActionRegistrationOptions CreateRegistrationOptions(CodeActionCapability capability, ClientCapabilities clientCapabilities) => new CodeActionRegistrationOptions + protected override CodeActionRegistrationOptions CreateRegistrationOptions(CodeActionCapability capability, ClientCapabilities clientCapabilities) + { + return new() { - // TODO: What do we do with the arguments? - DocumentSelector = LspUtils.PowerShellDocumentSelector, - CodeActionKinds = new CodeActionKind[] { CodeActionKind.QuickFix } - }; + // TODO: What do we do with the arguments? + DocumentSelector = LspUtils.PowerShellDocumentSelector, + CodeActionKinds = new CodeActionKind[] { CodeActionKind.QuickFix } + }; + } // TODO: Either fix or ignore "method lacks 'await'" warning. public override async Task Handle(CodeAction request, CancellationToken cancellationToken) @@ -65,7 +64,7 @@ public override async Task Handle(CodeActionParams return Array.Empty(); } - var codeActions = new List(); + List codeActions = new(); // If there are any code fixes, send these commands first so they appear at top of "Code Fix" menu in the client UI. foreach (Diagnostic diagnostic in request.Context.Diagnostics) @@ -108,7 +107,7 @@ public override async Task Handle(CodeActionParams // Add "show documentation" commands last so they appear at the bottom of the client UI. // These commands do not require code fixes. Sometimes we get a batch of diagnostics // to create commands for. No need to create multiple show doc commands for the same rule. - var ruleNamesProcessed = new HashSet(); + HashSet ruleNamesProcessed = new(); foreach (Diagnostic diagnostic in request.Context.Diagnostics) { if ( @@ -122,8 +121,8 @@ public override async Task Handle(CodeActionParams if (string.Equals(diagnostic.Source, "PSScriptAnalyzer", StringComparison.OrdinalIgnoreCase) && !ruleNamesProcessed.Contains(diagnostic.Code?.String)) { - ruleNamesProcessed.Add(diagnostic.Code?.String); - var title = $"Show documentation for: {diagnostic.Code?.String}"; + _ = ruleNamesProcessed.Add(diagnostic.Code?.String); + string title = $"Show documentation for: {diagnostic.Code?.String}"; codeActions.Add(new CodeAction { Title = title, @@ -135,7 +134,7 @@ public override async Task Handle(CodeActionParams { Title = title, Name = "PowerShell.ShowCodeActionDocumentation", - Arguments = JArray.FromObject(new[] { diagnostic.Code?.String }) + Arguments = Newtonsoft.Json.Linq.JArray.FromObject(new[] { diagnostic.Code?.String }) } }); }