From 2eac75e6e75cb0a324e62b660c9f13e1aa879138 Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 4 Oct 2022 15:22:05 +0200 Subject: [PATCH 1/6] Initial implementation of AddFunctionToSignatureFileAction. --- .../FSharp.Psi.Intentions.fsproj | 1 + .../AddFunctionToSignatureFileAction.fs | 131 ++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj b/ReSharper.FSharp/src/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj index 64e69bee68..59df8c7b97 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj @@ -25,6 +25,7 @@ + diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs new file mode 100644 index 0000000000..256e7e1bba --- /dev/null +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs @@ -0,0 +1,131 @@ +namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Intentions.Intentions + +open FSharp.Compiler.Text +open FSharp.Compiler.Symbols +open JetBrains.ReSharper.Feature.Services.ContextActions +open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Intentions +open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree +open JetBrains.ReSharper.Plugins.FSharp.Psi +open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl +open JetBrains.ReSharper.Psi.ExtensionsAPI +open JetBrains.ReSharper.Resources.Shell +open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree +open JetBrains.ReSharper.Psi.Tree + +[] +type AddFunctionToSignatureFileAction(dataProvider: FSharpContextActionDataProvider) = + inherit FSharpContextActionBase(dataProvider) + + let (|ValFromImpl|_|) (symbol:FSharpSymbol) = + match symbol with + | :? FSharpMemberOrFunctionOrValue as valSymbol -> + valSymbol.SignatureLocation + |> Option.bind (fun range -> if range.FileName.EndsWith(".fs") then Some valSymbol else None) + | _ -> None + + let rec tryFindParameterName (p: IFSharpPattern) = + match p.IgnoreInnerParens() with + | :? ITypedPat as tp -> tryFindParameterName tp.Pattern + | :? ILocalReferencePat as rp -> Some rp.Identifier + | _ -> None + + let implBindingAndDecl = + let currentFSharpFile = dataProvider.PsiFile + if isNull currentFSharpFile then None else + // Don't show context action in signature file. + if currentFSharpFile.IsFSharpSigFile() then None else + + let fcsService = currentFSharpFile.FcsCheckerService + if isNull fcsService || isNull fcsService.FcsProjectProvider then None else + + let hasSignature = fcsService.FcsProjectProvider.HasPairFile dataProvider.SourceFile + if not hasSignature then None else + + let letBindings = dataProvider.GetSelectedElement() + if isNull letBindings then None else + // Currently excluding recursive bindings + if letBindings.Bindings.Count <> 1 then None else + let binding = letBindings.Bindings |> Seq.exactlyOne + let refPat = binding.HeadPattern.As() + if isNull refPat || isNull refPat.Reference then None else + + let moduleOrNamespaceDecl = QualifiableModuleLikeDeclarationNavigator.GetByMember(letBindings) + if isNull moduleOrNamespaceDecl then None else + let moduleOrNamespaceDeclaredElement = moduleOrNamespaceDecl.DeclaredElement + if isNull moduleOrNamespaceDeclaredElement then None else + + let signatureCounterPart = + moduleOrNamespaceDeclaredElement.GetDeclarations() + |> Seq.tryPick (fun d -> if d.IsFSharpSigFile() then Some d else None) + + match signatureCounterPart with + | None -> None + | Some signatureCounterPart -> + + let symbolUse = refPat.GetFcsSymbolUse() + match symbolUse.Symbol with + | ValFromImpl valSymbol -> + let text = + valSymbol.FormatLayout(symbolUse.DisplayContext) + |> Array.choose (fun (t : TaggedText) -> + match t.Tag with + | TextTag.UnknownEntity -> None + | _ -> Some t.Text) + |> String.concat "" + + Some (refPat, binding, text, signatureCounterPart) + | _ -> None + + override this.IsAvailable _ = Option.isSome implBindingAndDecl + + override this.ExecutePsiTransaction(_solution, _progress) = + match implBindingAndDecl with + | None -> null + | Some (refPat, binding, text, signatureModuleOrNamespaceDecl) -> + + use writeCookie = WriteLockCookie.Create(binding.IsPhysical()) + use disableFormatter = new DisableCodeFormatter() + + let factory = signatureModuleOrNamespaceDecl.CreateElementFactory() + let typeInfo = factory.CreateTypeUsageForSignature(text) + + // Enrich the type info with the found parameters from binding. + let rec visit (index:int) (t: ITypeUsage) = + if index = binding.ParameterPatterns.Count then + match t with + | :? IFunctionTypeUsage -> + // If the return type is a function itself, the safest thing to do is to wrap it in parentheses. + // Example: `let g _ = (*) 3` + // `val g: 'a -> int -> int` is not valid, `val g: 'a -> (int -> int)` is. + replace t (factory.WrapParenAroundTypeUsageForSignature(t)) + | _ -> () + else + // TODO: take tuples into account. + let parameterAtIndex = tryFindParameterName (binding.ParameterPatterns.Item(index)) + + match t, parameterAtIndex with + | :? IFunctionTypeUsage as ft, Some parameterName -> + match ft.ArgumentTypeUsage with + | :? IParameterSignatureTypeUsage as pstu -> + // Update the parameter name if it was found in the implementation file + // calling SetIdentifier on pstu does not add a ':' token. + let namedTypeUsage = factory.CreateParameterSignatureTypeUsage(parameterName, pstu.TypeUsage) + replace ft.ArgumentTypeUsage namedTypeUsage + | _ -> () + + visit (index + 1) ft.ReturnTypeUsage + | :? IFunctionTypeUsage as ft, None -> + visit (index + 1) ft.ReturnTypeUsage + | _ -> + () + + if not binding.ParameterPatterns.IsEmpty then + visit 0 typeInfo + + let valSig = factory.CreateBindingSignature(refPat, typeInfo) + let newlineNode = NewLine(signatureModuleOrNamespaceDecl.GetLineEnding()) :> ITreeNode + addNodesAfter signatureModuleOrNamespaceDecl.LastChild [| newlineNode; valSig; newlineNode |] |> ignore + + null + + override this.Text = "Add function to signature file" From ec16276d98f23375897f30cb51c09a0e8700ed88 Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 4 Oct 2022 15:54:56 +0200 Subject: [PATCH 2/6] Add some initial easy binding tests. --- .../AddFunctionToSignatureFileAction.fs | 6 +++-- .../Simple Binding - 01.fs | 3 +++ .../Simple Binding - 01.fs.gold | 3 +++ .../Simple Binding - 01.fsi | 1 + .../Simple Binding - 01.fsi.gold | 2 ++ .../Simple Binding - 02.fs | 3 +++ .../Simple Binding - 02.fs.gold | 3 +++ .../Simple Binding - 02.fsi | 1 + .../Simple Binding - 02.fsi.gold | 2 ++ .../Simple Binding - 03.fs | 3 +++ .../Simple Binding - 03.fs.gold | 3 +++ .../Simple Binding - 03.fsi | 1 + .../Simple Binding - 03.fsi.gold | 2 ++ .../Simple Binding - 04.fs | 3 +++ .../Simple Binding - 04.fs.gold | 3 +++ .../Simple Binding - 04.fsi | 1 + .../Simple Binding - 04.fsi.gold | 2 ++ .../FSharp.Intentions.Tests.fsproj | 1 + .../AddFunctionToSignatureFileActionTest.fs | 24 +++++++++++++++++++ 19 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fs create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fsi create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fsi.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fs create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fsi create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fsi.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fs create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fsi create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fsi.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fs create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fsi create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fsi.gold create mode 100644 ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs index 256e7e1bba..91280759ff 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs @@ -1,4 +1,4 @@ -namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Intentions.Intentions +namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Intentions open FSharp.Compiler.Text open FSharp.Compiler.Symbols @@ -63,6 +63,8 @@ type AddFunctionToSignatureFileAction(dataProvider: FSharpContextActionDataProvi | Some signatureCounterPart -> let symbolUse = refPat.GetFcsSymbolUse() + if isNull symbolUse then None else + match symbolUse.Symbol with | ValFromImpl valSymbol -> let text = @@ -124,7 +126,7 @@ type AddFunctionToSignatureFileAction(dataProvider: FSharpContextActionDataProvi let valSig = factory.CreateBindingSignature(refPat, typeInfo) let newlineNode = NewLine(signatureModuleOrNamespaceDecl.GetLineEnding()) :> ITreeNode - addNodesAfter signatureModuleOrNamespaceDecl.LastChild [| newlineNode; valSig; newlineNode |] |> ignore + addNodesAfter signatureModuleOrNamespaceDecl.LastChild [| newlineNode; valSig |] |> ignore null diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fs b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fs new file mode 100644 index 0000000000..4bdf207535 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fs @@ -0,0 +1,3 @@ +module Test + +let a{caret} b c = b + c diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fs.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fs.gold new file mode 100644 index 0000000000..4bdf207535 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fs.gold @@ -0,0 +1,3 @@ +module Test + +let a{caret} b c = b + c diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fsi b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fsi new file mode 100644 index 0000000000..ac248bbd7a --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fsi @@ -0,0 +1 @@ +module Test diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fsi.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fsi.gold new file mode 100644 index 0000000000..4adea847f5 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 01.fsi.gold @@ -0,0 +1,2 @@ +module Test +val a: b: int -> c: int -> int diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fs b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fs new file mode 100644 index 0000000000..e5631656ef --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fs @@ -0,0 +1,3 @@ +module Test + +let a{caret} (b:string) c = c + 1 diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fs.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fs.gold new file mode 100644 index 0000000000..e5631656ef --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fs.gold @@ -0,0 +1,3 @@ +module Test + +let a{caret} (b:string) c = c + 1 diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fsi b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fsi new file mode 100644 index 0000000000..ac248bbd7a --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fsi @@ -0,0 +1 @@ +module Test diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fsi.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fsi.gold new file mode 100644 index 0000000000..a9c861cbe7 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 02.fsi.gold @@ -0,0 +1,2 @@ +module Test +val a: b: string -> c: int -> int diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fs b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fs new file mode 100644 index 0000000000..75f248e77b --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fs @@ -0,0 +1,3 @@ +module Test + +let a{caret} b (c: char) d = b + d + 1 diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fs.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fs.gold new file mode 100644 index 0000000000..75f248e77b --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fs.gold @@ -0,0 +1,3 @@ +module Test + +let a{caret} b (c: char) d = b + d + 1 diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fsi b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fsi new file mode 100644 index 0000000000..ac248bbd7a --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fsi @@ -0,0 +1 @@ +module Test diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fsi.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fsi.gold new file mode 100644 index 0000000000..e6b8a99f20 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 03.fsi.gold @@ -0,0 +1,2 @@ +module Test +val a: b: int -> c: char -> d: int -> int diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fs b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fs new file mode 100644 index 0000000000..efd73b1add --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fs @@ -0,0 +1,3 @@ +module Test + +let a{caret} b : int = printfn "%s" b ; 0 diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fs.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fs.gold new file mode 100644 index 0000000000..efd73b1add --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fs.gold @@ -0,0 +1,3 @@ +module Test + +let a{caret} b : int = printfn "%s" b ; 0 diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fsi b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fsi new file mode 100644 index 0000000000..ac248bbd7a --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fsi @@ -0,0 +1 @@ +module Test diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fsi.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fsi.gold new file mode 100644 index 0000000000..0becddf6fd --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Simple Binding - 04.fsi.gold @@ -0,0 +1,2 @@ +module Test +val a: b: string -> int diff --git a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/FSharp.Intentions.Tests.fsproj b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/FSharp.Intentions.Tests.fsproj index 3dbcefcdc4..80f5f9c517 100644 --- a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/FSharp.Intentions.Tests.fsproj +++ b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/FSharp.Intentions.Tests.fsproj @@ -47,6 +47,7 @@ + diff --git a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs new file mode 100644 index 0000000000..4b6df3ae1a --- /dev/null +++ b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs @@ -0,0 +1,24 @@ +namespace JetBrains.ReSharper.Plugins.FSharp.Tests.Intentions.Intentions + +open JetBrains.ReSharper.Plugins.FSharp +open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Intentions +open NUnit.Framework + +type AddFunctionToSignatureFileActionTest() = + inherit FSharpContextActionExecuteTestBase() + + // TODO: is there an equivalent to CheckAllFiles for FSharpContextActionExecuteTestBase<'T>? + // override this.CheckAllFiles = true + + override this.ExtraPath = "addFunctionToSignature" + + member x.DoNamedTestWithSignature() = + let testName = x.TestMethodName + let fsExt = FSharpProjectFileType.FsExtension + let fsiExt = FSharpSignatureProjectFileType.FsiExtension + x.DoTestSolution(testName + fsiExt, testName + fsExt) + + [] member x.``Simple Binding - 01`` () = x.DoNamedTestWithSignature() + [] member x.``Simple Binding - 02`` () = x.DoNamedTestWithSignature() + [] member x.``Simple Binding - 03`` () = x.DoNamedTestWithSignature() + [] member x.``Simple Binding - 04`` () = x.DoNamedTestWithSignature() From e0e46d7cb4b0e26bdb88b7c1cdc1d995c8da5eff Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 5 Oct 2022 09:36:31 +0200 Subject: [PATCH 3/6] Add support for tuples and attributes. --- .../AddFunctionToSignatureFileAction.fs | 59 +++++++++++++++---- .../AddFunctionToSignatureFileActionTest.fs | 4 ++ 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs index 91280759ff..28b85fe13b 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs @@ -12,6 +12,12 @@ open JetBrains.ReSharper.Resources.Shell open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree open JetBrains.ReSharper.Psi.Tree +[] +type private ParameterNameFromPattern = + | NoNameFound + | SingleName of name: IFSharpIdentifier * attributes: string + | TupleName of ParameterNameFromPattern list + [] type AddFunctionToSignatureFileAction(dataProvider: FSharpContextActionDataProvider) = inherit FSharpContextActionBase(dataProvider) @@ -23,11 +29,26 @@ type AddFunctionToSignatureFileAction(dataProvider: FSharpContextActionDataProvi |> Option.bind (fun range -> if range.FileName.EndsWith(".fs") then Some valSymbol else None) | _ -> None - let rec tryFindParameterName (p: IFSharpPattern) = + let rec tryFindParameterName (isTopLevel: bool) (p: IFSharpPattern) : ParameterNameFromPattern = match p.IgnoreInnerParens() with - | :? ITypedPat as tp -> tryFindParameterName tp.Pattern - | :? ILocalReferencePat as rp -> Some rp.Identifier - | _ -> None + | :? ITypedPat as tp -> tryFindParameterName isTopLevel tp.Pattern + | :? ILocalReferencePat as rp -> ParameterNameFromPattern.SingleName (rp.Identifier, "") + | :? IAttribPat as ap -> + match tryFindParameterName isTopLevel ap.Pattern with + | ParameterNameFromPattern.SingleName(name, _) -> + let attributes = Seq.map (fun (al:IAttributeList) -> al.GetText()) ap.AttributeListsEnumerable |> String.concat "" + ParameterNameFromPattern.SingleName(name, attributes) + | _ -> + ParameterNameFromPattern.NoNameFound + | :? ITuplePat as tp -> + if not isTopLevel then + ParameterNameFromPattern.NoNameFound + else + + Seq.map (tryFindParameterName false) tp.Patterns + |> Seq.toList + |> ParameterNameFromPattern.TupleName + | _ -> ParameterNameFromPattern.NoNameFound let implBindingAndDecl = let currentFSharpFile = dataProvider.PsiFile @@ -102,22 +123,34 @@ type AddFunctionToSignatureFileAction(dataProvider: FSharpContextActionDataProvi replace t (factory.WrapParenAroundTypeUsageForSignature(t)) | _ -> () else - // TODO: take tuples into account. - let parameterAtIndex = tryFindParameterName (binding.ParameterPatterns.Item(index)) + let parameterAtIndex = tryFindParameterName true (binding.ParameterPatterns.Item(index)) match t, parameterAtIndex with - | :? IFunctionTypeUsage as ft, Some parameterName -> + | :? IFunctionTypeUsage as ft, ParameterNameFromPattern.NoNameFound -> + visit (index + 1) ft.ReturnTypeUsage + + | :? IFunctionTypeUsage as ft, ParameterNameFromPattern.SingleName (name, attributes) -> match ft.ArgumentTypeUsage with | :? IParameterSignatureTypeUsage as pstu -> - // Update the parameter name if it was found in the implementation file - // calling SetIdentifier on pstu does not add a ':' token. - let namedTypeUsage = factory.CreateParameterSignatureTypeUsage(parameterName, pstu.TypeUsage) - replace ft.ArgumentTypeUsage namedTypeUsage + factory.CreateParameterSignatureTypeUsage(attributes, name, pstu.TypeUsage) + |> replace ft.ArgumentTypeUsage | _ -> () visit (index + 1) ft.ReturnTypeUsage - | :? IFunctionTypeUsage as ft, None -> - visit (index + 1) ft.ReturnTypeUsage + + | :? IFunctionTypeUsage as ft, ParameterNameFromPattern.TupleName multipleParameterNames -> + match ft.ArgumentTypeUsage with + | :? ITupleTypeUsage as tt when tt.Items.Count = multipleParameterNames.Length -> + (multipleParameterNames, tt.Items) + ||> Seq.zip + |> Seq.iter (fun (p,t) -> + match t, p with + | :? IParameterSignatureTypeUsage as pstu, ParameterNameFromPattern.SingleName (name, attributes) -> + factory.CreateParameterSignatureTypeUsage(attributes, name, pstu.TypeUsage) + |> replace t + | _ -> () + ) + | _ -> visit (index + 1) ft.ReturnTypeUsage | _ -> () diff --git a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs index 4b6df3ae1a..51f6291687 100644 --- a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs @@ -22,3 +22,7 @@ type AddFunctionToSignatureFileActionTest() = [] member x.``Simple Binding - 02`` () = x.DoNamedTestWithSignature() [] member x.``Simple Binding - 03`` () = x.DoNamedTestWithSignature() [] member x.``Simple Binding - 04`` () = x.DoNamedTestWithSignature() + [] member x.``Tuple parameter - 01`` () = x.DoNamedTestWithSignature() + [] member x.``Tuple parameter - 02`` () = x.DoNamedTestWithSignature() + [] member x.``Attribute in parameter - 01`` () = x.DoNamedTestWithSignature() + [] member x.``Attribute in parameter - 02`` () = x.DoNamedTestWithSignature() From 9d336762b57e9105185da36060ed4d9269902297 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 5 Oct 2022 09:46:13 +0200 Subject: [PATCH 4/6] =?UTF-8?q?Add=20test=20files=20=F0=9F=99=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../addFunctionToSignature/Attribute in parameter - 01.fs | 4 ++++ .../Attribute in parameter - 01.fs.gold | 4 ++++ .../addFunctionToSignature/Attribute in parameter - 01.fsi | 2 ++ .../Attribute in parameter - 01.fsi.gold | 3 +++ .../addFunctionToSignature/Attribute in parameter - 02.fs | 3 +++ .../Attribute in parameter - 02.fs.gold | 3 +++ .../addFunctionToSignature/Attribute in parameter - 02.fsi | 1 + .../Attribute in parameter - 02.fsi.gold | 2 ++ .../addFunctionToSignature/Attribute in parameter - 03.fs | 3 +++ .../Attribute in parameter - 03.fs.gold | 3 +++ .../addFunctionToSignature/Attribute in parameter - 03.fsi | 2 ++ .../Attribute in parameter - 03.fsi.gold | 3 +++ .../intentions/addFunctionToSignature/Tuple parameter - 01.fs | 3 +++ .../addFunctionToSignature/Tuple parameter - 01.fs.gold | 3 +++ .../addFunctionToSignature/Tuple parameter - 01.fsi | 1 + .../addFunctionToSignature/Tuple parameter - 01.fsi.gold | 2 ++ .../intentions/addFunctionToSignature/Tuple parameter - 02.fs | 3 +++ .../addFunctionToSignature/Tuple parameter - 02.fs.gold | 3 +++ .../addFunctionToSignature/Tuple parameter - 02.fsi | 1 + .../addFunctionToSignature/Tuple parameter - 02.fsi.gold | 2 ++ .../src/Intentions/AddFunctionToSignatureFileActionTest.fs | 1 + 21 files changed, 52 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fs create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fsi create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fsi.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fs create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fsi create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fsi.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fs create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fsi create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fsi.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fs create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fsi create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fsi.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fs create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fsi create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fsi.gold diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fs b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fs new file mode 100644 index 0000000000..5a30b3caf5 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fs @@ -0,0 +1,4 @@ +module Test + +open System.Diagnostics.CodeAnalysis +let x{caret} ([] y) = y + 0 diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fs.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fs.gold new file mode 100644 index 0000000000..5a30b3caf5 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fs.gold @@ -0,0 +1,4 @@ +module Test + +open System.Diagnostics.CodeAnalysis +let x{caret} ([] y) = y + 0 diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fsi b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fsi new file mode 100644 index 0000000000..84ca8d66f7 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fsi @@ -0,0 +1,2 @@ +module Test +open System.Diagnostics.CodeAnalysis diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fsi.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fsi.gold new file mode 100644 index 0000000000..101aa6088e --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 01.fsi.gold @@ -0,0 +1,3 @@ +module Test +open System.Diagnostics.CodeAnalysis +val x: [] y: int -> int diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fs b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fs new file mode 100644 index 0000000000..e3fdd5c484 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fs @@ -0,0 +1,3 @@ +module Test + +let x{caret} ([] y : int) = y + 0 diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fs.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fs.gold new file mode 100644 index 0000000000..e3fdd5c484 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fs.gold @@ -0,0 +1,3 @@ +module Test + +let x{caret} ([] y : int) = y + 0 diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fsi b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fsi new file mode 100644 index 0000000000..ac248bbd7a --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fsi @@ -0,0 +1 @@ +module Test diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fsi.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fsi.gold new file mode 100644 index 0000000000..7c2ef7b351 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 02.fsi.gold @@ -0,0 +1,2 @@ +module Test +val x: [] y: int -> int diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fs b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fs new file mode 100644 index 0000000000..5199180c5b --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fs @@ -0,0 +1,3 @@ +module Test +open System.Diagnostics.CodeAnalysis +let x{caret} ([] y : int, [] z: string) = y + 0 diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fs.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fs.gold new file mode 100644 index 0000000000..5199180c5b --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fs.gold @@ -0,0 +1,3 @@ +module Test +open System.Diagnostics.CodeAnalysis +let x{caret} ([] y : int, [] z: string) = y + 0 diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fsi b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fsi new file mode 100644 index 0000000000..84ca8d66f7 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fsi @@ -0,0 +1,2 @@ +module Test +open System.Diagnostics.CodeAnalysis diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fsi.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fsi.gold new file mode 100644 index 0000000000..a5bc0e9549 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Attribute in parameter - 03.fsi.gold @@ -0,0 +1,3 @@ +module Test +open System.Diagnostics.CodeAnalysis +val x: [] y: int * [] z: string -> int diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fs b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fs new file mode 100644 index 0000000000..e0f5baffb8 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fs @@ -0,0 +1,3 @@ +module Test + +let a{caret} (b, c) = b + c diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fs.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fs.gold new file mode 100644 index 0000000000..e0f5baffb8 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fs.gold @@ -0,0 +1,3 @@ +module Test + +let a{caret} (b, c) = b + c diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fsi b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fsi new file mode 100644 index 0000000000..ac248bbd7a --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fsi @@ -0,0 +1 @@ +module Test diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fsi.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fsi.gold new file mode 100644 index 0000000000..3e94793c05 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 01.fsi.gold @@ -0,0 +1,2 @@ +module Test +val a: b: int * c: int -> int diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fs b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fs new file mode 100644 index 0000000000..be9be71d10 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fs @@ -0,0 +1,3 @@ +module Test + +let a{caret} (b, _, d) = printfn "%b" d ; b + 1 diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fs.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fs.gold new file mode 100644 index 0000000000..be9be71d10 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fs.gold @@ -0,0 +1,3 @@ +module Test + +let a{caret} (b, _, d) = printfn "%b" d ; b + 1 diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fsi b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fsi new file mode 100644 index 0000000000..ac248bbd7a --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fsi @@ -0,0 +1 @@ +module Test diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fsi.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fsi.gold new file mode 100644 index 0000000000..bcd5472988 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Tuple parameter - 02.fsi.gold @@ -0,0 +1,2 @@ +module Test +val a: b: int * 'a * d: bool -> int diff --git a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs index 51f6291687..04e8551f48 100644 --- a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs @@ -26,3 +26,4 @@ type AddFunctionToSignatureFileActionTest() = [] member x.``Tuple parameter - 02`` () = x.DoNamedTestWithSignature() [] member x.``Attribute in parameter - 01`` () = x.DoNamedTestWithSignature() [] member x.``Attribute in parameter - 02`` () = x.DoNamedTestWithSignature() + [] member x.``Attribute in parameter - 03`` () = x.DoNamedTestWithSignature() \ No newline at end of file From 65a9c099b41f194b84275e91c3e5cf5201204188 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 5 Oct 2022 10:15:30 +0200 Subject: [PATCH 5/6] Ignore constraints in signature for now. --- .../src/Intentions/AddFunctionToSignatureFileAction.fs | 7 +++++++ .../addFunctionToSignature/Generic constraints - 01.fs | 7 +++++++ .../Generic constraints - 01.fs.gold | 1 + .../addFunctionToSignature/Generic constraints - 01.fsi | 1 + .../src/Intentions/AddFunctionToSignatureFileActionTest.fs | 6 +++++- 5 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Generic constraints - 01.fs create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Generic constraints - 01.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Generic constraints - 01.fsi diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs index 28b85fe13b..3c505069e1 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs @@ -25,6 +25,13 @@ type AddFunctionToSignatureFileAction(dataProvider: FSharpContextActionDataProvi let (|ValFromImpl|_|) (symbol:FSharpSymbol) = match symbol with | :? FSharpMemberOrFunctionOrValue as valSymbol -> + let hasConstraints = + valSymbol.GenericParameters + |> Seq.exists (fun gp -> not (Seq.isEmpty gp.Constraints)) + + // Ignore constraints for now. + if hasConstraints then None else + valSymbol.SignatureLocation |> Option.bind (fun range -> if range.FileName.EndsWith(".fs") then Some valSymbol else None) | _ -> None diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Generic constraints - 01.fs b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Generic constraints - 01.fs new file mode 100644 index 0000000000..e0c44abb74 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Generic constraints - 01.fs @@ -0,0 +1,7 @@ +module Test + +let memoizeBy{caret} (g: 'a -> 'c) (f: 'a -> 'b) = + let cache = + System.Collections.Concurrent.ConcurrentDictionary<_, _>(HashIdentity.Structural) + + fun x -> cache.GetOrAdd(Some(g x), lazy (f x)).Force() diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Generic constraints - 01.fs.gold b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Generic constraints - 01.fs.gold new file mode 100644 index 0000000000..b6b78ddc05 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Generic constraints - 01.fs.gold @@ -0,0 +1 @@ +NOT AVAILABLE diff --git a/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Generic constraints - 01.fsi b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Generic constraints - 01.fsi new file mode 100644 index 0000000000..ac248bbd7a --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/addFunctionToSignature/Generic constraints - 01.fsi @@ -0,0 +1 @@ +module Test diff --git a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs index 04e8551f48..a087896bae 100644 --- a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/AddFunctionToSignatureFileActionTest.fs @@ -26,4 +26,8 @@ type AddFunctionToSignatureFileActionTest() = [] member x.``Tuple parameter - 02`` () = x.DoNamedTestWithSignature() [] member x.``Attribute in parameter - 01`` () = x.DoNamedTestWithSignature() [] member x.``Attribute in parameter - 02`` () = x.DoNamedTestWithSignature() - [] member x.``Attribute in parameter - 03`` () = x.DoNamedTestWithSignature() \ No newline at end of file + [] member x.``Attribute in parameter - 03`` () = x.DoNamedTestWithSignature() + // Ignore generic constraints for now + + // This test requires `when 'c: equality` at the end of the signature. + [] member x.``Generic constraints - 01`` () = x.DoNamedTestWithSignature() From 60f10a7c917dfcc60ce662ad6da8b919ecc3f09a Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 2 Nov 2022 09:17:14 +0100 Subject: [PATCH 6/6] Update changes to new CreateTypeUsage API. --- .../LanguageService/FSharpElementFactory.fs | 18 ++++++++++++++++++ .../AddFunctionToSignatureFileAction.fs | 19 +++++++++++-------- .../FSharp.Psi/src/IFSharpElementFactory.cs | 3 +++ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Features/src/LanguageService/FSharpElementFactory.fs b/ReSharper.FSharp/src/FSharp.Psi.Features/src/LanguageService/FSharpElementFactory.fs index ab4f5b5293..0557a02d6b 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Features/src/LanguageService/FSharpElementFactory.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Features/src/LanguageService/FSharpElementFactory.fs @@ -94,6 +94,11 @@ type FSharpElementFactory(languageService: IFSharpLanguageService, sourceFile: I let exprStatement = getExpressionStatement source exprStatement.AttributeLists[0] + let createBindingSignature () = + let source = "module V\nval a: obj" + let moduleMember = getModuleMember source + moduleMember :?> IBindingSignature + interface IFSharpElementFactory with member x.CreateOpenStatement(ns) = // todo: mangle ns @@ -342,6 +347,12 @@ type FSharpElementFactory(languageService: IFSharpLanguageService, sourceFile: I | _ -> System.ArgumentOutOfRangeException() |> raise + member x.CreateParenType() : IParenTypeUsage = + let expr = getExpression "do () : (unit)" + let doExpr = expr :?> IDoExpr + let typedExpr = doExpr.Expression :?> ITypedExpr + typedExpr.TypeUsage :?> IParenTypeUsage + member x.CreateSetExpr(left: IFSharpExpression, right: IFSharpExpression) = let source = "() <- ()" let expr = getExpression source @@ -385,3 +396,10 @@ type FSharpElementFactory(languageService: IFSharpLanguageService, sourceFile: I moduleMember.As().TypeDeclarations[0] :?> IFSharpTypeDeclaration typeDeclaration.TypeParameterDeclarationList + + member x.CreateBindingSignature(bindingName: IFSharpPattern, returnType: ITypeUsage) = + assert sourceFile.IsFSharpSignatureFile + let signature = createBindingSignature () + signature.SetHeadPattern(bindingName) |> ignore + replace signature.ReturnTypeInfo.ReturnType returnType + signature \ No newline at end of file diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs index 3c505069e1..1706652c0d 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/AddFunctionToSignatureFileAction.fs @@ -116,8 +116,8 @@ type AddFunctionToSignatureFileAction(dataProvider: FSharpContextActionDataProvi use writeCookie = WriteLockCookie.Create(binding.IsPhysical()) use disableFormatter = new DisableCodeFormatter() - let factory = signatureModuleOrNamespaceDecl.CreateElementFactory() - let typeInfo = factory.CreateTypeUsageForSignature(text) + let factory = binding.CreateElementFactory() + let typeInfo = factory.CreateTypeUsage(text, TypeUsageContext.Return) // Enrich the type info with the found parameters from binding. let rec visit (index:int) (t: ITypeUsage) = @@ -127,7 +127,9 @@ type AddFunctionToSignatureFileAction(dataProvider: FSharpContextActionDataProvi // If the return type is a function itself, the safest thing to do is to wrap it in parentheses. // Example: `let g _ = (*) 3` // `val g: 'a -> int -> int` is not valid, `val g: 'a -> (int -> int)` is. - replace t (factory.WrapParenAroundTypeUsageForSignature(t)) + let parenType = factory.CreateParenType() + replace parenType.InnerTypeUsage t + replace t parenType | _ -> () else let parameterAtIndex = tryFindParameterName true (binding.ParameterPatterns.Item(index)) @@ -139,8 +141,7 @@ type AddFunctionToSignatureFileAction(dataProvider: FSharpContextActionDataProvi | :? IFunctionTypeUsage as ft, ParameterNameFromPattern.SingleName (name, attributes) -> match ft.ArgumentTypeUsage with | :? IParameterSignatureTypeUsage as pstu -> - factory.CreateParameterSignatureTypeUsage(attributes, name, pstu.TypeUsage) - |> replace ft.ArgumentTypeUsage + pstu.SetIdentifier(name) |> ignore | _ -> () visit (index + 1) ft.ReturnTypeUsage @@ -153,8 +154,7 @@ type AddFunctionToSignatureFileAction(dataProvider: FSharpContextActionDataProvi |> Seq.iter (fun (p,t) -> match t, p with | :? IParameterSignatureTypeUsage as pstu, ParameterNameFromPattern.SingleName (name, attributes) -> - factory.CreateParameterSignatureTypeUsage(attributes, name, pstu.TypeUsage) - |> replace t + pstu.SetIdentifier(name) |> ignore | _ -> () ) | _ -> visit (index + 1) ft.ReturnTypeUsage @@ -164,7 +164,10 @@ type AddFunctionToSignatureFileAction(dataProvider: FSharpContextActionDataProvi if not binding.ParameterPatterns.IsEmpty then visit 0 typeInfo - let valSig = factory.CreateBindingSignature(refPat, typeInfo) + let valSig = + let signatureFactory = signatureModuleOrNamespaceDecl.CreateElementFactory() + signatureFactory.CreateBindingSignature(refPat, typeInfo) + let newlineNode = NewLine(signatureModuleOrNamespaceDecl.GetLineEnding()) :> ITreeNode addNodesAfter signatureModuleOrNamespaceDecl.LastChild [| newlineNode; valSig |] |> ignore diff --git a/ReSharper.FSharp/src/FSharp.Psi/src/IFSharpElementFactory.cs b/ReSharper.FSharp/src/FSharp.Psi/src/IFSharpElementFactory.cs index a7c14531f0..0e70dd393e 100644 --- a/ReSharper.FSharp/src/FSharp.Psi/src/IFSharpElementFactory.cs +++ b/ReSharper.FSharp/src/FSharp.Psi/src/IFSharpElementFactory.cs @@ -41,6 +41,7 @@ public interface IFSharpElementFactory ITypedPat CreateTypedPat(IFSharpPattern pattern, ITypeUsage typeUsage); ITypeUsage CreateTypeUsage(string typeUsage, TypeUsageContext context); + IParenTypeUsage CreateParenType(); IReturnTypeInfo CreateReturnTypeInfo(ITypeUsage typeSignature); @@ -62,5 +63,7 @@ public interface IFSharpElementFactory IMemberDeclaration CreatePropertyWithAccessor(string propertyName, string accessorName, FSharpList args); ITypeParameterDeclarationList CreateTypeParameterOfTypeList(FSharpList names); + + IBindingSignature CreateBindingSignature(IFSharpPattern bindingName, ITypeUsage returnType); } }