From df83900f6f8c717d67941d66efe20f1ac379ec83 Mon Sep 17 00:00:00 2001 From: gparmigiani Date: Fri, 1 Sep 2023 17:08:31 +0200 Subject: [PATCH 1/5] add code fix for wildcard operator suggestion in pattern match for fs43 --- .../CodeFixes/AddMissingWildcardOperator.fs | 110 ++++++++++++++++++ .../CodeFixes/AddMissingWildcardOperator.fsi | 12 ++ .../LspServers/AdaptiveFSharpLspServer.fs | 1 + .../LspServers/FsAutoComplete.Lsp.fs | 1 + .../AddMissingWildcardOperatorTests.fs | 37 ++++++ .../CodeFixTests/Tests.fs | 4 +- 6 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fs create mode 100644 src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fsi create mode 100644 test/FsAutoComplete.Tests.Lsp/CodeFixTests/AddMissingWildcardOperatorTests.fs diff --git a/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fs b/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fs new file mode 100644 index 000000000..fdd05f347 --- /dev/null +++ b/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fs @@ -0,0 +1,110 @@ +module FsAutoComplete.CodeFix.AddMissingWildcardOperator + +open FsToolkit.ErrorHandling +open FsAutoComplete.CodeFix.Navigation +open FsAutoComplete.CodeFix.Types +open Ionide.LanguageServerProtocol.Types +open FsAutoComplete +open FsAutoComplete.LspHelpers +open FSharp.Compiler.Syntax +open FSharp.Compiler.Text +open FSharp.Compiler.SyntaxTrivia + +let title = "Add missing wildcard operator" + + +let tryFindPattern pos input = + + let visitor = + { new SyntaxVisitorBase() with + + member _.VisitExpr(path, traverseSynExpr, defaultTraverse, expr) = + match expr with + | SynExpr.LongIdent( + longDotId = + SynLongIdent.SynLongIdent( + trivia = [ Some(IdentTrivia.OriginalNotation("|->")) ] + ) + range = range) when FSharp.Compiler.Text.Range.rangeContainsPos range pos -> + + Some(range) + + | _ -> defaultTraverse expr + } + + SyntaxTraversal.Traverse(pos, input, visitor) + + + +/// a codefix that adds a missing 'fun' keyword to a lambda +let fix (getParseResultsForFile: GetParseResultsForFile) : CodeFix = + Run.ifDiagnosticByCode (Set.ofList [ "43" ]) (fun diagnostic codeActionParams -> + asyncResult { + + let filePath = codeActionParams.TextDocument.GetFilePath() |> Utils.normalizePath + let fcsPos = protocolPosToPos codeActionParams.Range.Start + let! (parseAndCheck, lineStr, _sourceText) = getParseResultsForFile filePath fcsPos + + match tryFindPattern fcsPos parseAndCheck.GetAST with + | None -> return [] + | Some operatorRange -> + + let lspRange = fcsRangeToLsp operatorRange + + return + [ { Title = title + File = codeActionParams.TextDocument + SourceDiagnostic = Some diagnostic + Edits = + [| { Range = lspRange + NewText = "| _ ->" } + |] + Kind = FixKind.Fix } ] + // let fileName = codeActionParams.TextDocument.GetFilePath() |> Utils.normalizePath + + // let! lines = getFileLines fileName + // let! errorText = getLineText lines diagnostic.Range + // do! Result.guard (fun _ -> errorText = "->") "Expected error source code text not matched" + + // let! lineLen = + // lines.GetLineLength(protocolPosToPos diagnostic.Range.Start) + // |> Result.ofOption (fun _ -> "Could not get line length") + + // let! line = + // getLineText + // lines + // { Start = + // { diagnostic.Range.Start with + // Character = 0 } + // End = + // { diagnostic.Range.End with + // Character = lineLen } } + + // let! prevPos = + // dec lines diagnostic.Range.Start + // |> Result.ofOption (fun _ -> "previous position wasn't valid") + + // let adjustedPos = + // walkBackUntilCondition lines prevPos (System.Char.IsWhiteSpace >> not) + + // match adjustedPos with + // | None -> return [] + // | Some firstNonWhitespacePos -> + // let fcsPos = protocolPosToPos firstNonWhitespacePos + + // match Lexer.getSymbol fcsPos.Line fcsPos.Column line SymbolLookupKind.Fuzzy [||] with + // | Some lexSym -> + // let fcsStartPos = FSharp.Compiler.Text.Position.mkPos lexSym.Line lexSym.LeftColumn + + // let symbolStartRange = fcsPosToProtocolRange fcsStartPos + + // return + // [ { Title = title + // File = codeActionParams.TextDocument + // SourceDiagnostic = Some diagnostic + // Edits = + // [| { Range = symbolStartRange + // NewText = "fun " } |] + // Kind = FixKind.Fix } ] + // | None -> return [] + }) diff --git a/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fsi b/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fsi new file mode 100644 index 000000000..a828a4aa9 --- /dev/null +++ b/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fsi @@ -0,0 +1,12 @@ +module FsAutoComplete.CodeFix.AddMissingWildcardOperator + +open FsToolkit.ErrorHandling +open FsAutoComplete.CodeFix.Navigation +open FsAutoComplete.CodeFix.Types +open Ionide.LanguageServerProtocol.Types +open FsAutoComplete +open FsAutoComplete.LspHelpers + +val title: string +/// a codefix that adds a missing 'fun' keyword to a lambda +val fix: getParseResultsForFile: GetParseResultsForFile -> (CodeActionParams -> Async>) diff --git a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs index b92ac2875..1c8b3c7bc 100644 --- a/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs +++ b/src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs @@ -1806,6 +1806,7 @@ type AdaptiveFSharpLspServer RemoveUnnecessaryReturnOrYield.fix tryGetParseResultsForFile getLineText ConvertCSharpLambdaToFSharpLambda.fix tryGetParseResultsForFile getLineText AddMissingFunKeyword.fix forceFindSourceText getLineText + AddMissingWildcardOperator.fix tryGetParseResultsForFile MakeOuterBindingRecursive.fix tryGetParseResultsForFile getLineText AddMissingRecKeyword.fix forceFindSourceText getLineText ConvertBangEqualsToInequality.fix getRangeText diff --git a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs index b11db9eee..87be6ccf4 100644 --- a/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs +++ b/src/FsAutoComplete/LspServers/FsAutoComplete.Lsp.fs @@ -1152,6 +1152,7 @@ type FSharpLspServer(state: State, lspClient: FSharpLspClient, sourceTextFactory RemoveUnnecessaryReturnOrYield.fix tryGetParseResultsForFile getLineText ConvertCSharpLambdaToFSharpLambda.fix tryGetParseResultsForFile getLineText AddMissingFunKeyword.fix getFileLines getLineText + AddMissingWildcardOperator.fix tryGetParseResultsForFile MakeOuterBindingRecursive.fix tryGetParseResultsForFile getLineText AddMissingRecKeyword.fix getFileLines getLineText ConvertBangEqualsToInequality.fix getRangeText diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/AddMissingWildcardOperatorTests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/AddMissingWildcardOperatorTests.fs new file mode 100644 index 000000000..836f81950 --- /dev/null +++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/AddMissingWildcardOperatorTests.fs @@ -0,0 +1,37 @@ +module private FsAutoComplete.Tests.CodeFixTests.AddMissingWildcardOperatorTests + +open Expecto +open Helpers +open Utils.ServerTests +open Utils.CursorbasedTests +open FsAutoComplete.CodeFix + +let tests state = + serverTestList (nameof AddMissingWildcardOperator) state defaultConfigDto None (fun server -> [ + let selectCodeFix = CodeFix.withTitle AddMissingWildcardOperator.title + ftestCaseAsync "can suggest wildcard pattern for missing match case" <| + CodeFix.check server + """ + type SomeUnion = + | First + | Second + + let testMatch su = + match su with + | First -> "hey" + $0|-> "hello" + """ + (Diagnostics.expectCode "43") + selectCodeFix + """ + type SomeUnion = + | First + | Second + + let testMatch su = + match su with + | First -> "hey" + | _ -> "hello" + """ + ] + ) diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs index 9230d36a8..9ef1de7b4 100644 --- a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs +++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs @@ -3351,4 +3351,6 @@ let tests state = useTripleQuotedInterpolationTests state wrapExpressionInParenthesesTests state removeRedundantAttributeSuffixTests state - removePatternArgumentTests state ] + removePatternArgumentTests state + AddMissingWildcardOperatorTests.tests state + ] From a0e0cd5fe5f3afdd26270ddb7208aa9068b50f24 Mon Sep 17 00:00:00 2001 From: jkone27 Date: Wed, 6 Sep 2023 10:52:17 +0200 Subject: [PATCH 2/5] Update src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fsi Co-authored-by: dawe --- src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fsi b/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fsi index a828a4aa9..bca8d7d06 100644 --- a/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fsi +++ b/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fsi @@ -8,5 +8,5 @@ open FsAutoComplete open FsAutoComplete.LspHelpers val title: string -/// a codefix that adds a missing 'fun' keyword to a lambda +/// a codefix that adds a missing wildcard pattern to a match case val fix: getParseResultsForFile: GetParseResultsForFile -> (CodeActionParams -> Async>) From 543e242b732475df6e739a62d32cb6ae630279e2 Mon Sep 17 00:00:00 2001 From: jkone27 Date: Wed, 6 Sep 2023 10:53:33 +0200 Subject: [PATCH 3/5] remove-commented-code remove comments --- .../CodeFixes/AddMissingWildcardOperator.fs | 47 ------------------- 1 file changed, 47 deletions(-) diff --git a/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fs b/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fs index fdd05f347..b4cca2a50 100644 --- a/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fs +++ b/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fs @@ -60,51 +60,4 @@ let fix (getParseResultsForFile: GetParseResultsForFile) : CodeFix = NewText = "| _ ->" } |] Kind = FixKind.Fix } ] - // let fileName = codeActionParams.TextDocument.GetFilePath() |> Utils.normalizePath - - // let! lines = getFileLines fileName - // let! errorText = getLineText lines diagnostic.Range - // do! Result.guard (fun _ -> errorText = "->") "Expected error source code text not matched" - - // let! lineLen = - // lines.GetLineLength(protocolPosToPos diagnostic.Range.Start) - // |> Result.ofOption (fun _ -> "Could not get line length") - - // let! line = - // getLineText - // lines - // { Start = - // { diagnostic.Range.Start with - // Character = 0 } - // End = - // { diagnostic.Range.End with - // Character = lineLen } } - - // let! prevPos = - // dec lines diagnostic.Range.Start - // |> Result.ofOption (fun _ -> "previous position wasn't valid") - - // let adjustedPos = - // walkBackUntilCondition lines prevPos (System.Char.IsWhiteSpace >> not) - - // match adjustedPos with - // | None -> return [] - // | Some firstNonWhitespacePos -> - // let fcsPos = protocolPosToPos firstNonWhitespacePos - - // match Lexer.getSymbol fcsPos.Line fcsPos.Column line SymbolLookupKind.Fuzzy [||] with - // | Some lexSym -> - // let fcsStartPos = FSharp.Compiler.Text.Position.mkPos lexSym.Line lexSym.LeftColumn - - // let symbolStartRange = fcsPosToProtocolRange fcsStartPos - - // return - // [ { Title = title - // File = codeActionParams.TextDocument - // SourceDiagnostic = Some diagnostic - // Edits = - // [| { Range = symbolStartRange - // NewText = "fun " } |] - // Kind = FixKind.Fix } ] - // | None -> return [] }) From 55294bcaee7085a4199757aac25f4b3307652424 Mon Sep 17 00:00:00 2001 From: jkone27 Date: Thu, 7 Sep 2023 22:57:54 +0200 Subject: [PATCH 4/5] Update AddMissingWildcardOperator.fsi --- src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fsi b/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fsi index bca8d7d06..ff5286f6f 100644 --- a/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fsi +++ b/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fsi @@ -9,4 +9,4 @@ open FsAutoComplete.LspHelpers val title: string /// a codefix that adds a missing wildcard pattern to a match case -val fix: getParseResultsForFile: GetParseResultsForFile -> (CodeActionParams -> Async>) +val fix: getParseResultsForFile: GetParseResultsForFile -> CodeFix From d3d6f8dd83bfa4c70c6b39dbec0ca0bedc37dd00 Mon Sep 17 00:00:00 2001 From: gparmigiani Date: Wed, 13 Sep 2023 17:02:38 +0200 Subject: [PATCH 5/5] applied formatting with dotnet fantomas --- .../CodeFixes/AddMissingWildcardOperator.fs | 25 +++++++------------ .../AddMissingWildcardOperatorTests.fs | 14 +++++------ .../CodeFixTests/Tests.fs | 3 +-- 3 files changed, 17 insertions(+), 25 deletions(-) diff --git a/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fs b/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fs index b4cca2a50..0ddbf5108 100644 --- a/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fs +++ b/src/FsAutoComplete/CodeFixes/AddMissingWildcardOperator.fs @@ -21,16 +21,12 @@ let tryFindPattern pos input = member _.VisitExpr(path, traverseSynExpr, defaultTraverse, expr) = match expr with | SynExpr.LongIdent( - longDotId = - SynLongIdent.SynLongIdent( - trivia = [ Some(IdentTrivia.OriginalNotation("|->")) ] - ) - range = range) when FSharp.Compiler.Text.Range.rangeContainsPos range pos -> + longDotId = SynLongIdent.SynLongIdent(trivia = [ Some(IdentTrivia.OriginalNotation("|->")) ]) + range = range) when FSharp.Compiler.Text.Range.rangeContainsPos range pos -> - Some(range) + Some(range) - | _ -> defaultTraverse expr - } + | _ -> defaultTraverse expr } SyntaxTraversal.Traverse(pos, input, visitor) @@ -52,12 +48,9 @@ let fix (getParseResultsForFile: GetParseResultsForFile) : CodeFix = let lspRange = fcsRangeToLsp operatorRange return - [ { Title = title - File = codeActionParams.TextDocument - SourceDiagnostic = Some diagnostic - Edits = - [| { Range = lspRange - NewText = "| _ ->" } - |] - Kind = FixKind.Fix } ] + [ { Title = title + File = codeActionParams.TextDocument + SourceDiagnostic = Some diagnostic + Edits = [| { Range = lspRange; NewText = "| _ ->" } |] + Kind = FixKind.Fix } ] }) diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/AddMissingWildcardOperatorTests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/AddMissingWildcardOperatorTests.fs index 836f81950..309dfbeac 100644 --- a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/AddMissingWildcardOperatorTests.fs +++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/AddMissingWildcardOperatorTests.fs @@ -7,10 +7,12 @@ open Utils.CursorbasedTests open FsAutoComplete.CodeFix let tests state = - serverTestList (nameof AddMissingWildcardOperator) state defaultConfigDto None (fun server -> [ - let selectCodeFix = CodeFix.withTitle AddMissingWildcardOperator.title - ftestCaseAsync "can suggest wildcard pattern for missing match case" <| - CodeFix.check server + serverTestList (nameof AddMissingWildcardOperator) state defaultConfigDto None (fun server -> + [ let selectCodeFix = CodeFix.withTitle AddMissingWildcardOperator.title + + ftestCaseAsync "can suggest wildcard pattern for missing match case" + <| CodeFix.check + server """ type SomeUnion = | First @@ -32,6 +34,4 @@ let tests state = match su with | First -> "hey" | _ -> "hello" - """ - ] - ) + """ ]) diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs index 9ef1de7b4..91b7d0467 100644 --- a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs +++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs @@ -3352,5 +3352,4 @@ let tests state = wrapExpressionInParenthesesTests state removeRedundantAttributeSuffixTests state removePatternArgumentTests state - AddMissingWildcardOperatorTests.tests state - ] + AddMissingWildcardOperatorTests.tests state ]