Skip to content

Commit

Permalink
Add codefix for redundant attribute suffix. (#1132)
Browse files Browse the repository at this point in the history
  • Loading branch information
nojaf authored Jul 9, 2023
1 parent 732ccc8 commit ba90409
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 0 deletions.
53 changes: 53 additions & 0 deletions src/FsAutoComplete/CodeFixes/RemoveRedundantAttributeSuffix.fs
Original file line number Diff line number Diff line change
@@ -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 })
}
1 change: 1 addition & 0 deletions src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
97 changes: 97 additions & 0 deletions test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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
[<ObsoleteAttribute$0("Meh")>]
let f x y = x + y
"""
Diagnostics.acceptAll
selectCodeFix
"""
open System
[<Obsolete("Meh")>]
let f x y = x + y
"""

testCaseAsync "redundant attribute suffix on type definition"
<| CodeFix.check
server
"""
open System
type FooAttribute() = inherit Attribute()
[<FooAttribute$0>]
type A =
class end
"""
Diagnostics.acceptAll
selectCodeFix
"""
open System
type FooAttribute() = inherit Attribute()
[<Foo>]
type A =
class end
"""

testCaseAsync "redundant attribute suffix with target and constructor"
<| CodeFix.check
server
"""
open System
type FooAttribute() = inherit Attribute()
[<type: FooAttribute$0()>]
type A =
class end
"""
Diagnostics.acceptAll
selectCodeFix
"""
open System
type FooAttribute() = inherit Attribute()
[<type: Foo()>]
type A =
class end
"""

testCaseAsync "redundant attribute suffix in multiple attributes"
<| CodeFix.check
server
"""
open System
type FooAttribute() = inherit Attribute()
type BarAttribute() = inherit Attribute()
[<FooAttribute$0; Bar>]
type A =
class end
"""
Diagnostics.acceptAll
selectCodeFix
"""
open System
type FooAttribute() = inherit Attribute()
type BarAttribute() = inherit Attribute()
[<Foo; Bar>]
type A =
class end
""" ])

let tests state = testList "CodeFix-tests" [
HelpersTests.tests

Expand Down Expand Up @@ -2819,4 +2915,5 @@ let tests state = testList "CodeFix-tests" [
useMutationWhenValueIsMutableTests state
useTripleQuotedInterpolationTests state
wrapExpressionInParenthesesTests state
removeRedundantAttributeSuffixTests state
]

0 comments on commit ba90409

Please sign in to comment.