Skip to content

Commit 413a7cb

Browse files
gedareowenca
authored andcommitted
[clang-format] Support block indenting array/struct list initializers
C89 and C99 list initializers are treated differently than Cpp11 braced initializers. This patch identifies the C array/struct initializer lists by finding the preceding equal sign before a left brace, and applies formatting rules for BracketAlignmentStyle.BlockIndent to those list initializers. Fixes #57878. Differential Revision: https://reviews.llvm.org/D153205
1 parent ad14659 commit 413a7cb

File tree

7 files changed

+185
-9
lines changed

7 files changed

+185
-9
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,8 @@ the configuration (without a prefix: ``Auto``).
241241

242242
.. warning::
243243

244-
Note: This currently only applies to parentheses.
244+
This currently only applies to braced initializer lists (when
245+
``Cpp11BracedListStyle`` is ``true``) and parentheses.
245246

246247

247248

clang/include/clang/Format/Format.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ struct FormatStyle {
9393
/// \endcode
9494
///
9595
/// \warning
96-
/// Note: This currently only applies to parentheses.
96+
/// This currently only applies to braced initializer lists (when
97+
/// ``Cpp11BracedListStyle`` is ``true``) and parentheses.
9798
/// \endwarning
9899
BAS_BlockIndent,
99100
};

clang/lib/Format/ContinuationIndenter.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,9 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
362362
return true;
363363
}
364364
if (CurrentState.BreakBeforeClosingBrace &&
365-
Current.closesBlockOrBlockTypeList(Style)) {
365+
(Current.closesBlockOrBlockTypeList(Style) ||
366+
(Current.is(tok::r_brace) &&
367+
Current.isBlockIndentedInitRBrace(Style)))) {
366368
return true;
367369
}
368370
if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren))
@@ -1168,7 +1170,10 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
11681170
return State.Stack[State.Stack.size() - 2].LastSpace;
11691171
}
11701172
if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent &&
1171-
Current.is(tok::r_paren) && State.Stack.size() > 1) {
1173+
(Current.is(tok::r_paren) ||
1174+
(Current.is(tok::r_brace) &&
1175+
Current.MatchingParen->is(BK_BracedInit))) &&
1176+
State.Stack.size() > 1) {
11721177
return State.Stack[State.Stack.size() - 2].LastSpace;
11731178
}
11741179
if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())

clang/lib/Format/FormatToken.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,21 @@ bool FormatToken::isTypeOrIdentifier() const {
7575
return isSimpleTypeSpecifier() || Tok.isOneOf(tok::kw_auto, tok::identifier);
7676
}
7777

