From 0d751f1bcc3b7962c08dd1280ed741aa9329a6ee Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 7 Mar 2024 19:03:05 +0100 Subject: [PATCH 1/4] 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 = ()" + ]) From 3c3ef391a80eb022e7be311d34fc9a46dbffd18c Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 15 Mar 2024 14:43:00 +0100 Subject: [PATCH 2/4] Add unit tests --- .../UpdateTypeAbbreviationInSignatureFile.fs | 3 +- ...ateTypeAbbreviationInSignatureFileTests.fs | 68 ++++++++++++++++--- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fs b/src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fs index e511d523f..ecbab677a 100644 --- a/src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fs +++ b/src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fs @@ -9,8 +9,7 @@ open FsAutoComplete.CodeFix.Types open FsAutoComplete open FsAutoComplete.LspHelpers -// TODO: add proper title for code fix -let title = "UpdateTypeAbbreviationInSignatureFile Codefix" +let title = "Update type abbreviation in signature file" let fix (getParseResultsForFile: GetParseResultsForFile) : CodeFix = Run.ifDiagnosticByCode (Set.ofList [ "318" ]) (fun diagnostic codeActionParams -> diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/UpdateTypeAbbreviationInSignatureFileTests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/UpdateTypeAbbreviationInSignatureFileTests.fs index 47a17b9a2..19f239f7b 100644 --- a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/UpdateTypeAbbreviationInSignatureFileTests.fs +++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/UpdateTypeAbbreviationInSignatureFileTests.fs @@ -1,20 +1,66 @@ module private FsAutoComplete.Tests.CodeFixTests.UpdateTypeAbbreviationInSignatureFileTests +open System.IO open Expecto open Helpers open Utils.ServerTests open Utils.CursorbasedTests open FsAutoComplete.CodeFix +let path = + Path.Combine(__SOURCE_DIRECTORY__, @"../TestCases/CodeFixTests/RenameParamToMatchSignature/") + 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 = ()" - ]) + serverTestList (nameof UpdateTypeAbbreviationInSignatureFile) state defaultConfigDto (Some path) (fun server -> + let selectCodeFix = CodeFix.withTitle UpdateTypeAbbreviationInSignatureFile.title + + let test name sigBefore impl sigAfter = + ftestCaseAsync + name + (CodeFix.checkCodeFixInImplementationAndVerifySignature + server + sigBefore + impl + (Diagnostics.expectCode "318") + selectCodeFix + sigAfter) + + [ + + test + "Update anonymous record in signature file" + """ +namespace Foo + +type X = {| y: int |} +""" + """ +namespace Foo + +type X$0 = {| y: int; z: string |} +""" + """ +namespace Foo + +type X = {| y: int; z: string |} +""" + + test + "Update function type in signature file" + """ +namespace Foo + +type X = unit -> int +""" + """ +namespace Foo + +type X$0 = int -> int +""" + """ +namespace Foo + +type X = int -> int +""" + + ]) From 396cda80e69aedba93e51f24081abbe92137945b Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 15 Mar 2024 16:41:31 +0100 Subject: [PATCH 3/4] Extract re-usable logic into partial active patterns. --- src/FsAutoComplete.Core/TypedAstPatterns.fs | 26 +++ src/FsAutoComplete.Core/TypedAstPatterns.fsi | 7 + .../CodeFixes/AddTypeAliasToSignatureFile.fs | 189 ++++++++---------- .../UpdateTypeAbbreviationInSignatureFile.fs | 73 +++---- 4 files changed, 148 insertions(+), 147 deletions(-) diff --git a/src/FsAutoComplete.Core/TypedAstPatterns.fs b/src/FsAutoComplete.Core/TypedAstPatterns.fs index 55c765a87..7fedb4d82 100644 --- a/src/FsAutoComplete.Core/TypedAstPatterns.fs +++ b/src/FsAutoComplete.Core/TypedAstPatterns.fs @@ -3,6 +3,7 @@ module FsAutoComplete.Patterns open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Symbols +open FSharp.Compiler.Text /// Active patterns over `FSharpSymbolUse`. @@ -253,6 +254,31 @@ module SymbolUse = | Entity(entity, _) when entity.IsAttributeType -> Some entity | _ -> None + let trySignatureLocation (signatureLocation: range option) = + match signatureLocation with + | None -> None + | Some signatureLocation -> + if not (isSignatureFile signatureLocation.FileName) then + None + else + Some signatureLocation + + let (|IsInSignature|_|) (symbolUse: FSharpSymbolUse) = trySignatureLocation symbolUse.Symbol.SignatureLocation + + let (|IsParentInSignature|_|) (symbolUse: FSharpSymbolUse) = + match trySignatureLocation symbolUse.Symbol.SignatureLocation with + // We are interested in the scenarios when the current symbol is not in a signature file but the parent is. + | Some _ -> None + | None -> + let parentOpt = + match symbolUse.Symbol with + | :? FSharpEntity as entity -> entity.DeclaringEntity + | :? FSharpMemberOrFunctionOrValue as mfv -> mfv.DeclaringEntity + | _ -> None + + parentOpt + |> Option.bind (fun parentEntity -> trySignatureLocation parentEntity.SignatureLocation) + /// Active patterns over `FSharpSymbol`. [] module SymbolPatterns = diff --git a/src/FsAutoComplete.Core/TypedAstPatterns.fsi b/src/FsAutoComplete.Core/TypedAstPatterns.fsi index 2cdc67b71..00d7ef0a4 100644 --- a/src/FsAutoComplete.Core/TypedAstPatterns.fsi +++ b/src/FsAutoComplete.Core/TypedAstPatterns.fsi @@ -3,6 +3,7 @@ module FsAutoComplete.Patterns open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Symbols +open FSharp.Compiler.Text /// Active patterns over `FSharpSymbolUse`. module SymbolUse = @@ -36,6 +37,12 @@ module SymbolUse = val (|ValueType|_|): (FSharpSymbolUse -> FSharpEntity option) val (|ComputationExpression|_|): symbol: FSharpSymbolUse -> FSharpSymbolUse option val (|Attribute|_|): (FSharpSymbolUse -> FSharpEntity option) + /// Check if the symbolUse.Symbol.SignatureLocation is in an actual signature file. + val (|IsInSignature|_|): symbolUse: FSharpSymbolUse -> range option + /// Check if the symbolUse.Symbol is not in an actual signature file + /// but the declaring entity (in case the symbol is FSharpEntity or FSharpMemberOrFunctionOrValue) + /// is located inside an actual signature file. + val (|IsParentInSignature|_|): symbolUse: FSharpSymbolUse -> range option /// Active patterns over `FSharpSymbol`. [] diff --git a/src/FsAutoComplete/CodeFixes/AddTypeAliasToSignatureFile.fs b/src/FsAutoComplete/CodeFixes/AddTypeAliasToSignatureFile.fs index 539f6a68d..c7537c2d5 100644 --- a/src/FsAutoComplete/CodeFixes/AddTypeAliasToSignatureFile.fs +++ b/src/FsAutoComplete/CodeFixes/AddTypeAliasToSignatureFile.fs @@ -1,7 +1,6 @@ module FsAutoComplete.CodeFix.AddTypeAliasToSignatureFile open System -open FSharp.Compiler.Symbols open FSharp.Compiler.Syntax open FSharp.Compiler.Text open FSharp.Compiler.CodeAnalysis @@ -10,6 +9,7 @@ open Ionide.LanguageServerProtocol.Types open FsAutoComplete.CodeFix.Types open FsAutoComplete open FsAutoComplete.LspHelpers +open FsAutoComplete.Patterns.SymbolUse let mkLongIdRange (lid: LongIdent) = lid |> List.map (fun ident -> ident.idRange) |> List.reduce Range.unionRanges @@ -90,111 +90,88 @@ let fix | Some(typeName, mTypeDefn) -> match parseAndCheckResults.TryGetSymbolUseFromIdent sourceText typeName with - | None -> return [] - | Some typeSymbolUse -> - - match typeSymbolUse.Symbol with - | :? FSharpEntity as entity -> - let isPartOfSignature = - match entity.SignatureLocation with - | None -> false - | Some sigLocation -> Utils.isSignatureFile sigLocation.FileName - - if isPartOfSignature then - return [] - else - - let implFilePath = codeActionParams.TextDocument.GetFilePath() - 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 parentSigLocation = - entity.DeclaringEntity - |> Option.bind (fun parentEntity -> - match parentEntity.SignatureLocation with - | Some sigLocation when Utils.isSignatureFile sigLocation.FileName -> Some sigLocation - | _ -> None) - - match parentSigLocation with - | None -> return [] - | Some parentSigLocation -> - - // Find a good location to insert the type alias - let insertText = - (parentSigLocation.Start, sigParseAndCheckResults.GetParseResults.ParseTree) - ||> ParsedInput.tryPick (fun _path node -> + | Some(IsParentInSignature parentSigLocation) -> + + let implFilePath = codeActionParams.TextDocument.GetFilePath() + 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) + + // Find a good location to insert the type alias + let insertText = + (parentSigLocation.Start, sigParseAndCheckResults.GetParseResults.ParseTree) + ||> ParsedInput.tryPick (fun _path node -> + match node with + | SyntaxNode.SynModuleOrNamespaceSig(SynModuleOrNamespaceSig(longId = longId; decls = decls)) + | SyntaxNode.SynModuleSigDecl(SynModuleSigDecl.NestedModule( + moduleInfo = SynComponentInfo(longId = longId); moduleDecls = decls)) -> + let mSigName = mkLongIdRange longId + + // `parentSigLocation` will only contain the single identifier in case a module is prefixed with a namespace. + if not (Range.rangeContainsRange mSigName parentSigLocation) then + None + else + + let aliasText = + let text = sourceText.GetSubTextFromRange mTypeDefn + + if not (text.StartsWith("and", StringComparison.Ordinal)) then + text + else + String.Concat("type", text.Substring 3) + + match decls with + | [] -> match node with - | SyntaxNode.SynModuleOrNamespaceSig(SynModuleOrNamespaceSig(longId = longId; decls = decls)) + | SyntaxNode.SynModuleOrNamespaceSig nm -> + Some(nm.Range.EndRange, String.Concat("\n\n", aliasText)) + | SyntaxNode.SynModuleSigDecl(SynModuleSigDecl.NestedModule( - moduleInfo = SynComponentInfo(longId = longId); moduleDecls = decls)) -> - let mSigName = mkLongIdRange longId - - // `parentSigLocation` will only contain the single identifier in case a module is prefixed with a namespace. - if not (Range.rangeContainsRange mSigName parentSigLocation) then - None - else - - let aliasText = - let text = sourceText.GetSubTextFromRange mTypeDefn - - if not (text.StartsWith("and", StringComparison.Ordinal)) then - text - else - String.Concat("type", text.Substring 3) - - match decls with - | [] -> - match node with - | SyntaxNode.SynModuleOrNamespaceSig nm -> - Some(nm.Range.EndRange, String.Concat("\n\n", aliasText)) - - | SyntaxNode.SynModuleSigDecl(SynModuleSigDecl.NestedModule( - range = mNested - trivia = { ModuleKeyword = Some mModule - EqualsRange = Some mEquals })) -> - let moduleEqualsText = - sigSourceText.GetSubTextFromRange(Range.unionRanges mModule mEquals) - // Can this grabbed from configuration? - let indent = " " - - Some(mNested, String.Concat(moduleEqualsText, "\n", indent, aliasText)) - | _ -> None - | AllOpenOrHashDirective mLastDecl -> Some(mLastDecl, String.Concat("\n\n", aliasText)) - | decls -> - - decls - // Skip open statements - |> List.tryFind (function - | SynModuleSigDecl.Open _ - | SynModuleSigDecl.HashDirective _ -> false - | _ -> true) - |> Option.map (fun mdl -> - let offset = - if mdl.Range.StartColumn = 0 then - String.Empty - else - String.replicate mdl.Range.StartColumn " " - - mdl.Range.StartRange, String.Concat(aliasText, "\n\n", offset)) - | _ -> None) - - match insertText with - | None -> return [] - | Some(mInsert, newText) -> - - return - [ { SourceDiagnostic = None - Title = title - File = sigTextDocumentIdentifier - Edits = - [| { Range = fcsRangeToLsp mInsert - NewText = newText } |] - Kind = FixKind.Fix } ] - | _ -> return [] + range = mNested + trivia = { ModuleKeyword = Some mModule + EqualsRange = Some mEquals })) -> + let moduleEqualsText = + sigSourceText.GetSubTextFromRange(Range.unionRanges mModule mEquals) + // Can this grabbed from configuration? + let indent = " " + + Some(mNested, String.Concat(moduleEqualsText, "\n", indent, aliasText)) + | _ -> None + | AllOpenOrHashDirective mLastDecl -> Some(mLastDecl, String.Concat("\n\n", aliasText)) + | decls -> + + decls + // Skip open statements + |> List.tryFind (function + | SynModuleSigDecl.Open _ + | SynModuleSigDecl.HashDirective _ -> false + | _ -> true) + |> Option.map (fun mdl -> + let offset = + if mdl.Range.StartColumn = 0 then + String.Empty + else + String.replicate mdl.Range.StartColumn " " + + mdl.Range.StartRange, String.Concat(aliasText, "\n\n", offset)) + | _ -> None) + + match insertText with + | None -> return [] + | Some(mInsert, newText) -> + + return + [ { SourceDiagnostic = None + Title = title + File = sigTextDocumentIdentifier + Edits = + [| { Range = fcsRangeToLsp mInsert + NewText = newText } |] + Kind = FixKind.Fix } ] + | _ -> return [] }) diff --git a/src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fs b/src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fs index ecbab677a..154662322 100644 --- a/src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fs +++ b/src/FsAutoComplete/CodeFixes/UpdateTypeAbbreviationInSignatureFile.fs @@ -8,6 +8,7 @@ open Ionide.LanguageServerProtocol.Types open FsAutoComplete.CodeFix.Types open FsAutoComplete open FsAutoComplete.LspHelpers +open FsAutoComplete.Patterns.SymbolUse let title = "Update type abbreviation in signature file" @@ -39,50 +40,40 @@ let fix (getParseResultsForFile: GetParseResultsForFile) : CodeFix = | 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 + | Some(IsInSignature signatureLocation) -> + let sigFilePath = $"%s{implFilePath}i" + let sigFileName = Utils.normalizePath sigFilePath - let sigTextDocumentIdentifier: TextDocumentIdentifier = - { Uri = $"%s{codeActionParams.TextDocument.Uri}i" } + let sigTextDocumentIdentifier: TextDocumentIdentifier = + { Uri = $"%s{codeActionParams.TextDocument.Uri}i" } - let! (sigParseAndCheckResults: ParseAndCheckResults, _sigLine: string, _sigSourceText: IFSACSourceText) = - getParseResultsForFile sigFileName (Position.mkPos 1 0) + 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) + 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 + 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 [] + return + [ { SourceDiagnostic = None + Title = title + File = sigTextDocumentIdentifier + Edits = + [| { Range = fcsRangeToLsp mSigTypeAbbrev + NewText = newText } |] + Kind = FixKind.Fix } ] + | _ -> return [] }) From abef9edd9de86c5efd5d73219769a1af16c48855 Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 15 Mar 2024 16:50:05 +0100 Subject: [PATCH 4/4] No focus tests --- .../CodeFixTests/UpdateTypeAbbreviationInSignatureFileTests.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/UpdateTypeAbbreviationInSignatureFileTests.fs b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/UpdateTypeAbbreviationInSignatureFileTests.fs index 19f239f7b..a45d35fba 100644 --- a/test/FsAutoComplete.Tests.Lsp/CodeFixTests/UpdateTypeAbbreviationInSignatureFileTests.fs +++ b/test/FsAutoComplete.Tests.Lsp/CodeFixTests/UpdateTypeAbbreviationInSignatureFileTests.fs @@ -15,7 +15,7 @@ let tests state = let selectCodeFix = CodeFix.withTitle UpdateTypeAbbreviationInSignatureFile.title let test name sigBefore impl sigAfter = - ftestCaseAsync + testCaseAsync name (CodeFix.checkCodeFixInImplementationAndVerifySignature server