[clang] [clang-format] Fix BreakAfterOpenBracket options being ignored with larger continuation indents (PR #228085)
Hadong Lee via cfe-commits
cfe-commits at lists.llvm.org
Sat Oct 3 05:27:48 PDT 2026
https://github.com/ChrisLee02 updated https://github.com/llvm/llvm-project/pull/228085
>From d84b258b67e6c65c8b23761665b93b4c6c0af924 Mon Sep 17 00:00:00 2001
From: Chrislee02 <hdchris765 at snu.ac.kr>
Date: Thu, 1 Oct 2026 21:46:08 +0900
Subject: [PATCH 1/3] [clang-format] Add baseline tests for
BreakAfterOpenBracket options
---
clang/unittests/Format/AlignBracketsTest.cpp | 92 ++++++++++++++++++++
1 file changed, 92 insertions(+)
diff --git a/clang/unittests/Format/AlignBracketsTest.cpp b/clang/unittests/Format/AlignBracketsTest.cpp
index e7e57bf839c0e1..171872d6740774 100644
--- a/clang/unittests/Format/AlignBracketsTest.cpp
+++ b/clang/unittests/Format/AlignBracketsTest.cpp
@@ -861,6 +861,98 @@ TEST_F(AlignBracketsTest, BlockIndentAndNamespace) {
Style);
}
+TEST_F(AlignBracketsTest, BreakAfterOpenBracketIfStatement) {
+ auto Style = getLLVMStyleWithColumns(40);
+ Style.PackArguments.BinPack = FormatStyle::BPAS_OnePerLine;
+ Style.BreakAfterOpenBracketIf = true;
+
+ verifyFormat("void f() {\n"
+ " if (call(aaaaaaaaaaaaaaaaaaaa,\n"
+ " bbbbbbbbbbbbbbbbbbbb,\n"
+ " cccccccccccccccccccc) < 0)\n"
+ " return;\n"
+ "}",
+ "void f() {\n"
+ " if (call(aaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbb, "
+ "cccccccccccccccccccc) < 0) return;\n"
+ "}",
+ Style);
+}
+
+TEST_F(AlignBracketsTest, BreakAfterOpenBracketFunctionCall) {
+ auto Style = getLLVMStyleWithColumns(40);
+ Style.PackArguments.BinPack = FormatStyle::BPAS_OnePerLine;
+ Style.BreakAfterOpenBracketFunction = true;
+
+ verifyFormat("void f() {\n"
+ " g(aaaaaaaaaaaaaaaaaaaa,\n"
+ " bbbbbbbbbbbbbbbbbbbb,\n"
+ " cccccccccccccccccccc);\n"
+ "}",
+ "void f() {\n"
+ " g(aaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbb, "
+ "cccccccccccccccccccc);\n"
+ "}",
+ Style);
+}
+
+TEST_F(AlignBracketsTest, BreakAfterOpenBracketLoopStatement) {
+ auto Style = getLLVMStyleWithColumns(40);
+ Style.ContinuationIndentWidth = 7;
+ Style.PackArguments.BinPack = FormatStyle::BPAS_OnePerLine;
+ Style.BreakAfterOpenBracketLoop = true;
+
+ verifyFormat("void f() {\n"
+ " while (call(aaaaaaaaaaaaaaaaaaaa,\n"
+ " bbbbbbbbbbbbbbbbbbbb,\n"
+ " cccccccccccccccccccc) < 0)\n"
+ " return;\n"
+ "}",
+ "void f() {\n"
+ " while (call(aaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbb, "
+ "cccccccccccccccccccc) < 0) return;\n"
+ "}",
+ Style);
+}
+
+TEST_F(AlignBracketsTest, BreakAfterOpenBracketSwitchStatement) {
+ auto Style = getLLVMStyleWithColumns(40);
+ Style.ContinuationIndentWidth = 8;
+ Style.PackArguments.BinPack = FormatStyle::BPAS_OnePerLine;
+ Style.BreakAfterOpenBracketSwitch = true;
+
+ verifyFormat("void f() {\n"
+ " switch (call(aaaaaaaaaaaaaaaaaaaa,\n"
+ " bbbbbbbbbbbbbbbbbbbb,\n"
+ " cccccccccccccccccccc)) {\n"
+ " default:\n"
+ " return;\n"
+ " }\n"
+ "}",
+ "void f() {\n"
+ " switch (call(aaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbb, "
+ "cccccccccccccccccccc)) { default: return; }\n"
+ "}",
+ Style);
+}
+
+TEST_F(AlignBracketsTest, BreakAfterOpenBracketBracedList) {
+ auto Style = getLLVMStyle();
+ Style.ContinuationIndentWidth = 11;
+ Style.BreakAfterOpenBracketBracedList = true;
+
+ verifyFormat("void f() {\n"
+ " int a[] = {111111111111111111, 222222222222222222, "
+ "333333333333333333,\n"
+ " 444444444444444444};\n"
+ "}",
+ "void f() {\n"
+ " int a[] = {111111111111111111, 222222222222222222, "
+ "333333333333333333, 444444444444444444};\n"
+ "}",
+ Style);
+}
+
} // namespace
} // namespace test
} // namespace format
>From dbe30504212d86a1ed61755081727181f3b5df55 Mon Sep 17 00:00:00 2001
From: Chrislee02 <hdchris765 at snu.ac.kr>
Date: Thu, 1 Oct 2026 23:00:40 +0900
Subject: [PATCH 2/3] [clang-format] Fix BreakAfterOpenBracket options being
ignored with larger continuation indents
---
clang/lib/Format/ContinuationIndenter.cpp | 10 ++++++++--
clang/unittests/Format/AlignBracketsTest.cpp | 19 ++++++++++++-------
clang/unittests/Format/FormatTest.cpp | 3 ++-
clang/unittests/Format/FormatTestJS.cpp | 14 ++++++++------
4 files changed, 30 insertions(+), 16 deletions(-)
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index cb3dee9d75c23c..1791d0fbfe8b85 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -918,7 +918,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
// In "AlwaysBreak" or "BlockIndent" mode, enforce wrapping directly after the
// parenthesis by disallowing any further line breaks if there is no line
// break after the opening parenthesis. Don't break if it doesn't conserve
- // columns.
+ // columns, unless the style option applies and a break is allowed.
auto IsOpeningBracket = [&](const FormatToken &Tok) {
auto IsStartOfBracedList = [&]() {
return Tok.is(tok::l_brace) && Tok.isNot(BK_Block) &&
@@ -996,7 +996,13 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
Next->is(TT_FunctionDeclarationLParen) || IsFunctionCallParen(*Next);
};
if (IsOpeningBracket(Previous) &&
- State.Column > getNewLineColumn(State).Total &&
+ (State.Column > getNewLineColumn(State).Total ||
+ // IsOpeningBracket checks BreakAfterOpenBracketBracedList before its
+ // (!Tok.Previous) shortcut. All other true returns with a preceding
+ // token require a BreakAfterOpenBracket* option.
+ // Only forbid later breaks if a break here is possible to prevent
+ // alternatives from being blocked.
+ ((Previous.Previous || Previous.is(tok::l_brace)) && canBreak(State))) &&
// Don't do this for simple (no expressions) one-argument function calls
// as that feels like needlessly wasting whitespace, e.g.:
//
diff --git a/clang/unittests/Format/AlignBracketsTest.cpp b/clang/unittests/Format/AlignBracketsTest.cpp
index 171872d6740774..fe47ccae86c9f1 100644
--- a/clang/unittests/Format/AlignBracketsTest.cpp
+++ b/clang/unittests/Format/AlignBracketsTest.cpp
@@ -867,7 +867,8 @@ TEST_F(AlignBracketsTest, BreakAfterOpenBracketIfStatement) {
Style.BreakAfterOpenBracketIf = true;
verifyFormat("void f() {\n"
- " if (call(aaaaaaaaaaaaaaaaaaaa,\n"
+ " if (\n"
+ " call(aaaaaaaaaaaaaaaaaaaa,\n"
" bbbbbbbbbbbbbbbbbbbb,\n"
" cccccccccccccccccccc) < 0)\n"
" return;\n"
@@ -885,9 +886,10 @@ TEST_F(AlignBracketsTest, BreakAfterOpenBracketFunctionCall) {
Style.BreakAfterOpenBracketFunction = true;
verifyFormat("void f() {\n"
- " g(aaaaaaaaaaaaaaaaaaaa,\n"
- " bbbbbbbbbbbbbbbbbbbb,\n"
- " cccccccccccccccccccc);\n"
+ " g(\n"
+ " aaaaaaaaaaaaaaaaaaaa,\n"
+ " bbbbbbbbbbbbbbbbbbbb,\n"
+ " cccccccccccccccccccc);\n"
"}",
"void f() {\n"
" g(aaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbb, "
@@ -903,7 +905,8 @@ TEST_F(AlignBracketsTest, BreakAfterOpenBracketLoopStatement) {
Style.BreakAfterOpenBracketLoop = true;
verifyFormat("void f() {\n"
- " while (call(aaaaaaaaaaaaaaaaaaaa,\n"
+ " while (\n"
+ " call(aaaaaaaaaaaaaaaaaaaa,\n"
" bbbbbbbbbbbbbbbbbbbb,\n"
" cccccccccccccccccccc) < 0)\n"
" return;\n"
@@ -922,7 +925,8 @@ TEST_F(AlignBracketsTest, BreakAfterOpenBracketSwitchStatement) {
Style.BreakAfterOpenBracketSwitch = true;
verifyFormat("void f() {\n"
- " switch (call(aaaaaaaaaaaaaaaaaaaa,\n"
+ " switch (\n"
+ " call(aaaaaaaaaaaaaaaaaaaa,\n"
" bbbbbbbbbbbbbbbbbbbb,\n"
" cccccccccccccccccccc)) {\n"
" default:\n"
@@ -942,7 +946,8 @@ TEST_F(AlignBracketsTest, BreakAfterOpenBracketBracedList) {
Style.BreakAfterOpenBracketBracedList = true;
verifyFormat("void f() {\n"
- " int a[] = {111111111111111111, 222222222222222222, "
+ " int a[] = {\n"
+ " 111111111111111111, 222222222222222222, "
"333333333333333333,\n"
" 444444444444444444};\n"
"}",
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 0a5950c25c60ef..09bebd446da0c8 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -21724,7 +21724,8 @@ TEST_F(FormatTest, FormatsLambdas) {
Style.BraceWrapping.BeforeLambdaBody = true;
verifyFormat("void foo() {\n"
" aFunction(\n"
- " 1, b(c(foo, Bar{}, baz, [](d) -> Foo\n"
+ " 1, b(c(\n"
+ " foo, Bar{}, baz, [](d) -> Foo\n"
" {\n"
" auto f = e(\n"
" [&]\n"
diff --git a/clang/unittests/Format/FormatTestJS.cpp b/clang/unittests/Format/FormatTestJS.cpp
index b405a73bce0860..710f8d3682ad8a 100644
--- a/clang/unittests/Format/FormatTestJS.cpp
+++ b/clang/unittests/Format/FormatTestJS.cpp
@@ -238,7 +238,8 @@ TEST_F(FormatTestJS, UnderstandsJavaScriptOperators) {
verifyFormat("aaaaaaa ===\n b;", getGoogleJSStyleWithColumns(10));
verifyFormat("a !== b;");
verifyFormat("aaaaaaa !==\n b;", getGoogleJSStyleWithColumns(10));
- verifyFormat("if (a + b + c +\n"
+ verifyFormat("if (\n"
+ " a + b + c +\n"
" d !==\n"
" e + f + g)\n"
" q();",
@@ -250,7 +251,8 @@ TEST_F(FormatTestJS, UnderstandsJavaScriptOperators) {
verifyFormat("aaaaaaa >>>\n b;", getGoogleJSStyleWithColumns(10));
verifyFormat("a >>>= b;");
verifyFormat("aaaaaaa >>>=\n b;", getGoogleJSStyleWithColumns(10));
- verifyFormat("if (a + b + c +\n"
+ verifyFormat("if (\n"
+ " a + b + c +\n"
" d >>>\n"
" e + f + g)\n"
" q();",
@@ -1273,10 +1275,10 @@ TEST_F(FormatTestJS, ArrowFunctions) {
verifyFormat("var x = (a) => a;");
verifyFormat("return () => [];");
verifyFormat("var aaaaaaaaaaaaaaaaaaaa = {\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaa:\n"
- " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) =>\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaa: (\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) =>\n"
+ " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
"};");
verifyFormat("var a = a.aaaaaaa(\n"
" (a: a) => aaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbbbb) &&\n"
>From f3e28468fbb4ee296f3ea31a16726a6908c76f2b Mon Sep 17 00:00:00 2001
From: Chrislee02 <hdchris765 at snu.ac.kr>
Date: Sat, 3 Oct 2026 21:27:28 +0900
Subject: [PATCH 3/3] [clang-format] Clarify BreakAfterOpenBracket option
matching
---
clang/lib/Format/ContinuationIndenter.cpp | 25 +++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 1791d0fbfe8b85..f64c3b3907b71e 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -942,6 +942,26 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
}
return false;
};
+
+ auto ShouldBreakAfterOpeningBracket = [&](const FormatToken &Tok) {
+ // Suppose that IsOpeningBracket returned true for a Tok
+
+ // Corresponds to BreakAfterOpenBracketBracedList
+ if (Tok.is(tok::l_brace))
+ return true;
+
+ const auto *Before = Tok.Previous;
+ if (!Before)
+ return false;
+
+ // Corresponds to BreakAfterOpenBracketIf, BreakAfterOpenBracketLoop,
+ // BreakAfterOpenBracketSwitch, BreakAfterOpenBracketFunction.
+ return Before->isIf() || Before->isLoop(Style) ||
+ Before->is(tok::kw_switch) ||
+ (!Before->is(TT_CastRParen) &&
+ !(Style.isJavaScript() && Tok.is(Keywords.kw_await)));
+ };
+
auto IsFunctionCallParen = [](const FormatToken &Tok) {
return Tok.is(tok::l_paren) && Tok.ParameterCount > 0 && Tok.Previous &&
Tok.Previous->is(tok::identifier);
@@ -997,12 +1017,9 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
};
if (IsOpeningBracket(Previous) &&
(State.Column > getNewLineColumn(State).Total ||
- // IsOpeningBracket checks BreakAfterOpenBracketBracedList before its
- // (!Tok.Previous) shortcut. All other true returns with a preceding
- // token require a BreakAfterOpenBracket* option.
// Only forbid later breaks if a break here is possible to prevent
// alternatives from being blocked.
- ((Previous.Previous || Previous.is(tok::l_brace)) && canBreak(State))) &&
+ (ShouldBreakAfterOpeningBracket(Previous) && canBreak(State))) &&
// Don't do this for simple (no expressions) one-argument function calls
// as that feels like needlessly wasting whitespace, e.g.:
//
More information about the cfe-commits
mailing list