From ac61efe7670acfa06cee2edaf61d4f7c368e4ce7 Mon Sep 17 00:00:00 2001 From: sobaya Date: Tue, 30 Jul 2019 13:02:48 +0900 Subject: [PATCH 1/7] Fix: Issue 256 "named member struct initialisers" --- src/dfmt/ast_info.d | 13 +++++++++++++ src/dfmt/formatter.d | 8 +++++++- tests/allman/issue0256.d.ref | 4 ++++ tests/issue0256.d | 4 ++++ tests/otbs/issue0256.d.ref | 3 +++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/allman/issue0256.d.ref create mode 100644 tests/issue0256.d create mode 100644 tests/otbs/issue0256.d.ref diff --git a/src/dfmt/ast_info.d b/src/dfmt/ast_info.d index 9c3f68f..83082d1 100644 --- a/src/dfmt/ast_info.d +++ b/src/dfmt/ast_info.d @@ -23,6 +23,12 @@ struct BraceIndentInfo uint beginIndentLevel; } +struct StructInitializerInfo +{ + size_t startLocation; + size_t endLocation; +} + /// AST information that is needed by the formatter. struct ASTInformation { @@ -53,6 +59,8 @@ struct ASTInformation sort(sharedStaticConstructorDestructorLocations); sort!((a,b) => a.endLocation < b.endLocation) (indentInfoSortedByEndLocation); + sort!((a,b) => a.endLocation < b.endLocation) + (structInfoSortedByEndLocation); sort(ufcsHintLocations); ufcsHintLocations = ufcsHintLocations.uniq().array(); } @@ -118,6 +126,9 @@ struct ASTInformation size_t[] ufcsHintLocations; BraceIndentInfo[] indentInfoSortedByEndLocation; + + /// Opening & closing braces of struct initializers + StructInitializerInfo[] structInfoSortedByEndLocation; } /// Collects information from the AST that is useful for the formatter @@ -272,6 +283,8 @@ final class FormatVisitor : ASTVisitor { astInformation.structInitStartLocations ~= structInitializer.startLocation; astInformation.structInitEndLocations ~= structInitializer.endLocation; + astInformation.structInfoSortedByEndLocation ~= + StructInitializerInfo(structInitializer.startLocation, structInitializer.endLocation); astInformation.indentInfoSortedByEndLocation ~= BraceIndentInfo(structInitializer.startLocation, structInitializer.endLocation); diff --git a/src/dfmt/formatter.d b/src/dfmt/formatter.d index ee36f40..56fc27a 100644 --- a/src/dfmt/formatter.d +++ b/src/dfmt/formatter.d @@ -725,10 +725,14 @@ private: void formatColon() { import dfmt.editorconfig : OptionalBoolean; + import std.algorithm : canFind; immutable bool isCase = astInformation.caseEndLocations.canFindIndex(current.index); immutable bool isAttribute = astInformation.attributeDeclarationLines.canFindIndex( current.line); + immutable bool isStructInitializer = astInformation.structInfoSortedByEndLocation + .canFind!(st => st.startLocation < current.index && current.index < st.endLocation); + if (isCase || isAttribute) { writeToken(); @@ -748,7 +752,9 @@ private: || peekBack2Is(tok!":", true)) && !(isBlockHeader(1) && !peekIs(tok!"if"))) { writeToken(); - if (!currentIs(tok!"{")) + if (isStructInitializer) + write(" "); + else if (!currentIs(tok!"{")) newline(); } else diff --git a/tests/allman/issue0256.d.ref b/tests/allman/issue0256.d.ref new file mode 100644 index 0000000..41c1237 --- /dev/null +++ b/tests/allman/issue0256.d.ref @@ -0,0 +1,4 @@ +void foo() +{ + S s = {a: 3}; +} diff --git a/tests/issue0256.d b/tests/issue0256.d new file mode 100644 index 0000000..59d78e4 --- /dev/null +++ b/tests/issue0256.d @@ -0,0 +1,4 @@ +void foo() +{ + S s = { a: 3 }; +} diff --git a/tests/otbs/issue0256.d.ref b/tests/otbs/issue0256.d.ref new file mode 100644 index 0000000..e5ab49c --- /dev/null +++ b/tests/otbs/issue0256.d.ref @@ -0,0 +1,3 @@ +void foo() { + S s = {a: 3}; +} From 1024f167154aa37e754fa46abad84a528ea9f99e Mon Sep 17 00:00:00 2001 From: sobaya Date: Tue, 30 Jul 2019 23:04:02 +0900 Subject: [PATCH 2/7] Add: struct fields to the test of issue 256 --- tests/allman/issue0256.d.ref | 4 +++- tests/issue0256.d | 4 +++- tests/otbs/issue0256.d.ref | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/allman/issue0256.d.ref b/tests/allman/issue0256.d.ref index 41c1237..2003daf 100644 --- a/tests/allman/issue0256.d.ref +++ b/tests/allman/issue0256.d.ref @@ -1,4 +1,6 @@ void foo() { - S s = {a: 3}; + S s1 = {a: 3}; + S s2 = {a: 3, b : "test string"}; + S s3 = {a: 3, b : "test string", c : {x: 3.14, y : 3 + 4}}; } diff --git a/tests/issue0256.d b/tests/issue0256.d index 59d78e4..11dccdf 100644 --- a/tests/issue0256.d +++ b/tests/issue0256.d @@ -1,4 +1,6 @@ void foo() { - S s = { a: 3 }; + S s1 = { a: 3 }; + S s2 = { a: 3, b:"test string" }; + S s3 = { a: 3, b:"test string", c: {x: 3.14, y: 3 + 4} }; } diff --git a/tests/otbs/issue0256.d.ref b/tests/otbs/issue0256.d.ref index e5ab49c..ed62ae0 100644 --- a/tests/otbs/issue0256.d.ref +++ b/tests/otbs/issue0256.d.ref @@ -1,3 +1,5 @@ void foo() { - S s = {a: 3}; + S s1 = {a: 3}; + S s2 = {a: 3, b : "test string"}; + S s3 = {a: 3, b : "test string", c : {x: 3.14, y : 3 + 4}}; } From 81c607a115c9c987cd31bf76413108c30319db1b Mon Sep 17 00:00:00 2001 From: sobaya Date: Thu, 1 Aug 2019 16:58:41 +0900 Subject: [PATCH 3/7] Fix: extrace space after first field --- src/dfmt/formatter.d | 3 ++- tests/allman/issue0256.d.ref | 4 ++-- tests/otbs/issue0256.d.ref | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/dfmt/formatter.d b/src/dfmt/formatter.d index 56fc27a..3f6d1c7 100644 --- a/src/dfmt/formatter.d +++ b/src/dfmt/formatter.d @@ -749,7 +749,8 @@ private: } else if (peekBackIs(tok!"identifier") && (peekBack2Is(tok!"{", true) || peekBack2Is(tok!"}", true) || peekBack2Is(tok!";", true) - || peekBack2Is(tok!":", true)) && !(isBlockHeader(1) && !peekIs(tok!"if"))) + || peekBack2Is(tok!":", true) || peekBack2Is(tok!",", true)) + && !(isBlockHeader(1) && !peekIs(tok!"if"))) { writeToken(); if (isStructInitializer) diff --git a/tests/allman/issue0256.d.ref b/tests/allman/issue0256.d.ref index 2003daf..0a18239 100644 --- a/tests/allman/issue0256.d.ref +++ b/tests/allman/issue0256.d.ref @@ -1,6 +1,6 @@ void foo() { S s1 = {a: 3}; - S s2 = {a: 3, b : "test string"}; - S s3 = {a: 3, b : "test string", c : {x: 3.14, y : 3 + 4}}; + S s2 = {a: 3, b: "test string"}; + S s3 = {a: 3, b: "test string", c: {x: 3.14, y: 3 + 4}}; } diff --git a/tests/otbs/issue0256.d.ref b/tests/otbs/issue0256.d.ref index ed62ae0..576e0bd 100644 --- a/tests/otbs/issue0256.d.ref +++ b/tests/otbs/issue0256.d.ref @@ -1,5 +1,5 @@ void foo() { S s1 = {a: 3}; - S s2 = {a: 3, b : "test string"}; - S s3 = {a: 3, b : "test string", c : {x: 3.14, y : 3 + 4}}; + S s2 = {a: 3, b: "test string"}; + S s3 = {a: 3, b: "test string", c: {x: 3.14, y: 3 + 4}}; } From 05db8ae8fa7608329f9acf407317a73b9fe3065b Mon Sep 17 00:00:00 2001 From: sobaya Date: Thu, 1 Aug 2019 17:43:45 +0900 Subject: [PATCH 4/7] Fix: indentation for wrapping in struct initializer --- src/dfmt/formatter.d | 8 +++++++- tests/allman/issue0256.d.ref | 10 ++++++---- tests/issue0256.d | 16 +++++++++++----- tests/otbs/issue0256.d.ref | 10 ++++++---- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/dfmt/formatter.d b/src/dfmt/formatter.d index 3f6d1c7..18f958c 100644 --- a/src/dfmt/formatter.d +++ b/src/dfmt/formatter.d @@ -1515,7 +1515,7 @@ private: void newline() { import std.range : assumeSorted; - import std.algorithm : max; + import std.algorithm : max, canFind; import dfmt.editorconfig : OptionalBoolean; if (currentIs(tok!"comment") && index > 0 && current.line == tokenEndLine(tokens[index - 1])) @@ -1558,6 +1558,12 @@ private: immutable l = indents.indentToMostRecent(tok!"switch"); if (l != -1 && config.dfmt_align_switch_statements == OptionalBoolean.t) indentLevel = l; + else if (astInformation.structInfoSortedByEndLocation + .canFind!(st => st.startLocation < current.index && current.index < st.endLocation)) { + immutable l2 = indents.indentToMostRecent(tok!"{"); + assert(l2 != -1); + indentLevel = l2 + 1; + } else if (config.dfmt_compact_labeled_statements == OptionalBoolean.f || !isBlockHeader(2) || peek2Is(tok!"if")) { diff --git a/tests/allman/issue0256.d.ref b/tests/allman/issue0256.d.ref index 0a18239..e7463d5 100644 --- a/tests/allman/issue0256.d.ref +++ b/tests/allman/issue0256.d.ref @@ -1,6 +1,8 @@ -void foo() +void main() { - S s1 = {a: 3}; - S s2 = {a: 3, b: "test string"}; - S s3 = {a: 3, b: "test string", c: {x: 3.14, y: 3 + 4}}; + S s = { + someStructMember1: 2, someStructMember2: 42, someStructMember3: null, // foobar + someOtherMember1: objA, someOtherMember2: objB, someOtherMember3: 0, + somethingMore: null, someFlagInThisStruct: -1 + }; } diff --git a/tests/issue0256.d b/tests/issue0256.d index 11dccdf..f4d44dc 100644 --- a/tests/issue0256.d +++ b/tests/issue0256.d @@ -1,6 +1,12 @@ -void foo() -{ - S s1 = { a: 3 }; - S s2 = { a: 3, b:"test string" }; - S s3 = { a: 3, b:"test string", c: {x: 3.14, y: 3 + 4} }; +void main() { + S s = { + someStructMember1: 2, + someStructMember2: 42, + someStructMember3: null, // foobar + someOtherMember1: objA, + someOtherMember2: objB, + someOtherMember3: 0, + somethingMore: null, + someFlagInThisStruct: -1 + }; } diff --git a/tests/otbs/issue0256.d.ref b/tests/otbs/issue0256.d.ref index 576e0bd..2d0098f 100644 --- a/tests/otbs/issue0256.d.ref +++ b/tests/otbs/issue0256.d.ref @@ -1,5 +1,7 @@ -void foo() { - S s1 = {a: 3}; - S s2 = {a: 3, b: "test string"}; - S s3 = {a: 3, b: "test string", c: {x: 3.14, y: 3 + 4}}; +void main() { + S s = { + someStructMember1: 2, someStructMember2: 42, someStructMember3: null, // foobar + someOtherMember1: objA, someOtherMember2: objB, someOtherMember3: 0, + somethingMore: null, someFlagInThisStruct: -1 + }; } From b3946b75253ef680363619b9e75221e36fa6253e Mon Sep 17 00:00:00 2001 From: sobaya Date: Sat, 3 Aug 2019 08:55:32 +0900 Subject: [PATCH 5/7] Add: Test for nested struct formatting --- tests/allman/issue0256.d.ref | 5 ++++- tests/issue0256.d | 5 ++++- tests/otbs/issue0256.d.ref | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/allman/issue0256.d.ref b/tests/allman/issue0256.d.ref index e7463d5..5776aec 100644 --- a/tests/allman/issue0256.d.ref +++ b/tests/allman/issue0256.d.ref @@ -1,6 +1,9 @@ void main() { - S s = { + S s1 = {a: 3}; + S s2 = {a: 3, b: "test string"}; + S s3 = {a: 3, b: "test string", c: {x: 3.14, y: 3 + 4}}; + T t = { someStructMember1: 2, someStructMember2: 42, someStructMember3: null, // foobar someOtherMember1: objA, someOtherMember2: objB, someOtherMember3: 0, somethingMore: null, someFlagInThisStruct: -1 diff --git a/tests/issue0256.d b/tests/issue0256.d index f4d44dc..18f4c98 100644 --- a/tests/issue0256.d +++ b/tests/issue0256.d @@ -1,5 +1,8 @@ void main() { - S s = { + S s1 = { a: 3 }; + S s2 = { a: 3, b:"test string" }; + S s3 = { a: 3, b:"test string", c: {x: 3.14, y: 3 + 4} }; + T t = { someStructMember1: 2, someStructMember2: 42, someStructMember3: null, // foobar diff --git a/tests/otbs/issue0256.d.ref b/tests/otbs/issue0256.d.ref index 2d0098f..ca215a4 100644 --- a/tests/otbs/issue0256.d.ref +++ b/tests/otbs/issue0256.d.ref @@ -1,5 +1,8 @@ void main() { - S s = { + S s1 = {a: 3}; + S s2 = {a: 3, b: "test string"}; + S s3 = {a: 3, b: "test string", c: {x: 3.14, y: 3 + 4}}; + T t = { someStructMember1: 2, someStructMember2: 42, someStructMember3: null, // foobar someOtherMember1: objA, someOtherMember2: objB, someOtherMember3: 0, somethingMore: null, someFlagInThisStruct: -1 From ac8e34815f15469ac2b824dcb49b60f9145c29b5 Mon Sep 17 00:00:00 2001 From: sobaya Date: Sun, 4 Aug 2019 13:04:39 +0900 Subject: [PATCH 6/7] Fix: Use more readable expression --- src/dfmt/formatter.d | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/dfmt/formatter.d b/src/dfmt/formatter.d index 18f958c..04d80bd 100644 --- a/src/dfmt/formatter.d +++ b/src/dfmt/formatter.d @@ -725,7 +725,7 @@ private: void formatColon() { import dfmt.editorconfig : OptionalBoolean; - import std.algorithm : canFind; + import std.algorithm : canFind, any; immutable bool isCase = astInformation.caseEndLocations.canFindIndex(current.index); immutable bool isAttribute = astInformation.attributeDeclarationLines.canFindIndex( @@ -747,10 +747,10 @@ private: newline(); } } - else if (peekBackIs(tok!"identifier") && (peekBack2Is(tok!"{", true) - || peekBack2Is(tok!"}", true) || peekBack2Is(tok!";", true) - || peekBack2Is(tok!":", true) || peekBack2Is(tok!",", true)) - && !(isBlockHeader(1) && !peekIs(tok!"if"))) + else if (peekBackIs(tok!"identifier") + && [tok!"{", tok!"}", tok!";", tok!":", tok!","] + .any!((ptrdiff_t token) => peekBack2Is(cast(IdType)token, true)) + && (!isBlockHeader(1) || peekIs(tok!"if"))) { writeToken(); if (isStructInitializer) From 06881d8654aaf28b61d8fb826ebf7b09c8e9aa01 Mon Sep 17 00:00:00 2001 From: sobaya Date: Sun, 4 Aug 2019 13:05:39 +0900 Subject: [PATCH 7/7] Fix: assertion message in indent manipulation of struct initializer --- src/dfmt/formatter.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dfmt/formatter.d b/src/dfmt/formatter.d index 04d80bd..c8d63a6 100644 --- a/src/dfmt/formatter.d +++ b/src/dfmt/formatter.d @@ -1561,7 +1561,7 @@ private: else if (astInformation.structInfoSortedByEndLocation .canFind!(st => st.startLocation < current.index && current.index < st.endLocation)) { immutable l2 = indents.indentToMostRecent(tok!"{"); - assert(l2 != -1); + assert(l2 != -1, "Recent '{' is not found despite being in struct initializer"); indentLevel = l2 + 1; } else if (config.dfmt_compact_labeled_statements == OptionalBoolean.f