78+
bool FormatToken::isBlockIndentedInitRBrace(const FormatStyle &Style) const {
79+
assert(is(tok::r_brace));
80+
if (!Style.Cpp11BracedListStyle ||
81+
Style.AlignAfterOpenBracket != FormatStyle::BAS_BlockIndent) {
82+
return false;
83+
}
84+
const auto *LBrace = MatchingParen;
85+
assert(LBrace && LBrace->is(tok::l_brace));
86+
if (LBrace->is(BK_BracedInit))
87+
return true;
88+
if (LBrace->Previous && LBrace->Previous->is(tok::equal))
89+
return true;
90+
return false;
91+
}
92+
7893
bool FormatToken::opensBlockOrBlockTypeList(const FormatStyle &Style) const {
7994
// C# Does not indent object initialisers as continuations.
8095
if (is(tok::l_brace) && getBlockKind() == BK_BracedInit && Style.isCSharp())

clang/lib/Format/FormatToken.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,9 @@ struct FormatToken {
774774
return Tok;
775775
}
776776

777+
/// Returns \c true if this token ends a block indented initializer list.
778+
[[nodiscard]] bool isBlockIndentedInitRBrace(const FormatStyle &Style) const;
779+
777780
/// Returns \c true if this tokens starts a block-type list, i.e. a
778781
/// list that should be indented with a block indent.
779782
[[nodiscard]] bool opensBlockOrBlockTypeList(const FormatStyle &Style) const;

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5482,8 +5482,10 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
54825482

54835483
// We only break before r_brace if there was a corresponding break before
54845484
// the l_brace, which is tracked by BreakBeforeClosingBrace.
5485-
if (Right.is(tok::r_brace))
5486-
return Right.MatchingParen && Right.MatchingParen->is(BK_Block);
5485+
if (Right.is(tok::r_brace)) {
5486+
return Right.MatchingParen && (Right.MatchingParen->is(BK_Block) ||
5487+
(Right.isBlockIndentedInitRBrace(Style)));
5488+
}
54875489

54885490
// We only break before r_paren if we're in a block indented context.
54895491
if (Right.is(tok::r_paren)) {

clang/unittests/Format/FormatTest.cpp

Lines changed: 152 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4963,7 +4963,7 @@ TEST_F(FormatTest, BracedInitializerIndentWidth) {
49634963
" \"zzzzzzzzzzzzzzzz\"};\n",
49644964
Style);
49654965
// Designated initializers.
4966-
verifyFormat("int LooooooooooooooooooooooooongVariable[1] = {\n"
4966+
verifyFormat("int LooooooooooooooooooooooooongVariable[2] = {\n"
49674967
" [0] = 10000000, [1] = 20000000};",
49684968
Style);
49694969
verifyFormat("SomeStruct s{\n"
@@ -5073,7 +5073,7 @@ TEST_F(FormatTest, BracedInitializerIndentWidth) {
50735073
" bar,\n"
50745074
" },\n"
50755075
" SomeArrayT{},\n"
5076-
"}\n",
5076+
"};",
50775077
Style);
50785078
verifyFormat("SomeArrayT a[3] = {\n"
50795079
" {foo},\n"
@@ -5090,7 +5090,7 @@ TEST_F(FormatTest, BracedInitializerIndentWidth) {
50905090
" },\n"
50915091
" },\n"
50925092
" {baz},\n"
5093-
"}\n",
5093+
"};",
50945094
Style);
50955095

50965096
// Aligning after open braces unaffected by BracedInitializerIndentWidth.
@@ -25532,6 +25532,155 @@ TEST_F(FormatTest, AlignAfterOpenBracketBlockIndentForStatement) {
2553225532
Style);
2553325533
}
2553425534

25535+
TEST_F(FormatTest, AlignAfterOpenBracketBlockIndentInitializers) {
25536+
auto Style = getLLVMStyleWithColumns(60);
25537+
Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent;
25538+
// Aggregate initialization.
25539+
verifyFormat("int LooooooooooooooooooooooooongVariable[2] = {\n"
25540+
" 10000000, 20000000\n"
25541+
"};",
25542+
Style);
25543+
verifyFormat("SomeStruct s{\n"
25544+
" \"xxxxxxxxxxxxxxxx\", \"yyyyyyyyyyyyyyyy\",\n"
25545+
" \"zzzzzzzzzzzzzzzz\"\n"
25546+
"};",
25547+
Style);
25548+
// Designated initializers.
25549+
verifyFormat("int LooooooooooooooooooooooooongVariable[2] = {\n"
25550+
" [0] = 10000000, [1] = 20000000\n"
25551+
"};",
25552+
Style);
25553+
verifyFormat("SomeStruct s{\n"
25554+
" .foo = \"xxxxxxxxxxxxx\",\n"
25555+
" .bar = \"yyyyyyyyyyyyy\",\n"
25556+
" .baz = \"zzzzzzzzzzzzz\"\n"
25557+
"};",
25558+
Style);
25559+
// List initialization.
25560+
verifyFormat("SomeStruct s{\n"
25561+
" \"xxxxxxxxxxxxx\",\n"
25562+
" \"yyyyyyyyyyyyy\",\n"
25563+
" \"zzzzzzzzzzzzz\",\n"
25564+
"};",
25565+
Style);
25566+
verifyFormat("SomeStruct{\n"
25567+
" \"xxxxxxxxxxxxx\",\n"
25568+
" \"yyyyyyyyyyyyy\",\n"
25569+
" \"zzzzzzzzzzzzz\",\n"
25570+
"};",
25571+
Style);
25572+
verifyFormat("new SomeStruct{\n"
25573+
" \"xxxxxxxxxxxxx\",\n"
25574+
" \"yyyyyyyyyyyyy\",\n"
25575+
" \"zzzzzzzzzzzzz\",\n"
25576+
"};",
25577+
Style);
25578+
// Member initializer.
25579+
verifyFormat("class SomeClass {\n"
25580+
" SomeStruct s{\n"
25581+
" \"xxxxxxxxxxxxx\",\n"
25582+
" \"yyyyyyyyyyyyy\",\n"
25583+
" \"zzzzzzzzzzzzz\",\n"
25584+
" };\n"
25585+
"};",
25586+
Style);
25587+
// Constructor member initializer.
25588+
verifyFormat("SomeClass::SomeClass : strct{\n"
25589+
" \"xxxxxxxxxxxxx\",\n"
25590+
" \"yyyyyyyyyyyyy\",\n"
25591+
" \"zzzzzzzzzzzzz\",\n"
25592+
" } {}",
25593+
Style);
25594+
// Copy initialization.
25595+
verifyFormat("SomeStruct s = SomeStruct{\n"
25596+
" \"xxxxxxxxxxxxx\",\n"
25597+
" \"yyyyyyyyyyyyy\",\n"
25598+
" \"zzzzzzzzzzzzz\",\n"
25599+
"};",
25600+
Style);
25601+
// Copy list initialization.
25602+
verifyFormat("SomeStruct s = {\n"
25603+
" \"xxxxxxxxxxxxx\",\n"
25604+
" \"yyyyyyyyyyyyy\",\n"
25605+
" \"zzzzzzzzzzzzz\",\n"
25606+
"};",
25607+
Style);
25608+
// Assignment operand initialization.
25609+
verifyFormat("s = {\n"
25610+
" \"xxxxxxxxxxxxx\",\n"
25611+
" \"yyyyyyyyyyyyy\",\n"
25612+
" \"zzzzzzzzzzzzz\",\n"
25613+
"};",
25614+
Style);
25615+
// Returned object initialization.
25616+
verifyFormat("return {\n"
25617+
" \"xxxxxxxxxxxxx\",\n"
25618+
" \"yyyyyyyyyyyyy\",\n"
25619+
" \"zzzzzzzzzzzzz\",\n"
25620+
"};",
25621+
Style);
25622+
// Initializer list.
25623+
verifyFormat("auto initializerList = {\n"
25624+
" \"xxxxxxxxxxxxx\",\n"
25625+
" \"yyyyyyyyyyyyy\",\n"
25626+
" \"zzzzzzzzzzzzz\",\n"
25627+
"};",
25628+
Style);
25629+
// Function parameter initialization.
25630+
verifyFormat("func({\n"
25631+
" \"xxxxxxxxxxxxx\",\n"
25632+
" \"yyyyyyyyyyyyy\",\n"
25633+
" \"zzzzzzzzzzzzz\",\n"
25634+
"});",
25635+
Style);
25636+
// Nested init lists.
25637+
verifyFormat("SomeStruct s = {\n"
25638+
" {{init1, init2, init3, init4, init5},\n"
25639+
" {init1, init2, init3, init4, init5}}\n"
25640+
"};",
25641+
Style);
25642+
verifyFormat("SomeStruct s = {\n"
25643+
" {{\n"
25644+
" .init1 = 1,\n"
25645+
" .init2 = 2,\n"
25646+
" .init3 = 3,\n"
25647+
" .init4 = 4,\n"
25648+
" .init5 = 5,\n"
25649+
" },\n"
25650+
" {init1, init2, init3, init4, init5}}\n"
25651+
"};",
25652+
Style);
25653+
verifyFormat("SomeArrayT a[3] = {\n"
25654+
" {\n"
25655+
" foo,\n"
25656+
" bar,\n"
25657+
" },\n"
25658+
" {\n"
25659+
" foo,\n"
25660+
" bar,\n"
25661+
" },\n"
25662+
" SomeArrayT{},\n"
25663+
"};",
25664+
Style);
25665+
verifyFormat("SomeArrayT a[3] = {\n"
25666+
" {foo},\n"
25667+
" {\n"
25668+
" {\n"
25669+
" init1,\n"
25670+
" init2,\n"
25671+
" init3,\n"
25672+
" },\n"
25673+
" {\n"
25674+
" init1,\n"
25675+
" init2,\n"
25676+
" init3,\n"
25677+
" },\n"
25678+
" },\n"
25679+
" {baz},\n"
25680+
"};",
25681+
Style);
25682+
}
25683+
2553525684
TEST_F(FormatTest, UnderstandsDigraphs) {
2553625685
verifyFormat("int arr<:5:> = {};");
2553725686
verifyFormat("int arr[5] = <%%>;");

0 commit comments

Comments
 (0)