[clang] 413a7cb - [clang-format] Support block indenting array/struct list initializers
Owen Pan via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 6 13:42:18 PDT 2023
Author: Gedare Bloom
Date: 2023-07-06T13:42:11-07:00
New Revision: 413a7cb6e0db96b29bda0dab8541e225193ad139
URL: https://github.com/llvm/llvm-project/commit/413a7cb6e0db96b29bda0dab8541e225193ad139
DIFF: https://github.com/llvm/llvm-project/commit/413a7cb6e0db96b29bda0dab8541e225193ad139.diff
LOG: [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
Added:
Modified:
clang/docs/ClangFormatStyleOptions.rst
clang/include/clang/Format/Format.h
clang/lib/Format/ContinuationIndenter.cpp
clang/lib/Format/FormatToken.cpp
clang/lib/Format/FormatToken.h
clang/lib/Format/TokenAnnotator.cpp
clang/unittests/Format/FormatTest.cpp
Removed:
################################################################################
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index b715d1c20706e4..3dbb955347da2d 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -241,7 +241,8 @@ the configuration (without a prefix: ``Auto``).
.. warning::
- Note: This currently only applies to parentheses.
+ This currently only applies to braced initializer lists (when
+ ``Cpp11BracedListStyle`` is ``true``) and parentheses.
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 74b3e15918184a..ca4e89dcafc9d4 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -93,7 +93,8 @@ struct FormatStyle {
/// \endcode
///
/// \warning
- /// Note: This currently only applies to parentheses.
+ /// This currently only applies to braced initializer lists (when
+ /// ``Cpp11BracedListStyle`` is ``true``) and parentheses.
/// \endwarning
BAS_BlockIndent,
};
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 74d82db043e67f..66e66cc6856d8c 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -362,7 +362,9 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
return true;
}
if (CurrentState.BreakBeforeClosingBrace &&
- Current.closesBlockOrBlockTypeList(Style)) {
+ (Current.closesBlockOrBlockTypeList(Style) ||
+ (Current.is(tok::r_brace) &&
+ Current.isBlockIndentedInitRBrace(Style)))) {
return true;
}
if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren))
@@ -1168,7 +1170,10 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
return State.Stack[State.Stack.size() - 2].LastSpace;
}
if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent &&
- Current.is(tok::r_paren) && State.Stack.size() > 1) {
+ (Current.is(tok::r_paren) ||
+ (Current.is(tok::r_brace) &&
+ Current.MatchingParen->is(BK_BracedInit))) &&
+ State.Stack.size() > 1) {
return State.Stack[State.Stack.size() - 2].LastSpace;
}
if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp
index 3450c534a2d43c..d994ed0488996c 100644
--- a/clang/lib/Format/FormatToken.cpp
+++ b/clang/lib/Format/FormatToken.cpp
@@ -75,6 +75,21 @@ bool FormatToken::isTypeOrIdentifier() const {
return isSimpleTypeSpecifier() || Tok.isOneOf(tok::kw_auto, tok::identifier);
}
+bool FormatToken::isBlockIndentedInitRBrace(const FormatStyle &Style) const {
+ assert(is(tok::r_brace));
+ if (!Style.Cpp11BracedListStyle ||
+ Style.AlignAfterOpenBracket != FormatStyle::BAS_BlockIndent) {
+ return false;
+ }
+ const auto *LBrace = MatchingParen;
+ assert(LBrace && LBrace->is(tok::l_brace));
+ if (LBrace->is(BK_BracedInit))
+ return true;
+ if (LBrace->Previous && LBrace->Previous->is(tok::equal))
+ return true;
+ return false;
+}
+
bool FormatToken::opensBlockOrBlockTypeList(const FormatStyle &Style) const {
// C# Does not indent object initialisers as continuations.
if (is(tok::l_brace) && getBlockKind() == BK_BracedInit && Style.isCSharp())
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index bba030238338f7..a7f2a01683fb38 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -774,6 +774,9 @@ struct FormatToken {
return Tok;
}
+ /// Returns \c true if this token ends a block indented initializer list.
+ [[nodiscard]] bool isBlockIndentedInitRBrace(const FormatStyle &Style) const;
+
/// Returns \c true if this tokens starts a block-type list, i.e. a
/// list that should be indented with a block indent.
[[nodiscard]] bool opensBlockOrBlockTypeList(const FormatStyle &Style) const;
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 5536c89ae1067d..2ffa07bffa1f32 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -5482,8 +5482,10 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
// We only break before r_brace if there was a corresponding break before
// the l_brace, which is tracked by BreakBeforeClosingBrace.
- if (Right.is(tok::r_brace))
- return Right.MatchingParen && Right.MatchingParen->is(BK_Block);
+ if (Right.is(tok::r_brace)) {
+ return Right.MatchingParen && (Right.MatchingParen->is(BK_Block) ||
+ (Right.isBlockIndentedInitRBrace(Style)));
+ }
// We only break before r_paren if we're in a block indented context.
if (Right.is(tok::r_paren)) {
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 81f2a1361be328..7e8476f4082d31 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -4963,7 +4963,7 @@ TEST_F(FormatTest, BracedInitializerIndentWidth) {
" \"zzzzzzzzzzzzzzzz\"};\n",
Style);
// Designated initializers.
- verifyFormat("int LooooooooooooooooooooooooongVariable[1] = {\n"
+ verifyFormat("int LooooooooooooooooooooooooongVariable[2] = {\n"
" [0] = 10000000, [1] = 20000000};",
Style);
verifyFormat("SomeStruct s{\n"
@@ -5073,7 +5073,7 @@ TEST_F(FormatTest, BracedInitializerIndentWidth) {
" bar,\n"
" },\n"
" SomeArrayT{},\n"
- "}\n",
+ "};",
Style);
verifyFormat("SomeArrayT a[3] = {\n"
" {foo},\n"
@@ -5090,7 +5090,7 @@ TEST_F(FormatTest, BracedInitializerIndentWidth) {
" },\n"
" },\n"
" {baz},\n"
- "}\n",
+ "};",
Style);
// Aligning after open braces unaffected by BracedInitializerIndentWidth.
@@ -25532,6 +25532,155 @@ TEST_F(FormatTest, AlignAfterOpenBracketBlockIndentForStatement) {
Style);
}
+TEST_F(FormatTest, AlignAfterOpenBracketBlockIndentInitializers) {
+ auto Style = getLLVMStyleWithColumns(60);
+ Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent;
+ // Aggregate initialization.
+ verifyFormat("int LooooooooooooooooooooooooongVariable[2] = {\n"
+ " 10000000, 20000000\n"
+ "};",
+ Style);
+ verifyFormat("SomeStruct s{\n"
+ " \"xxxxxxxxxxxxxxxx\", \"yyyyyyyyyyyyyyyy\",\n"
+ " \"zzzzzzzzzzzzzzzz\"\n"
+ "};",
+ Style);
+ // Designated initializers.
+ verifyFormat("int LooooooooooooooooooooooooongVariable[2] = {\n"
+ " [0] = 10000000, [1] = 20000000\n"
+ "};",
+ Style);
+ verifyFormat("SomeStruct s{\n"
+ " .foo = \"xxxxxxxxxxxxx\",\n"
+ " .bar = \"yyyyyyyyyyyyy\",\n"
+ " .baz = \"zzzzzzzzzzzzz\"\n"
+ "};",
+ Style);
+ // List initialization.
+ verifyFormat("SomeStruct s{\n"
+ " \"xxxxxxxxxxxxx\",\n"
+ " \"yyyyyyyyyyyyy\",\n"
+ " \"zzzzzzzzzzzzz\",\n"
+ "};",
+ Style);
+ verifyFormat("SomeStruct{\n"
+ " \"xxxxxxxxxxxxx\",\n"
+ " \"yyyyyyyyyyyyy\",\n"
+ " \"zzzzzzzzzzzzz\",\n"
+ "};",
+ Style);
+ verifyFormat("new SomeStruct{\n"
+ " \"xxxxxxxxxxxxx\",\n"
+ " \"yyyyyyyyyyyyy\",\n"
+ " \"zzzzzzzzzzzzz\",\n"
+ "};",
+ Style);
+ // Member initializer.
+ verifyFormat("class SomeClass {\n"
+ " SomeStruct s{\n"
+ " \"xxxxxxxxxxxxx\",\n"
+ " \"yyyyyyyyyyyyy\",\n"
+ " \"zzzzzzzzzzzzz\",\n"
+ " };\n"
+ "};",
+ Style);
+ // Constructor member initializer.
+ verifyFormat("SomeClass::SomeClass : strct{\n"
+ " \"xxxxxxxxxxxxx\",\n"
+ " \"yyyyyyyyyyyyy\",\n"
+ " \"zzzzzzzzzzzzz\",\n"
+ " } {}",
+ Style);
+ // Copy initialization.
+ verifyFormat("SomeStruct s = SomeStruct{\n"
+ " \"xxxxxxxxxxxxx\",\n"
+ " \"yyyyyyyyyyyyy\",\n"
+ " \"zzzzzzzzzzzzz\",\n"
+ "};",
+ Style);
+ // Copy list initialization.
+ verifyFormat("SomeStruct s = {\n"
+ " \"xxxxxxxxxxxxx\",\n"
+ " \"yyyyyyyyyyyyy\",\n"
+ " \"zzzzzzzzzzzzz\",\n"
+ "};",
+ Style);
+ // Assignment operand initialization.
+ verifyFormat("s = {\n"
+ " \"xxxxxxxxxxxxx\",\n"
+ " \"yyyyyyyyyyyyy\",\n"
+ " \"zzzzzzzzzzzzz\",\n"
+ "};",
+ Style);
+ // Returned object initialization.
+ verifyFormat("return {\n"
+ " \"xxxxxxxxxxxxx\",\n"
+ " \"yyyyyyyyyyyyy\",\n"
+ " \"zzzzzzzzzzzzz\",\n"
+ "};",
+ Style);
+ // Initializer list.
+ verifyFormat("auto initializerList = {\n"
+ " \"xxxxxxxxxxxxx\",\n"
+ " \"yyyyyyyyyyyyy\",\n"
+ " \"zzzzzzzzzzzzz\",\n"
+ "};",
+ Style);
+ // Function parameter initialization.
+ verifyFormat("func({\n"
+ " \"xxxxxxxxxxxxx\",\n"
+ " \"yyyyyyyyyyyyy\",\n"
+ " \"zzzzzzzzzzzzz\",\n"
+ "});",
+ Style);
+ // Nested init lists.
+ verifyFormat("SomeStruct s = {\n"
+ " {{init1, init2, init3, init4, init5},\n"
+ " {init1, init2, init3, init4, init5}}\n"
+ "};",
+ Style);
+ verifyFormat("SomeStruct s = {\n"
+ " {{\n"
+ " .init1 = 1,\n"
+ " .init2 = 2,\n"
+ " .init3 = 3,\n"
+ " .init4 = 4,\n"
+ " .init5 = 5,\n"
+ " },\n"
+ " {init1, init2, init3, init4, init5}}\n"
+ "};",
+ Style);
+ verifyFormat("SomeArrayT a[3] = {\n"
+ " {\n"
+ " foo,\n"
+ " bar,\n"
+ " },\n"
+ " {\n"
+ " foo,\n"
+ " bar,\n"
+ " },\n"
+ " SomeArrayT{},\n"
+ "};",
+ Style);
+ verifyFormat("SomeArrayT a[3] = {\n"
+ " {foo},\n"
+ " {\n"
+ " {\n"
+ " init1,\n"
+ " init2,\n"
+ " init3,\n"
+ " },\n"
+ " {\n"
+ " init1,\n"
+ " init2,\n"
+ " init3,\n"
+ " },\n"
+ " },\n"
+ " {baz},\n"
+ "};",
+ Style);
+}
+
TEST_F(FormatTest, UnderstandsDigraphs) {
verifyFormat("int arr<:5:> = {};");
verifyFormat("int arr[5] = <%%>;");
More information about the cfe-commits
mailing list