Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RemovePatternArgument quick fix #1142

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions src/FsAutoComplete/CodeFixes/RemovePatternArgument.fs
Original file line number Diff line number Diff line change
@@ -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<range>() 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 } ]
})
3 changes: 2 additions & 1 deletion src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
3 changes: 2 additions & 1 deletion src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
217 changes: 217 additions & 0 deletions test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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 [<Literal>] A = 1

match 1 with
| A x$0 -> ()
"""
(Diagnostics.expectCode "3191")
selectCodeFix
"""
let [<Literal>] A = 1

match 1 with
| A -> ()
"""

testCaseAsync "Local literal constant pattern qualified parens parameter" <|
CodeFix.check server
"""
let [<Literal>] A = 1

match 1 with
| (A x$0) -> ()
"""
(Diagnostics.expectCode "3191")
selectCodeFix
"""
let [<Literal>] 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

Expand Down Expand Up @@ -2916,4 +3132,5 @@ let tests state = testList "CodeFix-tests" [
useTripleQuotedInterpolationTests state
wrapExpressionInParenthesesTests state
removeRedundantAttributeSuffixTests state
removePatternArgumentTests state
]