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

Add tests & fixes for Code Fixes #915

Merged
merged 29 commits into from
Apr 11, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2b8f3dd
Sort Code Fix Tests alphabetically
Booksbaum Apr 7, 2022
47b2e4d
Fix: `GenerateAbstractClassStub` triggers twice
Booksbaum Apr 8, 2022
d1e77e6
Fix: `AddMissingRecKeyword` uses wrong function name in title
Booksbaum Apr 8, 2022
ddf44ec
Fix: `AddTypeToIndeterminateValue` doesn't trigger
Booksbaum Apr 8, 2022
0505dd6
Fix: `UseMutationWhenValueIsMutable` adds `<-` after `=` instead of r…
Booksbaum Apr 8, 2022
0f36396
Fix: `ConvertCSharpLambdaToFSharpLambda` joins multi-line body to sin…
Booksbaum Apr 8, 2022
842c24a
Rename `ColonInFieldType` to `ChangeEqualsInFieldTypeToColon`
Booksbaum Apr 8, 2022
678295e
Add test for `ConvertBangEqualsToInequality`
Booksbaum Apr 8, 2022
00098f2
Add tests for `ConvertInvalidRecordToAnonRecord`
Booksbaum Apr 8, 2022
a72ea78
Add tests for `ConvertDoubleEqualsToSingleEquals`
Booksbaum Apr 8, 2022
1a1eb45
Fix: Goto Declaration fails when declaration is in untitled file
Booksbaum Apr 8, 2022
6e75b7f
Fix: `AddMissingEqualsToTypeDefinition` doesn't trigger
Booksbaum Apr 9, 2022
4942871
Rename `NegationToSubtraction` to `ChangePrefixNegationToInfixSubtrac…
Booksbaum Apr 9, 2022
99591d5
Rename `NewWithDisposables` to `AddNewKeywordToDisposableConstructorI…
Booksbaum Apr 9, 2022
dd350c8
Fix: `ConvertPositionalDUToNamed` doesn't put space before wildcard
Booksbaum Apr 9, 2022
82fa65a
Rename `ParenthesizeEpression` to `WrapExpressionInParentheses`
Booksbaum Apr 9, 2022
0d8239e
Rename `RedundantQualifier` to `RemoveRedundantQualifier`
Booksbaum Apr 9, 2022
68dfb19
Rename `RefCellAccesToNot` to `ChangeRefCellDerefToNot`
Booksbaum Apr 9, 2022
8c13b8e
Add tests for `RemoveUnnecessaryReturnOrYield`
Booksbaum Apr 9, 2022
d82e22a
Change: Trigger `ChangeDerefBangToValue` on Diag `3370`
Booksbaum Apr 9, 2022
c6012ee
Rename `UseSafeCastInsteadOfUnsafe` to `ChangeDowncastToUpcast`
Booksbaum Apr 9, 2022
e510802
Rename test to match CodeFix
Booksbaum Apr 9, 2022
d9fdfe4
Fix: Incorrect sorted tests
Booksbaum Apr 9, 2022
972fe48
Fix: `ResolveNamespace` doesn't trigger when target is in last line
Booksbaum Apr 9, 2022
2b43d61
Fix: `ReplaceWithSuggestion` surrounds identifiers in double-backtick…
Booksbaum Apr 9, 2022
6061722
Fix: `RemoveUnusedOpens` doesn't trigger in first line
Booksbaum Apr 10, 2022
bacbb21
Rename `UnusedValue` to `RenameUnusedValue`
Booksbaum Apr 10, 2022
cc2a49f
Fix: Sort order of Tests
Booksbaum Apr 11, 2022
1db5841
Remove uncommented code
Booksbaum Apr 11, 2022
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
82 changes: 82 additions & 0 deletions src/FsAutoComplete/CodeFixes/ChangeDerefBangToValue.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/// replace use of ! operator on ref cells with calls to .Value
module FsAutoComplete.CodeFix.ChangeDerefBangToValue

open FsToolkit.ErrorHandling
open FsAutoComplete.CodeFix.Types
open FsAutoComplete
open FsAutoComplete.LspHelpers
open FSharp.Compiler.Syntax
open FSharp.Compiler.Text.Range
open FSharp.UMX

// let fix (getParseResultsForFile: GetParseResultsForFile) (getLineText: GetLineText): CodeFix =
// fun codeActionParams ->
// asyncResult {
// let fileName = codeActionParams.TextDocument.GetFilePath() |> Utils.normalizePath
// let selectionRange = protocolRangeToRange (codeActionParams.TextDocument.GetFilePath()) codeActionParams.Range
// let! parseResults, line, lines = getParseResultsForFile fileName selectionRange.Start
// let! derefRange = parseResults.GetParseResults.TryRangeOfRefCellDereferenceContainingPos selectionRange.Start |> Result.ofOption (fun _ -> "No deref found at that pos")
// let! exprRange = parseResults.GetParseResults.TryRangeOfExpressionBeingDereferencedContainingPos selectionRange.Start |> Result.ofOption (fun _ -> "No expr found at that pos")
// let combinedRange = FSharp.Compiler.Text.Range.unionRanges derefRange exprRange
// let protocolRange = fcsRangeToLsp combinedRange
// let! badString = getLineText lines protocolRange
// let replacementString = badString.[1..] + ".Value"
// return [
// { Title = title
// File = codeActionParams.TextDocument
// SourceDiagnostic = None
// Kind = FixKind.Refactor
// Edits = [| { Range = protocolRange
// NewText = replacementString } |] }
// ]
// }

