diff --git a/src/FsAutoComplete/CodeFixes/RemovePatternArgument.fs b/src/FsAutoComplete/CodeFixes/RemovePatternArgument.fs new file mode 100644 index 000000000..0b95e9029 --- /dev/null +++ b/src/FsAutoComplete/CodeFixes/RemovePatternArgument.fs @@ -0,0 +1,54 @@ +module FsAutoComplete.CodeFix.RemovePatternArgument + +open FsToolkit.ErrorHandling +open FsAutoComplete.CodeFix.Types +open Ionide.LanguageServerProtocol.Types +open FsAutoComplete +open FsAutoComplete.LspHelpers +open FSharp.Compiler.Syntax +open FSharp.Compiler.Text.Range +open FSharp.Compiler.Text + +let title = "Remove argument" + +let tryFindPattern pos input = + let visitor = + { new SyntaxVisitorBase() with + + member _.VisitExpr(path, traverseSynExpr, defaultTraverse, expr) = defaultTraverse expr + + member this.VisitPat(path: SyntaxVisitorPath, defaultTraverse: SynPat -> range option, synPat: SynPat) = + match synPat with + | SynPat.LongIdent(longDotId = synLongIdent; argPats = SynArgPats.Pats(pats); range = m) when + rangeContainsPos synPat.Range pos && not pats.IsEmpty + -> + let mRemove = mkRange m.FileName synLongIdent.Range.End m.End + Some mRemove + | SynPat.Paren(pat = innerPat) -> + let nextPath = SyntaxNode.SynPat(synPat) :: path + this.VisitPat(nextPath, defaultTraverse, innerPat) + | _ -> None } + + SyntaxTraversal.Traverse(pos, input, visitor) + +let fix (getParseResultsForFile: GetParseResultsForFile) : CodeFix = + Run.ifDiagnosticByCode (Set.ofList [ "725"; "3191" ]) (fun _ codeActionParams -> + asyncResult { + let filePath = codeActionParams.TextDocument.GetFilePath() |> Utils.normalizePath + let fcsPos = protocolPosToPos codeActionParams.Range.Start + let! parseAndCheck, _, _ = getParseResultsForFile filePath fcsPos + + match tryFindPattern fcsPos parseAndCheck.GetAST with + | None -> return [] + | Some removeRange -> + let e = + { Range = fcsRangeToLsp removeRange + NewText = "" } + + return + [ { Edits = [| e |] + File = codeActionParams.TextDocument + Title = title + SourceDiagnostic = None + Kind = FixKind.Refactor } ] + }) diff --git a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs index 9ba2d2ece..74b7a8efc 100644 --- a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs +++ b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs @@ -1691,7 +1691,8 @@ type AdaptiveFSharpLspServer (fun _ -> config.AddPrivateAccessModifier) (AddPrivateAccessModifier.fix tryGetParseResultsForFile symbolUseWorkspace) UseTripleQuotedInterpolation.fix tryGetParseResultsForFile getRangeText - RenameParamToMatchSignature.fix tryGetParseResultsForFile |]) + RenameParamToMatchSignature.fix tryGetParseResultsForFile + RemovePatternArgument.fix tryGetParseResultsForFile |]) let forgetDocument (uri: DocumentUri) = async { diff --git a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs index c14275576..cb349fb72 100644 --- a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs +++ b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs @@ -1228,7 +1228,8 @@ type FSharpLspServer(state: State, lspClient: FSharpLspClient, sourceTextFactory (fun _ -> config.AddPrivateAccessModifier) (AddPrivateAccessModifier.fix tryGetParseResultsForFile symbolUseWorkspace) UseTripleQuotedInterpolation.fix tryGetParseResultsForFile getRangeText - RenameParamToMatchSignature.fix tryGetParseResultsForFile |] + RenameParamToMatchSignature.fix tryGetParseResultsForFile + RemovePatternArgument.fix tryGetParseResultsForFile |] match p.RootPath, c.AutomaticWorkspaceInit with diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs index 452c9146b..7394860d6 100644 --- a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs +++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs @@ -2873,6 +2873,222 @@ let private removeRedundantAttributeSuffixTests state = class end """ ]) +let private removePatternArgumentTests state = + fserverTestList (nameof RemovePatternArgument) state defaultConfigDto None (fun server -> [ + let selectCodeFix = CodeFix.withTitle RemovePatternArgument.title + testCaseAsync "Literal pattern qualified single parameter" <| + CodeFix.check server + """ + type E = + | A = 1 + | B = 2 + + let (E.A x$0) = E.A + """ + (Diagnostics.expectCode "3191") + selectCodeFix + """ + type E = + | A = 1 + | B = 2 + + let (E.A) = E.A + """ + + testCaseAsync "Local literal pattern qualified match parens parameter" <| + CodeFix.check server + """ + type E = + | A = 1 + | B = 2 + + match E.A with + | (E.A x$0) -> () + """ + (Diagnostics.expectCode "3191") + selectCodeFix + """ + type E = + | A = 1 + | B = 2 + + match E.A with + | (E.A) -> () + """ + + testCaseAsync "Local literal pattern qualified single parameter" <| + CodeFix.check server + """ + type E = + | A = 1 + | B = 2 + + do + let (E.A x$0) = E.A + () + """ + (Diagnostics.expectCode "3191") + selectCodeFix + """ + type E = + | A = 1 + | B = 2 + + do + let (E.A) = E.A + () + """ + + testCaseAsync "Local literal constant pattern qualified parameter" <| + CodeFix.check server + """ + let [] A = 1 + + match 1 with + | A x$0 -> () + """ + (Diagnostics.expectCode "3191") + selectCodeFix + """ + let [] A = 1 + + match 1 with + | A -> () + """ + + testCaseAsync "Local literal constant pattern qualified parens parameter" <| + CodeFix.check server + """ + let [] A = 1 + + match 1 with + | (A x$0) -> () + """ + (Diagnostics.expectCode "3191") + selectCodeFix + """ + let [] A = 1 + + match 1 with + | (A) -> () + """ + + testCaseAsync "Local match qualified single parameter" <| + CodeFix.check server + """ + match None with + | Option.None x$0 -> () + """ + (Diagnostics.expectCode "725") + selectCodeFix + """ + match None with + | Option.None -> () + """ + + testCaseAsync "Local match qualified single parens parameter" <| + CodeFix.check server + """ + match None with + | (Option.None x$0) -> () + """ + (Diagnostics.expectCode "725") + selectCodeFix + """ + match None with + | (Option.None) -> () + """ + + testCaseAsync "Qualified single parameter" <| + CodeFix.check server + """ + let (Option.None x$0) = None + """ + (Diagnostics.expectCode "725") + selectCodeFix + """ + let (Option.None) = None + """ + + testCaseAsync "Local single parameter" <| + CodeFix.check server + """ + do + let (Option.None x$0) = None + () + """ + (Diagnostics.expectCode "725") + selectCodeFix + """ + do + let (Option.None) = None + () + """ + + testCaseAsync "Local two match parameters" <| + CodeFix.check server + """ + match None with + | None x$0 y -> () + """ + (Diagnostics.expectCode "725") + selectCodeFix + """ + match None with + | None -> () + """ + + testCaseAsync "Local two match parens parameters" <| + CodeFix.check server + """ + match None with + | None (x$0 y) -> () + """ + (Diagnostics.expectCode "725") + selectCodeFix + """ + match None with + | None -> () + """ + + testCaseAsync "Local two parameter" <| + CodeFix.check server + """ + do + let (Option.None x$0 y) = None + () + """ + (Diagnostics.expectCode "725") + selectCodeFix + """ + do + let (Option.None) = None + () + """ + + testCaseAsync "Single parameter" <| + CodeFix.check server + """ + let (None x$0) = None + """ + (Diagnostics.expectCode "725") + selectCodeFix + """ + let (None) = None + """ + + testCaseAsync "Two parameters" <| + CodeFix.check server + """ + let (None x$0 y) = None + """ + (Diagnostics.expectCode "725") + selectCodeFix + """ + let (None) = None + """ + ]) + let tests state = testList "CodeFix-tests" [ HelpersTests.tests @@ -2916,4 +3132,5 @@ let tests state = testList "CodeFix-tests" [ useTripleQuotedInterpolationTests state wrapExpressionInParenthesesTests state removeRedundantAttributeSuffixTests state + removePatternArgumentTests state ]