From 5f27e0a4927449c6028c553f3b00ae6535fce44d Mon Sep 17 00:00:00 2001 From: nojaf Date: Fri, 26 Jun 2020 11:31:52 +0200 Subject: [PATCH] Don't add additional newline before middle attribute scenario. Fixes #933 --- src/Fantomas.Tests/TypeDeclarationTests.fs | 46 ++++++++++++++++++++++ src/Fantomas/AstTransformer.fs | 38 +++++++++--------- src/Fantomas/Trivia.fs | 10 ++++- src/Fantomas/TriviaTypes.fs | 3 +- 4 files changed, 75 insertions(+), 22 deletions(-) diff --git a/src/Fantomas.Tests/TypeDeclarationTests.fs b/src/Fantomas.Tests/TypeDeclarationTests.fs index 9c5f441a5d..25530efcb8 100644 --- a/src/Fantomas.Tests/TypeDeclarationTests.fs +++ b/src/Fantomas.Tests/TypeDeclarationTests.fs @@ -1345,3 +1345,49 @@ type Message = { [] Body: string } """ + +[] +let ``attribute on abstract member followed by type with attribute, 933`` () = + formatSourceString false """ +[] +type SubGroupStackOptions = + [] + abstract Item: name:string -> bool with get, set + +[] +type DataGroup = + abstract className: string option with get, set +""" config + |> prepend newline + |> should equal """ +[] +type SubGroupStackOptions = + [] + abstract Item: name:string -> bool with get, set + +[] +type DataGroup = + abstract className: string option with get, set +""" + +[] +let ``attribute on abstract member followed by let binding with attribute`` () = + formatSourceString false """ +[] +type SubGroupStackOptions = + [] + abstract Item: name:string -> bool with get, set + +[] +let foo bar = zero +""" config + |> prepend newline + |> should equal """ +[] +type SubGroupStackOptions = + [] + abstract Item: name:string -> bool with get, set + +[] +let foo bar = zero +""" diff --git a/src/Fantomas/AstTransformer.fs b/src/Fantomas/AstTransformer.fs index d8958ea004..20453351ef 100644 --- a/src/Fantomas/AstTransformer.fs +++ b/src/Fantomas/AstTransformer.fs @@ -69,7 +69,7 @@ module private Ast = FsAstNode = modOrNs Childs = [yield! (if isModule = SynModuleOrNamespaceKind.DeclaredNamespace then collectIdents longIdent else []) - yield! attrs |> List.map visitSynAttributeList + yield! attrs |> List.map (visitSynAttributeList modOrNs) yield! (decls |> List.map visitSynModuleDecl)]} and visitSynModuleDecl(ast: SynModuleDecl) : Node = @@ -125,7 +125,7 @@ module private Ast = Range = r range Properties = p [] FsAstNode = ast - Childs = attrs |> List.map visitSynAttributeList} + Childs = attrs |> List.map (visitSynAttributeList ast)} | SynModuleDecl.HashDirective(hash,range) -> {Type = "SynModuleDecl.HashDirective" Range = r range @@ -810,7 +810,7 @@ module private Ast = if access.IsSome then yield "access" ==> (access.Value |> visitSynAccess)] FsAstNode = mbrDef Childs = - [yield! attrs |> List.map visitSynAttributeList + [yield! attrs |> List.map (visitSynAttributeList mbrDef) yield visitSynSimplePats ctorArgs]} | SynMemberDefn.ImplicitInherit(inheritType,inheritArgs,inheritAlias,range) -> {Type = "SynMemberDefn.ImplicitInherit" @@ -871,7 +871,7 @@ module private Ast = if getSetRange.IsSome then yield "getSetRange" ==> (getSetRange.Value |> r)] FsAstNode = mbrDef Childs = - [yield! attrs |> List.map visitSynAttributeList + [yield! attrs |> List.map (visitSynAttributeList mbrDef) if typeOpt.IsSome then yield visitSynType typeOpt.Value yield visitSynExpr synExpr]} @@ -902,7 +902,7 @@ module private Ast = FsAstNode = sp Childs = [yield visitSynSimplePat simplePat - yield! attrs |> List.map visitSynAttributeList]} + yield! attrs |> List.map (visitSynAttributeList sp)]} and visitSynSimplePats(sp: SynSimplePats): Node = match sp with @@ -933,7 +933,7 @@ module private Ast = if access.IsSome then yield "access" ==> (access.Value |> visitSynAccess)] FsAstNode = binding Childs = - [yield! attrs |> List.map visitSynAttributeList + [yield! attrs |> List.map (visitSynAttributeList binding) yield visitSynValData valData yield visitSynPat headPat if returnInfo.IsSome then yield visitSynBindingReturnInfo returnInfo.Value @@ -960,7 +960,7 @@ module private Ast = if access.IsSome then yield "access" ==> (access.Value |> visitSynAccess)] FsAstNode = svs Childs = - [yield! attrs |> List.map visitSynAttributeList + [yield! attrs |> List.map (visitSynAttributeList svs) yield visitSynValTyparDecls explicitValDecls yield visitSynType synType yield visitSynValInfo arity @@ -983,7 +983,7 @@ module private Ast = Properties = p [] FsAstNode = std Childs = - [yield! attrs |> List.map visitSynAttributeList + [yield! attrs |> List.map (visitSynAttributeList std) yield visitSynTypar typar]} and visitSynTypar(typar: SynTypar): Node = @@ -1012,7 +1012,7 @@ module private Ast = FsAstNode = returnInfo Childs = [yield visitSynType typeName - yield! (attrs |> List.map visitSynAttributeList)]} + yield! (attrs |> List.map (visitSynAttributeList returnInfo))]} and visitSynPat(sp: SynPat): Node = match sp with @@ -1052,7 +1052,7 @@ module private Ast = FsAstNode = sp Childs = [yield visitSynPat synPat - yield! attrs |> List.map visitSynAttributeList]} + yield! attrs |> List.map (visitSynAttributeList sp)]} | SynPat.Or(synPat,synPat2,range) -> {Type = "SynPat.Or" Range = r range @@ -1177,7 +1177,7 @@ module private Ast = if access.IsSome then yield "access" ==> (access.Value |> visitSynAccess)] FsAstNode = sci Childs = - [yield! (attribs |> List.map visitSynAttributeList) + [yield! (attribs |> List.map (visitSynAttributeList sci)) yield! (typeParams |> List.map(visitSynTyparDecl))]} and visitSynTypeDefnRepr(stdr: SynTypeDefnRepr): Node = @@ -1346,7 +1346,7 @@ module private Ast = if access.IsSome then yield "access" ==> (access.Value |> visitSynAccess)] FsAstNode = sedr Childs = - [yield! attrs |> List.map visitSynAttributeList + [yield! attrs |> List.map (visitSynAttributeList sedr) yield visitSynUnionCase unionCase]} and visitSynAttribute(attr: SynAttribute): Node = @@ -1360,10 +1360,10 @@ module private Ast = FsAstNode = attr Childs = [visitSynExpr attr.ArgExpr]} - and visitSynAttributeList(attrs: SynAttributeList): Node = + and visitSynAttributeList (parent:obj) (attrs: SynAttributeList): Node = {Type = "SynAttributeList" Range = r attrs.Range - Properties = p [] + Properties = p ["parent", parent] FsAstNode = attrs Childs = attrs.Attributes |> List.map visitSynAttribute } @@ -1379,7 +1379,7 @@ module private Ast = FsAstNode = uc Childs = [yield visitSynUnionCaseType uct - yield! attrs |> List.map visitSynAttributeList]} + yield! attrs |> List.map (visitSynAttributeList uc)]} and visitSynUnionCaseType(uct: SynUnionCaseType) = match uct with @@ -1405,7 +1405,7 @@ module private Ast = Range = r range Properties = p [] FsAstNode = sec - Childs = [yield! attrs |> List.map visitSynAttributeList; yield visitIdent ident]} + Childs = [yield! attrs |> List.map (visitSynAttributeList sec); yield visitIdent ident]} and visitSynField(sfield: SynField): Node = match sfield with @@ -1418,7 +1418,7 @@ module private Ast = if access.IsSome then yield "access" ==> (access.Value |> visitSynAccess)] FsAstNode = sfield Childs = - [yield! attrs |> List.map visitSynAttributeList + [yield! attrs |> List.map (visitSynAttributeList sfield) yield visitSynType typ]} and visitSynType(st: SynType) = @@ -1566,7 +1566,7 @@ module private Ast = p [if ident.IsSome then yield "ident" ==> i ident.Value yield "optional" ==> optional] FsAstNode = sai - Childs = [yield! attrs |> List.map visitSynAttributeList]} + Childs = [yield! attrs |> List.map (visitSynAttributeList sai)]} and visitSynAccess(a: SynAccess) = match a with @@ -1613,7 +1613,7 @@ module private Ast = FsAstNode = modOrNs Childs = [yield! (if isModule = SynModuleOrNamespaceKind.DeclaredNamespace then visitLongIdent longIdent else []) - yield! attrs |> List.map visitSynAttributeList + yield! attrs |> List.map (visitSynAttributeList modOrNs) yield! (decls |> List.map visitSynModuleSigDecl)]} and visitSynModuleSigDecl(ast: SynModuleSigDecl) : Node = diff --git a/src/Fantomas/Trivia.fs b/src/Fantomas/Trivia.fs index 3501d76d51..6e2e0b9f6f 100644 --- a/src/Fantomas/Trivia.fs +++ b/src/Fantomas/Trivia.fs @@ -146,7 +146,9 @@ let private findConstNodeAfter (nodes: TriviaNodeAssigner list) (range: range) = let private mapNodeToTriviaNode (node: Node) = node.Range - |> Option.map (fun range -> TriviaNodeAssigner(MainNode(node.Type), range)) + |> Option.map (fun range -> + let attributeParent = Map.tryFind "parent" node.Properties + TriviaNodeAssigner(MainNode(node.Type), range, attributeParent)) let private commentIsAfterLastTriviaNode (triviaNodes: TriviaNodeAssigner list) (range: range) = match List.filter isMainNodeButNotAnonModule triviaNodes with @@ -223,7 +225,11 @@ let private triviaBetweenAttributeAndParentBinding (triviaNodes: TriviaNodeAssig | a, p when (a.Type = MainNode("SynAttributeList") && a.Range.StartLine < line && a.Range.StartLine = a.Range.EndLine) -> match p.Type with | MainNode("SynModuleDecl.Let") when (p.Range.StartLine > line) -> true - | MainNode("SynAttributeList") when (p.Range.StartLine > line) -> true + | MainNode("SynAttributeList") when (p.Range.StartLine > line) -> + // This is an edge case scenario where the trivia needs to fit between two attributes of the same parent node. + match p.AttributeParent, a.AttributeParent with + | Some pp, Some ap -> pp = ap + | _ -> false | MainNode("SynModuleDecl.Types") when (p.Range.StartLine > line) -> true | _ -> false | _ -> false) diff --git a/src/Fantomas/TriviaTypes.fs b/src/Fantomas/TriviaTypes.fs index 049772cac8..7065da46f6 100644 --- a/src/Fantomas/TriviaTypes.fs +++ b/src/Fantomas/TriviaTypes.fs @@ -57,9 +57,10 @@ type TriviaNode = ContentAfter: TriviaContent list Range: range } -type internal TriviaNodeAssigner(nodeType: TriviaNodeType, range: range) = +type internal TriviaNodeAssigner(nodeType: TriviaNodeType, range: range, ?attributeParent: obj) = member this.Type = nodeType member this.Range = range + member this.AttributeParent = attributeParent member val ContentBefore = ResizeArray() with get,set member val ContentItself = Option.None with get,set member val ContentAfter = ResizeArray() with get,set \ No newline at end of file