/// adopted from `dotnet/fsharp` -> `FSharp.Compiler.CodeAnalysis.FSharpParseFileResults.TryRangeOfExpressionBeingDereferencedContainingPos`
let private tryGetRangeOfDeref input derefPos =
baronfel marked this conversation as resolved.
Show resolved Hide resolved
SyntaxTraversal.Traverse(derefPos, input, { new SyntaxVisitorBase<_>() with
member _.VisitExpr(_, _, defaultTraverse, expr) =
match expr with
| SynExpr.App(_, false, SynExpr.Ident funcIdent, expr, _) ->
if funcIdent.idText = "op_Dereference" && rangeContainsPos funcIdent.idRange derefPos then
Some (funcIdent.idRange, expr.Range)
else
None
| _ -> defaultTraverse expr })

let title = "Use `.Value` instead of dereference operator"
let fix
(getParseResultsForFile: GetParseResultsForFile)
(getLineText: GetLineText)
: CodeFix =
Run.ifDiagnosticByCode
(Set.ofList ["3370"])
(fun diagnostic codeActionParams -> asyncResult {
let fileName = codeActionParams.TextDocument.GetFilePath() |> Utils.normalizePath

let derefOpRange = protocolRangeToRange (UMX.untag fileName) diagnostic.Range
let! parseResults, _, _ = getParseResultsForFile fileName derefOpRange.Start

let! (derefOpRange', exprRange) =
tryGetRangeOfDeref parseResults.GetParseResults.ParseTree derefOpRange.End
|> Result.ofOption (fun _ -> "No deref found at that pos")
assert(derefOpRange = derefOpRange')

return [
{
Title = title
File = codeActionParams.TextDocument
SourceDiagnostic = None
Kind = FixKind.Refactor
Edits = [|
// remove leading `!` (and whitespaces after `!`)
{ Range = { Start = fcsPosToLsp derefOpRange'.Start; End = fcsPosToLsp exprRange.Start }
NewText = "" }
// Append trailing `.Value`
{ Range =
let lspPos = fcsPosToLsp exprRange.End
{ Start = lspPos; End = lspPos }
NewText = ".Value" }
|]
}
]
})
29 changes: 0 additions & 29 deletions src/FsAutoComplete/CodeFixes/ReplaceBangWithValueFunction.fs

This file was deleted.

2 changes: 1 addition & 1 deletion src/FsAutoComplete/FsAutoComplete.Lsp.fs
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,7 @@ type FSharpLspServer(backgroundServiceEnabled: bool, state: State, lspClient: FS
MakeOuterBindingRecursive.fix tryGetParseResultsForFile getLineText
AddMissingRecKeyword.fix getFileLines getLineText
ConvertBangEqualsToInequality.fix getRangeText
ReplaceBangWithValueFunction.fix tryGetParseResultsForFile getLineText
ChangeDerefBangToValue.fix tryGetParseResultsForFile getLineText
RemoveUnusedBinding.fix tryGetParseResultsForFile
AddTypeToIndeterminateValue.fix tryGetParseResultsForFile tryGetProjectOptions
ChangeTypeOfNameToNameOf.fix tryGetParseResultsForFile
Expand Down
66 changes: 66 additions & 0 deletions test/FsAutoComplete.Tests.Lsp/CodeFixTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,71 @@ let private addTypeToIndeterminateValueTests state =
"""
])

let private changeDerefBangToValueTests state =
serverTestList (nameof ChangeDerefBangToValue) state defaultConfigDto None (fun server -> [
let selectCodeFix = CodeFix.withTitle ChangeDerefBangToValue.title
testCaseAsync "can replace ! with .Value" <|
CodeFix.check server
"""
let rv = ref 5
let v = $0!rv
"""
(Diagnostics.expectCode "3370")
selectCodeFix
"""
let rv = ref 5
let v = rv.Value
"""
testCaseAsync "can replace ! with .Value when parens" <|
CodeFix.check server
"""
let rv = ref 5
let v = $0!(rv)
"""
(Diagnostics.expectCode "3370")
selectCodeFix
"""
let rv = ref 5
let v = (rv).Value
"""
testCaseAsync "can replace ! with .Value when function in parens" <|
CodeFix.check server
"""
let fr a = ref a
let v = $0!(fr 5)
"""
(Diagnostics.expectCode "3370")
selectCodeFix
"""
let fr a = ref a
let v = (fr 5).Value
"""
testCaseAsync "can replace ! with .Value when space between ! and variable" <|
CodeFix.check server
"""
let rv = ref 5
let v = $0! rv
"""
(Diagnostics.expectCode "3370")
selectCodeFix
"""
let rv = ref 5
let v = rv.Value
"""
testCaseAsync "can replace ! with .Value when when parens and space between ! and variable" <|
CodeFix.check server
"""
let rv = ref 5
let v = $0! (rv)
"""
(Diagnostics.expectCode "3370")
selectCodeFix
"""
let rv = ref 5
let v = (rv).Value
"""
])

let private changeEqualsInFieldTypeToColonTests state =
serverTestList (nameof ChangeEqualsInFieldTypeToColon) state defaultConfigDto None (fun server -> [
let selectCodeFix = CodeFix.withTitle ChangeEqualsInFieldTypeToColon.title
Expand Down Expand Up @@ -1211,6 +1276,7 @@ let tests state = testList "CodeFix tests" [
addMissingRecKeywordTests state
addNewKeywordToDisposableConstructorInvocationTests state
addTypeToIndeterminateValueTests state
changeDerefBangToValueTests state
changeEqualsInFieldTypeToColonTests state
changePrefixNegationToInfixSubtractionTests state
changeRefCellDerefToNotTests state
Expand Down