From e3f0fd78710cfafc2b0ca9196c72ee6bd6205401 Mon Sep 17 00:00:00 2001 From: nojaf Date: Sun, 9 Jul 2023 12:04:05 +0200 Subject: [PATCH] Add codefix for redundant attribute suffix. --- .../RemoveRedundantAttributeSuffix.fs | 53 ++++++++++ .../LspServers/AdaptiveFSharpLspServer.fs | 1 + .../LspServers/FsAutoComplete.Lsp.fs | 1 + .../CodeFixTests/Tests.fs | 97 +++++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 src/FsAutoComplete/CodeFixes/RemoveRedundantAttributeSuffix.fs diff --git a/src/FsAutoComplete/CodeFixes/RemoveRedundantAttributeSuffix.fs b/src/FsAutoComplete/CodeFixes/RemoveRedundantAttributeSuffix.fs new file mode 100644 index 000000000..1326e179f --- /dev/null +++ b/src/FsAutoComplete/CodeFixes/RemoveRedundantAttributeSuffix.fs @@ -0,0 +1,53 @@ +module FsAutoComplete.CodeFix.RemoveRedundantAttributeSuffix + +open FSharp.Compiler.Syntax +open FsToolkit.ErrorHandling +open FsAutoComplete.CodeFix.Types +open Ionide.LanguageServerProtocol.Types +open FsAutoComplete +open FsAutoComplete.LspHelpers + +let title = "Remove redundant attribute suffix" + +let fix (getParseResultsForFile: GetParseResultsForFile) : CodeFix = + fun codeActionParams -> + asyncResult { + let filePath = codeActionParams.TextDocument.GetFilePath() |> Utils.normalizePath + let fcsPos = protocolPosToPos codeActionParams.Range.Start + let! parseAndCheck, _, _ = getParseResultsForFile filePath fcsPos + + let isAttributeWithRedundantSuffix = + SyntaxTraversal.Traverse( + fcsPos, + parseAndCheck.GetParseResults.ParseTree, + { new SyntaxVisitorBase<_>() with + member _.VisitAttributeApplication(path, attributes) = + let attributesWithRedundantSuffix = + attributes.Attributes + |> List.choose (fun a -> + match List.tryLast a.TypeName.LongIdent with + | Some ident when ident.idText.EndsWith("Attribute") -> Some ident + | _ -> None) + + if List.isEmpty attributesWithRedundantSuffix then + None + else + Some attributesWithRedundantSuffix } + ) + + match isAttributeWithRedundantSuffix with + | None -> return [] + | Some redundantSuffixIdents -> + return + redundantSuffixIdents + |> List.map (fun ident -> + let updateText = ident.idText.Replace("Attribute", "") + + { Edits = + [| { Range = fcsRangeToLsp ident.idRange + NewText = updateText } |] + 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 305670663..9ba2d2ece 100644 --- a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs +++ b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs @@ -1686,6 +1686,7 @@ type AdaptiveFSharpLspServer ConvertPositionalDUToNamed.fix tryGetParseResultsForFile getRangeText ConvertTripleSlashCommentToXmlTaggedDoc.fix tryGetParseResultsForFile getRangeText GenerateXmlDocumentation.fix tryGetParseResultsForFile + RemoveRedundantAttributeSuffix.fix tryGetParseResultsForFile Run.ifEnabled (fun _ -> config.AddPrivateAccessModifier) (AddPrivateAccessModifier.fix tryGetParseResultsForFile symbolUseWorkspace) diff --git a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs index 7ffad8fdd..c14275576 100644 --- a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs +++ b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs @@ -1223,6 +1223,7 @@ type FSharpLspServer(state: State, lspClient: FSharpLspClient, sourceTextFactory ConvertPositionalDUToNamed.fix tryGetParseResultsForFile getRangeText ConvertTripleSlashCommentToXmlTaggedDoc.fix tryGetParseResultsForFile getRangeText GenerateXmlDocumentation.fix tryGetParseResultsForFile + RemoveRedundantAttributeSuffix.fix tryGetParseResultsForFile Run.ifEnabled (fun _ -> config.AddPrivateAccessModifier) (AddPrivateAccessModifier.fix tryGetParseResultsForFile symbolUseWorkspace) diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs index 216017423..452c9146b 100644 --- a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs +++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs @@ -2777,6 +2777,102 @@ let private wrapExpressionInParenthesesTests state = selectCodeFix ]) +let private removeRedundantAttributeSuffixTests state = + serverTestList (nameof RemoveRedundantAttributeSuffix) state defaultConfigDto None (fun server -> + [ let selectCodeFix = CodeFix.withTitle RemoveRedundantAttributeSuffix.title + + testCaseAsync "redundant attribute suffix in let binding" + <| CodeFix.check + server + """ + open System + + [] + let f x y = x + y + """ + Diagnostics.acceptAll + selectCodeFix + """ + open System + + [] + let f x y = x + y + """ + + testCaseAsync "redundant attribute suffix on type definition" + <| CodeFix.check + server + """ + open System + + type FooAttribute() = inherit Attribute() + + [] + type A = + class end + """ + Diagnostics.acceptAll + selectCodeFix + """ + open System + + type FooAttribute() = inherit Attribute() + + [] + type A = + class end + """ + + testCaseAsync "redundant attribute suffix with target and constructor" + <| CodeFix.check + server + """ + open System + + type FooAttribute() = inherit Attribute() + + [] + type A = + class end + """ + Diagnostics.acceptAll + selectCodeFix + """ + open System + + type FooAttribute() = inherit Attribute() + + [] + type A = + class end + """ + + testCaseAsync "redundant attribute suffix in multiple attributes" + <| CodeFix.check + server + """ + open System + + type FooAttribute() = inherit Attribute() + type BarAttribute() = inherit Attribute() + + [] + type A = + class end + """ + Diagnostics.acceptAll + selectCodeFix + """ + open System + + type FooAttribute() = inherit Attribute() + type BarAttribute() = inherit Attribute() + + [] + type A = + class end + """ ]) + let tests state = testList "CodeFix-tests" [ HelpersTests.tests @@ -2819,4 +2915,5 @@ let tests state = testList "CodeFix-tests" [ useMutationWhenValueIsMutableTests state useTripleQuotedInterpolationTests state wrapExpressionInParenthesesTests state + removeRedundantAttributeSuffixTests state ]