From 1dcd7f31fe761c45f36ff1e0d712b3df5e2dbf10 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 13 Feb 2023 15:56:34 +0100 Subject: [PATCH 01/75] Initial generation signature feature toggle. --- .../src/Settings/FSharpOptions.fs | 8 +- .../src/Util/FSharpExperimentalFeatures.fs | 2 + .../FSharp.Psi.Intentions.fsproj | 1 + .../Intentions/GenerateSignatureFileAction.fs | 100 ++++++++++++++++++ 4 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs diff --git a/ReSharper.FSharp/src/FSharp.Common/src/Settings/FSharpOptions.fs b/ReSharper.FSharp/src/FSharp.Common/src/Settings/FSharpOptions.fs index 753cf0ad99..a3f0d79197 100644 --- a/ReSharper.FSharp/src/FSharp.Common/src/Settings/FSharpOptions.fs +++ b/ReSharper.FSharp/src/FSharp.Common/src/Settings/FSharpOptions.fs @@ -86,7 +86,7 @@ module FSharpExperimentalFeatures = let [] outOfProcessTypeProviders = "Host type providers out-of-process" let [] generativeTypeProvidersInMemoryAnalysis = "Enable generative type providers analysis in C#/VB.NET projects" let [] tryRecoverFcsProjects = "Try to reuse FCS results on project changes" - + let [] generateSignatureFile = "Generate signature file" [, "F# experimental features")>] type FSharpExperimentalFeatures = @@ -109,8 +109,10 @@ type FSharpExperimentalFeatures = mutable GenerativeTypeProvidersInMemoryAnalysis: bool [] - mutable TryRecoverFcsProjects: bool } + mutable TryRecoverFcsProjects: bool + [] + mutable GenerateSignatureFile: bool } [] type FSharpSettingsProviderBase<'T>(lifetime: Lifetime, settings: IContextBoundSettingsStoreLive, @@ -146,6 +148,7 @@ type FSharpExperimentalFeaturesProvider(lifetime, solution, settings, settingsSc member val OutOfProcessTypeProviders = base.GetValueProperty("OutOfProcessTypeProviders") member val GenerativeTypeProvidersInMemoryAnalysis = base.GetValueProperty("GenerativeTypeProvidersInMemoryAnalysis") member val TryRecoverFcsProjects = base.GetValueProperty("TryRecoverFcsProjects") + member val GenerateSignatureFile = base.GetValueProperty("GenerateSignatureFile") [] @@ -220,6 +223,7 @@ type FSharpOptionsPage(lifetime: Lifetime, optionsPageContext, settings, this.AddBoolOption((fun key -> key.PostfixTemplates), RichText(FSharpExperimentalFeatures.postfixTemplates), null) |> ignore this.AddBoolOption((fun key -> key.RedundantParensAnalysis), RichText(FSharpExperimentalFeatures.redundantParenAnalysis), null) |> ignore this.AddBoolOption((fun key -> key.Formatter), RichText(FSharpExperimentalFeatures.formatter), null) |> ignore + this.AddBoolOption((fun key -> key.GenerateSignatureFile), RichText(FSharpExperimentalFeatures.generateSignatureFile)) |> ignore [] diff --git a/ReSharper.FSharp/src/FSharp.Common/src/Util/FSharpExperimentalFeatures.fs b/ReSharper.FSharp/src/FSharp.Common/src/Util/FSharpExperimentalFeatures.fs index 0acca3f522..2ab7deeb3c 100644 --- a/ReSharper.FSharp/src/FSharp.Common/src/Util/FSharpExperimentalFeatures.fs +++ b/ReSharper.FSharp/src/FSharp.Common/src/Util/FSharpExperimentalFeatures.fs @@ -13,6 +13,7 @@ type ExperimentalFeature = | RedundantParenAnalysis = 3 | AssemblyReaderShim = 4 | TryRecoverFcsProjects = 5 + | GenerateSignatureFile = 6 type FSharpExperimentalFeatureCookie(feature: ExperimentalFeature) = static let cookies = OneToListMap() @@ -45,6 +46,7 @@ type FSharpExperimentalFeatures() = | ExperimentalFeature.PostfixTemplates -> experimentalFeatures.EnablePostfixTemplates.Value | ExperimentalFeature.RedundantParenAnalysis -> experimentalFeatures.RedundantParensAnalysis.Value | ExperimentalFeature.TryRecoverFcsProjects -> experimentalFeatures.TryRecoverFcsProjects.Value + | ExperimentalFeature.GenerateSignatureFile -> experimentalFeatures.GenerateSignatureFile.Value | _ -> failwith $"Unexpected feature: {feature}" [] 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 46c94eff22..5ca0e5581e 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj @@ -26,6 +26,7 @@ + diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs new file mode 100644 index 0000000000..e6683249b8 --- /dev/null +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs @@ -0,0 +1,100 @@ +namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions + +open System.IO +open JetBrains.ReSharper.Feature.Services.ContextActions +open JetBrains.ReSharper.Plugins.FSharp.Psi +open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Intentions +open type JetBrains.ReSharper.Psi.PsiSourceFileExtensions +open JetBrains.ReSharper.Plugins.FSharp +open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree +open JetBrains.ReSharper.Psi +open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree + +type TopLevelModuleOrNamespace = + { + IsModule: bool + Name: string + NestedModules: NestedModule list + } + +and NestedModule = + { + Name: string + NestedModules: NestedModule list + } + +[] +type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) = + inherit FSharpContextActionBase(dataProvider) + + let mkSignatureFile (fsharpFile: IFSharpFile) : IFSharpFile = + let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory() + let signatureFile : IFSharpFile = factory.CreateEmptyFile() + + let rec processModuleMembers (parent: IFSharpTreeNode) (members: IModuleMember seq) = + for m in members do + match m with + | :? INestedModuleDeclaration as nmd -> + let nestedModuleNode = factory.CreateNestedModule(nmd.NameIdentifier.Name) + // TODO: if the nested module has nested modules, clear the content (`begin end`) and process them. + ModificationUtil.AddChild(parent, nestedModuleNode) |> ignore + | _ -> () + + for decl in fsharpFile.ModuleDeclarations do + match decl with + | :? INamedModuleDeclaration as nmd -> + let moduleNode = factory.CreateModule(nmd.NameIdentifier.Name) + processModuleMembers moduleNode nmd.Members + ModificationUtil.AddChild(signatureFile, moduleNode) |> ignore + | :? INamedNamespaceDeclaration as nnd -> + let namespaceNode = factory.CreateModule(nnd.NameIdentifier.Name) + processModuleMembers namespaceNode nnd.Members + ModificationUtil.AddChild(signatureFile, namespaceNode) |> ignore + | _ -> () + + signatureFile + + override this.Text = "Generate signature file for current file" + + override this.IsAvailable _ = + let solution = dataProvider.Solution + let isSettingEnabled = solution.IsFSharpExperimentalFeatureEnabled(ExperimentalFeature.GenerateSignatureFile) + if not isSettingEnabled then false else + let currentFSharpFile = dataProvider.PsiFile + let fcsService = currentFSharpFile.FcsCheckerService + let hasSignature = fcsService.FcsProjectProvider.HasPairFile dataProvider.SourceFile + not hasSignature + + override this.ExecutePsiTransaction(solution, _) = + let projectFile = dataProvider.SourceFile.ToProjectFile() + let fsharpFile = projectFile.GetPrimaryPsiFile().AsFSharpFile() + let physicalPath = dataProvider.SourceFile.ToProjectFile().Location.FileAccessPath + let fsiFile = Path.ChangeExtension(physicalPath, ".fsi") + + let signatureFile = mkSignatureFile fsharpFile + // try + // let currentFSharpFile = dataProvider.PsiFile + // let fcsService = currentFSharpFile.FcsCheckerService + // let checkResult = fcsService.ParseAndCheckFile(currentFSharpFile.GetSourceFile(), "for signature file", true) + // do + // match checkResult with + // | None -> () + // | Some { CheckResults = checkResult } -> + // + // match checkResult.GenerateSignature() with + // | None -> () + // | Some signatureSourceText -> + // let content = string signatureSourceText + // File.WriteAllText(fsiFile, content) + // with ex -> + // // TODO: show some balloon thing? + // () + + // solution.InvokeUnderTransaction(fun transactionCookie -> + // let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() + // let relativeTo = RelativeTo(projectFile, RelativeToType.Before) + // transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) + // |> ignore) + + null \ No newline at end of file From dcecc1b2aa8dd6fe4475c8c0eeb76e84aecf4d00 Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 14 Feb 2023 16:50:59 +0100 Subject: [PATCH 02/75] After pair programming session. --- .../src/Parsing/FSharpImplTreeBuilder.fs | 11 +- .../Intentions/GenerateSignatureFileAction.fs | 117 +++++++++--------- .../src/Tree/IModuleLikeDeclaration.cs | 3 + 3 files changed, 71 insertions(+), 60 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpImplTreeBuilder.fs b/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpImplTreeBuilder.fs index 6681e4e390..8f529072f4 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpImplTreeBuilder.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpImplTreeBuilder.fs @@ -35,11 +35,11 @@ type FSharpImplTreeBuilder(lexer, document, decls, lifetime, path, projectedOffs let (SynModuleOrNamespace(lid, _, moduleKind, decls, XmlDoc xmlDoc, attrs, _, range, _)) = moduleOrNamespace let mark, elementType = x.StartTopLevelDeclaration(lid, attrs, moduleKind, xmlDoc, range) for decl in decls do - x.ProcessModuleMemberDeclaration(decl) + x.ProcessModuleMemberDeclaration(decl, moduleOrNamespace.Range) x.EnsureMembersAreFinished() x.FinishTopLevelDeclaration(mark, range, elementType) - member x.ProcessModuleMemberDeclaration(moduleMember) = + member x.ProcessModuleMemberDeclaration(moduleMember, parentRange) = match unfinishedDeclaration with | None -> () | Some(mark, range, elementType) -> @@ -53,7 +53,12 @@ type FSharpImplTreeBuilder(lexer, document, decls, lifetime, path, projectedOffs | SynModuleDecl.NestedModule(SynComponentInfo(attrs, _, _, _, XmlDoc xmlDoc, _, _, _), _, decls, _, range, _) -> let mark = x.MarkAndProcessIntro(attrs, xmlDoc, null, range) for decl in decls do - x.ProcessModuleMemberDeclaration(decl) + x.ProcessModuleMemberDeclaration(decl, parentRange) + + if decls.IsEmpty then + x.AdvanceToTokenOrRangeEnd(FSharpTokenType.END, parentRange) + x.Advance() + x.Done(range, mark, ElementType.NESTED_MODULE_DECLARATION) | SynModuleDecl.Types(typeDefns, range) -> diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs index e6683249b8..37a71d2aee 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs @@ -1,57 +1,72 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions open System.IO +open JetBrains.ReSharper.Psi.Tree +open JetBrains.DocumentManagers.Transactions.ProjectHostActions.Ordering +open JetBrains.ProjectModel.ProjectsHost +open JetBrains.RdBackend.Common.Features.ProjectModel open JetBrains.ReSharper.Feature.Services.ContextActions open JetBrains.ReSharper.Plugins.FSharp.Psi open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Intentions -open type JetBrains.ReSharper.Psi.PsiSourceFileExtensions open JetBrains.ReSharper.Plugins.FSharp +open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree open JetBrains.ReSharper.Psi open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree -type TopLevelModuleOrNamespace = - { - IsModule: bool - Name: string - NestedModules: NestedModule list - } - -and NestedModule = - { - Name: string - NestedModules: NestedModule list - } +// extract value -> ctrl alt v +// undo that -> ctrl alt n [] type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) = inherit FSharpContextActionBase(dataProvider) - + let mkSignatureFile (fsharpFile: IFSharpFile) : IFSharpFile = let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory() let signatureFile : IFSharpFile = factory.CreateEmptyFile() - - let rec processModuleMembers (parent: IFSharpTreeNode) (members: IModuleMember seq) = - for m in members do - match m with - | :? INestedModuleDeclaration as nmd -> - let nestedModuleNode = factory.CreateNestedModule(nmd.NameIdentifier.Name) - // TODO: if the nested module has nested modules, clear the content (`begin end`) and process them. - ModificationUtil.AddChild(parent, nestedModuleNode) |> ignore - | _ -> () + let lineEnding = fsharpFile.GetLineEnding() + + let rec processModuleLikeDeclaration (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleSig: IModuleLikeDeclaration) : IFSharpTreeNode = + for moduleMember in moduleDecl.Members do + // newline + indentation whitespace + addNodesAfter moduleSig.LastChild [ + NewLine(lineEnding) + Whitespace(indentation) + match moduleMember with + | :? INestedModuleDeclaration as nestedNestedModule -> + let nestedSigModule = factory.CreateNestedModule(nestedNestedModule.NameIdentifier.Name) + let members = nestedNestedModule.Members + let shouldEmptyContent = + not members.IsEmpty + && members |> Seq.forall (function | :? IExpressionStatement -> false | _ -> true) + + if shouldEmptyContent then + ModificationUtil.DeleteChildRange (nestedSigModule.EqualsToken.NextSibling, nestedSigModule.LastChild) + processModuleLikeDeclaration (indentation + moduleDecl.GetIndentSize()) nestedNestedModule nestedSigModule + | :? IOpenStatement as openStatement -> + openStatement.Copy() + | _ -> () + ] + |> ignore + + moduleSig for decl in fsharpFile.ModuleDeclarations do - match decl with - | :? INamedModuleDeclaration as nmd -> - let moduleNode = factory.CreateModule(nmd.NameIdentifier.Name) - processModuleMembers moduleNode nmd.Members - ModificationUtil.AddChild(signatureFile, moduleNode) |> ignore - | :? INamedNamespaceDeclaration as nnd -> - let namespaceNode = factory.CreateModule(nnd.NameIdentifier.Name) - processModuleMembers namespaceNode nnd.Members - ModificationUtil.AddChild(signatureFile, namespaceNode) |> ignore - | _ -> () + let signatureModule : IModuleLikeDeclaration = + match decl with + | :? INamedModuleDeclaration as nmd -> + factory.CreateModule(nmd.DeclaredElement.GetClrName().FullName) + | :? IGlobalNamespaceDeclaration -> + factory.CreateNamespace("global") :?> _ + | :? INamedNamespaceDeclaration as nnd -> + // TODO: add an interface that could unify named and global namespace. + factory.CreateNamespace(nnd.QualifiedName) :?> _ + | decl -> failwithf $"Unexpected declaration, got: %A{decl}" + + ModificationUtil.AddChildAfter(signatureModule.LastChild, NewLine(lineEnding)) |> ignore + let signatureModule = processModuleLikeDeclaration 0 decl signatureModule + ModificationUtil.AddChild(signatureFile, signatureModule) |> ignore signatureFile @@ -71,30 +86,18 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) let fsharpFile = projectFile.GetPrimaryPsiFile().AsFSharpFile() let physicalPath = dataProvider.SourceFile.ToProjectFile().Location.FileAccessPath let fsiFile = Path.ChangeExtension(physicalPath, ".fsi") - let signatureFile = mkSignatureFile fsharpFile - // try - // let currentFSharpFile = dataProvider.PsiFile - // let fcsService = currentFSharpFile.FcsCheckerService - // let checkResult = fcsService.ParseAndCheckFile(currentFSharpFile.GetSourceFile(), "for signature file", true) - // do - // match checkResult with - // | None -> () - // | Some { CheckResults = checkResult } -> - // - // match checkResult.GenerateSignature() with - // | None -> () - // | Some signatureSourceText -> - // let content = string signatureSourceText - // File.WriteAllText(fsiFile, content) - // with ex -> - // // TODO: show some balloon thing? - // () + File.WriteAllText(fsiFile, signatureFile.GetText()) - // solution.InvokeUnderTransaction(fun transactionCookie -> - // let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() - // let relativeTo = RelativeTo(projectFile, RelativeToType.Before) - // transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) - // |> ignore) + solution.InvokeUnderTransaction(fun transactionCookie -> + let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() + let relativeTo = RelativeTo(projectFile, RelativeToType.Before) + transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) + |> ignore) - null \ No newline at end of file + // TODO: it would be nice if we opened the signature file that was just created. Maybe split? + null + + // First test name would be: ``ModuleStructure 01`` , ``NamespaceStructure 01`` + + // TODO: raise parser issue. \ No newline at end of file diff --git a/ReSharper.FSharp/src/FSharp.Psi/src/Tree/IModuleLikeDeclaration.cs b/ReSharper.FSharp/src/FSharp.Psi/src/Tree/IModuleLikeDeclaration.cs index aa50cf9132..ab8a0cf791 100644 --- a/ReSharper.FSharp/src/FSharp.Psi/src/Tree/IModuleLikeDeclaration.cs +++ b/ReSharper.FSharp/src/FSharp.Psi/src/Tree/IModuleLikeDeclaration.cs @@ -1,5 +1,8 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Tree { + // TODO: add triple slash comment. + // this is either a namespace,module or nested module, global namespace, anon module + // see inherits! (ctrl alt b) public partial interface IModuleLikeDeclaration : IFSharpDeclaration { } From 932adba5e76e2b74004d728a1d566dcbf9b8ff80 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 15 Feb 2023 13:56:42 +0100 Subject: [PATCH 03/75] Open signature file after generation. --- .../Intentions/GenerateSignatureFileAction.fs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs index 37a71d2aee..86ef31300f 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs @@ -1,6 +1,8 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions open System.IO +open JetBrains.Application.UI.PopupLayout +open JetBrains.ReSharper.Feature.Services.Navigation open JetBrains.ReSharper.Psi.Tree open JetBrains.DocumentManagers.Transactions.ProjectHostActions.Ordering open JetBrains.ProjectModel.ProjectsHost @@ -13,6 +15,7 @@ open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree open JetBrains.ReSharper.Psi open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree +open JetBrains.ReSharper.Resources.Shell // extract value -> ctrl alt v // undo that -> ctrl alt n @@ -92,10 +95,19 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) solution.InvokeUnderTransaction(fun transactionCookie -> let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() let relativeTo = RelativeTo(projectFile, RelativeToType.Before) - transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) - |> ignore) + let projectFile = transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) + + if (not Shell.Instance.IsTestShell) then + let navigationOptions = NavigationOptions.FromWindowContext(Shell.Instance.GetComponent().Source, "") + NavigationManager + .GetInstance(solution) + .Navigate( + ProjectFileNavigationPoint(projectFile), + navigationOptions + ) + |> ignore + ) - // TODO: it would be nice if we opened the signature file that was just created. Maybe split? null // First test name would be: ``ModuleStructure 01`` , ``NamespaceStructure 01`` From 9cbf0da12a68848fe742b86303895af36f10a5b3 Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 28 Feb 2023 11:03:47 +0100 Subject: [PATCH 04/75] Right after pair programming session. --- .../src/Parsing/FSharpParser.fs | 6 +- .../Intentions/GenerateSignatureFileAction.fs | 161 +++++++++++++++--- .../src/FSharpTreeNodeExtensions.cs | 4 +- .../ModuleStructure - 01.fs | 5 + .../ModuleStructure - 01.fs.gold | 5 + .../ModuleStructure - 01.fsi.gold | 3 + .../FSharp.Intentions.Tests.fsproj | 1 + .../Intentions/GenerateSignatureFileTest.fs | 17 ++ 8 files changed, 174 insertions(+), 28 deletions(-) create mode 100644 ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs create mode 100644 ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fsi.gold create mode 100644 ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs diff --git a/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpParser.fs b/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpParser.fs index f51260b1ee..b94f1ab1e8 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpParser.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpParser.fs @@ -56,6 +56,9 @@ type FSharpParser(lexer: ILexer, document: IDocument, path: VirtualFileSystemPat ResolvedSymbolsCache = symbolsCache, LanguageType = language) + static member val SandBoxPath = VirtualFileSystemPath.Parse("Sandbox.fs", InteractionContext.SolutionContext) + static member val SandBoxSignaturePath = VirtualFileSystemPath.Parse("Sandbox.fsi", InteractionContext.SolutionContext) + new (lexer, [] sourceFile: IPsiSourceFile, checkerService, symbolsCache) = // During rename of type + file the source file returns the new path, // but the parsing/project options still have the old one. It doesn't seem to affect anything. @@ -75,9 +78,6 @@ type FSharpParser(lexer: ILexer, document: IDocument, path: VirtualFileSystemPat FSharpParser(lexer, document, path, sourceFile, checkerService, symbolsCache) - static member val SandBoxPath = VirtualFileSystemPath.Parse("Sandbox.fs", InteractionContext.SolutionContext) - static member val SandBoxSignaturePath = VirtualFileSystemPath.Parse("Sandbox.fsi", InteractionContext.SolutionContext) - interface IFSharpParser with member this.ParseFSharpFile(noCache) = parseFile noCache member this.ParseFile() = parseFile false :> _ diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs index 86ef31300f..2e947306bc 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs @@ -1,8 +1,13 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions open System.IO +open System.Linq +open System.Text +open FSharp.Compiler.Symbols open JetBrains.Application.UI.PopupLayout open JetBrains.ReSharper.Feature.Services.Navigation +open JetBrains.ReSharper.Plugins.FSharp.Psi.Parsing +open JetBrains.ReSharper.Psi.Naming open JetBrains.ReSharper.Psi.Tree open JetBrains.DocumentManagers.Transactions.ProjectHostActions.Ordering open JetBrains.ProjectModel.ProjectsHost @@ -20,41 +25,150 @@ open JetBrains.ReSharper.Resources.Shell // extract value -> ctrl alt v // undo that -> ctrl alt n +// TODO: what about attributes, type parameters, delegates, exceptions + +// FSharpTokenType.AND.CreateLeafElement() + [] type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) = inherit FSharpContextActionBase(dataProvider) let mkSignatureFile (fsharpFile: IFSharpFile) : IFSharpFile = - let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory() + let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory(extension = FSharpSignatureProjectFileType.FsiExtension) let signatureFile : IFSharpFile = factory.CreateEmptyFile() let lineEnding = fsharpFile.GetLineEnding() + let getName (decl: IFSharpDeclaration) = NamingManager.GetNamingLanguageService(fsharpFile.Language).MangleNameIfNecessary(decl.SourceName) + + let rec createModuleMemberSig (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleMember: IModuleMember) : IFSharpTreeNode = + match moduleMember with + | :? ITypeDeclarationGroup as typeGroup -> + let sigTypeDeclGroups = + // TODO: Update type into and keyword for second IFSharpTypeDeclaration in a group. + + typeGroup.TypeDeclarations + |> Seq.choose (function + | :? IFSharpTypeDeclaration as typeDecl -> + // TODO: update and keyword + (* + ModificationUtil.ReplaceChild( + sigTypeGroup.TypeDeclarations.[1].TypeKeyword, + (FSharpTokenType.AND.CreateLeafElement())) + *) + + // Resharper implementation + //typeDecl.MemberDeclarations + + // Untyped tree like + // typeDecl.TypeMembers + let sigMembers = + typeDecl.TypeMembers + |> Seq.choose (createMemberDeclaration >> Option.ofObj) + + match typeDecl.TypeRepresentation with + // TODO: checkout delegates + | :? ITypeAbbreviationRepresentation as abbr -> + let sigTypeGroup = factory.CreateModuleMember($"type {getName typeDecl} = int") + match sigTypeGroup with + | :? ITypeDeclarationGroup as sigTypeGroup -> + let sigDecl = sigTypeGroup.TypeDeclarations.[0] :?> IFSharpTypeDeclaration + + + + ModificationUtil.DeleteChildRange(sigDecl.EqualsToken.NextSibling, sigDecl.LastChild) + addNodesAfter sigDecl.EqualsToken [ + Whitespace() + abbr.Copy() + ] + |> ignore + Some sigTypeGroup + | _ -> None + | :? ISimpleTypeRepresentation as repr -> + let sigTypeGroup = factory.CreateModuleMember($"type {getName typeDecl} = int") + match sigTypeGroup with + | :? ITypeDeclarationGroup as sigTypeGroup -> + let sigDecl = sigTypeGroup.TypeDeclarations.[0] :?> IFSharpTypeDeclaration + ModificationUtil.DeleteChildRange(sigDecl.EqualsToken.NextSibling, sigDecl.LastChild) + addNodesAfter sigDecl.EqualsToken [ + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + repr.Copy() + for sigMember in sigMembers do + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + sigMember + ] + |> ignore + Some sigTypeGroup + | _ -> None + | _ -> None + + + + | _ -> None) // TODO: address this + + sigTypeDeclGroups.FirstOrDefault() + // TODO : ITypeExtensionDeclaration + + | :? INestedModuleDeclaration as nestedNestedModule -> + let nestedSigModule = factory.CreateNestedModule(nestedNestedModule.NameIdentifier.Name) + let members = nestedNestedModule.Members + let shouldEmptyContent = + not members.IsEmpty + && members |> Seq.forall (function | :? IExpressionStatement -> false | _ -> true) + + if shouldEmptyContent then + ModificationUtil.DeleteChildRange (nestedSigModule.EqualsToken.NextSibling, nestedSigModule.LastChild) + processModuleLikeDeclaration (indentation + moduleDecl.GetIndentSize()) nestedNestedModule nestedSigModule + | :? IOpenStatement as openStatement -> + openStatement.Copy() + | _ -> null - let rec processModuleLikeDeclaration (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleSig: IModuleLikeDeclaration) : IFSharpTreeNode = + and processModuleLikeDeclaration (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleSig: IModuleLikeDeclaration) : IFSharpTreeNode = for moduleMember in moduleDecl.Members do - // newline + indentation whitespace - addNodesAfter moduleSig.LastChild [ - NewLine(lineEnding) - Whitespace(indentation) - match moduleMember with - | :? INestedModuleDeclaration as nestedNestedModule -> - let nestedSigModule = factory.CreateNestedModule(nestedNestedModule.NameIdentifier.Name) - let members = nestedNestedModule.Members - let shouldEmptyContent = - not members.IsEmpty - && members |> Seq.forall (function | :? IExpressionStatement -> false | _ -> true) - - if shouldEmptyContent then - ModificationUtil.DeleteChildRange (nestedSigModule.EqualsToken.NextSibling, nestedSigModule.LastChild) - processModuleLikeDeclaration (indentation + moduleDecl.GetIndentSize()) nestedNestedModule nestedSigModule - | :? IOpenStatement as openStatement -> - openStatement.Copy() - | _ -> () - ] - |> ignore + let signatureMember = createModuleMemberSig indentation moduleDecl moduleMember + + if isNotNull signatureMember then + // newline + indentation whitespace + addNodesAfter moduleSig.LastChild [ + NewLine(lineEnding) + Whitespace(indentation) + signatureMember + ] + |> ignore moduleSig - + + and createMemberDeclaration (memberDecl: IFSharpTypeMemberDeclaration) : IFSharpTypeMemberDeclaration = + match memberDecl with + | :? IMemberDeclaration as memberDecl -> + let sourceString = + let sb = StringBuilder() + + if memberDecl.IsStatic then + sb.Append("static ") |> ignore + + sb.Append(memberDecl.MemberKeyword.GetText()) |> ignore + sb.Append(" ") |> ignore + + if isNotNull memberDecl.AccessModifier then + sb.Append(memberDecl.AccessModifier.GetText()) |> ignore + + sb.Append(getName memberDecl) |> ignore + sb.Append(": ") |> ignore + + let symbolUse = memberDecl.GetFcsSymbolUse() + if isNotNull symbolUse then + let mfv = symbolUse.Symbol.As() + if isNotNull mfv then + sb.Append(mfv.FullType.Format(symbolUse.DisplayContext)) |> ignore + + sb.ToString() + + factory.CreateTypeMemberSignature(sourceString) + | _ -> null + + for decl in fsharpFile.ModuleDeclarations do let signatureModule : IModuleLikeDeclaration = match decl with @@ -81,6 +195,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) if not isSettingEnabled then false else let currentFSharpFile = dataProvider.PsiFile let fcsService = currentFSharpFile.FcsCheckerService + // TODO: don't check has pair in unit test let hasSignature = fcsService.FcsProjectProvider.HasPairFile dataProvider.SourceFile not hasSignature diff --git a/ReSharper.FSharp/src/FSharp.Psi/src/FSharpTreeNodeExtensions.cs b/ReSharper.FSharp/src/FSharp.Psi/src/FSharpTreeNodeExtensions.cs index 585b1e23d7..34611e21b6 100644 --- a/ReSharper.FSharp/src/FSharp.Psi/src/FSharpTreeNodeExtensions.cs +++ b/ReSharper.FSharp/src/FSharp.Psi/src/FSharpTreeNodeExtensions.cs @@ -12,8 +12,8 @@ public static IFSharpLanguageService GetFSharpLanguageService([NotNull] this ITr treeNode.GetPsiServices().GetComponent().GetService(treeNode.Language); [NotNull] - public static IFSharpElementFactory CreateElementFactory([NotNull] this ITreeNode treeNode) => - treeNode.GetFSharpLanguageService().CreateElementFactory(treeNode.GetSourceFile(), treeNode.GetPsiModule()); + public static IFSharpElementFactory CreateElementFactory([NotNull] this ITreeNode treeNode, string extension = null) => + treeNode.GetFSharpLanguageService().CreateElementFactory(treeNode.GetSourceFile(), treeNode.GetPsiModule(), extension); public static bool IsFSharpSigFile([NotNull] this ITreeNode treeNode) => treeNode.GetContainingFile() is IFSharpSigFile; diff --git a/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs b/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs new file mode 100644 index 0000000000..aaf1dee7fb --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs @@ -0,0 +1,5 @@ +module Foo + +open System +{caret} +let a = 0 diff --git a/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs.gold b/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs.gold new file mode 100644 index 0000000000..aaf1dee7fb --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs.gold @@ -0,0 +1,5 @@ +module Foo + +open System +{caret} +let a = 0 diff --git a/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fsi.gold b/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fsi.gold new file mode 100644 index 0000000000..af8e7ed833 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fsi.gold @@ -0,0 +1,3 @@ +module Test + +open System 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 64e68cb7f0..967df98f30 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 @@ -49,6 +49,7 @@ + diff --git a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs new file mode 100644 index 0000000000..26b60d59ba --- /dev/null +++ b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs @@ -0,0 +1,17 @@ +namespace JetBrains.ReSharper.Plugins.FSharp.Tests.Intentions.Intentions + +open System.Linq +open JetBrains.ProjectModel +open JetBrains.ReSharper.FeaturesTestFramework.Refactorings +open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions +open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Intentions +open JetBrains.ReSharper.Plugins.FSharp.Services.Formatter +open JetBrains.ReSharper.TestFramework +open NUnit.Framework + +type GenerateSignatureFileTest() = + inherit FSharpContextActionExecuteTestBase() + + override this.ExtraPath = "generateSignatureFile" + + // [] member x.``ModuleStructure - 01`` () = x.DoNamedTestWithSignature() \ No newline at end of file From 90ccfad68d0afb2d8f7d8750378d08cd36410e72 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 1 Mar 2023 10:45:41 +0100 Subject: [PATCH 05/75] Refactor TypeDeclarationGroup grouping. Take care of the and keyword. --- .../Intentions/GenerateSignatureFileAction.fs | 139 ++++++++---------- 1 file changed, 63 insertions(+), 76 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs index 2e947306bc..baf3f48160 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs @@ -1,12 +1,10 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions open System.IO -open System.Linq open System.Text open FSharp.Compiler.Symbols open JetBrains.Application.UI.PopupLayout open JetBrains.ReSharper.Feature.Services.Navigation -open JetBrains.ReSharper.Plugins.FSharp.Psi.Parsing open JetBrains.ReSharper.Psi.Naming open JetBrains.ReSharper.Psi.Tree open JetBrains.DocumentManagers.Transactions.ProjectHostActions.Ordering @@ -34,7 +32,7 @@ open JetBrains.ReSharper.Resources.Shell type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) = inherit FSharpContextActionBase(dataProvider) - let mkSignatureFile (fsharpFile: IFSharpFile) : IFSharpFile = + let mkSignatureFile (fsharpFile: IFSharpFile): IFSharpFile = let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory(extension = FSharpSignatureProjectFileType.FsiExtension) let signatureFile : IFSharpFile = factory.CreateEmptyFile() let lineEnding = fsharpFile.GetLineEnding() @@ -43,72 +41,62 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) let rec createModuleMemberSig (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleMember: IModuleMember) : IFSharpTreeNode = match moduleMember with | :? ITypeDeclarationGroup as typeGroup -> - let sigTypeDeclGroups = - // TODO: Update type into and keyword for second IFSharpTypeDeclaration in a group. - + // Filter out the IFSharpTypeDeclaration where we support the TypeRepresentation for now. + let supportedTypeDeclarations = typeGroup.TypeDeclarations |> Seq.choose (function | :? IFSharpTypeDeclaration as typeDecl -> - // TODO: update and keyword - (* - ModificationUtil.ReplaceChild( - sigTypeGroup.TypeDeclarations.[1].TypeKeyword, - (FSharpTokenType.AND.CreateLeafElement())) - *) - - // Resharper implementation - //typeDecl.MemberDeclarations - - // Untyped tree like - // typeDecl.TypeMembers - let sigMembers = - typeDecl.TypeMembers - |> Seq.choose (createMemberDeclaration >> Option.ofObj) - match typeDecl.TypeRepresentation with - // TODO: checkout delegates - | :? ITypeAbbreviationRepresentation as abbr -> - let sigTypeGroup = factory.CreateModuleMember($"type {getName typeDecl} = int") - match sigTypeGroup with - | :? ITypeDeclarationGroup as sigTypeGroup -> - let sigDecl = sigTypeGroup.TypeDeclarations.[0] :?> IFSharpTypeDeclaration - - - - ModificationUtil.DeleteChildRange(sigDecl.EqualsToken.NextSibling, sigDecl.LastChild) - addNodesAfter sigDecl.EqualsToken [ - Whitespace() - abbr.Copy() - ] - |> ignore - Some sigTypeGroup - | _ -> None - | :? ISimpleTypeRepresentation as repr -> - let sigTypeGroup = factory.CreateModuleMember($"type {getName typeDecl} = int") - match sigTypeGroup with - | :? ITypeDeclarationGroup as sigTypeGroup -> - let sigDecl = sigTypeGroup.TypeDeclarations.[0] :?> IFSharpTypeDeclaration - ModificationUtil.DeleteChildRange(sigDecl.EqualsToken.NextSibling, sigDecl.LastChild) - addNodesAfter sigDecl.EqualsToken [ - NewLine(lineEnding) - Whitespace(indentation + moduleDecl.GetIndentSize()) - repr.Copy() - for sigMember in sigMembers do - NewLine(lineEnding) - Whitespace(indentation + moduleDecl.GetIndentSize()) - sigMember - ] - |> ignore - Some sigTypeGroup - | _ -> None + | :? ITypeAbbreviationRepresentation + | :? ISimpleTypeRepresentation -> Some typeDecl | _ -> None - - - - | _ -> None) // TODO: address this - - sigTypeDeclGroups.FirstOrDefault() - // TODO : ITypeExtensionDeclaration + | _ -> None) + |> Seq.mapi (fun idx typeDecl -> + let kw = if idx = 0 then "type" else "and" + {| SignatureIdx = idx ; TypeDeclaration = typeDecl; SourceText = $"{kw} {getName typeDecl} = int" |}) + |> Seq.toArray + + if Array.isEmpty supportedTypeDeclarations then null else + + let sourceText = supportedTypeDeclarations |> Array.map (fun info -> info.SourceText) |> String.concat "\n" + let sigTypeDeclarationGroup = factory.CreateModuleMember(sourceText) :?> ITypeDeclarationGroup + + if isNull sigTypeDeclarationGroup then null else + + for info in supportedTypeDeclarations do + let typeDecl: IFSharpTypeDeclaration = info.TypeDeclaration + let sigTypeDecl = sigTypeDeclarationGroup.TypeDeclarations.[info.SignatureIdx] :?> IFSharpTypeDeclaration + if isNull sigTypeDecl then () else + + let sigMembers = + typeDecl.TypeMembers + |> Seq.choose (createMemberDeclaration >> Option.ofObj) + + match typeDecl.TypeRepresentation with + | :? ITypeAbbreviationRepresentation as abbr -> + ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) + addNodesAfter sigTypeDecl.EqualsToken [ + Whitespace() + abbr.Copy() + // TODO: there technically could be members here. + // Although I think this would need the `with` keyword. + ] |> ignore + | :? ISimpleTypeRepresentation as repr -> + ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) + addNodesAfter sigTypeDecl.EqualsToken [ + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + repr.Copy() + for sigMember in sigMembers do + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + sigMember + ] |> ignore + | repr -> + // This pattern match should match the types we filtered out earlier for supportedTypeDeclarations + failwith $"Unexpected representation {repr.GetType()}" + + sigTypeDeclarationGroup | :? INestedModuleDeclaration as nestedNestedModule -> let nestedSigModule = factory.CreateNestedModule(nestedNestedModule.NameIdentifier.Name) @@ -127,7 +115,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) and processModuleLikeDeclaration (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleSig: IModuleLikeDeclaration) : IFSharpTreeNode = for moduleMember in moduleDecl.Members do let signatureMember = createModuleMemberSig indentation moduleDecl moduleMember - + if isNotNull signatureMember then // newline + indentation whitespace addNodesAfter moduleSig.LastChild [ @@ -155,19 +143,18 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) sb.Append(memberDecl.AccessModifier.GetText()) |> ignore sb.Append(getName memberDecl) |> ignore - sb.Append(": ") |> ignore - + sb.Append(": ") |> ignore + let symbolUse = memberDecl.GetFcsSymbolUse() if isNotNull symbolUse then let mfv = symbolUse.Symbol.As() if isNotNull mfv then sb.Append(mfv.FullType.Format(symbolUse.DisplayContext)) |> ignore - + sb.ToString() factory.CreateTypeMemberSignature(sourceString) | _ -> null - for decl in fsharpFile.ModuleDeclarations do let signatureModule : IModuleLikeDeclaration = @@ -182,13 +169,13 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) | decl -> failwithf $"Unexpected declaration, got: %A{decl}" ModificationUtil.AddChildAfter(signatureModule.LastChild, NewLine(lineEnding)) |> ignore - let signatureModule = processModuleLikeDeclaration 0 decl signatureModule + let signatureModule = processModuleLikeDeclaration 0 decl signatureModule ModificationUtil.AddChild(signatureFile, signatureModule) |> ignore signatureFile override this.Text = "Generate signature file for current file" - + override this.IsAvailable _ = let solution = dataProvider.Solution let isSettingEnabled = solution.IsFSharpExperimentalFeatureEnabled(ExperimentalFeature.GenerateSignatureFile) @@ -198,7 +185,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) // TODO: don't check has pair in unit test let hasSignature = fcsService.FcsProjectProvider.HasPairFile dataProvider.SourceFile not hasSignature - + override this.ExecutePsiTransaction(solution, _) = let projectFile = dataProvider.SourceFile.ToProjectFile() let fsharpFile = projectFile.GetPrimaryPsiFile().AsFSharpFile() @@ -211,7 +198,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() let relativeTo = RelativeTo(projectFile, RelativeToType.Before) let projectFile = transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) - + if (not Shell.Instance.IsTestShell) then let navigationOptions = NavigationOptions.FromWindowContext(Shell.Instance.GetComponent().Source, "") NavigationManager @@ -224,7 +211,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) ) null - + // First test name would be: ``ModuleStructure 01`` , ``NamespaceStructure 01`` - - // TODO: raise parser issue. \ No newline at end of file + + // TODO: raise parser issue. From 14726867dab7c60633abf2c403b030cf00a3b766 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 3 Apr 2023 09:06:28 +0200 Subject: [PATCH 06/75] Migrate code to FSharpGenerateSignatureProvider --- .../FSharp.Psi.Intentions.fsproj | 1 - .../FSharp.Psi.Services.fsproj | 1 + .../src/Generate/FSharpGeneratorContext.fs | 2 +- .../Generate/GenerateSignatureProvider.fs} | 124 ++++++++++++------ .../generate/signatureFiles/Sample Test.fs | 6 + .../Intentions/GenerateSignatureFileTest.fs | 8 +- .../test/src/FSharp.Tests/FSharp.Tests.fsproj | 1 + .../Generate/FsharpGenerateSignatureTest.fs | 13 ++ 8 files changed, 110 insertions(+), 46 deletions(-) rename ReSharper.FSharp/src/{FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs => FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs} (71%) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Sample Test.fs create mode 100644 ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.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 5ca0e5581e..46c94eff22 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj @@ -26,7 +26,6 @@ - diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/FSharp.Psi.Services.fsproj b/ReSharper.FSharp/src/FSharp.Psi.Services/FSharp.Psi.Services.fsproj index d695266268..271dc3d9cf 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/FSharp.Psi.Services.fsproj +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/FSharp.Psi.Services.fsproj @@ -64,6 +64,7 @@ + diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/FSharpGeneratorContext.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/FSharpGeneratorContext.fs index 136dcf41ff..270763f009 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/FSharpGeneratorContext.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/FSharpGeneratorContext.fs @@ -26,7 +26,7 @@ type FSharpGeneratorContext(kind, [] treeNode: ITreeNode, [] override x.Language = FSharpLanguage.Instance :> _ - override x.Root = typeDecl :> _ + override x.Root = treeNode override val Anchor = null with get, set override x.PsiModule = treeNode.GetPsiModule() diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs similarity index 71% rename from ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs rename to ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index baf3f48160..67e5e18feb 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -1,37 +1,61 @@ -namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions +namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features -open System.IO open System.Text open FSharp.Compiler.Symbols +open JetBrains.ReSharper.Feature.Services.Generate +open JetBrains.ReSharper.Feature.Services.Generate.Workflows +open JetBrains.ReSharper.Plugins.FSharp.Psi +open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Generate +open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree +open JetBrains.ReSharper.Psi.Transactions +open JetBrains.ReSharper.Psi.Tree +open JetBrains.ReSharper.Plugins.FSharp +open System.IO open JetBrains.Application.UI.PopupLayout open JetBrains.ReSharper.Feature.Services.Navigation -open JetBrains.ReSharper.Psi.Naming -open JetBrains.ReSharper.Psi.Tree open JetBrains.DocumentManagers.Transactions.ProjectHostActions.Ordering open JetBrains.ProjectModel.ProjectsHost open JetBrains.RdBackend.Common.Features.ProjectModel -open JetBrains.ReSharper.Feature.Services.ContextActions -open JetBrains.ReSharper.Plugins.FSharp.Psi -open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Intentions -open JetBrains.ReSharper.Plugins.FSharp -open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree -open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree open JetBrains.ReSharper.Psi -open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree open JetBrains.ReSharper.Resources.Shell +open JetBrains.ReSharper.Feature.Services.Generate.Actions +open JetBrains.ReSharper.Feature.Services.Resources +open JetBrains.ReSharper.Psi.Naming +open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree +open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree -// extract value -> ctrl alt v -// undo that -> ctrl alt n - -// TODO: what about attributes, type parameters, delegates, exceptions - -// FSharpTokenType.AND.CreateLeafElement() - -[] -type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) = - inherit FSharpContextActionBase(dataProvider) - +module FSharpGeneratorKinds = + let [] SignatureFile = "SignatureFile" + +type FSharpGeneratorSignatureElement(fsFile: IFSharpFile) = + inherit GeneratorElementBase() + + override this.GetPresentationObject() = fsFile + override this.Matches(_searchText, matcher) = matcher.Matches(this.TestDescriptor) + override this.TestDescriptor = "Generate signature file title" // fsFile.GetSourceFile().Name + + interface IGeneratorElementPresenter with + member this.InitGeneratorPresenter(presenter) = + presenter.Present(fun value item structureelement state -> + item.RichText <- + // Text seen in the popup of the selectable item. + JetBrains.UI.RichText.RichText(fsFile.GetSourceFile().Name) + item.Images.Add(PsiServicesThemedIcons.HasImplementations.Id)) + +[)>] +type FSharpGenerateSignatureProvider() = + inherit GeneratorProviderBase() + + override this.Populate(context: FSharpGeneratorContext): unit = + let node = context.Root :?> IFSharpTreeNode + context.ProvidedElements.Add(FSharpGeneratorSignatureElement(node.FSharpFile)) + +[)>] +type FSharpGenerateSignatureBuilder() = + inherit GeneratorBuilderBase() + + // TODO: what about attributes, type parameters, delegates, exceptions + let mkSignatureFile (fsharpFile: IFSharpFile): IFSharpFile = let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory(extension = FSharpSignatureProjectFileType.FsiExtension) let signatureFile : IFSharpFile = factory.CreateEmptyFile() @@ -174,26 +198,31 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) signatureFile - override this.Text = "Generate signature file for current file" - - override this.IsAvailable _ = - let solution = dataProvider.Solution + override this.IsAvailable(context: FSharpGeneratorContext): bool = + let node = context.Root :?> IFSharpTreeNode + let currentFSharpFile = node.FSharpFile + if currentFSharpFile.IsFSharpSigFile() then false else + let solution = node.GetSolution() let isSettingEnabled = solution.IsFSharpExperimentalFeatureEnabled(ExperimentalFeature.GenerateSignatureFile) if not isSettingEnabled then false else - let currentFSharpFile = dataProvider.PsiFile let fcsService = currentFSharpFile.FcsCheckerService // TODO: don't check has pair in unit test - let hasSignature = fcsService.FcsProjectProvider.HasPairFile dataProvider.SourceFile + let hasSignature = fcsService.FcsProjectProvider.HasPairFile (node.GetSourceFile()) not hasSignature - override this.ExecutePsiTransaction(solution, _) = - let projectFile = dataProvider.SourceFile.ToProjectFile() - let fsharpFile = projectFile.GetPrimaryPsiFile().AsFSharpFile() - let physicalPath = dataProvider.SourceFile.ToProjectFile().Location.FileAccessPath + override this.Process(context) = + let node = context.Root :?> IFSharpTreeNode + use writeCookie = WriteLockCookie.Create(node.IsPhysical()) + use transactionCookie = + PsiTransactionCookie.CreateAutoCommitCookieWithCachesUpdate(node.GetPsiServices(), FSharpGeneratorKinds.SignatureFile) + + let currentFSharpFile = node.FSharpFile + let projectFile = node.GetSourceFile().ToProjectFile() + let physicalPath = projectFile.Location.FileAccessPath let fsiFile = Path.ChangeExtension(physicalPath, ".fsi") - let signatureFile = mkSignatureFile fsharpFile + let signatureFile = mkSignatureFile currentFSharpFile File.WriteAllText(fsiFile, signatureFile.GetText()) - + let solution = node.GetSolution() solution.InvokeUnderTransaction(fun transactionCookie -> let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() let relativeTo = RelativeTo(projectFile, RelativeToType.Before) @@ -210,8 +239,23 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) |> ignore ) - null - - // First test name would be: ``ModuleStructure 01`` , ``NamespaceStructure 01`` - - // TODO: raise parser issue. +type FSharpGenerateSignatureWorkflow() = + inherit GenerateCodeWorkflowBase( + FSharpGeneratorKinds.SignatureFile, + PsiServicesThemedIcons.Implements.Id, + // Seen in the dropdown menu when alt + insert is pressed. + "Generate signature file", + GenerateActionGroup.CLR_LANGUAGE, + // Title of the window that opens up when the workflow is started. + "Generate signature file", + // Description of the window that opens up when the workflow is started. + $"Generate a signature file for the current file.", + FSharpGeneratorKinds.SignatureFile) + + override this.Order = 10. // See GeneratorStandardOrder.cs + +[] +type FSharpGenerateSignatureWorkflowProvider() = + interface IGenerateImplementationsWorkflowProvider with + member this.CreateWorkflow _ = + [| FSharpGenerateSignatureWorkflow() |] diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Sample Test.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Sample Test.fs new file mode 100644 index 0000000000..7ccec98cb9 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Sample Test.fs @@ -0,0 +1,6 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +open System +{caret} diff --git a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs index 26b60d59ba..6098c5953d 100644 --- a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs @@ -9,9 +9,9 @@ open JetBrains.ReSharper.Plugins.FSharp.Services.Formatter open JetBrains.ReSharper.TestFramework open NUnit.Framework -type GenerateSignatureFileTest() = - inherit FSharpContextActionExecuteTestBase() - - override this.ExtraPath = "generateSignatureFile" +// type GenerateSignatureFileTest() = +// inherit FSharpContextActionExecuteTestBase() +// +// override this.ExtraPath = "generateSignatureFile" // [] member x.``ModuleStructure - 01`` () = x.DoNamedTestWithSignature() \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/FSharp.Tests.fsproj b/ReSharper.FSharp/test/src/FSharp.Tests/FSharp.Tests.fsproj index 9d36e9dfbf..23654b2c41 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/FSharp.Tests.fsproj +++ b/ReSharper.FSharp/test/src/FSharp.Tests/FSharp.Tests.fsproj @@ -32,6 +32,7 @@ + diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs new file mode 100644 index 0000000000..906c3b6bf4 --- /dev/null +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -0,0 +1,13 @@ +namespace JetBrains.ReSharper.Plugins.FSharp.Tests.Features.Generate + +open JetBrains.ReSharper.FeaturesTestFramework.Generate +open JetBrains.ReSharper.Plugins.FSharp +open JetBrains.ReSharper.Plugins.FSharp.Tests +open NUnit.Framework + +[] +type FsharpGenerateSignatureTest() = + inherit GenerateTestBase() + override x.RelativeTestDataPath = "features/generate/signatureFiles" + // override this.DumpTextControl(textControl, dumpCaret, dumpSelection) = + [] member x.``Sample Test`` () = x.DoNamedTest() From e30febe6b6d53ead3b9493c34470f249dc37a5f2 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Wed, 19 Apr 2023 14:17:14 +0200 Subject: [PATCH 07/75] Queue the project model transaction after the psi transaction --- .../src/Generate/GenerateSignatureProvider.fs | 51 ++++++++++--------- .../Generate/FsharpGenerateSignatureTest.fs | 19 ++++++- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 67e5e18feb..fc2ffa09e6 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -1,28 +1,28 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features +open System.IO open System.Text open FSharp.Compiler.Symbols -open JetBrains.ReSharper.Feature.Services.Generate -open JetBrains.ReSharper.Feature.Services.Generate.Workflows -open JetBrains.ReSharper.Plugins.FSharp.Psi -open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Generate -open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree -open JetBrains.ReSharper.Psi.Transactions -open JetBrains.ReSharper.Psi.Tree -open JetBrains.ReSharper.Plugins.FSharp -open System.IO +open JetBrains.Application.Threading open JetBrains.Application.UI.PopupLayout -open JetBrains.ReSharper.Feature.Services.Navigation open JetBrains.DocumentManagers.Transactions.ProjectHostActions.Ordering open JetBrains.ProjectModel.ProjectsHost open JetBrains.RdBackend.Common.Features.ProjectModel -open JetBrains.ReSharper.Psi -open JetBrains.ReSharper.Resources.Shell +open JetBrains.ReSharper.Feature.Services.Generate open JetBrains.ReSharper.Feature.Services.Generate.Actions +open JetBrains.ReSharper.Feature.Services.Generate.Workflows +open JetBrains.ReSharper.Feature.Services.Navigation open JetBrains.ReSharper.Feature.Services.Resources -open JetBrains.ReSharper.Psi.Naming +open JetBrains.ReSharper.Plugins.FSharp +open JetBrains.ReSharper.Plugins.FSharp.Psi +open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Generate open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree +open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree +open JetBrains.ReSharper.Psi open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree +open JetBrains.ReSharper.Psi.Naming +open JetBrains.ReSharper.Psi.Tree +open JetBrains.ReSharper.Resources.Shell module FSharpGeneratorKinds = let [] SignatureFile = "SignatureFile" @@ -202,9 +202,11 @@ type FSharpGenerateSignatureBuilder() = let node = context.Root :?> IFSharpTreeNode let currentFSharpFile = node.FSharpFile if currentFSharpFile.IsFSharpSigFile() then false else + let solution = node.GetSolution() let isSettingEnabled = solution.IsFSharpExperimentalFeatureEnabled(ExperimentalFeature.GenerateSignatureFile) if not isSettingEnabled then false else + let fcsService = currentFSharpFile.FcsCheckerService // TODO: don't check has pair in unit test let hasSignature = fcsService.FcsProjectProvider.HasPairFile (node.GetSourceFile()) @@ -213,22 +215,22 @@ type FSharpGenerateSignatureBuilder() = override this.Process(context) = let node = context.Root :?> IFSharpTreeNode use writeCookie = WriteLockCookie.Create(node.IsPhysical()) - use transactionCookie = - PsiTransactionCookie.CreateAutoCommitCookieWithCachesUpdate(node.GetPsiServices(), FSharpGeneratorKinds.SignatureFile) - let currentFSharpFile = node.FSharpFile let projectFile = node.GetSourceFile().ToProjectFile() let physicalPath = projectFile.Location.FileAccessPath let fsiFile = Path.ChangeExtension(physicalPath, ".fsi") - let signatureFile = mkSignatureFile currentFSharpFile + let signatureFile = mkSignatureFile node.FSharpFile File.WriteAllText(fsiFile, signatureFile.GetText()) - let solution = node.GetSolution() - solution.InvokeUnderTransaction(fun transactionCookie -> - let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() - let relativeTo = RelativeTo(projectFile, RelativeToType.Before) - let projectFile = transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) - if (not Shell.Instance.IsTestShell) then + let solution = context.Solution + solution.Locks.ExecuteOrQueue(FSharpGeneratorKinds.SignatureFile, fun _ -> + solution.InvokeUnderTransaction(fun transactionCookie -> + let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() + let relativeTo = RelativeTo(projectFile, RelativeToType.Before) + let projectFile = transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) + + if Shell.Instance.IsTestShell then () else + let navigationOptions = NavigationOptions.FromWindowContext(Shell.Instance.GetComponent().Source, "") NavigationManager .GetInstance(solution) @@ -237,7 +239,8 @@ type FSharpGenerateSignatureBuilder() = navigationOptions ) |> ignore - ) + ) + ) |> ignore type FSharpGenerateSignatureWorkflow() = inherit GenerateCodeWorkflowBase( diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 906c3b6bf4..aa928ba3f6 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -1,13 +1,30 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Tests.Features.Generate +open JetBrains.Diagnostics +open JetBrains.IDE +open JetBrains.ProjectModel open JetBrains.ReSharper.FeaturesTestFramework.Generate open JetBrains.ReSharper.Plugins.FSharp open JetBrains.ReSharper.Plugins.FSharp.Tests +open JetBrains.Util open NUnit.Framework [] type FsharpGenerateSignatureTest() = inherit GenerateTestBase() + override x.RelativeTestDataPath = "features/generate/signatureFiles" - // override this.DumpTextControl(textControl, dumpCaret, dumpSelection) = + + override this.DoTest(lifetime, testProject) = + this.SetAsyncBehaviorAllowed(lifetime) + base.DoTest(lifetime, testProject) + + override this.DumpTextControl(_, dumpCaret, dumpSelection) = + let editorManager = this.Solution.GetComponent() + let fsiPath = this.GetCaretPosition().FileName.ChangeExtension("fsi") + let textControl = editorManager.OpenFileAsync(fsiPath, OpenFileOptions.DefaultActivate).Result.NotNull() + this.TestLifetime.OnTermination(fun _ -> editorManager.CloseTextControl(textControl)) |> ignore + + base.DumpTextControl(textControl, dumpCaret, dumpSelection) + [] member x.``Sample Test`` () = x.DoNamedTest() From 8e167d012f1ac96e009a80af13b3099efed3833d Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Wed, 19 Apr 2023 14:26:43 +0200 Subject: [PATCH 08/75] Use existing text control lifetime --- .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index aa928ba3f6..f2fcded2b1 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -19,12 +19,13 @@ type FsharpGenerateSignatureTest() = this.SetAsyncBehaviorAllowed(lifetime) base.DoTest(lifetime, testProject) - override this.DumpTextControl(_, dumpCaret, dumpSelection) = + override this.DumpTextControl(textControl, dumpCaret, dumpSelection) = let editorManager = this.Solution.GetComponent() let fsiPath = this.GetCaretPosition().FileName.ChangeExtension("fsi") - let textControl = editorManager.OpenFileAsync(fsiPath, OpenFileOptions.DefaultActivate).Result.NotNull() - this.TestLifetime.OnTermination(fun _ -> editorManager.CloseTextControl(textControl)) |> ignore + let fsiTextControl = editorManager.OpenFileAsync(fsiPath, OpenFileOptions.DefaultActivate).Result.NotNull() + textControl.Lifetime.OnTermination(fun _ -> editorManager.CloseTextControl(fsiTextControl)) |> ignore - base.DumpTextControl(textControl, dumpCaret, dumpSelection) + base.DumpTextControl(fsiTextControl, dumpCaret, dumpSelection) [] member x.``Sample Test`` () = x.DoNamedTest() + [] member x.``Sample Test 02`` () = x.DoNamedTest() From 4539663a488922bfa5baf2daa5baece0d6d32c5e Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 19 Apr 2023 15:22:50 +0200 Subject: [PATCH 09/75] Add namespace test. --- .../{Sample Test.fs => Module structure 01.fs} | 0 .../generate/signatureFiles/Module structure 01.fs.gold | 6 ++++++ .../generate/signatureFiles/Namespace structure 01.fs | 6 ++++++ .../generate/signatureFiles/Namespace structure 01.fs.gold | 6 ++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 4 ++-- 5 files changed, 20 insertions(+), 2 deletions(-) rename ReSharper.FSharp/test/data/features/generate/signatureFiles/{Sample Test.fs => Module structure 01.fs} (100%) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 01.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs.gold diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Sample Test.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 01.fs similarity index 100% rename from ReSharper.FSharp/test/data/features/generate/signatureFiles/Sample Test.fs rename to ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 01.fs diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 01.fs.gold new file mode 100644 index 0000000000..fdc928fe72 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 01.fs.gold @@ -0,0 +1,6 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +open System \ No newline at end of file diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs new file mode 100644 index 0000000000..dea44726b7 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs @@ -0,0 +1,6 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +namespace Foo + +open System +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs.gold new file mode 100644 index 0000000000..8924a36be0 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs.gold @@ -0,0 +1,6 @@ +Provided elements: + 0: Generate signature file title + +{caret}namespace Foo + +open System \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index f2fcded2b1..3b78c7c7c2 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -27,5 +27,5 @@ type FsharpGenerateSignatureTest() = base.DumpTextControl(fsiTextControl, dumpCaret, dumpSelection) - [] member x.``Sample Test`` () = x.DoNamedTest() - [] member x.``Sample Test 02`` () = x.DoNamedTest() + [] member x.``Module structure 01`` () = x.DoNamedTest() + [] member x.``Namespace structure 01`` () = x.DoNamedTest() From 39733c311c422495696d365868c52f2d4fb4cb60 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 19 Apr 2023 15:25:40 +0200 Subject: [PATCH 10/75] Remove old tests file. --- .../FSharp.Intentions.Tests.fsproj | 1 - .../src/Intentions/GenerateSignatureFileTest.fs | 17 ----------------- 2 files changed, 18 deletions(-) delete mode 100644 ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs 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 967df98f30..64e68cb7f0 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 @@ -49,7 +49,6 @@ - diff --git a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs deleted file mode 100644 index 6098c5953d..0000000000 --- a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs +++ /dev/null @@ -1,17 +0,0 @@ -namespace JetBrains.ReSharper.Plugins.FSharp.Tests.Intentions.Intentions - -open System.Linq -open JetBrains.ProjectModel -open JetBrains.ReSharper.FeaturesTestFramework.Refactorings -open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions -open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Intentions -open JetBrains.ReSharper.Plugins.FSharp.Services.Formatter -open JetBrains.ReSharper.TestFramework -open NUnit.Framework - -// type GenerateSignatureFileTest() = -// inherit FSharpContextActionExecuteTestBase() -// -// override this.ExtraPath = "generateSignatureFile" - - // [] member x.``ModuleStructure - 01`` () = x.DoNamedTestWithSignature() \ No newline at end of file From b6e573a8092955de3a98064c5615e7c5b4f52c6b Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 20 Apr 2023 08:00:10 +0200 Subject: [PATCH 11/75] Add _.fsi test. --- .../test/src/FSharp.Tests/Parsing/FSharpParserTest.fs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs index 0635c15c0a..3620b8aa27 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs @@ -683,6 +683,9 @@ type FSharpSignatureParserTest() = inherit ParserTestBase() override x.RelativeTestDataPath = "parsing/signatures" + + /// Use this test case to dump the psi tree for a given file, see `_.fsi`. + [] member x.``_``() = x.DoNamedTest() /// Use this test case to dump the psi tree for a given file, see `_.fsi`. [] member x.``_``() = x.DoNamedTest() @@ -767,7 +770,7 @@ type FSharpErrorsParserTest() = inherit ParserTestBase() override x.RelativeTestDataPath = "parsing/errors" - + [] member x.``Expr - Unfinished let 01``() = x.DoNamedTest() [] member x.``Expr - Unfinished let 02 - In``() = x.DoNamedTest() [] member x.``Expr - Unfinished let 03 - Inline in``() = x.DoNamedTest() From 02585297bd9639a7c8d49ebbf7406e626539a4c7 Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 20 Apr 2023 08:01:58 +0200 Subject: [PATCH 12/75] Add initial unit tests. --- .../features/generate/signatureFiles/Nested module 01.fs | 7 +++++++ .../generate/signatureFiles/Nested module 01.fs.gold | 7 +++++++ .../data/features/generate/signatureFiles/Record 01.fs | 6 ++++++ .../features/generate/signatureFiles/Record 01.fs.gold | 7 +++++++ .../generate/signatureFiles/TypeAbbreviation 01.fs | 6 ++++++ .../generate/signatureFiles/TypeAbbreviation 01.fs.gold | 6 ++++++ .../test/data/features/generate/signatureFiles/Union 01.fs | 6 ++++++ .../data/features/generate/signatureFiles/Union 01.fs.gold | 7 +++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 4 ++++ 9 files changed, 56 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs.gold diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs new file mode 100644 index 0000000000..2f3eda1e9a --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs @@ -0,0 +1,7 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + + module Bar = + open System +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs.gold new file mode 100644 index 0000000000..7a9a656e05 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs.gold @@ -0,0 +1,7 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +module Bar = + open System \ No newline at end of file diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs new file mode 100644 index 0000000000..8ed064d076 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs @@ -0,0 +1,6 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type Bar = { A:int; B: int } +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs.gold new file mode 100644 index 0000000000..ebd75ac780 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs.gold @@ -0,0 +1,7 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type Bar = + { A:int; B: int } \ No newline at end of file diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs new file mode 100644 index 0000000000..7bc22a9114 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs @@ -0,0 +1,6 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type Bar = int +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs.gold new file mode 100644 index 0000000000..95d5a49a48 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs.gold @@ -0,0 +1,6 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type Bar = int \ No newline at end of file diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs new file mode 100644 index 0000000000..674e364cf7 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs @@ -0,0 +1,6 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type Bar = | Bar of a:int * b:int +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs.gold new file mode 100644 index 0000000000..faf084b85b --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs.gold @@ -0,0 +1,7 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type Bar = + | Bar of a:int * b:int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 3b78c7c7c2..945a859ca9 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -29,3 +29,7 @@ type FsharpGenerateSignatureTest() = [] member x.``Module structure 01`` () = x.DoNamedTest() [] member x.``Namespace structure 01`` () = x.DoNamedTest() + [] member x.``TypeAbbreviation 01`` () = x.DoNamedTest() + [] member x.``Record 01`` () = x.DoNamedTest() + [] member x.``Union 01`` () = x.DoNamedTest() + [] member x.``Nested module 01`` () = x.DoNamedTest() From ae3d79440246ecebdeceb0030ad81aef4bfd2fb9 Mon Sep 17 00:00:00 2001 From: dawe Date: Thu, 20 Apr 2023 10:26:39 +0200 Subject: [PATCH 13/75] add test 01 for recursive types --- .../features/generate/signatureFiles/Recursive types 01.fs | 7 +++++++ .../generate/signatureFiles/Recursive types 01.fs.gold | 7 +++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 1 + 3 files changed, 15 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs.gold diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs new file mode 100644 index 0000000000..fa41fcf13f --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs @@ -0,0 +1,7 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type N = int +and R = float +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs.gold new file mode 100644 index 0000000000..bb425d78be --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs.gold @@ -0,0 +1,7 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type N = int +and R = float \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 945a859ca9..97afdee1d0 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -33,3 +33,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Record 01`` () = x.DoNamedTest() [] member x.``Union 01`` () = x.DoNamedTest() [] member x.``Nested module 01`` () = x.DoNamedTest() + [] member x.``Recursive types 01`` () = x.DoNamedTest() From e5f5898bd00abe6b3f0047fa0db8d3c9c9762d4f Mon Sep 17 00:00:00 2001 From: dawe Date: Mon, 24 Apr 2023 11:28:31 +0200 Subject: [PATCH 14/75] add test for record with static member --- .../data/features/generate/signatureFiles/Record 02.fs | 7 +++++++ .../features/generate/signatureFiles/Record 02.fs.gold | 8 ++++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 1 + 3 files changed, 16 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs.gold diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs new file mode 100644 index 0000000000..c15733b769 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs @@ -0,0 +1,7 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type Bar = { A:int; B: int } + static member Add x y = x + y +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs.gold new file mode 100644 index 0000000000..a9e3f90fc5 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs.gold @@ -0,0 +1,8 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type Bar = + { A:int; B: int } + static member Add: int -> int -> int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 97afdee1d0..0c5817ebf3 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -31,6 +31,7 @@ type FsharpGenerateSignatureTest() = [] member x.``Namespace structure 01`` () = x.DoNamedTest() [] member x.``TypeAbbreviation 01`` () = x.DoNamedTest() [] member x.``Record 01`` () = x.DoNamedTest() + [] member x.``Record 02`` () = x.DoNamedTest() [] member x.``Union 01`` () = x.DoNamedTest() [] member x.``Nested module 01`` () = x.DoNamedTest() [] member x.``Recursive types 01`` () = x.DoNamedTest() From 90e700ea752e5f5f289ffa9fcec983b315ade329 Mon Sep 17 00:00:00 2001 From: dawe Date: Mon, 24 Apr 2023 11:38:23 +0200 Subject: [PATCH 15/75] add test for union with static member note, we should improve the signature with naming --- .../data/features/generate/signatureFiles/Union 02.fs | 7 +++++++ .../features/generate/signatureFiles/Union 02.fs.gold | 8 ++++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 1 + 3 files changed, 16 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs.gold diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs new file mode 100644 index 0000000000..879b596eb0 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs @@ -0,0 +1,7 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type Bar = | Bar of a:int * b:int + static member Add x y = x + y +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs.gold new file mode 100644 index 0000000000..a4d782af7b --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs.gold @@ -0,0 +1,8 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type Bar = + | Bar of a:int * b:int + static member Add: int -> int -> int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 0c5817ebf3..87b8f71529 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -33,5 +33,6 @@ type FsharpGenerateSignatureTest() = [] member x.``Record 01`` () = x.DoNamedTest() [] member x.``Record 02`` () = x.DoNamedTest() [] member x.``Union 01`` () = x.DoNamedTest() + [] member x.``Union 02`` () = x.DoNamedTest() [] member x.``Nested module 01`` () = x.DoNamedTest() [] member x.``Recursive types 01`` () = x.DoNamedTest() From 4de6d350dc841f486420b5388564c425ab341e83 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 26 Apr 2023 09:35:48 +0200 Subject: [PATCH 16/75] Add test for instance member. --- .../src/Generate/GenerateSignatureProvider.fs | 15 ++++++++++++++- .../generate/signatureFiles/Instance Member 01.fs | 10 ++++++++++ .../signatureFiles/Instance Member 01.fs.gold | 10 ++++++++++ .../Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index fc2ffa09e6..148ea21e96 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -173,7 +173,20 @@ type FSharpGenerateSignatureBuilder() = if isNotNull symbolUse then let mfv = symbolUse.Symbol.As() if isNotNull mfv then - sb.Append(mfv.FullType.Format(symbolUse.DisplayContext)) |> ignore + if memberDecl.IsStatic then + sb.Append(mfv.FullType.Format(symbolUse.DisplayContext)) |> ignore + else + // mfv.FullType will contain the type of the instance, so we cannot use that. + let parameters = + mfv.CurriedParameterGroups + |> Seq.map (fun parameterGroup -> + parameterGroup + |> Seq.map (fun parameter -> parameter.Type.Format(symbolUse.DisplayContext)) + |> String.concat " * " + ) + |> String.concat " -> " + let returnType = mfv.ReturnParameter.Type.Format(symbolUse.DisplayContext) + sb.Append($"{parameters} -> {returnType}") |> ignore sb.ToString() diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs new file mode 100644 index 0000000000..fff62f4096 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs @@ -0,0 +1,10 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type X = + { + Y: int + } + member x.A b c = x.Y - b + c +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs.gold new file mode 100644 index 0000000000..08893bf23f --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs.gold @@ -0,0 +1,10 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type X = + { + Y: int + } + member A: int -> int -> int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 87b8f71529..85992d8bc0 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -36,3 +36,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Union 02`` () = x.DoNamedTest() [] member x.``Nested module 01`` () = x.DoNamedTest() [] member x.``Recursive types 01`` () = x.DoNamedTest() + [] member x.``Instance Member 01`` () = x.DoNamedTest() From e4946ff1355fd41d59f812764aad2a9bbdd4180e Mon Sep 17 00:00:00 2001 From: dawe Date: Thu, 27 Apr 2023 11:58:52 +0200 Subject: [PATCH 17/75] add test for instance member with optional parameter --- .../generate/signatureFiles/Instance Member 02.fs | 8 ++++++++ .../generate/signatureFiles/Instance Member 02.fs.gold | 8 ++++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 1 + 3 files changed, 17 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs.gold diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs new file mode 100644 index 0000000000..11a70ea12f --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs @@ -0,0 +1,8 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type R = + { F: int } + member _.Func (?x:int -> int) = 23 +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs.gold new file mode 100644 index 0000000000..1bb91c9eca --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs.gold @@ -0,0 +1,8 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type R = + { F: int } + member Func: (int -> int) option -> int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 85992d8bc0..9fbd8ee3fb 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -37,3 +37,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Nested module 01`` () = x.DoNamedTest() [] member x.``Recursive types 01`` () = x.DoNamedTest() [] member x.``Instance Member 01`` () = x.DoNamedTest() + [] member x.``Instance Member 02`` () = x.DoNamedTest() From f5f677bdc56b5d750a4665fabb1042df16712f18 Mon Sep 17 00:00:00 2001 From: dawe Date: Thu, 27 Apr 2023 16:29:46 +0200 Subject: [PATCH 18/75] start supporting structs, we might handle it as IObjectModelTypeRepresentation in the future, let's see. --- .../src/Generate/GenerateSignatureProvider.fs | 12 ++++++++++++ .../features/generate/signatureFiles/Struct 01.fs | 9 +++++++++ .../generate/signatureFiles/Struct 01.fs.gold | 9 +++++++++ .../Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 31 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 148ea21e96..b83cb83ac9 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -72,6 +72,7 @@ type FSharpGenerateSignatureBuilder() = | :? IFSharpTypeDeclaration as typeDecl -> match typeDecl.TypeRepresentation with | :? ITypeAbbreviationRepresentation + | :? IStructRepresentation | :? ISimpleTypeRepresentation -> Some typeDecl | _ -> None | _ -> None) @@ -116,6 +117,17 @@ type FSharpGenerateSignatureBuilder() = Whitespace(indentation + moduleDecl.GetIndentSize()) sigMember ] |> ignore + | :? IStructRepresentation as repr -> + ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) + addNodesAfter sigTypeDecl.EqualsToken [ + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + repr.Copy() + for sigMember in sigMembers do + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + sigMember + ] |> ignore | repr -> // This pattern match should match the types we filtered out earlier for supportedTypeDeclarations failwith $"Unexpected representation {repr.GetType()}" diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs new file mode 100644 index 0000000000..14e9f565ef --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs @@ -0,0 +1,9 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type Bar = + struct + val X: int + end +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs.gold new file mode 100644 index 0000000000..b903373996 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs.gold @@ -0,0 +1,9 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type Bar = + struct + val X: int + end \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 9fbd8ee3fb..2f2499a912 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -38,3 +38,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Recursive types 01`` () = x.DoNamedTest() [] member x.``Instance Member 01`` () = x.DoNamedTest() [] member x.``Instance Member 02`` () = x.DoNamedTest() + [] member x.``Struct 01`` () = x.DoNamedTest() From d59037c3074c94d55e087771ce94d29051a3f167 Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 2 May 2023 11:59:50 +0200 Subject: [PATCH 19/75] start supporting signature generation for ILetBindingsDeclaration --- .../src/Generate/GenerateSignatureProvider.fs | 23 +++++++++++++++++++ .../signatureFiles/Module structure 02.fs | 11 +++++++++ .../Module structure 02.fs.gold | 11 +++++++++ .../Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 46 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index b83cb83ac9..f286a57dc2 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -146,6 +146,29 @@ type FSharpGenerateSignatureBuilder() = processModuleLikeDeclaration (indentation + moduleDecl.GetIndentSize()) nestedNestedModule nestedSigModule | :? IOpenStatement as openStatement -> openStatement.Copy() + | :? ILetBindingsDeclaration as letBindingsDeclaration -> + + let sourceString (binding: IBinding) = + let sb = StringBuilder() + + sb.Append("val ") |> ignore + sb.Append(binding.HeadPattern.GetText()) |> ignore + sb.Append(": ") |> ignore + + let refPat = binding.HeadPattern.As() + if isNotNull refPat then + let symbolUse = refPat.GetFcsSymbolUse() + if isNotNull symbolUse then + let mfv = symbolUse.Symbol :?> FSharpMemberOrFunctionOrValue + sb.Append(mfv.FullType.Format(symbolUse.DisplayContext)) |> ignore + + sb.ToString() + + let sigStrings = + Seq.map sourceString letBindingsDeclaration.Bindings + |> String.concat System.Environment.NewLine + + factory.CreateTypeMemberSignature(sigStrings) | _ -> null and processModuleLikeDeclaration (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleSig: IModuleLikeDeclaration) : IFSharpTreeNode = diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs new file mode 100644 index 0000000000..5ac9cb3319 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs @@ -0,0 +1,11 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +open System + let c = Math.PI + let d = 23 + let e = "bar" + let f x y = x * y + let g x = x +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold new file mode 100644 index 0000000000..7dcc9e6522 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold @@ -0,0 +1,11 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +open System +val c: float +val d: int +val e: string +val f: int -> int -> int +val g: 'a -> 'a \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 2f2499a912..59229e413c 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -28,6 +28,7 @@ type FsharpGenerateSignatureTest() = base.DumpTextControl(fsiTextControl, dumpCaret, dumpSelection) [] member x.``Module structure 01`` () = x.DoNamedTest() + [] member x.``Module structure 02`` () = x.DoNamedTest() [] member x.``Namespace structure 01`` () = x.DoNamedTest() [] member x.``TypeAbbreviation 01`` () = x.DoNamedTest() [] member x.``Record 01`` () = x.DoNamedTest() From 8665b3f1235b43cd3ce86011059df0587e13d00f Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 2 May 2023 16:19:39 +0200 Subject: [PATCH 20/75] remove superfluous indentation --- .../generate/signatureFiles/Module structure 02.fs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs index 5ac9cb3319..feb93282b9 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs @@ -3,9 +3,9 @@ module Foo open System - let c = Math.PI - let d = 23 - let e = "bar" - let f x y = x * y - let g x = x +let c = Math.PI +let d = 23 +let e = "bar" +let f x y = x * y +let g x = x {caret} From d9fe302484b42cae77498106fb23ed200a4bf0f3 Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 2 May 2023 16:21:48 +0200 Subject: [PATCH 21/75] Use "\n" instead of System.Environment.NewLine --- .../src/Generate/GenerateSignatureProvider.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index f286a57dc2..b4d23008e5 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -166,7 +166,7 @@ type FSharpGenerateSignatureBuilder() = let sigStrings = Seq.map sourceString letBindingsDeclaration.Bindings - |> String.concat System.Environment.NewLine + |> String.concat "\n" factory.CreateTypeMemberSignature(sigStrings) | _ -> null From a18129282527f4379ebca512e964dcd928d44096 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 10:35:18 +0200 Subject: [PATCH 22/75] Add basic exception. --- .../src/Generate/GenerateSignatureProvider.fs | 2 ++ .../data/features/generate/signatureFiles/Exception 01.fs | 6 ++++++ .../features/generate/signatureFiles/Exception 01.fs.gold | 6 ++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 15 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index b4d23008e5..f722d7b21e 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -169,6 +169,8 @@ type FSharpGenerateSignatureBuilder() = |> String.concat "\n" factory.CreateTypeMemberSignature(sigStrings) + | :? IExceptionDeclaration as exceptionDeclaration -> + exceptionDeclaration.Copy() | _ -> null and processModuleLikeDeclaration (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleSig: IModuleLikeDeclaration) : IFSharpTreeNode = diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs new file mode 100644 index 0000000000..74e770bb88 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs @@ -0,0 +1,6 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +exception A of int * string +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs.gold new file mode 100644 index 0000000000..40caaa0ed8 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs.gold @@ -0,0 +1,6 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +exception A of int * string \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 59229e413c..045c4c6d9d 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -40,3 +40,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Instance Member 01`` () = x.DoNamedTest() [] member x.``Instance Member 02`` () = x.DoNamedTest() [] member x.``Struct 01`` () = x.DoNamedTest() + [] member x.``Exception 01`` () = x.DoNamedTest() From acde246024e849857e47c864448530eebebdf7c2 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 10:46:45 +0200 Subject: [PATCH 23/75] Add members to exceptions. --- .../src/Generate/GenerateSignatureProvider.fs | 17 ++++++++++++++++- .../generate/signatureFiles/Exception 02.fs | 7 +++++++ .../signatureFiles/Exception 02.fs.gold | 7 +++++++ .../Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index f722d7b21e..4bf2b257be 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -170,7 +170,22 @@ type FSharpGenerateSignatureBuilder() = factory.CreateTypeMemberSignature(sigStrings) | :? IExceptionDeclaration as exceptionDeclaration -> - exceptionDeclaration.Copy() + let sigExceptionDeclaration = exceptionDeclaration.Copy() + if not (Seq.isEmpty exceptionDeclaration.MemberDeclarations) then + let sigMembers = + exceptionDeclaration.TypeMembers + |> Seq.choose (createMemberDeclaration >> Option.ofObj) + + ModificationUtil.DeleteChildRange(sigExceptionDeclaration.WithKeyword.NextSibling, sigExceptionDeclaration.LastChild) + + addNodesAfter sigExceptionDeclaration.WithKeyword [ + for sigMember in sigMembers do + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + sigMember + ] |> ignore + + sigExceptionDeclaration | _ -> null and processModuleLikeDeclaration (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleSig: IModuleLikeDeclaration) : IFSharpTreeNode = diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs new file mode 100644 index 0000000000..5b5542cb1c --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs @@ -0,0 +1,7 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +exception A of int * string with + member a.B (c: string) = 0 +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs.gold new file mode 100644 index 0000000000..a248745202 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs.gold @@ -0,0 +1,7 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +exception A of int * string with + member B: string -> int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 045c4c6d9d..499dc2f6b4 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -41,3 +41,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Instance Member 02`` () = x.DoNamedTest() [] member x.``Struct 01`` () = x.DoNamedTest() [] member x.``Exception 01`` () = x.DoNamedTest() + [] member x.``Exception 02`` () = x.DoNamedTest() From 91bf31b725b10e50c60133a7b6024573d212bc6b Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 10:58:42 +0200 Subject: [PATCH 24/75] Add support for delegates. --- .../src/Generate/GenerateSignatureProvider.fs | 9 ++++++++- .../data/features/generate/signatureFiles/Delegate 01.fs | 6 ++++++ .../features/generate/signatureFiles/Delegate 01.fs.gold | 6 ++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 4bf2b257be..35ff3416a3 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -73,7 +73,8 @@ type FSharpGenerateSignatureBuilder() = match typeDecl.TypeRepresentation with | :? ITypeAbbreviationRepresentation | :? IStructRepresentation - | :? ISimpleTypeRepresentation -> Some typeDecl + | :? ISimpleTypeRepresentation + | :? IDelegateRepresentation -> Some typeDecl | _ -> None | _ -> None) |> Seq.mapi (fun idx typeDecl -> @@ -128,6 +129,12 @@ type FSharpGenerateSignatureBuilder() = Whitespace(indentation + moduleDecl.GetIndentSize()) sigMember ] |> ignore + | :? IDelegateRepresentation as repr -> + ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) + addNodesAfter sigTypeDecl.EqualsToken [ + Whitespace() + repr.Copy() + ] |> ignore | repr -> // This pattern match should match the types we filtered out earlier for supportedTypeDeclarations failwith $"Unexpected representation {repr.GetType()}" diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs new file mode 100644 index 0000000000..2e2a2ff5f6 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs @@ -0,0 +1,6 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type A = delegate of int * string -> float +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs.gold new file mode 100644 index 0000000000..f0a7872c58 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs.gold @@ -0,0 +1,6 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type A = delegate of int * string -> float \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 499dc2f6b4..f714c2928c 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -42,3 +42,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Struct 01`` () = x.DoNamedTest() [] member x.``Exception 01`` () = x.DoNamedTest() [] member x.``Exception 02`` () = x.DoNamedTest() + [] member x.``Delegate 01`` () = x.DoNamedTest() From ee4dd8c4017fc009dc74e2832211e9b189c98809 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 11:55:43 +0200 Subject: [PATCH 25/75] Implicit unit constructor. --- .../src/Generate/GenerateSignatureProvider.fs | 27 +++++++++++++++++-- .../signatureFiles/Implicit Constructor 01.fs | 7 +++++ .../Implicit Constructor 01.fs.gold | 8 ++++++ .../Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 35ff3416a3..cd530da348 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -54,7 +54,7 @@ type FSharpGenerateSignatureProvider() = type FSharpGenerateSignatureBuilder() = inherit GeneratorBuilderBase() - // TODO: what about attributes, type parameters, delegates, exceptions + // TODO: what about attributes, type parameters let mkSignatureFile (fsharpFile: IFSharpFile): IFSharpFile = let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory(extension = FSharpSignatureProjectFileType.FsiExtension) @@ -74,7 +74,9 @@ type FSharpGenerateSignatureBuilder() = | :? ITypeAbbreviationRepresentation | :? IStructRepresentation | :? ISimpleTypeRepresentation - | :? IDelegateRepresentation -> Some typeDecl + | :? IDelegateRepresentation + // Regular classes have no representation. + | null -> Some typeDecl | _ -> None | _ -> None) |> Seq.mapi (fun idx typeDecl -> @@ -135,6 +137,18 @@ type FSharpGenerateSignatureBuilder() = Whitespace() repr.Copy() ] |> ignore + | null -> + ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) + addNodesAfter sigTypeDecl.EqualsToken [ + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + if isNotNull typeDecl.PrimaryConstructorDeclaration then + createPrimaryConstructorSignature (getName typeDecl) typeDecl.PrimaryConstructorDeclaration + for sigMember in sigMembers do + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + sigMember + ] |> ignore | repr -> // This pattern match should match the types we filtered out earlier for supportedTypeDeclarations failwith $"Unexpected representation {repr.GetType()}" @@ -252,6 +266,15 @@ type FSharpGenerateSignatureBuilder() = factory.CreateTypeMemberSignature(sourceString) | _ -> null + and createPrimaryConstructorSignature (typeName: string) (primaryConstructorDeclaration: IPrimaryConstructorDeclaration) : IFSharpTreeNode = + let signature = + match primaryConstructorDeclaration.ParameterPatterns with + | :? IUnitPat -> + $"new: unit -> {typeName}" + | _ -> failwithf "todo" + + factory.CreateTypeMemberSignature(signature) + for decl in fsharpFile.ModuleDeclarations do let signatureModule : IModuleLikeDeclaration = match decl with diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs new file mode 100644 index 0000000000..21b6e0d942 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs @@ -0,0 +1,7 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type A() = + member this.B() : int = 0 +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs.gold new file mode 100644 index 0000000000..5bb6a4ccd0 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs.gold @@ -0,0 +1,8 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type A = + new: unit -> A + member B: unit -> int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index f714c2928c..bbb4ced17b 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -43,3 +43,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Exception 01`` () = x.DoNamedTest() [] member x.``Exception 02`` () = x.DoNamedTest() [] member x.``Delegate 01`` () = x.DoNamedTest() + [] member x.``Implicit Constructor 01`` () = x.DoNamedTest() From 3fde6eec1b8a1eb9148c908fb778101f9404ea12 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 12:05:49 +0200 Subject: [PATCH 26/75] Implicit constructor with parameters. --- .../src/Generate/GenerateSignatureProvider.fs | 32 +++++++++++++------ .../signatureFiles/Implicit Constructor 02.fs | 8 +++++ .../Implicit Constructor 02.fs.gold | 8 +++++ .../Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 40 insertions(+), 9 deletions(-) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index cd530da348..41b8bd485a 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -143,7 +143,7 @@ type FSharpGenerateSignatureBuilder() = NewLine(lineEnding) Whitespace(indentation + moduleDecl.GetIndentSize()) if isNotNull typeDecl.PrimaryConstructorDeclaration then - createPrimaryConstructorSignature (getName typeDecl) typeDecl.PrimaryConstructorDeclaration + yield! createPrimaryConstructorSignature (getName typeDecl) typeDecl.PrimaryConstructorDeclaration for sigMember in sigMembers do NewLine(lineEnding) Whitespace(indentation + moduleDecl.GetIndentSize()) @@ -266,15 +266,29 @@ type FSharpGenerateSignatureBuilder() = factory.CreateTypeMemberSignature(sourceString) | _ -> null - and createPrimaryConstructorSignature (typeName: string) (primaryConstructorDeclaration: IPrimaryConstructorDeclaration) : IFSharpTreeNode = - let signature = - match primaryConstructorDeclaration.ParameterPatterns with - | :? IUnitPat -> - $"new: unit -> {typeName}" - | _ -> failwithf "todo" + and createPrimaryConstructorSignature (typeName: string) (primaryConstructorDeclaration: IPrimaryConstructorDeclaration) : ITreeNode seq = + match primaryConstructorDeclaration.ParameterPatterns with + | :? IUnitPat -> + factory.CreateTypeMemberSignature $"new: unit -> {typeName}" + :> ITreeNode + |> Seq.singleton + | _ -> + let symbolUse = primaryConstructorDeclaration.GetFcsSymbolUse() + if isNull symbolUse then Seq.empty else + let mfv = symbolUse.Symbol.As() + if isNull mfv then Seq.empty else + let parameters = + mfv.CurriedParameterGroups + |> Seq.map (fun parameterGroup -> + parameterGroup + |> Seq.map (fun parameter -> parameter.Type.Format(symbolUse.DisplayContext)) + |> String.concat " * " + ) + |> String.concat " -> " + factory.CreateTypeMemberSignature $"new: {parameters} -> {typeName}" + :> ITreeNode + |> Seq.singleton - factory.CreateTypeMemberSignature(signature) - for decl in fsharpFile.ModuleDeclarations do let signatureModule : IModuleLikeDeclaration = match decl with diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs new file mode 100644 index 0000000000..223acc7005 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs @@ -0,0 +1,8 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type A(a:int,b) = + do printfn "%s" b + member this.B() : int = 0 +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs.gold new file mode 100644 index 0000000000..f78d8b6a69 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs.gold @@ -0,0 +1,8 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type A = + new: int * string -> A + member B: unit -> int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index bbb4ced17b..930149c133 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -44,3 +44,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Exception 02`` () = x.DoNamedTest() [] member x.``Delegate 01`` () = x.DoNamedTest() [] member x.``Implicit Constructor 01`` () = x.DoNamedTest() + [] member x.``Implicit Constructor 02`` () = x.DoNamedTest() From 4778cc41b6c0e860dc77c101041c127ffa5a6ecf Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 12:08:27 +0200 Subject: [PATCH 27/75] Reuse lineEnding --- .../src/Generate/GenerateSignatureProvider.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 41b8bd485a..db12fb4188 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -86,7 +86,7 @@ type FSharpGenerateSignatureBuilder() = if Array.isEmpty supportedTypeDeclarations then null else - let sourceText = supportedTypeDeclarations |> Array.map (fun info -> info.SourceText) |> String.concat "\n" + let sourceText = supportedTypeDeclarations |> Array.map (fun info -> info.SourceText) |> String.concat lineEnding let sigTypeDeclarationGroup = factory.CreateModuleMember(sourceText) :?> ITypeDeclarationGroup if isNull sigTypeDeclarationGroup then null else @@ -187,7 +187,7 @@ type FSharpGenerateSignatureBuilder() = let sigStrings = Seq.map sourceString letBindingsDeclaration.Bindings - |> String.concat "\n" + |> String.concat lineEnding factory.CreateTypeMemberSignature(sigStrings) | :? IExceptionDeclaration as exceptionDeclaration -> From 522257391bc977144e08d180e594f660eeca8dc9 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 12:11:42 +0200 Subject: [PATCH 28/75] Filter out IExceptionFieldDeclaration for IExceptionDeclaration. --- .../src/Generate/GenerateSignatureProvider.fs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index db12fb4188..92533863fb 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -192,7 +192,12 @@ type FSharpGenerateSignatureBuilder() = factory.CreateTypeMemberSignature(sigStrings) | :? IExceptionDeclaration as exceptionDeclaration -> let sigExceptionDeclaration = exceptionDeclaration.Copy() - if not (Seq.isEmpty exceptionDeclaration.MemberDeclarations) then + let memberDeclarations = + exceptionDeclaration.MemberDeclarations + |> Seq.filter (function | :? IExceptionFieldDeclaration -> false | _ -> true) + |> Seq.toArray + + if memberDeclarations.Length > 0 then let sigMembers = exceptionDeclaration.TypeMembers |> Seq.choose (createMemberDeclaration >> Option.ofObj) From 78cf4fba4e1288fee5bde1af63dd47b2f734debd Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 13:32:41 +0200 Subject: [PATCH 29/75] Remove invalid comment. --- .../src/Generate/GenerateSignatureProvider.fs | 2 -- 1 file changed, 2 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 92533863fb..55f77b6c52 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -106,8 +106,6 @@ type FSharpGenerateSignatureBuilder() = addNodesAfter sigTypeDecl.EqualsToken [ Whitespace() abbr.Copy() - // TODO: there technically could be members here. - // Although I think this would need the `with` keyword. ] |> ignore | :? ISimpleTypeRepresentation as repr -> ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) From a3339fac3c1929502f9825b48c124dd98eed9928 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 13:56:00 +0200 Subject: [PATCH 30/75] Remove redundant unit pat check in createPrimaryConstructorSignature. --- .../src/Generate/GenerateSignatureProvider.fs | 36 ++++++++----------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 55f77b6c52..d19c7722d7 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -270,27 +270,21 @@ type FSharpGenerateSignatureBuilder() = | _ -> null and createPrimaryConstructorSignature (typeName: string) (primaryConstructorDeclaration: IPrimaryConstructorDeclaration) : ITreeNode seq = - match primaryConstructorDeclaration.ParameterPatterns with - | :? IUnitPat -> - factory.CreateTypeMemberSignature $"new: unit -> {typeName}" - :> ITreeNode - |> Seq.singleton - | _ -> - let symbolUse = primaryConstructorDeclaration.GetFcsSymbolUse() - if isNull symbolUse then Seq.empty else - let mfv = symbolUse.Symbol.As() - if isNull mfv then Seq.empty else - let parameters = - mfv.CurriedParameterGroups - |> Seq.map (fun parameterGroup -> - parameterGroup - |> Seq.map (fun parameter -> parameter.Type.Format(symbolUse.DisplayContext)) - |> String.concat " * " - ) - |> String.concat " -> " - factory.CreateTypeMemberSignature $"new: {parameters} -> {typeName}" - :> ITreeNode - |> Seq.singleton + let symbolUse = primaryConstructorDeclaration.GetFcsSymbolUse() + if isNull symbolUse then Seq.empty else + let mfv = symbolUse.Symbol.As() + if isNull mfv then Seq.empty else + let parameters = + mfv.CurriedParameterGroups + |> Seq.map (fun parameterGroup -> + parameterGroup + |> Seq.map (fun parameter -> parameter.Type.Format(symbolUse.DisplayContext)) + |> String.concat " * " + ) + |> String.concat " -> " + factory.CreateTypeMemberSignature $"new: {parameters} -> {typeName}" + :> ITreeNode + |> Seq.singleton for decl in fsharpFile.ModuleDeclarations do let signatureModule : IModuleLikeDeclaration = From 7e2bf99c47fa534e1e80e4922229cdd7e6d779ed Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 14:07:05 +0200 Subject: [PATCH 31/75] Don't show workflow item is setting is not enabled. --- .../src/Generate/GenerateSignatureProvider.fs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index d19c7722d7..d83f8f7958 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -19,6 +19,7 @@ open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Generate open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree open JetBrains.ReSharper.Psi +open JetBrains.ReSharper.Psi.DataContext open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree open JetBrains.ReSharper.Psi.Naming open JetBrains.ReSharper.Psi.Tree @@ -366,5 +367,12 @@ type FSharpGenerateSignatureWorkflow() = [] type FSharpGenerateSignatureWorkflowProvider() = interface IGenerateImplementationsWorkflowProvider with - member this.CreateWorkflow _ = - [| FSharpGenerateSignatureWorkflow() |] + member this.CreateWorkflow dataContext = + if dataContext.IsEmpty then Seq.empty else + let node = dataContext.GetData(PsiDataConstants.SOURCE_FILE) + if isNull node then Seq.empty else + let solution = node.GetSolution() + if not (solution.IsFSharpExperimentalFeatureEnabled(ExperimentalFeature.GenerateSignatureFile)) then + Seq.empty + else + [| FSharpGenerateSignatureWorkflow() |] From e676130797d569db1668b5c15910511451d18619 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 14:11:01 +0200 Subject: [PATCH 32/75] Use TypeMembers for IExceptionDeclaration. --- .../src/Generate/GenerateSignatureProvider.fs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index d83f8f7958..f570c7449f 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -191,12 +191,8 @@ type FSharpGenerateSignatureBuilder() = factory.CreateTypeMemberSignature(sigStrings) | :? IExceptionDeclaration as exceptionDeclaration -> let sigExceptionDeclaration = exceptionDeclaration.Copy() - let memberDeclarations = - exceptionDeclaration.MemberDeclarations - |> Seq.filter (function | :? IExceptionFieldDeclaration -> false | _ -> true) - |> Seq.toArray - if memberDeclarations.Length > 0 then + if not exceptionDeclaration.TypeMembers.IsEmpty then let sigMembers = exceptionDeclaration.TypeMembers |> Seq.choose (createMemberDeclaration >> Option.ofObj) @@ -209,7 +205,7 @@ type FSharpGenerateSignatureBuilder() = Whitespace(indentation + moduleDecl.GetIndentSize()) sigMember ] |> ignore - + sigExceptionDeclaration | _ -> null From 60e73bc6ccc3183fb5d4cf7ce1cc0f0cad2bdcde Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 16:02:37 +0200 Subject: [PATCH 33/75] Small fixes after rebase. --- .../src/Generate/GenerateSignatureProvider.fs | 6 +++--- .../test/src/FSharp.Tests/Parsing/FSharpParserTest.fs | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index f570c7449f..f1ce5d30f8 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -188,7 +188,7 @@ type FSharpGenerateSignatureBuilder() = Seq.map sourceString letBindingsDeclaration.Bindings |> String.concat lineEnding - factory.CreateTypeMemberSignature(sigStrings) + factory.CreateTypeMember(sigStrings) | :? IExceptionDeclaration as exceptionDeclaration -> let sigExceptionDeclaration = exceptionDeclaration.Copy() @@ -263,7 +263,7 @@ type FSharpGenerateSignatureBuilder() = sb.ToString() - factory.CreateTypeMemberSignature(sourceString) + factory.CreateTypeMember(sourceString) | _ -> null and createPrimaryConstructorSignature (typeName: string) (primaryConstructorDeclaration: IPrimaryConstructorDeclaration) : ITreeNode seq = @@ -279,7 +279,7 @@ type FSharpGenerateSignatureBuilder() = |> String.concat " * " ) |> String.concat " -> " - factory.CreateTypeMemberSignature $"new: {parameters} -> {typeName}" + factory.CreateTypeMember $"new: {parameters} -> {typeName}" :> ITreeNode |> Seq.singleton diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs index 3620b8aa27..8c6de3d704 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs @@ -687,9 +687,6 @@ type FSharpSignatureParserTest() = /// Use this test case to dump the psi tree for a given file, see `_.fsi`. [] member x.``_``() = x.DoNamedTest() - /// Use this test case to dump the psi tree for a given file, see `_.fsi`. - [] member x.``_``() = x.DoNamedTest() - [] member x.``Type decl - Union 01 - After nested module``() = x.DoNamedTest() [] member x.``Type decl - Union 02 - FullType``() = x.DoNamedTest() [] member x.``Type decl - Delegate``() = x.DoNamedTest() From c97a42e8b194a3c4ab4a32cce0cced60f7aabeff Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 9 May 2023 23:34:46 +0200 Subject: [PATCH 34/75] Support attributes on module members --- .../src/Generate/GenerateSignatureProvider.fs | 13 ++++++++----- .../generate/signatureFiles/Module structure 02.fs | 1 + .../signatureFiles/Module structure 02.fs.gold | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index f1ce5d30f8..19f6004041 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -171,15 +171,18 @@ type FSharpGenerateSignatureBuilder() = let sourceString (binding: IBinding) = let sb = StringBuilder() - sb.Append("val ") |> ignore - sb.Append(binding.HeadPattern.GetText()) |> ignore - sb.Append(": ") |> ignore - let refPat = binding.HeadPattern.As() if isNotNull refPat then let symbolUse = refPat.GetFcsSymbolUse() if isNotNull symbolUse then let mfv = symbolUse.Symbol :?> FSharpMemberOrFunctionOrValue + + mfv.Attributes + |> Seq.iter (fun a -> sb.Append($"{a.Format(symbolUse.DisplayContext)}{lineEnding}") |> ignore) + + sb.Append("val ") |> ignore + sb.Append(binding.HeadPattern.GetText()) |> ignore + sb.Append(": ") |> ignore sb.Append(mfv.FullType.Format(symbolUse.DisplayContext)) |> ignore sb.ToString() @@ -188,7 +191,7 @@ type FSharpGenerateSignatureBuilder() = Seq.map sourceString letBindingsDeclaration.Bindings |> String.concat lineEnding - factory.CreateTypeMember(sigStrings) + factory.CreateModuleMember(sigStrings) | :? IExceptionDeclaration as exceptionDeclaration -> let sigExceptionDeclaration = exceptionDeclaration.Copy() diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs index feb93282b9..92cb582c64 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs @@ -7,5 +7,6 @@ let c = Math.PI let d = 23 let e = "bar" let f x y = x * y +[] let g x = x {caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold index 7dcc9e6522..5b60ea58d5 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold @@ -8,4 +8,5 @@ val c: float val d: int val e: string val f: int -> int -> int +[] val g: 'a -> 'a \ No newline at end of file From 6f9fffc78559c7f09bed9be1d49856ee40412697 Mon Sep 17 00:00:00 2001 From: dawe Date: Wed, 10 May 2023 11:13:02 +0200 Subject: [PATCH 35/75] Add attribute with parameter for test --- .../features/generate/signatureFiles/Module structure 02.fs | 3 ++- .../generate/signatureFiles/Module structure 02.fs.gold | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs index 92cb582c64..ba729ca326 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs @@ -7,6 +7,7 @@ let c = Math.PI let d = 23 let e = "bar" let f x y = x * y -[] +[] +[] let g x = x {caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold index 5b60ea58d5..a843510cf2 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold @@ -8,5 +8,6 @@ val c: float val d: int val e: string val f: int -> int -> int -[] +[] +[] val g: 'a -> 'a \ No newline at end of file From ec038a21c583c1232bdce15c8e942c5c34a29779 Mon Sep 17 00:00:00 2001 From: dawe Date: Wed, 10 May 2023 14:13:05 +0200 Subject: [PATCH 36/75] Use GetText() to get original attributes from impl file. --- .../src/Generate/GenerateSignatureProvider.fs | 4 ++-- .../generate/signatureFiles/Module structure 02.fs | 4 ++++ .../signatureFiles/Module structure 02.fs.gold | 11 ++++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 19f6004041..4c314fe567 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -177,8 +177,8 @@ type FSharpGenerateSignatureBuilder() = if isNotNull symbolUse then let mfv = symbolUse.Symbol :?> FSharpMemberOrFunctionOrValue - mfv.Attributes - |> Seq.iter (fun a -> sb.Append($"{a.Format(symbolUse.DisplayContext)}{lineEnding}") |> ignore) + binding.Attributes + |> Seq.iter (fun a -> sb.Append($"[<{a.GetText()}>]{lineEnding}") |> ignore) sb.Append("val ") |> ignore sb.Append(binding.HeadPattern.GetText()) |> ignore diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs index ba729ca326..8a1d2703a7 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs @@ -7,7 +7,11 @@ let c = Math.PI let d = 23 let e = "bar" let f x y = x * y +[] [] [] let g x = x +let [] Hello = "Hello" +[] +let hello = 1 {caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold index a843510cf2..3280319397 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold @@ -8,6 +8,11 @@ val c: float val d: int val e: string val f: int -> int -> int -[] -[] -val g: 'a -> 'a \ No newline at end of file +[] +[] +[] +val g: 'a -> 'a +[] +val Hello: string +[] +val hello: int \ No newline at end of file From 2bf881caca4e54eeefadc66de19cdadb24d75324 Mon Sep 17 00:00:00 2001 From: dawe Date: Sat, 13 May 2023 16:42:56 +0200 Subject: [PATCH 37/75] WIP, add attributes and xml comments remove .copy() calls where not needed --- .../src/Generate/GenerateSignatureProvider.fs | 92 +++++++++++++++---- .../generate/signatureFiles/Delegate 01.fs | 2 + .../signatureFiles/Delegate 01.fs.gold | 2 + .../generate/signatureFiles/Exception 01.fs | 2 + .../signatureFiles/Exception 01.fs.gold | 2 + .../signatureFiles/Instance Member 01.fs | 2 + .../signatureFiles/Instance Member 01.fs.gold | 2 + .../signatureFiles/Module structure 02.fs | 7 +- .../Module structure 02.fs.gold | 8 +- .../signatureFiles/Nested module 01.fs | 2 + .../signatureFiles/Nested module 01.fs.gold | 2 + .../generate/signatureFiles/Record 01.fs | 2 + .../generate/signatureFiles/Record 01.fs.gold | 2 + .../generate/signatureFiles/Struct 01.fs | 2 + .../generate/signatureFiles/Struct 01.fs.gold | 2 + .../generate/signatureFiles/Union 01.fs | 2 + .../generate/signatureFiles/Union 01.fs.gold | 2 + .../generate/signatureFiles/Union 02.fs | 2 + .../generate/signatureFiles/Union 02.fs.gold | 2 + 19 files changed, 117 insertions(+), 22 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 4c314fe567..727c93614b 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -23,6 +23,7 @@ open JetBrains.ReSharper.Psi.DataContext open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree open JetBrains.ReSharper.Psi.Naming open JetBrains.ReSharper.Psi.Tree +open JetBrains.ReSharper.Psi.Util open JetBrains.ReSharper.Resources.Shell module FSharpGeneratorKinds = @@ -63,6 +64,37 @@ type FSharpGenerateSignatureBuilder() = let lineEnding = fsharpFile.GetLineEnding() let getName (decl: IFSharpDeclaration) = NamingManager.GetNamingLanguageService(fsharpFile.Language).MangleNameIfNecessary(decl.SourceName) + let addXmlDocBlock (indendation: int) anchor xmlDocBlock = + if isNotNull xmlDocBlock then + addNodesBefore anchor [ + Whitespace(indendation) + xmlDocBlock + NewLine(lineEnding) + ] |> ignore + + // Todo: normalize indentation for + // [] + let addAttributes (indentation: int) (attributeLists: TreeNodeCollection) (anchor: ITreeNode) = + if not attributeLists.IsEmpty then + let nodesToAdd = [ + for attributeList in attributeLists do + Whitespace(indentation) :> ITreeNode + attributeList :> ITreeNode + let last = + attributeList.NextTokens() + |> Seq.takeWhile (fun x -> isNewLine x || isWhitespaceOrComment x) + |> Seq.tryLast + match last with + | Some l -> + let treeRange = TreeRange(getNextSibling attributeList, l) + if treeRange.ToTreeNodeCollection().Any(isNewLine) then + NewLine(lineEnding) :> ITreeNode else Whitespace(1) :> ITreeNode + | _ -> () + ] + addNodesBefore anchor nodesToAdd |> ignore + else () + let rec createModuleMemberSig (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleMember: IModuleMember) : IFSharpTreeNode = match moduleMember with | :? ITypeDeclarationGroup as typeGroup -> @@ -97,26 +129,29 @@ type FSharpGenerateSignatureBuilder() = let sigTypeDecl = sigTypeDeclarationGroup.TypeDeclarations.[info.SignatureIdx] :?> IFSharpTypeDeclaration if isNull sigTypeDecl then () else + let indentForMembers = sigTypeDecl.Indent + moduleDecl.GetIndentSize() let sigMembers = typeDecl.TypeMembers - |> Seq.choose (createMemberDeclaration >> Option.ofObj) + |> Seq.choose (createMemberDeclaration indentForMembers >> Option.ofObj) + + addXmlDocBlock sigTypeDecl.Indent sigTypeDecl typeDecl.XmlDocBlock + addAttributes sigTypeDecl.Indent typeDecl.AttributeLists sigTypeDecl.TypeKeyword match typeDecl.TypeRepresentation with | :? ITypeAbbreviationRepresentation as abbr -> ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) addNodesAfter sigTypeDecl.EqualsToken [ Whitespace() - abbr.Copy() + abbr ] |> ignore | :? ISimpleTypeRepresentation as repr -> ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) addNodesAfter sigTypeDecl.EqualsToken [ NewLine(lineEnding) Whitespace(indentation + moduleDecl.GetIndentSize()) - repr.Copy() + repr for sigMember in sigMembers do NewLine(lineEnding) - Whitespace(indentation + moduleDecl.GetIndentSize()) sigMember ] |> ignore | :? IStructRepresentation as repr -> @@ -124,17 +159,16 @@ type FSharpGenerateSignatureBuilder() = addNodesAfter sigTypeDecl.EqualsToken [ NewLine(lineEnding) Whitespace(indentation + moduleDecl.GetIndentSize()) - repr.Copy() + repr for sigMember in sigMembers do NewLine(lineEnding) - Whitespace(indentation + moduleDecl.GetIndentSize()) sigMember ] |> ignore | :? IDelegateRepresentation as repr -> ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) addNodesAfter sigTypeDecl.EqualsToken [ Whitespace() - repr.Copy() + repr ] |> ignore | null -> ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) @@ -145,7 +179,6 @@ type FSharpGenerateSignatureBuilder() = yield! createPrimaryConstructorSignature (getName typeDecl) typeDecl.PrimaryConstructorDeclaration for sigMember in sigMembers do NewLine(lineEnding) - Whitespace(indentation + moduleDecl.GetIndentSize()) sigMember ] |> ignore | repr -> @@ -161,11 +194,14 @@ type FSharpGenerateSignatureBuilder() = not members.IsEmpty && members |> Seq.forall (function | :? IExpressionStatement -> false | _ -> true) + addXmlDocBlock indentation nestedSigModule.FirstChild nestedNestedModule.XmlDocBlock + addAttributes indentation nestedNestedModule.AttributeLists nestedSigModule.ModuleOrNamespaceKeyword + if shouldEmptyContent then ModificationUtil.DeleteChildRange (nestedSigModule.EqualsToken.NextSibling, nestedSigModule.LastChild) processModuleLikeDeclaration (indentation + moduleDecl.GetIndentSize()) nestedNestedModule nestedSigModule | :? IOpenStatement as openStatement -> - openStatement.Copy() + openStatement | :? ILetBindingsDeclaration as letBindingsDeclaration -> let sourceString (binding: IBinding) = @@ -177,9 +213,6 @@ type FSharpGenerateSignatureBuilder() = if isNotNull symbolUse then let mfv = symbolUse.Symbol :?> FSharpMemberOrFunctionOrValue - binding.Attributes - |> Seq.iter (fun a -> sb.Append($"[<{a.GetText()}>]{lineEnding}") |> ignore) - sb.Append("val ") |> ignore sb.Append(binding.HeadPattern.GetText()) |> ignore sb.Append(": ") |> ignore @@ -191,24 +224,34 @@ type FSharpGenerateSignatureBuilder() = Seq.map sourceString letBindingsDeclaration.Bindings |> String.concat lineEnding - factory.CreateModuleMember(sigStrings) + let memberSig = factory.CreateModuleMember(sigStrings) + + match memberSig with + | :? IBindingSignature as bindingSig -> + for letBinding in letBindingsDeclaration.Bindings do + addAttributes indentation letBinding.AttributeLists bindingSig.BindingKeyword + | _ -> () + + memberSig | :? IExceptionDeclaration as exceptionDeclaration -> let sigExceptionDeclaration = exceptionDeclaration.Copy() if not exceptionDeclaration.TypeMembers.IsEmpty then + let indentForMembers = indentation + moduleDecl.GetIndentSize() let sigMembers = exceptionDeclaration.TypeMembers - |> Seq.choose (createMemberDeclaration >> Option.ofObj) + |> Seq.choose (createMemberDeclaration indentForMembers >> Option.ofObj) ModificationUtil.DeleteChildRange(sigExceptionDeclaration.WithKeyword.NextSibling, sigExceptionDeclaration.LastChild) addNodesAfter sigExceptionDeclaration.WithKeyword [ for sigMember in sigMembers do NewLine(lineEnding) - Whitespace(indentation + moduleDecl.GetIndentSize()) sigMember ] |> ignore + addAttributes sigExceptionDeclaration.Indent sigExceptionDeclaration.AttributeLists sigExceptionDeclaration + sigExceptionDeclaration | _ -> null @@ -220,6 +263,14 @@ type FSharpGenerateSignatureBuilder() = // newline + indentation whitespace addNodesAfter moduleSig.LastChild [ NewLine(lineEnding) + match moduleMember with + | :? ILetBindingsDeclaration as letBindingsDecl when not letBindingsDecl.Bindings.IsEmpty -> + match letBindingsDecl.Bindings[0].FirstChild with + | :? XmlDocBlock as xmlDocBlock -> + xmlDocBlock + NewLine(lineEnding) + | _ -> () + | _ -> () Whitespace(indentation) signatureMember ] @@ -227,7 +278,7 @@ type FSharpGenerateSignatureBuilder() = moduleSig - and createMemberDeclaration (memberDecl: IFSharpTypeMemberDeclaration) : IFSharpTypeMemberDeclaration = + and createMemberDeclaration (indentation: int) (memberDecl: IFSharpTypeMemberDeclaration) : IFSharpTypeMemberDeclaration = match memberDecl with | :? IMemberDeclaration as memberDecl -> let sourceString = @@ -266,9 +317,16 @@ type FSharpGenerateSignatureBuilder() = sb.ToString() - factory.CreateTypeMember(sourceString) + let typeMember = factory.CreateTypeMember(sourceString) + + // Todo find better indentation approach + addNodeBefore typeMember.FirstChild (Whitespace(indentation)) + addAttributes indentation memberDecl.AttributeLists typeMember.FirstChild + addXmlDocBlock indentation typeMember.FirstChild memberDecl.XmlDocBlock + typeMember | _ -> null + // Todo refactor to reuse existing code and createPrimaryConstructorSignature (typeName: string) (primaryConstructorDeclaration: IPrimaryConstructorDeclaration) : ITreeNode seq = let symbolUse = primaryConstructorDeclaration.GetFcsSymbolUse() if isNull symbolUse then Seq.empty else diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs index 2e2a2ff5f6..d7e66a0cfd 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs @@ -2,5 +2,7 @@ // ${SELECT0:Generate signature file title} module Foo +/// comment that should be preserved +[] type A = delegate of int * string -> float {caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs.gold index f0a7872c58..61fcaa62a6 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs.gold +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs.gold @@ -3,4 +3,6 @@ {caret}module Foo +/// comment that should be preserved +[] type A = delegate of int * string -> float \ No newline at end of file diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs index 74e770bb88..3a5a9f1ae8 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs @@ -2,5 +2,7 @@ // ${SELECT0:Generate signature file title} module Foo +/// comment that should be preserved +[] exception A of int * string {caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs.gold index 40caaa0ed8..645b483f11 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs.gold +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs.gold @@ -3,4 +3,6 @@ {caret}module Foo +/// comment that should be preserved +[] exception A of int * string \ No newline at end of file diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs index fff62f4096..bafe934613 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs @@ -6,5 +6,7 @@ type X = { Y: int } + /// comment that should be preserved + [] member x.A b c = x.Y - b + c {caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs.gold index 08893bf23f..78165f9050 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs.gold +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs.gold @@ -7,4 +7,6 @@ type X = { Y: int } + /// comment that should be preserved + [] member A: int -> int -> int \ No newline at end of file diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs index 8a1d2703a7..9e7f94f1a8 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs @@ -7,11 +7,14 @@ let c = Math.PI let d = 23 let e = "bar" let f x y = x * y -[] +/// comment that should be preserved +[] // comment that should disappear 1 [] [] let g x = x -let [] Hello = "Hello" +let [] (* comment that should disappear 2 *) Hello = "Hello" [] let hello = 1 +[] +let h = 23 {caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold index 3280319397..fce06123a8 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold @@ -8,11 +8,13 @@ val c: float val d: int val e: string val f: int -> int -> int +/// comment that should be preserved [] [] [] val g: 'a -> 'a -[] -val Hello: string +[] val Hello: string [] -val hello: int \ No newline at end of file +val hello: int +[] +val h: int \ No newline at end of file diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs index 2f3eda1e9a..4c0b66fe47 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs @@ -2,6 +2,8 @@ // ${SELECT0:Generate signature file title} module Foo + /// comment that should be preserved + [] module Bar = open System {caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs.gold index 7a9a656e05..509473a1e8 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs.gold +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs.gold @@ -3,5 +3,7 @@ {caret}module Foo +/// comment that should be preserved +[] module Bar = open System \ No newline at end of file diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs index 8ed064d076..0e2eae95de 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs @@ -2,5 +2,7 @@ // ${SELECT0:Generate signature file title} module Foo +/// comment that should be preserved +[] type Bar = { A:int; B: int } {caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs.gold index ebd75ac780..2c058de285 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs.gold +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs.gold @@ -3,5 +3,7 @@ {caret}module Foo +/// comment that should be preserved +[] type Bar = { A:int; B: int } \ No newline at end of file diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs index 14e9f565ef..216821fdce 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs @@ -2,6 +2,8 @@ // ${SELECT0:Generate signature file title} module Foo +/// comment that should be preserved +[] type Bar = struct val X: int diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs.gold index b903373996..9074e9e543 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs.gold +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs.gold @@ -3,6 +3,8 @@ {caret}module Foo +/// comment that should be preserved +[] type Bar = struct val X: int diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs index 674e364cf7..05a942a08c 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs @@ -2,5 +2,7 @@ // ${SELECT0:Generate signature file title} module Foo +/// comment that should be preserved +[] type Bar = | Bar of a:int * b:int {caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs.gold index faf084b85b..de08dc94dc 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs.gold +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs.gold @@ -3,5 +3,7 @@ {caret}module Foo +/// comment that should be preserved +[] type Bar = | Bar of a:int * b:int \ No newline at end of file diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs index 879b596eb0..d47df473a3 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs @@ -3,5 +3,7 @@ module Foo type Bar = | Bar of a:int * b:int + /// comment that should be preserved + [] static member Add x y = x + y {caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs.gold index a4d782af7b..558973a6aa 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs.gold +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs.gold @@ -5,4 +5,6 @@ type Bar = | Bar of a:int * b:int + /// comment that should be preserved + [] static member Add: int -> int -> int \ No newline at end of file From 1defbf40a375d8208b3ded78e28d4e6ec796637d Mon Sep 17 00:00:00 2001 From: dawe Date: Sat, 13 May 2023 18:21:16 +0200 Subject: [PATCH 38/75] refactor to not add whitespace before node to indent --- .../src/Generate/GenerateSignatureProvider.fs | 65 ++++++++++++++----- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 727c93614b..896d4f0200 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -79,7 +79,7 @@ type FSharpGenerateSignatureBuilder() = if not attributeLists.IsEmpty then let nodesToAdd = [ for attributeList in attributeLists do - Whitespace(indentation) :> ITreeNode + Whitespace(indentation) :> ITreeNode // Todo: refactor to not add whitespace before anchor attributeList :> ITreeNode let last = attributeList.NextTokens() @@ -95,6 +95,22 @@ type FSharpGenerateSignatureBuilder() = addNodesBefore anchor nodesToAdd |> ignore else () + let genAttributes (attributeLists: TreeNodeCollection) = + seq { + for attributeList in attributeLists do + attributeList :> ITreeNode + let last = + attributeList.NextTokens() + |> Seq.takeWhile (fun x -> isNewLine x || isWhitespaceOrComment x) + |> Seq.tryLast + match last with + | Some l -> + let treeRange = TreeRange(getNextSibling attributeList, l) + if treeRange.ToTreeNodeCollection().Any(isNewLine) then + NewLine(lineEnding) :> ITreeNode else Whitespace(1) :> ITreeNode + | _ -> () + } + let rec createModuleMemberSig (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleMember: IModuleMember) : IFSharpTreeNode = match moduleMember with | :? ITypeDeclarationGroup as typeGroup -> @@ -132,7 +148,8 @@ type FSharpGenerateSignatureBuilder() = let indentForMembers = sigTypeDecl.Indent + moduleDecl.GetIndentSize() let sigMembers = typeDecl.TypeMembers - |> Seq.choose (createMemberDeclaration indentForMembers >> Option.ofObj) + |> Seq.map(createMemberDeclaration indentForMembers) + |> Seq.filter(Seq.isEmpty >> not) addXmlDocBlock sigTypeDecl.Indent sigTypeDecl typeDecl.XmlDocBlock addAttributes sigTypeDecl.Indent typeDecl.AttributeLists sigTypeDecl.TypeKeyword @@ -150,9 +167,9 @@ type FSharpGenerateSignatureBuilder() = NewLine(lineEnding) Whitespace(indentation + moduleDecl.GetIndentSize()) repr - for sigMember in sigMembers do + for sigMemberNodes in sigMembers do NewLine(lineEnding) - sigMember + yield! sigMemberNodes ] |> ignore | :? IStructRepresentation as repr -> ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) @@ -160,9 +177,9 @@ type FSharpGenerateSignatureBuilder() = NewLine(lineEnding) Whitespace(indentation + moduleDecl.GetIndentSize()) repr - for sigMember in sigMembers do + for sigMemberNodes in sigMembers do NewLine(lineEnding) - sigMember + yield! sigMemberNodes ] |> ignore | :? IDelegateRepresentation as repr -> ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) @@ -177,9 +194,10 @@ type FSharpGenerateSignatureBuilder() = Whitespace(indentation + moduleDecl.GetIndentSize()) if isNotNull typeDecl.PrimaryConstructorDeclaration then yield! createPrimaryConstructorSignature (getName typeDecl) typeDecl.PrimaryConstructorDeclaration - for sigMember in sigMembers do + + for sigMemberNodes in sigMembers do NewLine(lineEnding) - sigMember + yield! sigMemberNodes ] |> ignore | repr -> // This pattern match should match the types we filtered out earlier for supportedTypeDeclarations @@ -240,14 +258,15 @@ type FSharpGenerateSignatureBuilder() = let indentForMembers = indentation + moduleDecl.GetIndentSize() let sigMembers = exceptionDeclaration.TypeMembers - |> Seq.choose (createMemberDeclaration indentForMembers >> Option.ofObj) + |> Seq.map(createMemberDeclaration indentForMembers) + |> Seq.filter(Seq.isEmpty >> not) ModificationUtil.DeleteChildRange(sigExceptionDeclaration.WithKeyword.NextSibling, sigExceptionDeclaration.LastChild) addNodesAfter sigExceptionDeclaration.WithKeyword [ - for sigMember in sigMembers do + for sigMemberNodes in sigMembers do NewLine(lineEnding) - sigMember + yield! sigMemberNodes ] |> ignore addAttributes sigExceptionDeclaration.Indent sigExceptionDeclaration.AttributeLists sigExceptionDeclaration @@ -278,7 +297,7 @@ type FSharpGenerateSignatureBuilder() = moduleSig - and createMemberDeclaration (indentation: int) (memberDecl: IFSharpTypeMemberDeclaration) : IFSharpTypeMemberDeclaration = + and createMemberDeclaration (indentation: int) (memberDecl: IFSharpTypeMemberDeclaration) : seq = match memberDecl with | :? IMemberDeclaration as memberDecl -> let sourceString = @@ -319,12 +338,22 @@ type FSharpGenerateSignatureBuilder() = let typeMember = factory.CreateTypeMember(sourceString) - // Todo find better indentation approach - addNodeBefore typeMember.FirstChild (Whitespace(indentation)) - addAttributes indentation memberDecl.AttributeLists typeMember.FirstChild - addXmlDocBlock indentation typeMember.FirstChild memberDecl.XmlDocBlock - typeMember - | _ -> null + let attributes = genAttributes memberDecl.AttributeLists + seq { + if isNotNull memberDecl.XmlDocBlock then + Whitespace(indentation) + memberDecl.XmlDocBlock + NewLine(lineEnding) + for a in attributes do + match a with + | :? IAttributeList -> Whitespace(indentation) + | _ -> () + a + if Seq.isEmpty attributes || attributes |> Seq.last |> isNewLine then + Whitespace(indentation) + typeMember + } + | _ -> Seq.empty // Todo refactor to reuse existing code and createPrimaryConstructorSignature (typeName: string) (primaryConstructorDeclaration: IPrimaryConstructorDeclaration) : ITreeNode seq = From b5d33d2857835f11cca0e2a4e758984fc0f28fd1 Mon Sep 17 00:00:00 2001 From: dawe Date: Sat, 13 May 2023 19:47:09 +0200 Subject: [PATCH 39/75] cleanup --- .../src/Generate/GenerateSignatureProvider.fs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 896d4f0200..7875ac2664 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -145,10 +145,9 @@ type FSharpGenerateSignatureBuilder() = let sigTypeDecl = sigTypeDeclarationGroup.TypeDeclarations.[info.SignatureIdx] :?> IFSharpTypeDeclaration if isNull sigTypeDecl then () else - let indentForMembers = sigTypeDecl.Indent + moduleDecl.GetIndentSize() let sigMembers = typeDecl.TypeMembers - |> Seq.map(createMemberDeclaration indentForMembers) + |> Seq.map(createMemberDeclaration (indentation + moduleDecl.GetIndentSize())) |> Seq.filter(Seq.isEmpty >> not) addXmlDocBlock sigTypeDecl.Indent sigTypeDecl typeDecl.XmlDocBlock @@ -337,8 +336,8 @@ type FSharpGenerateSignatureBuilder() = sb.ToString() let typeMember = factory.CreateTypeMember(sourceString) - let attributes = genAttributes memberDecl.AttributeLists + seq { if isNotNull memberDecl.XmlDocBlock then Whitespace(indentation) From 83321e4a4e2565df2b85201530197ed27404db34 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 13 Feb 2023 15:56:34 +0100 Subject: [PATCH 40/75] Initial generation signature feature toggle. --- .../src/Settings/FSharpOptions.fs | 8 +- .../src/Util/FSharpExperimentalFeatures.fs | 2 + .../FSharp.Psi.Intentions.fsproj | 1 + .../Intentions/GenerateSignatureFileAction.fs | 100 ++++++++++++++++++ 4 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs diff --git a/ReSharper.FSharp/src/FSharp.Common/src/Settings/FSharpOptions.fs b/ReSharper.FSharp/src/FSharp.Common/src/Settings/FSharpOptions.fs index 753cf0ad99..a3f0d79197 100644 --- a/ReSharper.FSharp/src/FSharp.Common/src/Settings/FSharpOptions.fs +++ b/ReSharper.FSharp/src/FSharp.Common/src/Settings/FSharpOptions.fs @@ -86,7 +86,7 @@ module FSharpExperimentalFeatures = let [] outOfProcessTypeProviders = "Host type providers out-of-process" let [] generativeTypeProvidersInMemoryAnalysis = "Enable generative type providers analysis in C#/VB.NET projects" let [] tryRecoverFcsProjects = "Try to reuse FCS results on project changes" - + let [] generateSignatureFile = "Generate signature file" [, "F# experimental features")>] type FSharpExperimentalFeatures = @@ -109,8 +109,10 @@ type FSharpExperimentalFeatures = mutable GenerativeTypeProvidersInMemoryAnalysis: bool [] - mutable TryRecoverFcsProjects: bool } + mutable TryRecoverFcsProjects: bool + [] + mutable GenerateSignatureFile: bool } [] type FSharpSettingsProviderBase<'T>(lifetime: Lifetime, settings: IContextBoundSettingsStoreLive, @@ -146,6 +148,7 @@ type FSharpExperimentalFeaturesProvider(lifetime, solution, settings, settingsSc member val OutOfProcessTypeProviders = base.GetValueProperty("OutOfProcessTypeProviders") member val GenerativeTypeProvidersInMemoryAnalysis = base.GetValueProperty("GenerativeTypeProvidersInMemoryAnalysis") member val TryRecoverFcsProjects = base.GetValueProperty("TryRecoverFcsProjects") + member val GenerateSignatureFile = base.GetValueProperty("GenerateSignatureFile") [] @@ -220,6 +223,7 @@ type FSharpOptionsPage(lifetime: Lifetime, optionsPageContext, settings, this.AddBoolOption((fun key -> key.PostfixTemplates), RichText(FSharpExperimentalFeatures.postfixTemplates), null) |> ignore this.AddBoolOption((fun key -> key.RedundantParensAnalysis), RichText(FSharpExperimentalFeatures.redundantParenAnalysis), null) |> ignore this.AddBoolOption((fun key -> key.Formatter), RichText(FSharpExperimentalFeatures.formatter), null) |> ignore + this.AddBoolOption((fun key -> key.GenerateSignatureFile), RichText(FSharpExperimentalFeatures.generateSignatureFile)) |> ignore [] diff --git a/ReSharper.FSharp/src/FSharp.Common/src/Util/FSharpExperimentalFeatures.fs b/ReSharper.FSharp/src/FSharp.Common/src/Util/FSharpExperimentalFeatures.fs index 0acca3f522..2ab7deeb3c 100644 --- a/ReSharper.FSharp/src/FSharp.Common/src/Util/FSharpExperimentalFeatures.fs +++ b/ReSharper.FSharp/src/FSharp.Common/src/Util/FSharpExperimentalFeatures.fs @@ -13,6 +13,7 @@ type ExperimentalFeature = | RedundantParenAnalysis = 3 | AssemblyReaderShim = 4 | TryRecoverFcsProjects = 5 + | GenerateSignatureFile = 6 type FSharpExperimentalFeatureCookie(feature: ExperimentalFeature) = static let cookies = OneToListMap() @@ -45,6 +46,7 @@ type FSharpExperimentalFeatures() = | ExperimentalFeature.PostfixTemplates -> experimentalFeatures.EnablePostfixTemplates.Value | ExperimentalFeature.RedundantParenAnalysis -> experimentalFeatures.RedundantParensAnalysis.Value | ExperimentalFeature.TryRecoverFcsProjects -> experimentalFeatures.TryRecoverFcsProjects.Value + | ExperimentalFeature.GenerateSignatureFile -> experimentalFeatures.GenerateSignatureFile.Value | _ -> failwith $"Unexpected feature: {feature}" [] 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 46c94eff22..5ca0e5581e 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj @@ -26,6 +26,7 @@ + diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs new file mode 100644 index 0000000000..e6683249b8 --- /dev/null +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs @@ -0,0 +1,100 @@ +namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions + +open System.IO +open JetBrains.ReSharper.Feature.Services.ContextActions +open JetBrains.ReSharper.Plugins.FSharp.Psi +open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Intentions +open type JetBrains.ReSharper.Psi.PsiSourceFileExtensions +open JetBrains.ReSharper.Plugins.FSharp +open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree +open JetBrains.ReSharper.Psi +open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree + +type TopLevelModuleOrNamespace = + { + IsModule: bool + Name: string + NestedModules: NestedModule list + } + +and NestedModule = + { + Name: string + NestedModules: NestedModule list + } + +[] +type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) = + inherit FSharpContextActionBase(dataProvider) + + let mkSignatureFile (fsharpFile: IFSharpFile) : IFSharpFile = + let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory() + let signatureFile : IFSharpFile = factory.CreateEmptyFile() + + let rec processModuleMembers (parent: IFSharpTreeNode) (members: IModuleMember seq) = + for m in members do + match m with + | :? INestedModuleDeclaration as nmd -> + let nestedModuleNode = factory.CreateNestedModule(nmd.NameIdentifier.Name) + // TODO: if the nested module has nested modules, clear the content (`begin end`) and process them. + ModificationUtil.AddChild(parent, nestedModuleNode) |> ignore + | _ -> () + + for decl in fsharpFile.ModuleDeclarations do + match decl with + | :? INamedModuleDeclaration as nmd -> + let moduleNode = factory.CreateModule(nmd.NameIdentifier.Name) + processModuleMembers moduleNode nmd.Members + ModificationUtil.AddChild(signatureFile, moduleNode) |> ignore + | :? INamedNamespaceDeclaration as nnd -> + let namespaceNode = factory.CreateModule(nnd.NameIdentifier.Name) + processModuleMembers namespaceNode nnd.Members + ModificationUtil.AddChild(signatureFile, namespaceNode) |> ignore + | _ -> () + + signatureFile + + override this.Text = "Generate signature file for current file" + + override this.IsAvailable _ = + let solution = dataProvider.Solution + let isSettingEnabled = solution.IsFSharpExperimentalFeatureEnabled(ExperimentalFeature.GenerateSignatureFile) + if not isSettingEnabled then false else + let currentFSharpFile = dataProvider.PsiFile + let fcsService = currentFSharpFile.FcsCheckerService + let hasSignature = fcsService.FcsProjectProvider.HasPairFile dataProvider.SourceFile + not hasSignature + + override this.ExecutePsiTransaction(solution, _) = + let projectFile = dataProvider.SourceFile.ToProjectFile() + let fsharpFile = projectFile.GetPrimaryPsiFile().AsFSharpFile() + let physicalPath = dataProvider.SourceFile.ToProjectFile().Location.FileAccessPath + let fsiFile = Path.ChangeExtension(physicalPath, ".fsi") + + let signatureFile = mkSignatureFile fsharpFile + // try + // let currentFSharpFile = dataProvider.PsiFile + // let fcsService = currentFSharpFile.FcsCheckerService + // let checkResult = fcsService.ParseAndCheckFile(currentFSharpFile.GetSourceFile(), "for signature file", true) + // do + // match checkResult with + // | None -> () + // | Some { CheckResults = checkResult } -> + // + // match checkResult.GenerateSignature() with + // | None -> () + // | Some signatureSourceText -> + // let content = string signatureSourceText + // File.WriteAllText(fsiFile, content) + // with ex -> + // // TODO: show some balloon thing? + // () + + // solution.InvokeUnderTransaction(fun transactionCookie -> + // let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() + // let relativeTo = RelativeTo(projectFile, RelativeToType.Before) + // transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) + // |> ignore) + + null \ No newline at end of file From db546ce984ebc2a2eecfc5dabd55dddf6e7a129e Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 14 Feb 2023 16:50:59 +0100 Subject: [PATCH 41/75] After pair programming session. --- .../src/Parsing/FSharpImplTreeBuilder.fs | 11 +- .../Intentions/GenerateSignatureFileAction.fs | 117 +++++++++--------- .../src/Tree/IModuleLikeDeclaration.cs | 3 + 3 files changed, 71 insertions(+), 60 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpImplTreeBuilder.fs b/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpImplTreeBuilder.fs index 8a67570b13..c4a47c64bc 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpImplTreeBuilder.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpImplTreeBuilder.fs @@ -35,11 +35,11 @@ type FSharpImplTreeBuilder(lexer, document, decls, lifetime, path, projectedOffs let (SynModuleOrNamespace(lid, _, moduleKind, decls, XmlDoc xmlDoc, attrs, _, range, _)) = moduleOrNamespace let mark, elementType = x.StartTopLevelDeclaration(lid, attrs, moduleKind, xmlDoc, range) for decl in decls do - x.ProcessModuleMemberDeclaration(decl) + x.ProcessModuleMemberDeclaration(decl, moduleOrNamespace.Range) x.EnsureMembersAreFinished() x.FinishTopLevelDeclaration(mark, range, elementType) - member x.ProcessModuleMemberDeclaration(moduleMember) = + member x.ProcessModuleMemberDeclaration(moduleMember, parentRange) = match unfinishedDeclaration with | None -> () | Some(mark, range, elementType) -> @@ -53,7 +53,12 @@ type FSharpImplTreeBuilder(lexer, document, decls, lifetime, path, projectedOffs | SynModuleDecl.NestedModule(SynComponentInfo(attrs, _, _, _, XmlDoc xmlDoc, _, _, _), _, decls, _, range, _) -> let mark = x.MarkAndProcessIntro(attrs, xmlDoc, null, range) for decl in decls do - x.ProcessModuleMemberDeclaration(decl) + x.ProcessModuleMemberDeclaration(decl, parentRange) + + if decls.IsEmpty then + x.AdvanceToTokenOrRangeEnd(FSharpTokenType.END, parentRange) + x.Advance() + x.Done(range, mark, ElementType.NESTED_MODULE_DECLARATION) | SynModuleDecl.Types(typeDefns, range) -> diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs index e6683249b8..37a71d2aee 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs @@ -1,57 +1,72 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions open System.IO +open JetBrains.ReSharper.Psi.Tree +open JetBrains.DocumentManagers.Transactions.ProjectHostActions.Ordering +open JetBrains.ProjectModel.ProjectsHost +open JetBrains.RdBackend.Common.Features.ProjectModel open JetBrains.ReSharper.Feature.Services.ContextActions open JetBrains.ReSharper.Plugins.FSharp.Psi open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Intentions -open type JetBrains.ReSharper.Psi.PsiSourceFileExtensions open JetBrains.ReSharper.Plugins.FSharp +open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree open JetBrains.ReSharper.Psi open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree -type TopLevelModuleOrNamespace = - { - IsModule: bool - Name: string - NestedModules: NestedModule list - } - -and NestedModule = - { - Name: string - NestedModules: NestedModule list - } +// extract value -> ctrl alt v +// undo that -> ctrl alt n [] type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) = inherit FSharpContextActionBase(dataProvider) - + let mkSignatureFile (fsharpFile: IFSharpFile) : IFSharpFile = let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory() let signatureFile : IFSharpFile = factory.CreateEmptyFile() - - let rec processModuleMembers (parent: IFSharpTreeNode) (members: IModuleMember seq) = - for m in members do - match m with - | :? INestedModuleDeclaration as nmd -> - let nestedModuleNode = factory.CreateNestedModule(nmd.NameIdentifier.Name) - // TODO: if the nested module has nested modules, clear the content (`begin end`) and process them. - ModificationUtil.AddChild(parent, nestedModuleNode) |> ignore - | _ -> () + let lineEnding = fsharpFile.GetLineEnding() + + let rec processModuleLikeDeclaration (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleSig: IModuleLikeDeclaration) : IFSharpTreeNode = + for moduleMember in moduleDecl.Members do + // newline + indentation whitespace + addNodesAfter moduleSig.LastChild [ + NewLine(lineEnding) + Whitespace(indentation) + match moduleMember with + | :? INestedModuleDeclaration as nestedNestedModule -> + let nestedSigModule = factory.CreateNestedModule(nestedNestedModule.NameIdentifier.Name) + let members = nestedNestedModule.Members + let shouldEmptyContent = + not members.IsEmpty + && members |> Seq.forall (function | :? IExpressionStatement -> false | _ -> true) + + if shouldEmptyContent then + ModificationUtil.DeleteChildRange (nestedSigModule.EqualsToken.NextSibling, nestedSigModule.LastChild) + processModuleLikeDeclaration (indentation + moduleDecl.GetIndentSize()) nestedNestedModule nestedSigModule + | :? IOpenStatement as openStatement -> + openStatement.Copy() + | _ -> () + ] + |> ignore + + moduleSig for decl in fsharpFile.ModuleDeclarations do - match decl with - | :? INamedModuleDeclaration as nmd -> - let moduleNode = factory.CreateModule(nmd.NameIdentifier.Name) - processModuleMembers moduleNode nmd.Members - ModificationUtil.AddChild(signatureFile, moduleNode) |> ignore - | :? INamedNamespaceDeclaration as nnd -> - let namespaceNode = factory.CreateModule(nnd.NameIdentifier.Name) - processModuleMembers namespaceNode nnd.Members - ModificationUtil.AddChild(signatureFile, namespaceNode) |> ignore - | _ -> () + let signatureModule : IModuleLikeDeclaration = + match decl with + | :? INamedModuleDeclaration as nmd -> + factory.CreateModule(nmd.DeclaredElement.GetClrName().FullName) + | :? IGlobalNamespaceDeclaration -> + factory.CreateNamespace("global") :?> _ + | :? INamedNamespaceDeclaration as nnd -> + // TODO: add an interface that could unify named and global namespace. + factory.CreateNamespace(nnd.QualifiedName) :?> _ + | decl -> failwithf $"Unexpected declaration, got: %A{decl}" + + ModificationUtil.AddChildAfter(signatureModule.LastChild, NewLine(lineEnding)) |> ignore + let signatureModule = processModuleLikeDeclaration 0 decl signatureModule + ModificationUtil.AddChild(signatureFile, signatureModule) |> ignore signatureFile @@ -71,30 +86,18 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) let fsharpFile = projectFile.GetPrimaryPsiFile().AsFSharpFile() let physicalPath = dataProvider.SourceFile.ToProjectFile().Location.FileAccessPath let fsiFile = Path.ChangeExtension(physicalPath, ".fsi") - let signatureFile = mkSignatureFile fsharpFile - // try - // let currentFSharpFile = dataProvider.PsiFile - // let fcsService = currentFSharpFile.FcsCheckerService - // let checkResult = fcsService.ParseAndCheckFile(currentFSharpFile.GetSourceFile(), "for signature file", true) - // do - // match checkResult with - // | None -> () - // | Some { CheckResults = checkResult } -> - // - // match checkResult.GenerateSignature() with - // | None -> () - // | Some signatureSourceText -> - // let content = string signatureSourceText - // File.WriteAllText(fsiFile, content) - // with ex -> - // // TODO: show some balloon thing? - // () + File.WriteAllText(fsiFile, signatureFile.GetText()) - // solution.InvokeUnderTransaction(fun transactionCookie -> - // let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() - // let relativeTo = RelativeTo(projectFile, RelativeToType.Before) - // transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) - // |> ignore) + solution.InvokeUnderTransaction(fun transactionCookie -> + let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() + let relativeTo = RelativeTo(projectFile, RelativeToType.Before) + transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) + |> ignore) - null \ No newline at end of file + // TODO: it would be nice if we opened the signature file that was just created. Maybe split? + null + + // First test name would be: ``ModuleStructure 01`` , ``NamespaceStructure 01`` + + // TODO: raise parser issue. \ No newline at end of file diff --git a/ReSharper.FSharp/src/FSharp.Psi/src/Tree/IModuleLikeDeclaration.cs b/ReSharper.FSharp/src/FSharp.Psi/src/Tree/IModuleLikeDeclaration.cs index aa50cf9132..ab8a0cf791 100644 --- a/ReSharper.FSharp/src/FSharp.Psi/src/Tree/IModuleLikeDeclaration.cs +++ b/ReSharper.FSharp/src/FSharp.Psi/src/Tree/IModuleLikeDeclaration.cs @@ -1,5 +1,8 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Tree { + // TODO: add triple slash comment. + // this is either a namespace,module or nested module, global namespace, anon module + // see inherits! (ctrl alt b) public partial interface IModuleLikeDeclaration : IFSharpDeclaration { } From 7bb4e8b363217ba816d59e93bbc9c87a83e5b909 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 15 Feb 2023 13:56:42 +0100 Subject: [PATCH 42/75] Open signature file after generation. --- .../Intentions/GenerateSignatureFileAction.fs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs index 37a71d2aee..86ef31300f 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs @@ -1,6 +1,8 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions open System.IO +open JetBrains.Application.UI.PopupLayout +open JetBrains.ReSharper.Feature.Services.Navigation open JetBrains.ReSharper.Psi.Tree open JetBrains.DocumentManagers.Transactions.ProjectHostActions.Ordering open JetBrains.ProjectModel.ProjectsHost @@ -13,6 +15,7 @@ open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree open JetBrains.ReSharper.Psi open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree +open JetBrains.ReSharper.Resources.Shell // extract value -> ctrl alt v // undo that -> ctrl alt n @@ -92,10 +95,19 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) solution.InvokeUnderTransaction(fun transactionCookie -> let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() let relativeTo = RelativeTo(projectFile, RelativeToType.Before) - transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) - |> ignore) + let projectFile = transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) + + if (not Shell.Instance.IsTestShell) then + let navigationOptions = NavigationOptions.FromWindowContext(Shell.Instance.GetComponent().Source, "") + NavigationManager + .GetInstance(solution) + .Navigate( + ProjectFileNavigationPoint(projectFile), + navigationOptions + ) + |> ignore + ) - // TODO: it would be nice if we opened the signature file that was just created. Maybe split? null // First test name would be: ``ModuleStructure 01`` , ``NamespaceStructure 01`` From 7bf8314334bd4b7af95342814a2a33e956c8556e Mon Sep 17 00:00:00 2001 From: nojaf Date: Tue, 28 Feb 2023 11:03:47 +0100 Subject: [PATCH 43/75] Right after pair programming session. --- .../src/Parsing/FSharpParser.fs | 6 +- .../Intentions/GenerateSignatureFileAction.fs | 161 +++++++++++++++--- .../src/FSharpTreeNodeExtensions.cs | 4 +- .../ModuleStructure - 01.fs | 5 + .../ModuleStructure - 01.fs.gold | 5 + .../ModuleStructure - 01.fsi.gold | 3 + .../FSharp.Intentions.Tests.fsproj | 1 + .../Intentions/GenerateSignatureFileTest.fs | 17 ++ 8 files changed, 174 insertions(+), 28 deletions(-) create mode 100644 ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs create mode 100644 ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fsi.gold create mode 100644 ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs diff --git a/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpParser.fs b/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpParser.fs index f51260b1ee..b94f1ab1e8 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpParser.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Features/src/Parsing/FSharpParser.fs @@ -56,6 +56,9 @@ type FSharpParser(lexer: ILexer, document: IDocument, path: VirtualFileSystemPat ResolvedSymbolsCache = symbolsCache, LanguageType = language) + static member val SandBoxPath = VirtualFileSystemPath.Parse("Sandbox.fs", InteractionContext.SolutionContext) + static member val SandBoxSignaturePath = VirtualFileSystemPath.Parse("Sandbox.fsi", InteractionContext.SolutionContext) + new (lexer, [] sourceFile: IPsiSourceFile, checkerService, symbolsCache) = // During rename of type + file the source file returns the new path, // but the parsing/project options still have the old one. It doesn't seem to affect anything. @@ -75,9 +78,6 @@ type FSharpParser(lexer: ILexer, document: IDocument, path: VirtualFileSystemPat FSharpParser(lexer, document, path, sourceFile, checkerService, symbolsCache) - static member val SandBoxPath = VirtualFileSystemPath.Parse("Sandbox.fs", InteractionContext.SolutionContext) - static member val SandBoxSignaturePath = VirtualFileSystemPath.Parse("Sandbox.fsi", InteractionContext.SolutionContext) - interface IFSharpParser with member this.ParseFSharpFile(noCache) = parseFile noCache member this.ParseFile() = parseFile false :> _ diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs index 86ef31300f..2e947306bc 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs @@ -1,8 +1,13 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions open System.IO +open System.Linq +open System.Text +open FSharp.Compiler.Symbols open JetBrains.Application.UI.PopupLayout open JetBrains.ReSharper.Feature.Services.Navigation +open JetBrains.ReSharper.Plugins.FSharp.Psi.Parsing +open JetBrains.ReSharper.Psi.Naming open JetBrains.ReSharper.Psi.Tree open JetBrains.DocumentManagers.Transactions.ProjectHostActions.Ordering open JetBrains.ProjectModel.ProjectsHost @@ -20,41 +25,150 @@ open JetBrains.ReSharper.Resources.Shell // extract value -> ctrl alt v // undo that -> ctrl alt n +// TODO: what about attributes, type parameters, delegates, exceptions + +// FSharpTokenType.AND.CreateLeafElement() + [] type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) = inherit FSharpContextActionBase(dataProvider) let mkSignatureFile (fsharpFile: IFSharpFile) : IFSharpFile = - let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory() + let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory(extension = FSharpSignatureProjectFileType.FsiExtension) let signatureFile : IFSharpFile = factory.CreateEmptyFile() let lineEnding = fsharpFile.GetLineEnding() + let getName (decl: IFSharpDeclaration) = NamingManager.GetNamingLanguageService(fsharpFile.Language).MangleNameIfNecessary(decl.SourceName) + + let rec createModuleMemberSig (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleMember: IModuleMember) : IFSharpTreeNode = + match moduleMember with + | :? ITypeDeclarationGroup as typeGroup -> + let sigTypeDeclGroups = + // TODO: Update type into and keyword for second IFSharpTypeDeclaration in a group. + + typeGroup.TypeDeclarations + |> Seq.choose (function + | :? IFSharpTypeDeclaration as typeDecl -> + // TODO: update and keyword + (* + ModificationUtil.ReplaceChild( + sigTypeGroup.TypeDeclarations.[1].TypeKeyword, + (FSharpTokenType.AND.CreateLeafElement())) + *) + + // Resharper implementation + //typeDecl.MemberDeclarations + + // Untyped tree like + // typeDecl.TypeMembers + let sigMembers = + typeDecl.TypeMembers + |> Seq.choose (createMemberDeclaration >> Option.ofObj) + + match typeDecl.TypeRepresentation with + // TODO: checkout delegates + | :? ITypeAbbreviationRepresentation as abbr -> + let sigTypeGroup = factory.CreateModuleMember($"type {getName typeDecl} = int") + match sigTypeGroup with + | :? ITypeDeclarationGroup as sigTypeGroup -> + let sigDecl = sigTypeGroup.TypeDeclarations.[0] :?> IFSharpTypeDeclaration + + + + ModificationUtil.DeleteChildRange(sigDecl.EqualsToken.NextSibling, sigDecl.LastChild) + addNodesAfter sigDecl.EqualsToken [ + Whitespace() + abbr.Copy() + ] + |> ignore + Some sigTypeGroup + | _ -> None + | :? ISimpleTypeRepresentation as repr -> + let sigTypeGroup = factory.CreateModuleMember($"type {getName typeDecl} = int") + match sigTypeGroup with + | :? ITypeDeclarationGroup as sigTypeGroup -> + let sigDecl = sigTypeGroup.TypeDeclarations.[0] :?> IFSharpTypeDeclaration + ModificationUtil.DeleteChildRange(sigDecl.EqualsToken.NextSibling, sigDecl.LastChild) + addNodesAfter sigDecl.EqualsToken [ + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + repr.Copy() + for sigMember in sigMembers do + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + sigMember + ] + |> ignore + Some sigTypeGroup + | _ -> None + | _ -> None + + + + | _ -> None) // TODO: address this + + sigTypeDeclGroups.FirstOrDefault() + // TODO : ITypeExtensionDeclaration + + | :? INestedModuleDeclaration as nestedNestedModule -> + let nestedSigModule = factory.CreateNestedModule(nestedNestedModule.NameIdentifier.Name) + let members = nestedNestedModule.Members + let shouldEmptyContent = + not members.IsEmpty + && members |> Seq.forall (function | :? IExpressionStatement -> false | _ -> true) + + if shouldEmptyContent then + ModificationUtil.DeleteChildRange (nestedSigModule.EqualsToken.NextSibling, nestedSigModule.LastChild) + processModuleLikeDeclaration (indentation + moduleDecl.GetIndentSize()) nestedNestedModule nestedSigModule + | :? IOpenStatement as openStatement -> + openStatement.Copy() + | _ -> null - let rec processModuleLikeDeclaration (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleSig: IModuleLikeDeclaration) : IFSharpTreeNode = + and processModuleLikeDeclaration (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleSig: IModuleLikeDeclaration) : IFSharpTreeNode = for moduleMember in moduleDecl.Members do - // newline + indentation whitespace - addNodesAfter moduleSig.LastChild [ - NewLine(lineEnding) - Whitespace(indentation) - match moduleMember with - | :? INestedModuleDeclaration as nestedNestedModule -> - let nestedSigModule = factory.CreateNestedModule(nestedNestedModule.NameIdentifier.Name) - let members = nestedNestedModule.Members - let shouldEmptyContent = - not members.IsEmpty - && members |> Seq.forall (function | :? IExpressionStatement -> false | _ -> true) - - if shouldEmptyContent then - ModificationUtil.DeleteChildRange (nestedSigModule.EqualsToken.NextSibling, nestedSigModule.LastChild) - processModuleLikeDeclaration (indentation + moduleDecl.GetIndentSize()) nestedNestedModule nestedSigModule - | :? IOpenStatement as openStatement -> - openStatement.Copy() - | _ -> () - ] - |> ignore + let signatureMember = createModuleMemberSig indentation moduleDecl moduleMember + + if isNotNull signatureMember then + // newline + indentation whitespace + addNodesAfter moduleSig.LastChild [ + NewLine(lineEnding) + Whitespace(indentation) + signatureMember + ] + |> ignore moduleSig - + + and createMemberDeclaration (memberDecl: IFSharpTypeMemberDeclaration) : IFSharpTypeMemberDeclaration = + match memberDecl with + | :? IMemberDeclaration as memberDecl -> + let sourceString = + let sb = StringBuilder() + + if memberDecl.IsStatic then + sb.Append("static ") |> ignore + + sb.Append(memberDecl.MemberKeyword.GetText()) |> ignore + sb.Append(" ") |> ignore + + if isNotNull memberDecl.AccessModifier then + sb.Append(memberDecl.AccessModifier.GetText()) |> ignore + + sb.Append(getName memberDecl) |> ignore + sb.Append(": ") |> ignore + + let symbolUse = memberDecl.GetFcsSymbolUse() + if isNotNull symbolUse then + let mfv = symbolUse.Symbol.As() + if isNotNull mfv then + sb.Append(mfv.FullType.Format(symbolUse.DisplayContext)) |> ignore + + sb.ToString() + + factory.CreateTypeMemberSignature(sourceString) + | _ -> null + + for decl in fsharpFile.ModuleDeclarations do let signatureModule : IModuleLikeDeclaration = match decl with @@ -81,6 +195,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) if not isSettingEnabled then false else let currentFSharpFile = dataProvider.PsiFile let fcsService = currentFSharpFile.FcsCheckerService + // TODO: don't check has pair in unit test let hasSignature = fcsService.FcsProjectProvider.HasPairFile dataProvider.SourceFile not hasSignature diff --git a/ReSharper.FSharp/src/FSharp.Psi/src/FSharpTreeNodeExtensions.cs b/ReSharper.FSharp/src/FSharp.Psi/src/FSharpTreeNodeExtensions.cs index 585b1e23d7..34611e21b6 100644 --- a/ReSharper.FSharp/src/FSharp.Psi/src/FSharpTreeNodeExtensions.cs +++ b/ReSharper.FSharp/src/FSharp.Psi/src/FSharpTreeNodeExtensions.cs @@ -12,8 +12,8 @@ public static IFSharpLanguageService GetFSharpLanguageService([NotNull] this ITr treeNode.GetPsiServices().GetComponent().GetService(treeNode.Language); [NotNull] - public static IFSharpElementFactory CreateElementFactory([NotNull] this ITreeNode treeNode) => - treeNode.GetFSharpLanguageService().CreateElementFactory(treeNode.GetSourceFile(), treeNode.GetPsiModule()); + public static IFSharpElementFactory CreateElementFactory([NotNull] this ITreeNode treeNode, string extension = null) => + treeNode.GetFSharpLanguageService().CreateElementFactory(treeNode.GetSourceFile(), treeNode.GetPsiModule(), extension); public static bool IsFSharpSigFile([NotNull] this ITreeNode treeNode) => treeNode.GetContainingFile() is IFSharpSigFile; diff --git a/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs b/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs new file mode 100644 index 0000000000..aaf1dee7fb --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs @@ -0,0 +1,5 @@ +module Foo + +open System +{caret} +let a = 0 diff --git a/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs.gold b/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs.gold new file mode 100644 index 0000000000..aaf1dee7fb --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fs.gold @@ -0,0 +1,5 @@ +module Foo + +open System +{caret} +let a = 0 diff --git a/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fsi.gold b/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fsi.gold new file mode 100644 index 0000000000..af8e7ed833 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/intentions/generateSignatureFile/ModuleStructure - 01.fsi.gold @@ -0,0 +1,3 @@ +module Test + +open System 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 64e68cb7f0..967df98f30 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 @@ -49,6 +49,7 @@ + diff --git a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs new file mode 100644 index 0000000000..26b60d59ba --- /dev/null +++ b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs @@ -0,0 +1,17 @@ +namespace JetBrains.ReSharper.Plugins.FSharp.Tests.Intentions.Intentions + +open System.Linq +open JetBrains.ProjectModel +open JetBrains.ReSharper.FeaturesTestFramework.Refactorings +open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions +open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Intentions +open JetBrains.ReSharper.Plugins.FSharp.Services.Formatter +open JetBrains.ReSharper.TestFramework +open NUnit.Framework + +type GenerateSignatureFileTest() = + inherit FSharpContextActionExecuteTestBase() + + override this.ExtraPath = "generateSignatureFile" + + // [] member x.``ModuleStructure - 01`` () = x.DoNamedTestWithSignature() \ No newline at end of file From 1888eaa4dd7c512fa6f7bbdbc335fe9bb5f1f436 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 1 Mar 2023 10:45:41 +0100 Subject: [PATCH 44/75] Refactor TypeDeclarationGroup grouping. Take care of the and keyword. --- .../Intentions/GenerateSignatureFileAction.fs | 139 ++++++++---------- 1 file changed, 63 insertions(+), 76 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs index 2e947306bc..baf3f48160 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs @@ -1,12 +1,10 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions open System.IO -open System.Linq open System.Text open FSharp.Compiler.Symbols open JetBrains.Application.UI.PopupLayout open JetBrains.ReSharper.Feature.Services.Navigation -open JetBrains.ReSharper.Plugins.FSharp.Psi.Parsing open JetBrains.ReSharper.Psi.Naming open JetBrains.ReSharper.Psi.Tree open JetBrains.DocumentManagers.Transactions.ProjectHostActions.Ordering @@ -34,7 +32,7 @@ open JetBrains.ReSharper.Resources.Shell type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) = inherit FSharpContextActionBase(dataProvider) - let mkSignatureFile (fsharpFile: IFSharpFile) : IFSharpFile = + let mkSignatureFile (fsharpFile: IFSharpFile): IFSharpFile = let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory(extension = FSharpSignatureProjectFileType.FsiExtension) let signatureFile : IFSharpFile = factory.CreateEmptyFile() let lineEnding = fsharpFile.GetLineEnding() @@ -43,72 +41,62 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) let rec createModuleMemberSig (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleMember: IModuleMember) : IFSharpTreeNode = match moduleMember with | :? ITypeDeclarationGroup as typeGroup -> - let sigTypeDeclGroups = - // TODO: Update type into and keyword for second IFSharpTypeDeclaration in a group. - + // Filter out the IFSharpTypeDeclaration where we support the TypeRepresentation for now. + let supportedTypeDeclarations = typeGroup.TypeDeclarations |> Seq.choose (function | :? IFSharpTypeDeclaration as typeDecl -> - // TODO: update and keyword - (* - ModificationUtil.ReplaceChild( - sigTypeGroup.TypeDeclarations.[1].TypeKeyword, - (FSharpTokenType.AND.CreateLeafElement())) - *) - - // Resharper implementation - //typeDecl.MemberDeclarations - - // Untyped tree like - // typeDecl.TypeMembers - let sigMembers = - typeDecl.TypeMembers - |> Seq.choose (createMemberDeclaration >> Option.ofObj) - match typeDecl.TypeRepresentation with - // TODO: checkout delegates - | :? ITypeAbbreviationRepresentation as abbr -> - let sigTypeGroup = factory.CreateModuleMember($"type {getName typeDecl} = int") - match sigTypeGroup with - | :? ITypeDeclarationGroup as sigTypeGroup -> - let sigDecl = sigTypeGroup.TypeDeclarations.[0] :?> IFSharpTypeDeclaration - - - - ModificationUtil.DeleteChildRange(sigDecl.EqualsToken.NextSibling, sigDecl.LastChild) - addNodesAfter sigDecl.EqualsToken [ - Whitespace() - abbr.Copy() - ] - |> ignore - Some sigTypeGroup - | _ -> None - | :? ISimpleTypeRepresentation as repr -> - let sigTypeGroup = factory.CreateModuleMember($"type {getName typeDecl} = int") - match sigTypeGroup with - | :? ITypeDeclarationGroup as sigTypeGroup -> - let sigDecl = sigTypeGroup.TypeDeclarations.[0] :?> IFSharpTypeDeclaration - ModificationUtil.DeleteChildRange(sigDecl.EqualsToken.NextSibling, sigDecl.LastChild) - addNodesAfter sigDecl.EqualsToken [ - NewLine(lineEnding) - Whitespace(indentation + moduleDecl.GetIndentSize()) - repr.Copy() - for sigMember in sigMembers do - NewLine(lineEnding) - Whitespace(indentation + moduleDecl.GetIndentSize()) - sigMember - ] - |> ignore - Some sigTypeGroup - | _ -> None + | :? ITypeAbbreviationRepresentation + | :? ISimpleTypeRepresentation -> Some typeDecl | _ -> None - - - - | _ -> None) // TODO: address this - - sigTypeDeclGroups.FirstOrDefault() - // TODO : ITypeExtensionDeclaration + | _ -> None) + |> Seq.mapi (fun idx typeDecl -> + let kw = if idx = 0 then "type" else "and" + {| SignatureIdx = idx ; TypeDeclaration = typeDecl; SourceText = $"{kw} {getName typeDecl} = int" |}) + |> Seq.toArray + + if Array.isEmpty supportedTypeDeclarations then null else + + let sourceText = supportedTypeDeclarations |> Array.map (fun info -> info.SourceText) |> String.concat "\n" + let sigTypeDeclarationGroup = factory.CreateModuleMember(sourceText) :?> ITypeDeclarationGroup + + if isNull sigTypeDeclarationGroup then null else + + for info in supportedTypeDeclarations do + let typeDecl: IFSharpTypeDeclaration = info.TypeDeclaration + let sigTypeDecl = sigTypeDeclarationGroup.TypeDeclarations.[info.SignatureIdx] :?> IFSharpTypeDeclaration + if isNull sigTypeDecl then () else + + let sigMembers = + typeDecl.TypeMembers + |> Seq.choose (createMemberDeclaration >> Option.ofObj) + + match typeDecl.TypeRepresentation with + | :? ITypeAbbreviationRepresentation as abbr -> + ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) + addNodesAfter sigTypeDecl.EqualsToken [ + Whitespace() + abbr.Copy() + // TODO: there technically could be members here. + // Although I think this would need the `with` keyword. + ] |> ignore + | :? ISimpleTypeRepresentation as repr -> + ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) + addNodesAfter sigTypeDecl.EqualsToken [ + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + repr.Copy() + for sigMember in sigMembers do + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + sigMember + ] |> ignore + | repr -> + // This pattern match should match the types we filtered out earlier for supportedTypeDeclarations + failwith $"Unexpected representation {repr.GetType()}" + + sigTypeDeclarationGroup | :? INestedModuleDeclaration as nestedNestedModule -> let nestedSigModule = factory.CreateNestedModule(nestedNestedModule.NameIdentifier.Name) @@ -127,7 +115,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) and processModuleLikeDeclaration (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleSig: IModuleLikeDeclaration) : IFSharpTreeNode = for moduleMember in moduleDecl.Members do let signatureMember = createModuleMemberSig indentation moduleDecl moduleMember - + if isNotNull signatureMember then // newline + indentation whitespace addNodesAfter moduleSig.LastChild [ @@ -155,19 +143,18 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) sb.Append(memberDecl.AccessModifier.GetText()) |> ignore sb.Append(getName memberDecl) |> ignore - sb.Append(": ") |> ignore - + sb.Append(": ") |> ignore + let symbolUse = memberDecl.GetFcsSymbolUse() if isNotNull symbolUse then let mfv = symbolUse.Symbol.As() if isNotNull mfv then sb.Append(mfv.FullType.Format(symbolUse.DisplayContext)) |> ignore - + sb.ToString() factory.CreateTypeMemberSignature(sourceString) | _ -> null - for decl in fsharpFile.ModuleDeclarations do let signatureModule : IModuleLikeDeclaration = @@ -182,13 +169,13 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) | decl -> failwithf $"Unexpected declaration, got: %A{decl}" ModificationUtil.AddChildAfter(signatureModule.LastChild, NewLine(lineEnding)) |> ignore - let signatureModule = processModuleLikeDeclaration 0 decl signatureModule + let signatureModule = processModuleLikeDeclaration 0 decl signatureModule ModificationUtil.AddChild(signatureFile, signatureModule) |> ignore signatureFile override this.Text = "Generate signature file for current file" - + override this.IsAvailable _ = let solution = dataProvider.Solution let isSettingEnabled = solution.IsFSharpExperimentalFeatureEnabled(ExperimentalFeature.GenerateSignatureFile) @@ -198,7 +185,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) // TODO: don't check has pair in unit test let hasSignature = fcsService.FcsProjectProvider.HasPairFile dataProvider.SourceFile not hasSignature - + override this.ExecutePsiTransaction(solution, _) = let projectFile = dataProvider.SourceFile.ToProjectFile() let fsharpFile = projectFile.GetPrimaryPsiFile().AsFSharpFile() @@ -211,7 +198,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() let relativeTo = RelativeTo(projectFile, RelativeToType.Before) let projectFile = transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) - + if (not Shell.Instance.IsTestShell) then let navigationOptions = NavigationOptions.FromWindowContext(Shell.Instance.GetComponent().Source, "") NavigationManager @@ -224,7 +211,7 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) ) null - + // First test name would be: ``ModuleStructure 01`` , ``NamespaceStructure 01`` - - // TODO: raise parser issue. \ No newline at end of file + + // TODO: raise parser issue. From 2981c928a8f9d497f0ae2a694bd755e8c0817ae1 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 3 Apr 2023 09:06:28 +0200 Subject: [PATCH 45/75] Migrate code to FSharpGenerateSignatureProvider --- .../FSharp.Psi.Intentions.fsproj | 1 - .../FSharp.Psi.Services.fsproj | 1 + .../src/Generate/FSharpGeneratorContext.fs | 2 +- .../Generate/GenerateSignatureProvider.fs} | 124 ++++++++++++------ .../generate/signatureFiles/Sample Test.fs | 6 + .../Intentions/GenerateSignatureFileTest.fs | 8 +- .../test/src/FSharp.Tests/FSharp.Tests.fsproj | 1 + .../Generate/FsharpGenerateSignatureTest.fs | 13 ++ 8 files changed, 110 insertions(+), 46 deletions(-) rename ReSharper.FSharp/src/{FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs => FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs} (71%) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Sample Test.fs create mode 100644 ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.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 5ca0e5581e..46c94eff22 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj +++ b/ReSharper.FSharp/src/FSharp.Psi.Intentions/FSharp.Psi.Intentions.fsproj @@ -26,7 +26,6 @@ - diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/FSharp.Psi.Services.fsproj b/ReSharper.FSharp/src/FSharp.Psi.Services/FSharp.Psi.Services.fsproj index d695266268..271dc3d9cf 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/FSharp.Psi.Services.fsproj +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/FSharp.Psi.Services.fsproj @@ -64,6 +64,7 @@ + diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/FSharpGeneratorContext.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/FSharpGeneratorContext.fs index 136dcf41ff..270763f009 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/FSharpGeneratorContext.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/FSharpGeneratorContext.fs @@ -26,7 +26,7 @@ type FSharpGeneratorContext(kind, [] treeNode: ITreeNode, [] override x.Language = FSharpLanguage.Instance :> _ - override x.Root = typeDecl :> _ + override x.Root = treeNode override val Anchor = null with get, set override x.PsiModule = treeNode.GetPsiModule() diff --git a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs similarity index 71% rename from ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs rename to ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index baf3f48160..67e5e18feb 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Intentions/src/Intentions/GenerateSignatureFileAction.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -1,37 +1,61 @@ -namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions +namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features -open System.IO open System.Text open FSharp.Compiler.Symbols +open JetBrains.ReSharper.Feature.Services.Generate +open JetBrains.ReSharper.Feature.Services.Generate.Workflows +open JetBrains.ReSharper.Plugins.FSharp.Psi +open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Generate +open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree +open JetBrains.ReSharper.Psi.Transactions +open JetBrains.ReSharper.Psi.Tree +open JetBrains.ReSharper.Plugins.FSharp +open System.IO open JetBrains.Application.UI.PopupLayout open JetBrains.ReSharper.Feature.Services.Navigation -open JetBrains.ReSharper.Psi.Naming -open JetBrains.ReSharper.Psi.Tree open JetBrains.DocumentManagers.Transactions.ProjectHostActions.Ordering open JetBrains.ProjectModel.ProjectsHost open JetBrains.RdBackend.Common.Features.ProjectModel -open JetBrains.ReSharper.Feature.Services.ContextActions -open JetBrains.ReSharper.Plugins.FSharp.Psi -open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Intentions -open JetBrains.ReSharper.Plugins.FSharp -open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree -open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree open JetBrains.ReSharper.Psi -open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree open JetBrains.ReSharper.Resources.Shell +open JetBrains.ReSharper.Feature.Services.Generate.Actions +open JetBrains.ReSharper.Feature.Services.Resources +open JetBrains.ReSharper.Psi.Naming +open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree +open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree -// extract value -> ctrl alt v -// undo that -> ctrl alt n - -// TODO: what about attributes, type parameters, delegates, exceptions - -// FSharpTokenType.AND.CreateLeafElement() - -[] -type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) = - inherit FSharpContextActionBase(dataProvider) - +module FSharpGeneratorKinds = + let [] SignatureFile = "SignatureFile" + +type FSharpGeneratorSignatureElement(fsFile: IFSharpFile) = + inherit GeneratorElementBase() + + override this.GetPresentationObject() = fsFile + override this.Matches(_searchText, matcher) = matcher.Matches(this.TestDescriptor) + override this.TestDescriptor = "Generate signature file title" // fsFile.GetSourceFile().Name + + interface IGeneratorElementPresenter with + member this.InitGeneratorPresenter(presenter) = + presenter.Present(fun value item structureelement state -> + item.RichText <- + // Text seen in the popup of the selectable item. + JetBrains.UI.RichText.RichText(fsFile.GetSourceFile().Name) + item.Images.Add(PsiServicesThemedIcons.HasImplementations.Id)) + +[)>] +type FSharpGenerateSignatureProvider() = + inherit GeneratorProviderBase() + + override this.Populate(context: FSharpGeneratorContext): unit = + let node = context.Root :?> IFSharpTreeNode + context.ProvidedElements.Add(FSharpGeneratorSignatureElement(node.FSharpFile)) + +[)>] +type FSharpGenerateSignatureBuilder() = + inherit GeneratorBuilderBase() + + // TODO: what about attributes, type parameters, delegates, exceptions + let mkSignatureFile (fsharpFile: IFSharpFile): IFSharpFile = let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory(extension = FSharpSignatureProjectFileType.FsiExtension) let signatureFile : IFSharpFile = factory.CreateEmptyFile() @@ -174,26 +198,31 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) signatureFile - override this.Text = "Generate signature file for current file" - - override this.IsAvailable _ = - let solution = dataProvider.Solution + override this.IsAvailable(context: FSharpGeneratorContext): bool = + let node = context.Root :?> IFSharpTreeNode + let currentFSharpFile = node.FSharpFile + if currentFSharpFile.IsFSharpSigFile() then false else + let solution = node.GetSolution() let isSettingEnabled = solution.IsFSharpExperimentalFeatureEnabled(ExperimentalFeature.GenerateSignatureFile) if not isSettingEnabled then false else - let currentFSharpFile = dataProvider.PsiFile let fcsService = currentFSharpFile.FcsCheckerService // TODO: don't check has pair in unit test - let hasSignature = fcsService.FcsProjectProvider.HasPairFile dataProvider.SourceFile + let hasSignature = fcsService.FcsProjectProvider.HasPairFile (node.GetSourceFile()) not hasSignature - override this.ExecutePsiTransaction(solution, _) = - let projectFile = dataProvider.SourceFile.ToProjectFile() - let fsharpFile = projectFile.GetPrimaryPsiFile().AsFSharpFile() - let physicalPath = dataProvider.SourceFile.ToProjectFile().Location.FileAccessPath + override this.Process(context) = + let node = context.Root :?> IFSharpTreeNode + use writeCookie = WriteLockCookie.Create(node.IsPhysical()) + use transactionCookie = + PsiTransactionCookie.CreateAutoCommitCookieWithCachesUpdate(node.GetPsiServices(), FSharpGeneratorKinds.SignatureFile) + + let currentFSharpFile = node.FSharpFile + let projectFile = node.GetSourceFile().ToProjectFile() + let physicalPath = projectFile.Location.FileAccessPath let fsiFile = Path.ChangeExtension(physicalPath, ".fsi") - let signatureFile = mkSignatureFile fsharpFile + let signatureFile = mkSignatureFile currentFSharpFile File.WriteAllText(fsiFile, signatureFile.GetText()) - + let solution = node.GetSolution() solution.InvokeUnderTransaction(fun transactionCookie -> let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() let relativeTo = RelativeTo(projectFile, RelativeToType.Before) @@ -210,8 +239,23 @@ type GenerateSignatureFileAction(dataProvider: FSharpContextActionDataProvider) |> ignore ) - null - - // First test name would be: ``ModuleStructure 01`` , ``NamespaceStructure 01`` - - // TODO: raise parser issue. +type FSharpGenerateSignatureWorkflow() = + inherit GenerateCodeWorkflowBase( + FSharpGeneratorKinds.SignatureFile, + PsiServicesThemedIcons.Implements.Id, + // Seen in the dropdown menu when alt + insert is pressed. + "Generate signature file", + GenerateActionGroup.CLR_LANGUAGE, + // Title of the window that opens up when the workflow is started. + "Generate signature file", + // Description of the window that opens up when the workflow is started. + $"Generate a signature file for the current file.", + FSharpGeneratorKinds.SignatureFile) + + override this.Order = 10. // See GeneratorStandardOrder.cs + +[] +type FSharpGenerateSignatureWorkflowProvider() = + interface IGenerateImplementationsWorkflowProvider with + member this.CreateWorkflow _ = + [| FSharpGenerateSignatureWorkflow() |] diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Sample Test.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Sample Test.fs new file mode 100644 index 0000000000..7ccec98cb9 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Sample Test.fs @@ -0,0 +1,6 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +open System +{caret} diff --git a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs index 26b60d59ba..6098c5953d 100644 --- a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs @@ -9,9 +9,9 @@ open JetBrains.ReSharper.Plugins.FSharp.Services.Formatter open JetBrains.ReSharper.TestFramework open NUnit.Framework -type GenerateSignatureFileTest() = - inherit FSharpContextActionExecuteTestBase() - - override this.ExtraPath = "generateSignatureFile" +// type GenerateSignatureFileTest() = +// inherit FSharpContextActionExecuteTestBase() +// +// override this.ExtraPath = "generateSignatureFile" // [] member x.``ModuleStructure - 01`` () = x.DoNamedTestWithSignature() \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/FSharp.Tests.fsproj b/ReSharper.FSharp/test/src/FSharp.Tests/FSharp.Tests.fsproj index 9d36e9dfbf..23654b2c41 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/FSharp.Tests.fsproj +++ b/ReSharper.FSharp/test/src/FSharp.Tests/FSharp.Tests.fsproj @@ -32,6 +32,7 @@ + diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs new file mode 100644 index 0000000000..906c3b6bf4 --- /dev/null +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -0,0 +1,13 @@ +namespace JetBrains.ReSharper.Plugins.FSharp.Tests.Features.Generate + +open JetBrains.ReSharper.FeaturesTestFramework.Generate +open JetBrains.ReSharper.Plugins.FSharp +open JetBrains.ReSharper.Plugins.FSharp.Tests +open NUnit.Framework + +[] +type FsharpGenerateSignatureTest() = + inherit GenerateTestBase() + override x.RelativeTestDataPath = "features/generate/signatureFiles" + // override this.DumpTextControl(textControl, dumpCaret, dumpSelection) = + [] member x.``Sample Test`` () = x.DoNamedTest() From 3f9c3d3d189eb680dfadd920621b56a648d5cb3d Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Wed, 19 Apr 2023 14:17:14 +0200 Subject: [PATCH 46/75] Queue the project model transaction after the psi transaction --- .../src/Generate/GenerateSignatureProvider.fs | 51 ++++++++++--------- .../Generate/FsharpGenerateSignatureTest.fs | 19 ++++++- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 67e5e18feb..fc2ffa09e6 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -1,28 +1,28 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Psi.Features +open System.IO open System.Text open FSharp.Compiler.Symbols -open JetBrains.ReSharper.Feature.Services.Generate -open JetBrains.ReSharper.Feature.Services.Generate.Workflows -open JetBrains.ReSharper.Plugins.FSharp.Psi -open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Generate -open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree -open JetBrains.ReSharper.Psi.Transactions -open JetBrains.ReSharper.Psi.Tree -open JetBrains.ReSharper.Plugins.FSharp -open System.IO +open JetBrains.Application.Threading open JetBrains.Application.UI.PopupLayout -open JetBrains.ReSharper.Feature.Services.Navigation open JetBrains.DocumentManagers.Transactions.ProjectHostActions.Ordering open JetBrains.ProjectModel.ProjectsHost open JetBrains.RdBackend.Common.Features.ProjectModel -open JetBrains.ReSharper.Psi -open JetBrains.ReSharper.Resources.Shell +open JetBrains.ReSharper.Feature.Services.Generate open JetBrains.ReSharper.Feature.Services.Generate.Actions +open JetBrains.ReSharper.Feature.Services.Generate.Workflows +open JetBrains.ReSharper.Feature.Services.Navigation open JetBrains.ReSharper.Feature.Services.Resources -open JetBrains.ReSharper.Psi.Naming +open JetBrains.ReSharper.Plugins.FSharp +open JetBrains.ReSharper.Plugins.FSharp.Psi +open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Generate open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree +open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree +open JetBrains.ReSharper.Psi open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree +open JetBrains.ReSharper.Psi.Naming +open JetBrains.ReSharper.Psi.Tree +open JetBrains.ReSharper.Resources.Shell module FSharpGeneratorKinds = let [] SignatureFile = "SignatureFile" @@ -202,9 +202,11 @@ type FSharpGenerateSignatureBuilder() = let node = context.Root :?> IFSharpTreeNode let currentFSharpFile = node.FSharpFile if currentFSharpFile.IsFSharpSigFile() then false else + let solution = node.GetSolution() let isSettingEnabled = solution.IsFSharpExperimentalFeatureEnabled(ExperimentalFeature.GenerateSignatureFile) if not isSettingEnabled then false else + let fcsService = currentFSharpFile.FcsCheckerService // TODO: don't check has pair in unit test let hasSignature = fcsService.FcsProjectProvider.HasPairFile (node.GetSourceFile()) @@ -213,22 +215,22 @@ type FSharpGenerateSignatureBuilder() = override this.Process(context) = let node = context.Root :?> IFSharpTreeNode use writeCookie = WriteLockCookie.Create(node.IsPhysical()) - use transactionCookie = - PsiTransactionCookie.CreateAutoCommitCookieWithCachesUpdate(node.GetPsiServices(), FSharpGeneratorKinds.SignatureFile) - let currentFSharpFile = node.FSharpFile let projectFile = node.GetSourceFile().ToProjectFile() let physicalPath = projectFile.Location.FileAccessPath let fsiFile = Path.ChangeExtension(physicalPath, ".fsi") - let signatureFile = mkSignatureFile currentFSharpFile + let signatureFile = mkSignatureFile node.FSharpFile File.WriteAllText(fsiFile, signatureFile.GetText()) - let solution = node.GetSolution() - solution.InvokeUnderTransaction(fun transactionCookie -> - let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() - let relativeTo = RelativeTo(projectFile, RelativeToType.Before) - let projectFile = transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) - if (not Shell.Instance.IsTestShell) then + let solution = context.Solution + solution.Locks.ExecuteOrQueue(FSharpGeneratorKinds.SignatureFile, fun _ -> + solution.InvokeUnderTransaction(fun transactionCookie -> + let virtualPath = FileSystemPath.TryParse(fsiFile).ToVirtualFileSystemPath() + let relativeTo = RelativeTo(projectFile, RelativeToType.Before) + let projectFile = transactionCookie.AddFile(projectFile.ParentFolder, virtualPath, context = OrderingContext(relativeTo)) + + if Shell.Instance.IsTestShell then () else + let navigationOptions = NavigationOptions.FromWindowContext(Shell.Instance.GetComponent().Source, "") NavigationManager .GetInstance(solution) @@ -237,7 +239,8 @@ type FSharpGenerateSignatureBuilder() = navigationOptions ) |> ignore - ) + ) + ) |> ignore type FSharpGenerateSignatureWorkflow() = inherit GenerateCodeWorkflowBase( diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 906c3b6bf4..aa928ba3f6 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -1,13 +1,30 @@ namespace JetBrains.ReSharper.Plugins.FSharp.Tests.Features.Generate +open JetBrains.Diagnostics +open JetBrains.IDE +open JetBrains.ProjectModel open JetBrains.ReSharper.FeaturesTestFramework.Generate open JetBrains.ReSharper.Plugins.FSharp open JetBrains.ReSharper.Plugins.FSharp.Tests +open JetBrains.Util open NUnit.Framework [] type FsharpGenerateSignatureTest() = inherit GenerateTestBase() + override x.RelativeTestDataPath = "features/generate/signatureFiles" - // override this.DumpTextControl(textControl, dumpCaret, dumpSelection) = + + override this.DoTest(lifetime, testProject) = + this.SetAsyncBehaviorAllowed(lifetime) + base.DoTest(lifetime, testProject) + + override this.DumpTextControl(_, dumpCaret, dumpSelection) = + let editorManager = this.Solution.GetComponent() + let fsiPath = this.GetCaretPosition().FileName.ChangeExtension("fsi") + let textControl = editorManager.OpenFileAsync(fsiPath, OpenFileOptions.DefaultActivate).Result.NotNull() + this.TestLifetime.OnTermination(fun _ -> editorManager.CloseTextControl(textControl)) |> ignore + + base.DumpTextControl(textControl, dumpCaret, dumpSelection) + [] member x.``Sample Test`` () = x.DoNamedTest() From 355b36ea55d70538ae7870580d512e0c517624d2 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Wed, 19 Apr 2023 14:26:43 +0200 Subject: [PATCH 47/75] Use existing text control lifetime --- .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index aa928ba3f6..f2fcded2b1 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -19,12 +19,13 @@ type FsharpGenerateSignatureTest() = this.SetAsyncBehaviorAllowed(lifetime) base.DoTest(lifetime, testProject) - override this.DumpTextControl(_, dumpCaret, dumpSelection) = + override this.DumpTextControl(textControl, dumpCaret, dumpSelection) = let editorManager = this.Solution.GetComponent() let fsiPath = this.GetCaretPosition().FileName.ChangeExtension("fsi") - let textControl = editorManager.OpenFileAsync(fsiPath, OpenFileOptions.DefaultActivate).Result.NotNull() - this.TestLifetime.OnTermination(fun _ -> editorManager.CloseTextControl(textControl)) |> ignore + let fsiTextControl = editorManager.OpenFileAsync(fsiPath, OpenFileOptions.DefaultActivate).Result.NotNull() + textControl.Lifetime.OnTermination(fun _ -> editorManager.CloseTextControl(fsiTextControl)) |> ignore - base.DumpTextControl(textControl, dumpCaret, dumpSelection) + base.DumpTextControl(fsiTextControl, dumpCaret, dumpSelection) [] member x.``Sample Test`` () = x.DoNamedTest() + [] member x.``Sample Test 02`` () = x.DoNamedTest() From f9d591953e9b2c7cafcf4aa25023b720fae6bfdf Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 19 Apr 2023 15:22:50 +0200 Subject: [PATCH 48/75] Add namespace test. --- .../{Sample Test.fs => Module structure 01.fs} | 0 .../generate/signatureFiles/Module structure 01.fs.gold | 6 ++++++ .../generate/signatureFiles/Namespace structure 01.fs | 6 ++++++ .../generate/signatureFiles/Namespace structure 01.fs.gold | 6 ++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 4 ++-- 5 files changed, 20 insertions(+), 2 deletions(-) rename ReSharper.FSharp/test/data/features/generate/signatureFiles/{Sample Test.fs => Module structure 01.fs} (100%) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 01.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs.gold diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Sample Test.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 01.fs similarity index 100% rename from ReSharper.FSharp/test/data/features/generate/signatureFiles/Sample Test.fs rename to ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 01.fs diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 01.fs.gold new file mode 100644 index 0000000000..fdc928fe72 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 01.fs.gold @@ -0,0 +1,6 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +open System \ No newline at end of file diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs new file mode 100644 index 0000000000..dea44726b7 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs @@ -0,0 +1,6 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +namespace Foo + +open System +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs.gold new file mode 100644 index 0000000000..8924a36be0 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Namespace structure 01.fs.gold @@ -0,0 +1,6 @@ +Provided elements: + 0: Generate signature file title + +{caret}namespace Foo + +open System \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index f2fcded2b1..3b78c7c7c2 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -27,5 +27,5 @@ type FsharpGenerateSignatureTest() = base.DumpTextControl(fsiTextControl, dumpCaret, dumpSelection) - [] member x.``Sample Test`` () = x.DoNamedTest() - [] member x.``Sample Test 02`` () = x.DoNamedTest() + [] member x.``Module structure 01`` () = x.DoNamedTest() + [] member x.``Namespace structure 01`` () = x.DoNamedTest() From 501058e9280a9720b5ed06f5aa15a5653c2d0f5b Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 19 Apr 2023 15:25:40 +0200 Subject: [PATCH 49/75] Remove old tests file. --- .../FSharp.Intentions.Tests.fsproj | 1 - .../src/Intentions/GenerateSignatureFileTest.fs | 17 ----------------- 2 files changed, 18 deletions(-) delete mode 100644 ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs 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 967df98f30..64e68cb7f0 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 @@ -49,7 +49,6 @@ - diff --git a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs b/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs deleted file mode 100644 index 6098c5953d..0000000000 --- a/ReSharper.FSharp/test/src/FSharp.Intentions.Tests/src/Intentions/GenerateSignatureFileTest.fs +++ /dev/null @@ -1,17 +0,0 @@ -namespace JetBrains.ReSharper.Plugins.FSharp.Tests.Intentions.Intentions - -open System.Linq -open JetBrains.ProjectModel -open JetBrains.ReSharper.FeaturesTestFramework.Refactorings -open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.ContextActions -open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Intentions -open JetBrains.ReSharper.Plugins.FSharp.Services.Formatter -open JetBrains.ReSharper.TestFramework -open NUnit.Framework - -// type GenerateSignatureFileTest() = -// inherit FSharpContextActionExecuteTestBase() -// -// override this.ExtraPath = "generateSignatureFile" - - // [] member x.``ModuleStructure - 01`` () = x.DoNamedTestWithSignature() \ No newline at end of file From 6aa2c4e5a88142ab0f1f1a302b075405e5063834 Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 20 Apr 2023 08:00:10 +0200 Subject: [PATCH 50/75] Add _.fsi test. --- .../test/src/FSharp.Tests/Parsing/FSharpParserTest.fs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs index 0635c15c0a..3620b8aa27 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs @@ -683,6 +683,9 @@ type FSharpSignatureParserTest() = inherit ParserTestBase() override x.RelativeTestDataPath = "parsing/signatures" + + /// Use this test case to dump the psi tree for a given file, see `_.fsi`. + [] member x.``_``() = x.DoNamedTest() /// Use this test case to dump the psi tree for a given file, see `_.fsi`. [] member x.``_``() = x.DoNamedTest() @@ -767,7 +770,7 @@ type FSharpErrorsParserTest() = inherit ParserTestBase() override x.RelativeTestDataPath = "parsing/errors" - + [] member x.``Expr - Unfinished let 01``() = x.DoNamedTest() [] member x.``Expr - Unfinished let 02 - In``() = x.DoNamedTest() [] member x.``Expr - Unfinished let 03 - Inline in``() = x.DoNamedTest() From 4c82a2422b610cc0e13efcd0ab2e02a69d0f14ec Mon Sep 17 00:00:00 2001 From: nojaf Date: Thu, 20 Apr 2023 08:01:58 +0200 Subject: [PATCH 51/75] Add initial unit tests. --- .../features/generate/signatureFiles/Nested module 01.fs | 7 +++++++ .../generate/signatureFiles/Nested module 01.fs.gold | 7 +++++++ .../data/features/generate/signatureFiles/Record 01.fs | 6 ++++++ .../features/generate/signatureFiles/Record 01.fs.gold | 7 +++++++ .../generate/signatureFiles/TypeAbbreviation 01.fs | 6 ++++++ .../generate/signatureFiles/TypeAbbreviation 01.fs.gold | 6 ++++++ .../test/data/features/generate/signatureFiles/Union 01.fs | 6 ++++++ .../data/features/generate/signatureFiles/Union 01.fs.gold | 7 +++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 4 ++++ 9 files changed, 56 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs.gold create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs.gold diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs new file mode 100644 index 0000000000..2f3eda1e9a --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs @@ -0,0 +1,7 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + + module Bar = + open System +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs.gold new file mode 100644 index 0000000000..7a9a656e05 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Nested module 01.fs.gold @@ -0,0 +1,7 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +module Bar = + open System \ No newline at end of file diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs new file mode 100644 index 0000000000..8ed064d076 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs @@ -0,0 +1,6 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type Bar = { A:int; B: int } +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs.gold new file mode 100644 index 0000000000..ebd75ac780 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 01.fs.gold @@ -0,0 +1,7 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type Bar = + { A:int; B: int } \ No newline at end of file diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs new file mode 100644 index 0000000000..7bc22a9114 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs @@ -0,0 +1,6 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type Bar = int +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs.gold new file mode 100644 index 0000000000..95d5a49a48 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/TypeAbbreviation 01.fs.gold @@ -0,0 +1,6 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type Bar = int \ No newline at end of file diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs new file mode 100644 index 0000000000..674e364cf7 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs @@ -0,0 +1,6 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type Bar = | Bar of a:int * b:int +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs.gold new file mode 100644 index 0000000000..faf084b85b --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 01.fs.gold @@ -0,0 +1,7 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type Bar = + | Bar of a:int * b:int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 3b78c7c7c2..945a859ca9 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -29,3 +29,7 @@ type FsharpGenerateSignatureTest() = [] member x.``Module structure 01`` () = x.DoNamedTest() [] member x.``Namespace structure 01`` () = x.DoNamedTest() + [] member x.``TypeAbbreviation 01`` () = x.DoNamedTest() + [] member x.``Record 01`` () = x.DoNamedTest() + [] member x.``Union 01`` () = x.DoNamedTest() + [] member x.``Nested module 01`` () = x.DoNamedTest() From c9e864c0ed78e4dda70360ab0885590e2a137f41 Mon Sep 17 00:00:00 2001 From: dawe Date: Thu, 20 Apr 2023 10:26:39 +0200 Subject: [PATCH 52/75] add test 01 for recursive types --- .../features/generate/signatureFiles/Recursive types 01.fs | 7 +++++++ .../generate/signatureFiles/Recursive types 01.fs.gold | 7 +++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 1 + 3 files changed, 15 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs.gold diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs new file mode 100644 index 0000000000..fa41fcf13f --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs @@ -0,0 +1,7 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type N = int +and R = float +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs.gold new file mode 100644 index 0000000000..bb425d78be --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Recursive types 01.fs.gold @@ -0,0 +1,7 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type N = int +and R = float \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 945a859ca9..97afdee1d0 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -33,3 +33,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Record 01`` () = x.DoNamedTest() [] member x.``Union 01`` () = x.DoNamedTest() [] member x.``Nested module 01`` () = x.DoNamedTest() + [] member x.``Recursive types 01`` () = x.DoNamedTest() From bc9797b8b89b22195a73d3dd163db008b13c143e Mon Sep 17 00:00:00 2001 From: dawe Date: Mon, 24 Apr 2023 11:28:31 +0200 Subject: [PATCH 53/75] add test for record with static member --- .../data/features/generate/signatureFiles/Record 02.fs | 7 +++++++ .../features/generate/signatureFiles/Record 02.fs.gold | 8 ++++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 1 + 3 files changed, 16 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs.gold diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs new file mode 100644 index 0000000000..c15733b769 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs @@ -0,0 +1,7 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type Bar = { A:int; B: int } + static member Add x y = x + y +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs.gold new file mode 100644 index 0000000000..a9e3f90fc5 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Record 02.fs.gold @@ -0,0 +1,8 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type Bar = + { A:int; B: int } + static member Add: int -> int -> int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 97afdee1d0..0c5817ebf3 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -31,6 +31,7 @@ type FsharpGenerateSignatureTest() = [] member x.``Namespace structure 01`` () = x.DoNamedTest() [] member x.``TypeAbbreviation 01`` () = x.DoNamedTest() [] member x.``Record 01`` () = x.DoNamedTest() + [] member x.``Record 02`` () = x.DoNamedTest() [] member x.``Union 01`` () = x.DoNamedTest() [] member x.``Nested module 01`` () = x.DoNamedTest() [] member x.``Recursive types 01`` () = x.DoNamedTest() From d9d21c7ba1a645558ddc0aeb8f73e56bedf7c668 Mon Sep 17 00:00:00 2001 From: dawe Date: Mon, 24 Apr 2023 11:38:23 +0200 Subject: [PATCH 54/75] add test for union with static member note, we should improve the signature with naming --- .../data/features/generate/signatureFiles/Union 02.fs | 7 +++++++ .../features/generate/signatureFiles/Union 02.fs.gold | 8 ++++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 1 + 3 files changed, 16 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs.gold diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs new file mode 100644 index 0000000000..879b596eb0 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs @@ -0,0 +1,7 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type Bar = | Bar of a:int * b:int + static member Add x y = x + y +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs.gold new file mode 100644 index 0000000000..a4d782af7b --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Union 02.fs.gold @@ -0,0 +1,8 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type Bar = + | Bar of a:int * b:int + static member Add: int -> int -> int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 0c5817ebf3..87b8f71529 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -33,5 +33,6 @@ type FsharpGenerateSignatureTest() = [] member x.``Record 01`` () = x.DoNamedTest() [] member x.``Record 02`` () = x.DoNamedTest() [] member x.``Union 01`` () = x.DoNamedTest() + [] member x.``Union 02`` () = x.DoNamedTest() [] member x.``Nested module 01`` () = x.DoNamedTest() [] member x.``Recursive types 01`` () = x.DoNamedTest() From f7e363851524d128393e2dd16fd218e15927dc35 Mon Sep 17 00:00:00 2001 From: nojaf Date: Wed, 26 Apr 2023 09:35:48 +0200 Subject: [PATCH 55/75] Add test for instance member. --- .../src/Generate/GenerateSignatureProvider.fs | 15 ++++++++++++++- .../generate/signatureFiles/Instance Member 01.fs | 10 ++++++++++ .../signatureFiles/Instance Member 01.fs.gold | 10 ++++++++++ .../Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index fc2ffa09e6..148ea21e96 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -173,7 +173,20 @@ type FSharpGenerateSignatureBuilder() = if isNotNull symbolUse then let mfv = symbolUse.Symbol.As() if isNotNull mfv then - sb.Append(mfv.FullType.Format(symbolUse.DisplayContext)) |> ignore + if memberDecl.IsStatic then + sb.Append(mfv.FullType.Format(symbolUse.DisplayContext)) |> ignore + else + // mfv.FullType will contain the type of the instance, so we cannot use that. + let parameters = + mfv.CurriedParameterGroups + |> Seq.map (fun parameterGroup -> + parameterGroup + |> Seq.map (fun parameter -> parameter.Type.Format(symbolUse.DisplayContext)) + |> String.concat " * " + ) + |> String.concat " -> " + let returnType = mfv.ReturnParameter.Type.Format(symbolUse.DisplayContext) + sb.Append($"{parameters} -> {returnType}") |> ignore sb.ToString() diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs new file mode 100644 index 0000000000..fff62f4096 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs @@ -0,0 +1,10 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type X = + { + Y: int + } + member x.A b c = x.Y - b + c +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs.gold new file mode 100644 index 0000000000..08893bf23f --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 01.fs.gold @@ -0,0 +1,10 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type X = + { + Y: int + } + member A: int -> int -> int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 87b8f71529..85992d8bc0 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -36,3 +36,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Union 02`` () = x.DoNamedTest() [] member x.``Nested module 01`` () = x.DoNamedTest() [] member x.``Recursive types 01`` () = x.DoNamedTest() + [] member x.``Instance Member 01`` () = x.DoNamedTest() From d4d33aa57ee33327a17041c2d53805cfecad9ebd Mon Sep 17 00:00:00 2001 From: dawe Date: Thu, 27 Apr 2023 11:58:52 +0200 Subject: [PATCH 56/75] add test for instance member with optional parameter --- .../generate/signatureFiles/Instance Member 02.fs | 8 ++++++++ .../generate/signatureFiles/Instance Member 02.fs.gold | 8 ++++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 1 + 3 files changed, 17 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs.gold diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs new file mode 100644 index 0000000000..11a70ea12f --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs @@ -0,0 +1,8 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type R = + { F: int } + member _.Func (?x:int -> int) = 23 +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs.gold new file mode 100644 index 0000000000..1bb91c9eca --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Instance Member 02.fs.gold @@ -0,0 +1,8 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type R = + { F: int } + member Func: (int -> int) option -> int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 85992d8bc0..9fbd8ee3fb 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -37,3 +37,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Nested module 01`` () = x.DoNamedTest() [] member x.``Recursive types 01`` () = x.DoNamedTest() [] member x.``Instance Member 01`` () = x.DoNamedTest() + [] member x.``Instance Member 02`` () = x.DoNamedTest() From 7429d6d5eb7287f985c782ac3d623ac0eaf9a607 Mon Sep 17 00:00:00 2001 From: dawe Date: Thu, 27 Apr 2023 16:29:46 +0200 Subject: [PATCH 57/75] start supporting structs, we might handle it as IObjectModelTypeRepresentation in the future, let's see. --- .../src/Generate/GenerateSignatureProvider.fs | 12 ++++++++++++ .../features/generate/signatureFiles/Struct 01.fs | 9 +++++++++ .../generate/signatureFiles/Struct 01.fs.gold | 9 +++++++++ .../Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 31 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 148ea21e96..b83cb83ac9 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -72,6 +72,7 @@ type FSharpGenerateSignatureBuilder() = | :? IFSharpTypeDeclaration as typeDecl -> match typeDecl.TypeRepresentation with | :? ITypeAbbreviationRepresentation + | :? IStructRepresentation | :? ISimpleTypeRepresentation -> Some typeDecl | _ -> None | _ -> None) @@ -116,6 +117,17 @@ type FSharpGenerateSignatureBuilder() = Whitespace(indentation + moduleDecl.GetIndentSize()) sigMember ] |> ignore + | :? IStructRepresentation as repr -> + ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) + addNodesAfter sigTypeDecl.EqualsToken [ + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + repr.Copy() + for sigMember in sigMembers do + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + sigMember + ] |> ignore | repr -> // This pattern match should match the types we filtered out earlier for supportedTypeDeclarations failwith $"Unexpected representation {repr.GetType()}" diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs new file mode 100644 index 0000000000..14e9f565ef --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs @@ -0,0 +1,9 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type Bar = + struct + val X: int + end +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs.gold new file mode 100644 index 0000000000..b903373996 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Struct 01.fs.gold @@ -0,0 +1,9 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type Bar = + struct + val X: int + end \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 9fbd8ee3fb..2f2499a912 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -38,3 +38,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Recursive types 01`` () = x.DoNamedTest() [] member x.``Instance Member 01`` () = x.DoNamedTest() [] member x.``Instance Member 02`` () = x.DoNamedTest() + [] member x.``Struct 01`` () = x.DoNamedTest() From f1cb32eb7b256660223c19fcd9c6d28ccea39cff Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 2 May 2023 11:59:50 +0200 Subject: [PATCH 58/75] start supporting signature generation for ILetBindingsDeclaration --- .../src/Generate/GenerateSignatureProvider.fs | 23 +++++++++++++++++++ .../signatureFiles/Module structure 02.fs | 11 +++++++++ .../Module structure 02.fs.gold | 11 +++++++++ .../Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 46 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index b83cb83ac9..f286a57dc2 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -146,6 +146,29 @@ type FSharpGenerateSignatureBuilder() = processModuleLikeDeclaration (indentation + moduleDecl.GetIndentSize()) nestedNestedModule nestedSigModule | :? IOpenStatement as openStatement -> openStatement.Copy() + | :? ILetBindingsDeclaration as letBindingsDeclaration -> + + let sourceString (binding: IBinding) = + let sb = StringBuilder() + + sb.Append("val ") |> ignore + sb.Append(binding.HeadPattern.GetText()) |> ignore + sb.Append(": ") |> ignore + + let refPat = binding.HeadPattern.As() + if isNotNull refPat then + let symbolUse = refPat.GetFcsSymbolUse() + if isNotNull symbolUse then + let mfv = symbolUse.Symbol :?> FSharpMemberOrFunctionOrValue + sb.Append(mfv.FullType.Format(symbolUse.DisplayContext)) |> ignore + + sb.ToString() + + let sigStrings = + Seq.map sourceString letBindingsDeclaration.Bindings + |> String.concat System.Environment.NewLine + + factory.CreateTypeMemberSignature(sigStrings) | _ -> null and processModuleLikeDeclaration (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleSig: IModuleLikeDeclaration) : IFSharpTreeNode = diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs new file mode 100644 index 0000000000..5ac9cb3319 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs @@ -0,0 +1,11 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +open System + let c = Math.PI + let d = 23 + let e = "bar" + let f x y = x * y + let g x = x +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold new file mode 100644 index 0000000000..7dcc9e6522 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold @@ -0,0 +1,11 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +open System +val c: float +val d: int +val e: string +val f: int -> int -> int +val g: 'a -> 'a \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 2f2499a912..59229e413c 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -28,6 +28,7 @@ type FsharpGenerateSignatureTest() = base.DumpTextControl(fsiTextControl, dumpCaret, dumpSelection) [] member x.``Module structure 01`` () = x.DoNamedTest() + [] member x.``Module structure 02`` () = x.DoNamedTest() [] member x.``Namespace structure 01`` () = x.DoNamedTest() [] member x.``TypeAbbreviation 01`` () = x.DoNamedTest() [] member x.``Record 01`` () = x.DoNamedTest() From c487f069f5b883da6cc0580523bf9b281189cf2d Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 2 May 2023 16:19:39 +0200 Subject: [PATCH 59/75] remove superfluous indentation --- .../generate/signatureFiles/Module structure 02.fs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs index 5ac9cb3319..feb93282b9 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs @@ -3,9 +3,9 @@ module Foo open System - let c = Math.PI - let d = 23 - let e = "bar" - let f x y = x * y - let g x = x +let c = Math.PI +let d = 23 +let e = "bar" +let f x y = x * y +let g x = x {caret} From 30f8bb4840403160e2002c82f7fdde11f2f88136 Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 2 May 2023 16:21:48 +0200 Subject: [PATCH 60/75] Use "\n" instead of System.Environment.NewLine --- .../src/Generate/GenerateSignatureProvider.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index f286a57dc2..b4d23008e5 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -166,7 +166,7 @@ type FSharpGenerateSignatureBuilder() = let sigStrings = Seq.map sourceString letBindingsDeclaration.Bindings - |> String.concat System.Environment.NewLine + |> String.concat "\n" factory.CreateTypeMemberSignature(sigStrings) | _ -> null From a73a6db0a297fa78bfa53caab76b72cb2da70c45 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 10:35:18 +0200 Subject: [PATCH 61/75] Add basic exception. --- .../src/Generate/GenerateSignatureProvider.fs | 2 ++ .../data/features/generate/signatureFiles/Exception 01.fs | 6 ++++++ .../features/generate/signatureFiles/Exception 01.fs.gold | 6 ++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 15 insertions(+) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index b4d23008e5..f722d7b21e 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -169,6 +169,8 @@ type FSharpGenerateSignatureBuilder() = |> String.concat "\n" factory.CreateTypeMemberSignature(sigStrings) + | :? IExceptionDeclaration as exceptionDeclaration -> + exceptionDeclaration.Copy() | _ -> null and processModuleLikeDeclaration (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleSig: IModuleLikeDeclaration) : IFSharpTreeNode = diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs new file mode 100644 index 0000000000..74e770bb88 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs @@ -0,0 +1,6 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +exception A of int * string +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs.gold new file mode 100644 index 0000000000..40caaa0ed8 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 01.fs.gold @@ -0,0 +1,6 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +exception A of int * string \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 59229e413c..045c4c6d9d 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -40,3 +40,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Instance Member 01`` () = x.DoNamedTest() [] member x.``Instance Member 02`` () = x.DoNamedTest() [] member x.``Struct 01`` () = x.DoNamedTest() + [] member x.``Exception 01`` () = x.DoNamedTest() From 1d3699da6cd28e3460a494d6795c48f20ce51761 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 10:46:45 +0200 Subject: [PATCH 62/75] Add members to exceptions. --- .../src/Generate/GenerateSignatureProvider.fs | 17 ++++++++++++++++- .../generate/signatureFiles/Exception 02.fs | 7 +++++++ .../signatureFiles/Exception 02.fs.gold | 7 +++++++ .../Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index f722d7b21e..4bf2b257be 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -170,7 +170,22 @@ type FSharpGenerateSignatureBuilder() = factory.CreateTypeMemberSignature(sigStrings) | :? IExceptionDeclaration as exceptionDeclaration -> - exceptionDeclaration.Copy() + let sigExceptionDeclaration = exceptionDeclaration.Copy() + if not (Seq.isEmpty exceptionDeclaration.MemberDeclarations) then + let sigMembers = + exceptionDeclaration.TypeMembers + |> Seq.choose (createMemberDeclaration >> Option.ofObj) + + ModificationUtil.DeleteChildRange(sigExceptionDeclaration.WithKeyword.NextSibling, sigExceptionDeclaration.LastChild) + + addNodesAfter sigExceptionDeclaration.WithKeyword [ + for sigMember in sigMembers do + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + sigMember + ] |> ignore + + sigExceptionDeclaration | _ -> null and processModuleLikeDeclaration (indentation: int) (moduleDecl: IModuleLikeDeclaration) (moduleSig: IModuleLikeDeclaration) : IFSharpTreeNode = diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs new file mode 100644 index 0000000000..5b5542cb1c --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs @@ -0,0 +1,7 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +exception A of int * string with + member a.B (c: string) = 0 +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs.gold new file mode 100644 index 0000000000..a248745202 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Exception 02.fs.gold @@ -0,0 +1,7 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +exception A of int * string with + member B: string -> int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 045c4c6d9d..499dc2f6b4 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -41,3 +41,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Instance Member 02`` () = x.DoNamedTest() [] member x.``Struct 01`` () = x.DoNamedTest() [] member x.``Exception 01`` () = x.DoNamedTest() + [] member x.``Exception 02`` () = x.DoNamedTest() From 1f388e7cb55b2f1454a163d0b85ebc9b6b9206bf Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 10:58:42 +0200 Subject: [PATCH 63/75] Add support for delegates. --- .../src/Generate/GenerateSignatureProvider.fs | 9 ++++++++- .../data/features/generate/signatureFiles/Delegate 01.fs | 6 ++++++ .../features/generate/signatureFiles/Delegate 01.fs.gold | 6 ++++++ .../FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 4bf2b257be..35ff3416a3 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -73,7 +73,8 @@ type FSharpGenerateSignatureBuilder() = match typeDecl.TypeRepresentation with | :? ITypeAbbreviationRepresentation | :? IStructRepresentation - | :? ISimpleTypeRepresentation -> Some typeDecl + | :? ISimpleTypeRepresentation + | :? IDelegateRepresentation -> Some typeDecl | _ -> None | _ -> None) |> Seq.mapi (fun idx typeDecl -> @@ -128,6 +129,12 @@ type FSharpGenerateSignatureBuilder() = Whitespace(indentation + moduleDecl.GetIndentSize()) sigMember ] |> ignore + | :? IDelegateRepresentation as repr -> + ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) + addNodesAfter sigTypeDecl.EqualsToken [ + Whitespace() + repr.Copy() + ] |> ignore | repr -> // This pattern match should match the types we filtered out earlier for supportedTypeDeclarations failwith $"Unexpected representation {repr.GetType()}" diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs new file mode 100644 index 0000000000..2e2a2ff5f6 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs @@ -0,0 +1,6 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type A = delegate of int * string -> float +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs.gold new file mode 100644 index 0000000000..f0a7872c58 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Delegate 01.fs.gold @@ -0,0 +1,6 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type A = delegate of int * string -> float \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index 499dc2f6b4..f714c2928c 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -42,3 +42,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Struct 01`` () = x.DoNamedTest() [] member x.``Exception 01`` () = x.DoNamedTest() [] member x.``Exception 02`` () = x.DoNamedTest() + [] member x.``Delegate 01`` () = x.DoNamedTest() From f66276511081e16cc5ee401cc18fc7ef1ba06aea Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 11:55:43 +0200 Subject: [PATCH 64/75] Implicit unit constructor. --- .../src/Generate/GenerateSignatureProvider.fs | 27 +++++++++++++++++-- .../signatureFiles/Implicit Constructor 01.fs | 7 +++++ .../Implicit Constructor 01.fs.gold | 8 ++++++ .../Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 35ff3416a3..cd530da348 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -54,7 +54,7 @@ type FSharpGenerateSignatureProvider() = type FSharpGenerateSignatureBuilder() = inherit GeneratorBuilderBase() - // TODO: what about attributes, type parameters, delegates, exceptions + // TODO: what about attributes, type parameters let mkSignatureFile (fsharpFile: IFSharpFile): IFSharpFile = let factory : IFSharpElementFactory = fsharpFile.CreateElementFactory(extension = FSharpSignatureProjectFileType.FsiExtension) @@ -74,7 +74,9 @@ type FSharpGenerateSignatureBuilder() = | :? ITypeAbbreviationRepresentation | :? IStructRepresentation | :? ISimpleTypeRepresentation - | :? IDelegateRepresentation -> Some typeDecl + | :? IDelegateRepresentation + // Regular classes have no representation. + | null -> Some typeDecl | _ -> None | _ -> None) |> Seq.mapi (fun idx typeDecl -> @@ -135,6 +137,18 @@ type FSharpGenerateSignatureBuilder() = Whitespace() repr.Copy() ] |> ignore + | null -> + ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) + addNodesAfter sigTypeDecl.EqualsToken [ + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + if isNotNull typeDecl.PrimaryConstructorDeclaration then + createPrimaryConstructorSignature (getName typeDecl) typeDecl.PrimaryConstructorDeclaration + for sigMember in sigMembers do + NewLine(lineEnding) + Whitespace(indentation + moduleDecl.GetIndentSize()) + sigMember + ] |> ignore | repr -> // This pattern match should match the types we filtered out earlier for supportedTypeDeclarations failwith $"Unexpected representation {repr.GetType()}" @@ -252,6 +266,15 @@ type FSharpGenerateSignatureBuilder() = factory.CreateTypeMemberSignature(sourceString) | _ -> null + and createPrimaryConstructorSignature (typeName: string) (primaryConstructorDeclaration: IPrimaryConstructorDeclaration) : IFSharpTreeNode = + let signature = + match primaryConstructorDeclaration.ParameterPatterns with + | :? IUnitPat -> + $"new: unit -> {typeName}" + | _ -> failwithf "todo" + + factory.CreateTypeMemberSignature(signature) + for decl in fsharpFile.ModuleDeclarations do let signatureModule : IModuleLikeDeclaration = match decl with diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs new file mode 100644 index 0000000000..21b6e0d942 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs @@ -0,0 +1,7 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type A() = + member this.B() : int = 0 +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs.gold new file mode 100644 index 0000000000..5bb6a4ccd0 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 01.fs.gold @@ -0,0 +1,8 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type A = + new: unit -> A + member B: unit -> int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index f714c2928c..bbb4ced17b 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -43,3 +43,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Exception 01`` () = x.DoNamedTest() [] member x.``Exception 02`` () = x.DoNamedTest() [] member x.``Delegate 01`` () = x.DoNamedTest() + [] member x.``Implicit Constructor 01`` () = x.DoNamedTest() From 62a893806ebd20d98873b0e22fe217d5f26f0e87 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 12:05:49 +0200 Subject: [PATCH 65/75] Implicit constructor with parameters. --- .../src/Generate/GenerateSignatureProvider.fs | 32 +++++++++++++------ .../signatureFiles/Implicit Constructor 02.fs | 8 +++++ .../Implicit Constructor 02.fs.gold | 8 +++++ .../Generate/FsharpGenerateSignatureTest.fs | 1 + 4 files changed, 40 insertions(+), 9 deletions(-) create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs create mode 100644 ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs.gold diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index cd530da348..41b8bd485a 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -143,7 +143,7 @@ type FSharpGenerateSignatureBuilder() = NewLine(lineEnding) Whitespace(indentation + moduleDecl.GetIndentSize()) if isNotNull typeDecl.PrimaryConstructorDeclaration then - createPrimaryConstructorSignature (getName typeDecl) typeDecl.PrimaryConstructorDeclaration + yield! createPrimaryConstructorSignature (getName typeDecl) typeDecl.PrimaryConstructorDeclaration for sigMember in sigMembers do NewLine(lineEnding) Whitespace(indentation + moduleDecl.GetIndentSize()) @@ -266,15 +266,29 @@ type FSharpGenerateSignatureBuilder() = factory.CreateTypeMemberSignature(sourceString) | _ -> null - and createPrimaryConstructorSignature (typeName: string) (primaryConstructorDeclaration: IPrimaryConstructorDeclaration) : IFSharpTreeNode = - let signature = - match primaryConstructorDeclaration.ParameterPatterns with - | :? IUnitPat -> - $"new: unit -> {typeName}" - | _ -> failwithf "todo" + and createPrimaryConstructorSignature (typeName: string) (primaryConstructorDeclaration: IPrimaryConstructorDeclaration) : ITreeNode seq = + match primaryConstructorDeclaration.ParameterPatterns with + | :? IUnitPat -> + factory.CreateTypeMemberSignature $"new: unit -> {typeName}" + :> ITreeNode + |> Seq.singleton + | _ -> + let symbolUse = primaryConstructorDeclaration.GetFcsSymbolUse() + if isNull symbolUse then Seq.empty else + let mfv = symbolUse.Symbol.As() + if isNull mfv then Seq.empty else + let parameters = + mfv.CurriedParameterGroups + |> Seq.map (fun parameterGroup -> + parameterGroup + |> Seq.map (fun parameter -> parameter.Type.Format(symbolUse.DisplayContext)) + |> String.concat " * " + ) + |> String.concat " -> " + factory.CreateTypeMemberSignature $"new: {parameters} -> {typeName}" + :> ITreeNode + |> Seq.singleton - factory.CreateTypeMemberSignature(signature) - for decl in fsharpFile.ModuleDeclarations do let signatureModule : IModuleLikeDeclaration = match decl with diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs new file mode 100644 index 0000000000..223acc7005 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs @@ -0,0 +1,8 @@ +// ${KIND:SignatureFile} +// ${SELECT0:Generate signature file title} +module Foo + +type A(a:int,b) = + do printfn "%s" b + member this.B() : int = 0 +{caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs.gold new file mode 100644 index 0000000000..f78d8b6a69 --- /dev/null +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Implicit Constructor 02.fs.gold @@ -0,0 +1,8 @@ +Provided elements: + 0: Generate signature file title + +{caret}module Foo + +type A = + new: int * string -> A + member B: unit -> int \ No newline at end of file diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs index bbb4ced17b..930149c133 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Generate/FsharpGenerateSignatureTest.fs @@ -44,3 +44,4 @@ type FsharpGenerateSignatureTest() = [] member x.``Exception 02`` () = x.DoNamedTest() [] member x.``Delegate 01`` () = x.DoNamedTest() [] member x.``Implicit Constructor 01`` () = x.DoNamedTest() + [] member x.``Implicit Constructor 02`` () = x.DoNamedTest() From 0fac3aaa6ff81d79809d2465c0062264d80e5e1d Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 12:08:27 +0200 Subject: [PATCH 66/75] Reuse lineEnding --- .../src/Generate/GenerateSignatureProvider.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 41b8bd485a..db12fb4188 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -86,7 +86,7 @@ type FSharpGenerateSignatureBuilder() = if Array.isEmpty supportedTypeDeclarations then null else - let sourceText = supportedTypeDeclarations |> Array.map (fun info -> info.SourceText) |> String.concat "\n" + let sourceText = supportedTypeDeclarations |> Array.map (fun info -> info.SourceText) |> String.concat lineEnding let sigTypeDeclarationGroup = factory.CreateModuleMember(sourceText) :?> ITypeDeclarationGroup if isNull sigTypeDeclarationGroup then null else @@ -187,7 +187,7 @@ type FSharpGenerateSignatureBuilder() = let sigStrings = Seq.map sourceString letBindingsDeclaration.Bindings - |> String.concat "\n" + |> String.concat lineEnding factory.CreateTypeMemberSignature(sigStrings) | :? IExceptionDeclaration as exceptionDeclaration -> From 86f4a93104538ed38e5fb7602240202c4d06766e Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 12:11:42 +0200 Subject: [PATCH 67/75] Filter out IExceptionFieldDeclaration for IExceptionDeclaration. --- .../src/Generate/GenerateSignatureProvider.fs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index db12fb4188..92533863fb 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -192,7 +192,12 @@ type FSharpGenerateSignatureBuilder() = factory.CreateTypeMemberSignature(sigStrings) | :? IExceptionDeclaration as exceptionDeclaration -> let sigExceptionDeclaration = exceptionDeclaration.Copy() - if not (Seq.isEmpty exceptionDeclaration.MemberDeclarations) then + let memberDeclarations = + exceptionDeclaration.MemberDeclarations + |> Seq.filter (function | :? IExceptionFieldDeclaration -> false | _ -> true) + |> Seq.toArray + + if memberDeclarations.Length > 0 then let sigMembers = exceptionDeclaration.TypeMembers |> Seq.choose (createMemberDeclaration >> Option.ofObj) From 335bf48f89cc816de0c6f9ce64781837bb8e2c46 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 13:32:41 +0200 Subject: [PATCH 68/75] Remove invalid comment. --- .../src/Generate/GenerateSignatureProvider.fs | 2 -- 1 file changed, 2 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 92533863fb..55f77b6c52 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -106,8 +106,6 @@ type FSharpGenerateSignatureBuilder() = addNodesAfter sigTypeDecl.EqualsToken [ Whitespace() abbr.Copy() - // TODO: there technically could be members here. - // Although I think this would need the `with` keyword. ] |> ignore | :? ISimpleTypeRepresentation as repr -> ModificationUtil.DeleteChildRange(sigTypeDecl.EqualsToken.NextSibling, sigTypeDecl.LastChild) From a7833abbe9dfb30641fe2ac69b149e05e2ca81aa Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 13:56:00 +0200 Subject: [PATCH 69/75] Remove redundant unit pat check in createPrimaryConstructorSignature. --- .../src/Generate/GenerateSignatureProvider.fs | 36 ++++++++----------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 55f77b6c52..d19c7722d7 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -270,27 +270,21 @@ type FSharpGenerateSignatureBuilder() = | _ -> null and createPrimaryConstructorSignature (typeName: string) (primaryConstructorDeclaration: IPrimaryConstructorDeclaration) : ITreeNode seq = - match primaryConstructorDeclaration.ParameterPatterns with - | :? IUnitPat -> - factory.CreateTypeMemberSignature $"new: unit -> {typeName}" - :> ITreeNode - |> Seq.singleton - | _ -> - let symbolUse = primaryConstructorDeclaration.GetFcsSymbolUse() - if isNull symbolUse then Seq.empty else - let mfv = symbolUse.Symbol.As() - if isNull mfv then Seq.empty else - let parameters = - mfv.CurriedParameterGroups - |> Seq.map (fun parameterGroup -> - parameterGroup - |> Seq.map (fun parameter -> parameter.Type.Format(symbolUse.DisplayContext)) - |> String.concat " * " - ) - |> String.concat " -> " - factory.CreateTypeMemberSignature $"new: {parameters} -> {typeName}" - :> ITreeNode - |> Seq.singleton + let symbolUse = primaryConstructorDeclaration.GetFcsSymbolUse() + if isNull symbolUse then Seq.empty else + let mfv = symbolUse.Symbol.As() + if isNull mfv then Seq.empty else + let parameters = + mfv.CurriedParameterGroups + |> Seq.map (fun parameterGroup -> + parameterGroup + |> Seq.map (fun parameter -> parameter.Type.Format(symbolUse.DisplayContext)) + |> String.concat " * " + ) + |> String.concat " -> " + factory.CreateTypeMemberSignature $"new: {parameters} -> {typeName}" + :> ITreeNode + |> Seq.singleton for decl in fsharpFile.ModuleDeclarations do let signatureModule : IModuleLikeDeclaration = From 40d85a863943d97f01d9cf6f5ef6e3fb0b9c1783 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 14:07:05 +0200 Subject: [PATCH 70/75] Don't show workflow item is setting is not enabled. --- .../src/Generate/GenerateSignatureProvider.fs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index d19c7722d7..d83f8f7958 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -19,6 +19,7 @@ open JetBrains.ReSharper.Plugins.FSharp.Psi.Features.Generate open JetBrains.ReSharper.Plugins.FSharp.Psi.Impl.Tree open JetBrains.ReSharper.Plugins.FSharp.Psi.Tree open JetBrains.ReSharper.Psi +open JetBrains.ReSharper.Psi.DataContext open JetBrains.ReSharper.Psi.ExtensionsAPI.Tree open JetBrains.ReSharper.Psi.Naming open JetBrains.ReSharper.Psi.Tree @@ -366,5 +367,12 @@ type FSharpGenerateSignatureWorkflow() = [] type FSharpGenerateSignatureWorkflowProvider() = interface IGenerateImplementationsWorkflowProvider with - member this.CreateWorkflow _ = - [| FSharpGenerateSignatureWorkflow() |] + member this.CreateWorkflow dataContext = + if dataContext.IsEmpty then Seq.empty else + let node = dataContext.GetData(PsiDataConstants.SOURCE_FILE) + if isNull node then Seq.empty else + let solution = node.GetSolution() + if not (solution.IsFSharpExperimentalFeatureEnabled(ExperimentalFeature.GenerateSignatureFile)) then + Seq.empty + else + [| FSharpGenerateSignatureWorkflow() |] From 877ab518a7b9a21e212eb3f7a71a7219b5e52d78 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 14:11:01 +0200 Subject: [PATCH 71/75] Use TypeMembers for IExceptionDeclaration. --- .../src/Generate/GenerateSignatureProvider.fs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index d83f8f7958..f570c7449f 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -191,12 +191,8 @@ type FSharpGenerateSignatureBuilder() = factory.CreateTypeMemberSignature(sigStrings) | :? IExceptionDeclaration as exceptionDeclaration -> let sigExceptionDeclaration = exceptionDeclaration.Copy() - let memberDeclarations = - exceptionDeclaration.MemberDeclarations - |> Seq.filter (function | :? IExceptionFieldDeclaration -> false | _ -> true) - |> Seq.toArray - if memberDeclarations.Length > 0 then + if not exceptionDeclaration.TypeMembers.IsEmpty then let sigMembers = exceptionDeclaration.TypeMembers |> Seq.choose (createMemberDeclaration >> Option.ofObj) @@ -209,7 +205,7 @@ type FSharpGenerateSignatureBuilder() = Whitespace(indentation + moduleDecl.GetIndentSize()) sigMember ] |> ignore - + sigExceptionDeclaration | _ -> null From b3d2de741cfb83bd0f04d68b904187e5c0902220 Mon Sep 17 00:00:00 2001 From: nojaf Date: Mon, 8 May 2023 16:02:37 +0200 Subject: [PATCH 72/75] Small fixes after rebase. --- .../src/Generate/GenerateSignatureProvider.fs | 6 +++--- .../test/src/FSharp.Tests/Parsing/FSharpParserTest.fs | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index f570c7449f..f1ce5d30f8 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -188,7 +188,7 @@ type FSharpGenerateSignatureBuilder() = Seq.map sourceString letBindingsDeclaration.Bindings |> String.concat lineEnding - factory.CreateTypeMemberSignature(sigStrings) + factory.CreateTypeMember(sigStrings) | :? IExceptionDeclaration as exceptionDeclaration -> let sigExceptionDeclaration = exceptionDeclaration.Copy() @@ -263,7 +263,7 @@ type FSharpGenerateSignatureBuilder() = sb.ToString() - factory.CreateTypeMemberSignature(sourceString) + factory.CreateTypeMember(sourceString) | _ -> null and createPrimaryConstructorSignature (typeName: string) (primaryConstructorDeclaration: IPrimaryConstructorDeclaration) : ITreeNode seq = @@ -279,7 +279,7 @@ type FSharpGenerateSignatureBuilder() = |> String.concat " * " ) |> String.concat " -> " - factory.CreateTypeMemberSignature $"new: {parameters} -> {typeName}" + factory.CreateTypeMember $"new: {parameters} -> {typeName}" :> ITreeNode |> Seq.singleton diff --git a/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs b/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs index 3620b8aa27..8c6de3d704 100644 --- a/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs +++ b/ReSharper.FSharp/test/src/FSharp.Tests/Parsing/FSharpParserTest.fs @@ -687,9 +687,6 @@ type FSharpSignatureParserTest() = /// Use this test case to dump the psi tree for a given file, see `_.fsi`. [] member x.``_``() = x.DoNamedTest() - /// Use this test case to dump the psi tree for a given file, see `_.fsi`. - [] member x.``_``() = x.DoNamedTest() - [] member x.``Type decl - Union 01 - After nested module``() = x.DoNamedTest() [] member x.``Type decl - Union 02 - FullType``() = x.DoNamedTest() [] member x.``Type decl - Delegate``() = x.DoNamedTest() From da1180fb2d0a2a6ad1cebb1a0b38f7b88d6e0693 Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 9 May 2023 23:34:46 +0200 Subject: [PATCH 73/75] Support attributes on module members --- .../src/Generate/GenerateSignatureProvider.fs | 13 ++++++++----- .../generate/signatureFiles/Module structure 02.fs | 1 + .../signatureFiles/Module structure 02.fs.gold | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index f1ce5d30f8..19f6004041 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -171,15 +171,18 @@ type FSharpGenerateSignatureBuilder() = let sourceString (binding: IBinding) = let sb = StringBuilder() - sb.Append("val ") |> ignore - sb.Append(binding.HeadPattern.GetText()) |> ignore - sb.Append(": ") |> ignore - let refPat = binding.HeadPattern.As() if isNotNull refPat then let symbolUse = refPat.GetFcsSymbolUse() if isNotNull symbolUse then let mfv = symbolUse.Symbol :?> FSharpMemberOrFunctionOrValue + + mfv.Attributes + |> Seq.iter (fun a -> sb.Append($"{a.Format(symbolUse.DisplayContext)}{lineEnding}") |> ignore) + + sb.Append("val ") |> ignore + sb.Append(binding.HeadPattern.GetText()) |> ignore + sb.Append(": ") |> ignore sb.Append(mfv.FullType.Format(symbolUse.DisplayContext)) |> ignore sb.ToString() @@ -188,7 +191,7 @@ type FSharpGenerateSignatureBuilder() = Seq.map sourceString letBindingsDeclaration.Bindings |> String.concat lineEnding - factory.CreateTypeMember(sigStrings) + factory.CreateModuleMember(sigStrings) | :? IExceptionDeclaration as exceptionDeclaration -> let sigExceptionDeclaration = exceptionDeclaration.Copy() diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs index feb93282b9..92cb582c64 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs @@ -7,5 +7,6 @@ let c = Math.PI let d = 23 let e = "bar" let f x y = x * y +[] let g x = x {caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold index 7dcc9e6522..5b60ea58d5 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold @@ -8,4 +8,5 @@ val c: float val d: int val e: string val f: int -> int -> int +[] val g: 'a -> 'a \ No newline at end of file From 9713991ae8c410793f81d9503f2d495acb2194b9 Mon Sep 17 00:00:00 2001 From: dawe Date: Wed, 10 May 2023 11:13:02 +0200 Subject: [PATCH 74/75] Add attribute with parameter for test --- .../features/generate/signatureFiles/Module structure 02.fs | 3 ++- .../generate/signatureFiles/Module structure 02.fs.gold | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs index 92cb582c64..ba729ca326 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs @@ -7,6 +7,7 @@ let c = Math.PI let d = 23 let e = "bar" let f x y = x * y -[] +[] +[] let g x = x {caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold index 5b60ea58d5..a843510cf2 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold @@ -8,5 +8,6 @@ val c: float val d: int val e: string val f: int -> int -> int -[] +[] +[] val g: 'a -> 'a \ No newline at end of file From de6092e44fdeaf5ca5a9c7deb265208e480e77da Mon Sep 17 00:00:00 2001 From: dawe Date: Wed, 10 May 2023 14:13:05 +0200 Subject: [PATCH 75/75] Use GetText() to get original attributes from impl file. --- .../src/Generate/GenerateSignatureProvider.fs | 4 ++-- .../generate/signatureFiles/Module structure 02.fs | 4 ++++ .../signatureFiles/Module structure 02.fs.gold | 11 ++++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs index 19f6004041..4c314fe567 100644 --- a/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs +++ b/ReSharper.FSharp/src/FSharp.Psi.Services/src/Generate/GenerateSignatureProvider.fs @@ -177,8 +177,8 @@ type FSharpGenerateSignatureBuilder() = if isNotNull symbolUse then let mfv = symbolUse.Symbol :?> FSharpMemberOrFunctionOrValue - mfv.Attributes - |> Seq.iter (fun a -> sb.Append($"{a.Format(symbolUse.DisplayContext)}{lineEnding}") |> ignore) + binding.Attributes + |> Seq.iter (fun a -> sb.Append($"[<{a.GetText()}>]{lineEnding}") |> ignore) sb.Append("val ") |> ignore sb.Append(binding.HeadPattern.GetText()) |> ignore diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs index ba729ca326..8a1d2703a7 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs @@ -7,7 +7,11 @@ let c = Math.PI let d = 23 let e = "bar" let f x y = x * y +[] [] [] let g x = x +let [] Hello = "Hello" +[] +let hello = 1 {caret} diff --git a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold index a843510cf2..3280319397 100644 --- a/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold +++ b/ReSharper.FSharp/test/data/features/generate/signatureFiles/Module structure 02.fs.gold @@ -8,6 +8,11 @@ val c: float val d: int val e: string val f: int -> int -> int -[] -[] -val g: 'a -> 'a \ No newline at end of file +[] +[] +[] +val g: 'a -> 'a +[] +val Hello: string +[] +val hello: int \ No newline at end of file