From 8665f4571ce23cb6543b05d9b4f9b7db6f46ae37 Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 7 Mar 2024 19:03:05 +0100 Subject: [PATCH] Got one example working. --- .../UpdateTypeAbbreviationInSignatureFile.fs | 89 +++++++++++++++++++ .../UpdateTypeAbbreviationInSignatureFile.fsi | 6 ++ .../LspServers/AdaptiveServerState.fs | 3 +- .../CodeFixTests/Tests.fs | 3 +- ...ateTypeAbbreviationInSignatureFileTests.fs | 20 +++++ 5 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fs create mode 100644 src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fsi create mode 100644 test/FsAutoComplete.Tests.Lsp/CodeFixTests/UpdateTypeAbbreviationInSignatureFileTests.fs diff --git a/src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fs b/src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fs new file mode 100644 index 000000000..e511d523f --- /dev/null +++ b/src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fs @@ -0,0 +1,89 @@ +module FsAutoComplete.CodeFix.UpdateTypeAbbreviationInSignatureFile + +open FSharp.Compiler.Symbols +open FSharp.Compiler.Syntax +open FSharp.Compiler.Text +open FsToolkit.ErrorHandling +open Ionide.LanguageServerProtocol.Types +open FsAutoComplete.CodeFix.Types +open FsAutoComplete +open FsAutoComplete.LspHelpers + +// TODO: add proper title for code fix +let title = "UpdateTypeAbbreviationInSignatureFile Codefix" + +let fix (getParseResultsForFile: GetParseResultsForFile) : CodeFix = + Run.ifDiagnosticByCode (Set.ofList [ "318" ]) (fun diagnostic codeActionParams -> + asyncResult { + let implFilePath = codeActionParams.TextDocument.GetFilePath() + let implFileName = Utils.normalizePath implFilePath + + let! (implParseAndCheckResults: ParseAndCheckResults, _implLine: string, implSourceText: IFSACSourceText) = + getParseResultsForFile implFileName (protocolPosToPos diagnostic.Range.Start) + + let mDiag = + protocolRangeToRange implParseAndCheckResults.GetParseResults.FileName diagnostic.Range + + let implTypeName = + (mDiag.Start, implParseAndCheckResults.GetParseResults.ParseTree) + ||> ParsedInput.tryPick (fun _ node -> + match node with + | SyntaxNode.SynTypeDefn(SynTypeDefn( + typeInfo = SynComponentInfo(longId = [ typeIdent ]) + typeRepr = SynTypeDefnRepr.Simple(simpleRepr = SynTypeDefnSimpleRepr.TypeAbbrev _; range = mBody))) when + Range.equals typeIdent.idRange mDiag + -> + Some(typeIdent, mBody) + | _ -> None) + + match implTypeName with + | None -> return [] + | Some(typeName, mImplBody) -> + match implParseAndCheckResults.TryGetSymbolUseFromIdent implSourceText typeName with + | None -> return [] + | Some typeSymbolUse -> + match typeSymbolUse.Symbol with + | :? FSharpEntity as entity -> + match entity.SignatureLocation with + | None -> return [] + | Some signatureLocation -> + if not (Utils.isSignatureFile signatureLocation.FileName) then + // A little weird + return [] + else + let sigFilePath = $"%s{implFilePath}i" + let sigFileName = Utils.normalizePath sigFilePath + + let sigTextDocumentIdentifier: TextDocumentIdentifier = + { Uri = $"%s{codeActionParams.TextDocument.Uri}i" } + + let! (sigParseAndCheckResults: ParseAndCheckResults, _sigLine: string, _sigSourceText: IFSACSourceText) = + getParseResultsForFile sigFileName (Position.mkPos 1 0) + + let mSigTypeAbbrev = + (signatureLocation.Start, sigParseAndCheckResults.GetParseResults.ParseTree) + ||> ParsedInput.tryPick (fun _path node -> + match node with + | SyntaxNode.SynTypeDefnSig(SynTypeDefnSig( + typeInfo = SynComponentInfo(longId = [ typeIdent ]) + typeRepr = SynTypeDefnSigRepr.Simple(repr = SynTypeDefnSimpleRepr.TypeAbbrev _; range = m))) when + Range.equals typeIdent.idRange signatureLocation + -> + Some m + | _ -> None) + + match mSigTypeAbbrev with + | None -> return [] + | Some mSigTypeAbbrev -> + let newText = implSourceText.GetSubTextFromRange mImplBody + + return + [ { SourceDiagnostic = None + Title = title + File = sigTextDocumentIdentifier + Edits = + [| { Range = fcsRangeToLsp mSigTypeAbbrev + NewText = newText } |] + Kind = FixKind.Fix } ] + | _ -> return [] + }) diff --git a/src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fsi b/src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fsi new file mode 100644 index 000000000..463138bd2 --- /dev/null +++ b/src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fsi @@ -0,0 +1,6 @@ +module FsAutoComplete.CodeFix.UpdateTypeAbbreviationInSignatureFile + +open FsAutoComplete.CodeFix.Types + +val title: string +val fix: getParseResultsForFile: GetParseResultsForFile -> CodeFix diff --git a/src/FsAutoComplete/LspServers/AdaptiveServerState.fs b/src/FsAutoComplete/LspServers/AdaptiveServerState.fs index 84591cf26..b0e255cce 100644 --- a/src/FsAutoComplete/LspServers/AdaptiveServerState.fs +++ b/src/FsAutoComplete/LspServers/AdaptiveServerState.fs @@ -1903,7 +1903,8 @@ type AdaptiveState(lspClient: FSharpLspClient, sourceTextFactory: ISourceTextFac AdjustConstant.fix tryGetParseAndCheckResultsForFile UpdateValueInSignatureFile.fix tryGetParseAndCheckResultsForFile RemoveUnnecessaryParentheses.fix forceFindSourceText - AddTypeAliasToSignatureFile.fix forceGetFSharpProjectOptions tryGetParseAndCheckResultsForFile |]) + AddTypeAliasToSignatureFile.fix forceGetFSharpProjectOptions tryGetParseAndCheckResultsForFile + UpdateTypeAbbreviationInSignatureFile.fix tryGetParseAndCheckResultsForFile |]) let forgetDocument (uri: DocumentUri) = async { diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs index 301ff1ed1..6c3759db3 100644 --- a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs +++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/Tests.fs @@ -3433,4 +3433,5 @@ let tests textFactory state = removePatternArgumentTests state UpdateValueInSignatureFileTests.tests state removeUnnecessaryParenthesesTests state - AddTypeAliasToSignatureFileTests.tests state ] + AddTypeAliasToSignatureFileTests.tests state + UpdateTypeAbbreviationInSignatureFileTests.tests state ] diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/UpdateTypeAbbreviationInSignatureFileTests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/UpdateTypeAbbreviationInSignatureFileTests.fs new file mode 100644 index 000000000..47a17b9a2 --- /dev/null +++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/UpdateTypeAbbreviationInSignatureFileTests.fs @@ -0,0 +1,20 @@ +module private FsAutoComplete.Tests.CodeFixTests.UpdateTypeAbbreviationInSignatureFileTests + +open Expecto +open Helpers +open Utils.ServerTests +open Utils.CursorbasedTests +open FsAutoComplete.CodeFix + +let tests state = + serverTestList (nameof UpdateTypeAbbreviationInSignatureFile) state defaultConfigDto None (fun server -> + [ let selectCodeFix = CodeFix.withTitle UpdateTypeAbbreviationInSignatureFile.title + + ftestCaseAsync "first unit test for UpdateTypeAbbreviationInSignatureFile" + <| CodeFix.check + server + "let a$0 b c = ()" + Diagnostics.acceptAll + selectCodeFix + "let Text replaced by UpdateTypeAbbreviationInSignatureFile b c = ()" + ])