[clang] [clang-format] Add BinPackBinaryOperations configuration (PR #95013)
Ameer J via cfe-commits
cfe-commits at lists.llvm.org
Wed Jul 17 09:06:28 PDT 2024
https://github.com/ameerj updated https://github.com/llvm/llvm-project/pull/95013
>From a50f3d4395efd09eea8ba2e750bb785857f9a550 Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Mon, 10 Jun 2024 12:09:40 -0400
Subject: [PATCH 01/15] Add BinPackBinaryOperations
---
clang/include/clang/Format/Format.h | 16 ++++++++++++++++
clang/lib/Format/ContinuationIndenter.cpp | 15 +++++++++++++++
clang/lib/Format/Format.cpp | 2 ++
3 files changed, 33 insertions(+)
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 4fd6e013df25b..f30d767600061 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1192,6 +1192,21 @@ struct FormatStyle {
/// \version 3.7
bool BinPackArguments;
+ /// If ``false``, binary operations will either be all on the same line
+ /// or each operation will have one line each.
+ /// \code
+ /// true:
+ /// aaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaaaaaaa ||
+ /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
+ ///
+ /// false:
+ /// aaaaaaaaaaaaaaaaaaaa &&
+ /// aaaaaaaaaaaaaaaaaaaa ||
+ /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
+ /// \endcode
+ /// \version 19
+ bool BinPackBinaryOperations;
+
/// If ``false``, a function declaration's or function definition's
/// parameters will either all be on the same line or will have one line each.
/// \code
@@ -4978,6 +4993,7 @@ struct FormatStyle {
R.AlwaysBreakBeforeMultilineStrings &&
AttributeMacros == R.AttributeMacros &&
BinPackArguments == R.BinPackArguments &&
+ BinPackBinaryOperations == R.BinPackBinaryOperations &&
BinPackParameters == R.BinPackParameters &&
BitFieldColonSpacing == R.BitFieldColonSpacing &&
BracedInitializerIndentWidth == R.BracedInitializerIndentWidth &&
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index b07360425ca6e..0780d219b68b4 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -146,6 +146,14 @@ static bool startsNextParameter(const FormatToken &Current,
Style.BreakInheritanceList != FormatStyle::BILS_BeforeComma));
}
+// Returns \c true if \c Current starts a new operand in a binary operation.
+static bool startsNextOperand(const FormatToken &Current,
+ const FormatStyle &Style) {
+ const FormatToken &Previous = *Current.Previous;
+ return Previous.is(TT_BinaryOperator) && !Current.isTrailingComment() &&
+ (Previous.getPrecedence() > prec::Conditional);
+}
+
static bool opensProtoMessageField(const FormatToken &LessTok,
const FormatStyle &Style) {
if (LessTok.isNot(tok::less))
@@ -837,6 +845,9 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
}
if (CurrentState.AvoidBinPacking && startsNextParameter(Current, Style))
CurrentState.NoLineBreak = true;
+ if (!Style.BinPackBinaryOperations && startsNextOperand(Current, Style))
+ CurrentState.NoLineBreak = true;
+
if (startsSegmentOfBuilderTypeCall(Current) &&
State.Column > getNewLineColumn(State)) {
CurrentState.ContainsUnwrappedBuilder = true;
@@ -1203,6 +1214,10 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
}
}
+ if (!Style.BinPackBinaryOperations && Previous.is(TT_BinaryOperator) &&
+ (Previous.getPrecedence() > prec::Conditional)) {
+ CurrentState.BreakBeforeParameter = true;
+ }
return Penalty;
}
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index c015e03fa15e7..4d71ce95afe1d 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -935,6 +935,7 @@ template <> struct MappingTraits<FormatStyle> {
Style.AlwaysBreakBeforeMultilineStrings);
IO.mapOptional("AttributeMacros", Style.AttributeMacros);
IO.mapOptional("BinPackArguments", Style.BinPackArguments);
+ IO.mapOptional("BinPackBinaryOperations", Style.BinPackBinaryOperations);
IO.mapOptional("BinPackParameters", Style.BinPackParameters);
IO.mapOptional("BitFieldColonSpacing", Style.BitFieldColonSpacing);
IO.mapOptional("BracedInitializerIndentWidth",
@@ -1439,6 +1440,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.AlwaysBreakBeforeMultilineStrings = false;
LLVMStyle.AttributeMacros.push_back("__capability");
LLVMStyle.BinPackArguments = true;
+ LLVMStyle.BinPackBinaryOperations = true;
LLVMStyle.BinPackParameters = true;
LLVMStyle.BitFieldColonSpacing = FormatStyle::BFCS_Both;
LLVMStyle.BracedInitializerIndentWidth = std::nullopt;
>From 1fe691c6ee0393cc3f40f0c5e94e01fe79a909c3 Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Mon, 10 Jun 2024 12:43:56 -0400
Subject: [PATCH 02/15] Add BinPackBinaryOperations unit tests
---
clang/unittests/Format/FormatTest.cpp | 80 +++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index fb57333858529..cb20c5db4884b 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -27492,6 +27492,86 @@ TEST_F(FormatTest, SpaceBetweenKeywordAndLiteral) {
verifyFormat("return sizeof \"5\";");
}
+TEST_F(FormatTest, BinPackBinaryOperations) {
+ auto Style = getLLVMStyle();
+ Style.BinPackBinaryOperations = false;
+
+ // Logical operations
+ verifyFormat("if (condition1 && condition2) {\n"
+ "}",
+ Style);
+ verifyFormat("if (condition1 && // comment\n"
+ " condition2 &&\n"
+ " (condition3 || condition4) && // comment\n"
+ " condition5 &&\n"
+ " condition6) {\n"
+ "}",
+ Style);
+ verifyFormat("if (loooooooooooooooooooooongcondition1 &&\n"
+ " loooooooooooooooooooooongcondition2) {\n"
+ "}",
+ Style);
+
+ // Arithmetic
+ verifyFormat("const int result = lhs + rhs;\n", Style);
+ verifyFormat("const int result = loooooooooooooooooooooongop1 +\n"
+ " loooooooooooooooooooooongop2 +\n"
+ " loooooooooooooooooooooongop3;\n",
+ Style);
+
+ // clang-format off
+ verifyFormat("const int result =\n"
+ " operand1 + operand2 - (operand3 + operand4) - operand5 * operand6;\n",
+ Style);
+ // clang-format on
+
+ verifyFormat("const int result = longOperand1 +\n"
+ " longOperand2 -\n"
+ " (longOperand3 + longOperand4) -\n"
+ " longOperand5 * longOperand6;\n",
+ Style);
+
+ Style.BinPackBinaryOperations = true;
+
+ // Logical operations
+ verifyFormat("if (condition1 && condition2) {\n"
+ "}",
+ Style);
+
+ // clang-format off
+ verifyFormat("if (condition1 && condition2 && (condition3 || condition4) && condition5 &&\n"
+ " condition6) {\n"
+ "}",
+ Style);
+ // clang-format on
+
+ verifyFormat("if (loooooooooooooooooooooongcondition1 &&\n"
+ " loooooooooooooooooooooongcondition2) {\n"
+ "}",
+ Style);
+
+ // Arithmetic
+ verifyFormat("const int result = lhs + rhs;\n", Style);
+
+ // clang-format off
+ verifyFormat("const int result = loooooooooooooooooooooongop1 + loooooooooooooooooooooongop2 +\n"
+ " loooooooooooooooooooooongop3;\n",
+ Style);
+ // clang-format on
+
+ // clang-format off
+ verifyFormat("const int result = longOperand1 + longOperand2 - (longOperand3 + longOperand4) -\n"
+ " longOperand5 * longOperand6;\n",
+ Style);
+ // clang-format on
+
+ // clang-format off
+ verifyFormat("const int result =\n"
+ " operand1 + operand2 - (operand3 + operand4) - operand5 * operand6;\n",
+ Style);
+ // clang-format on
+}
+
} // namespace
} // namespace test
} // namespace format
>From d95bf096387aa1812b83604e05edd22cc22d9584 Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Mon, 10 Jun 2024 13:18:07 -0400
Subject: [PATCH 03/15] Update ClangFormatStyleOptions.rst
---
clang/docs/ClangFormatStyleOptions.rst | 17 +++++++++++++++++
clang/include/clang/Format/Format.h | 2 +-
2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index bb00c20922d36..246d98eef63e8 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -2065,6 +2065,23 @@ the configuration (without a prefix: ``Auto``).
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);
}
+.. _BinPackBinaryOperations:
+
+**BinPackBinaryOperations** (``Boolean``) :versionbadge:`clang-format 19` :ref:`¶ <BinPackBinaryOperations>`
+ If ``false``, binary operations will either be all on the same line
+ or each operation will have one line each.
+
+ .. code-block:: c++
+
+ true:
+ aaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaaaaaaa ||
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
+
+ false:
+ aaaaaaaaaaaaaaaaaaaa &&
+ aaaaaaaaaaaaaaaaaaaa ||
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
+
.. _BinPackParameters:
**BinPackParameters** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ <BinPackParameters>`
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index f30d767600061..19b9c60ab6e99 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1197,7 +1197,7 @@ struct FormatStyle {
/// \code
/// true:
/// aaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaaaaaaa ||
- /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
+ /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
///
/// false:
/// aaaaaaaaaaaaaaaaaaaa &&
>From e9308d70cd07ef1c11c6e61f54bf4582ffb140e3 Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Tue, 11 Jun 2024 09:47:59 -0400
Subject: [PATCH 04/15] cleanup startsNextOperand
---
clang/lib/Format/ContinuationIndenter.cpp | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 0780d219b68b4..0ca5aa25597a9 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -147,8 +147,7 @@ static bool startsNextParameter(const FormatToken &Current,
}
// Returns \c true if \c Current starts a new operand in a binary operation.
-static bool startsNextOperand(const FormatToken &Current,
- const FormatStyle &Style) {
+static bool startsNextOperand(const FormatToken &Current) {
const FormatToken &Previous = *Current.Previous;
return Previous.is(TT_BinaryOperator) && !Current.isTrailingComment() &&
(Previous.getPrecedence() > prec::Conditional);
@@ -845,7 +844,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
}
if (CurrentState.AvoidBinPacking && startsNextParameter(Current, Style))
CurrentState.NoLineBreak = true;
- if (!Style.BinPackBinaryOperations && startsNextOperand(Current, Style))
+ if (!Style.BinPackBinaryOperations && startsNextOperand(Current))
CurrentState.NoLineBreak = true;
if (startsSegmentOfBuilderTypeCall(Current) &&
@@ -1214,10 +1213,8 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
}
}
- if (!Style.BinPackBinaryOperations && Previous.is(TT_BinaryOperator) &&
- (Previous.getPrecedence() > prec::Conditional)) {
+ if (!Style.BinPackBinaryOperations && startsNextOperand(Current))
CurrentState.BreakBeforeParameter = true;
- }
return Penalty;
}
>From e58c8eb306801f8cc94279159d7b26619f03dc83 Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Tue, 11 Jun 2024 12:35:33 -0400
Subject: [PATCH 05/15] Cleanup BinPackBinaryOperations test
---
clang/unittests/Format/FormatTest.cpp | 65 +++++++++++----------------
1 file changed, 27 insertions(+), 38 deletions(-)
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index cb20c5db4884b..405382d77826d 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -27493,20 +27493,18 @@ TEST_F(FormatTest, SpaceBetweenKeywordAndLiteral) {
}
TEST_F(FormatTest, BinPackBinaryOperations) {
- auto Style = getLLVMStyle();
- Style.BinPackBinaryOperations = false;
-
+ auto Style = getLLVMStyleWithColumns(60);
// Logical operations
verifyFormat("if (condition1 && condition2) {\n"
"}",
Style);
- verifyFormat("if (condition1 && // comment\n"
- " condition2 &&\n"
- " (condition3 || condition4) && // comment\n"
- " condition5 &&\n"
+
+ verifyFormat("if (condition1 && condition2 &&\n"
+ " (condition3 || condition4) && condition5 &&\n"
" condition6) {\n"
"}",
Style);
+
verifyFormat("if (loooooooooooooooooooooongcondition1 &&\n"
" loooooooooooooooooooooongcondition2) {\n"
"}",
@@ -27514,37 +27512,31 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
// Arithmetic
verifyFormat("const int result = lhs + rhs;\n", Style);
- verifyFormat("const int result = loooooooooooooooooooooongop1 +\n"
- " loooooooooooooooooooooongop2 +\n"
+
+ verifyFormat("const int result = loooooooongop1 + looooooooongop2 +\n"
" loooooooooooooooooooooongop3;\n",
Style);
-
- // clang-format off
- verifyFormat("const int result =\n"
- " operand1 + operand2 - (operand3 + operand4) - operand5 * operand6;\n",
+ verifyFormat("result = longOperand1 + longOperand2 -\n"
+ " (longOperand3 + longOperand4) -\n"
+ " longOperand5 * longOperand6;\n",
Style);
- // clang-format on
-
- verifyFormat("const int result = longOperand1 +\n"
- " longOperand2 -\n"
- " (longOperand3 + longOperand4) -\n"
- " longOperand5 * longOperand6;\n",
+ verifyFormat("const int result =\n"
+ " operand1 + operand2 - (operand3 + operand4);\n",
Style);
- Style.BinPackBinaryOperations = true;
+ Style.BinPackBinaryOperations = false;
// Logical operations
verifyFormat("if (condition1 && condition2) {\n"
"}",
Style);
-
- // clang-format off
- verifyFormat("if (condition1 && condition2 && (condition3 || condition4) && condition5 &&\n"
+ verifyFormat("if (condition1 && // comment\n"
+ " condition2 &&\n"
+ " (condition3 || condition4) && // comment\n"
+ " condition5 &&\n"
" condition6) {\n"
"}",
Style);
- // clang-format on
-
verifyFormat("if (loooooooooooooooooooooongcondition1 &&\n"
" loooooooooooooooooooooongcondition2) {\n"
"}",
@@ -27552,24 +27544,21 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
// Arithmetic
verifyFormat("const int result = lhs + rhs;\n", Style);
-
- // clang-format off
- verifyFormat("const int result = loooooooooooooooooooooongop1 + loooooooooooooooooooooongop2 +\n"
- " loooooooooooooooooooooongop3;\n",
+ verifyFormat("result = loooooooooooooooooooooongop1 +\n"
+ " loooooooooooooooooooooongop2 +\n"
+ " loooooooooooooooooooooongop3;\n",
Style);
- // clang-format on
- // clang-format off
- verifyFormat("const int result = longOperand1 + longOperand2 - (longOperand3 + longOperand4) -\n"
- " longOperand5 * longOperand6;\n",
+ verifyFormat("const int result =\n"
+ " operand1 + operand2 - (operand3 + operand4);\n",
Style);
- // clang-format on
- // clang-format off
- verifyFormat("const int result =\n"
- " operand1 + operand2 - (operand3 + operand4) - operand5 * operand6;\n",
+ verifyFormat("result = longOperand1 +\n"
+ " longOperand2 -\n"
+ " (longOperand3 + longOperand4) -\n"
+ " longOperand5 +\n"
+ " longOperand6\n",
Style);
- // clang-format on
}
} // namespace
>From 1de25f86eea5221212a53516dc116d1658834b7d Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Tue, 11 Jun 2024 12:52:04 -0400
Subject: [PATCH 06/15] Add another test
---
clang/unittests/Format/FormatTest.cpp | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 405382d77826d..23e7359d043b6 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -27557,7 +27557,14 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
" longOperand2 -\n"
" (longOperand3 + longOperand4) -\n"
" longOperand5 +\n"
- " longOperand6\n",
+ " longOperand6;\n",
+ Style);
+ verifyFormat("result = operand1 +\n"
+ " operand2 -\n"
+ " operand3 +\n"
+ " operand4 -\n"
+ " operand5 +\n"
+ " operand6;\n",
Style);
}
>From 9c9e084fa29e96acc72ee40315f725dc8840b5b4 Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Mon, 1 Jul 2024 12:44:36 -0400
Subject: [PATCH 07/15] Fix mixed precedence formatting
---
clang/lib/Format/TokenAnnotator.cpp | 9 +++++++++
clang/unittests/Format/FormatTest.cpp | 22 ++++++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 1fe3b61a5a81f..2e1889337510d 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -3134,6 +3134,15 @@ class ExpressionParser {
parse(Precedence + 1);
int CurrentPrecedence = getCurrentPrecedence();
+ if (!Style.BinPackBinaryOperations &&
+ (CurrentPrecedence > prec::Conditional) &&
+ (CurrentPrecedence < prec::PointerToMember)) {
+ // With BinPackBinaryOperations disabled,
+ // all operations will be on the same line or on individual lines.
+ // Override precedence to avoid adding fake parenthesis which could
+ // group operations of a different precedence level on the same line
+ CurrentPrecedence = prec::Additive;
+ }
if (Precedence == CurrentPrecedence && Current &&
Current->is(TT_SelectorName)) {
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 23e7359d043b6..1a2a42ab65954 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -27566,6 +27566,28 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
" operand5 +\n"
" operand6;\n",
Style);
+
+ // Ensure mixed precedence operations are handled properly
+ verifyFormat("result = op1 + op2 * op3 - op4;", Style);
+ verifyFormat("result = operand1 +\n"
+ " operand2 /\n"
+ " operand3 +\n"
+ " operand4 /\n"
+ " operand5 *\n"
+ " operand6;\n",
+ Style);
+ verifyFormat("result = operand1 *\n"
+ " operand2 -\n"
+ " operand3 *\n"
+ " operand4 -\n"
+ " operand5 +\n"
+ " operand6;\n",
+ Style);
+ verifyFormat("result = operand1 *\n"
+ " (operand2 - operand3 * operand4) -\n"
+ " operand5 +\n"
+ " operand6;\n",
+ Style);
}
} // namespace
>From 28ef1c7f87d3cd37dc5f5c409aab5e9ca76f6578 Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Mon, 1 Jul 2024 12:57:08 -0400
Subject: [PATCH 08/15] Add pointer to member precedence sanity check
---
clang/lib/Format/ContinuationIndenter.cpp | 3 ++-
clang/unittests/Format/FormatTest.cpp | 5 +++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 0ca5aa25597a9..965c112236e18 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -150,7 +150,8 @@ static bool startsNextParameter(const FormatToken &Current,
static bool startsNextOperand(const FormatToken &Current) {
const FormatToken &Previous = *Current.Previous;
return Previous.is(TT_BinaryOperator) && !Current.isTrailingComment() &&
- (Previous.getPrecedence() > prec::Conditional);
+ (Previous.getPrecedence() > prec::Conditional) &&
+ (Previous.getPrecedence() < prec::PointerToMember);
}
static bool opensProtoMessageField(const FormatToken &LessTok,
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 1a2a42ab65954..eef307ec4f8be 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -27588,6 +27588,11 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
" operand5 +\n"
" operand6;\n",
Style);
+ verifyFormat("result = operand1.member *\n"
+ " (operand2.member() - operand3->mem * operand4) -\n"
+ " operand5.member() +\n"
+ " operand6->member;\n",
+ Style);
}
} // namespace
>From 66337574431c6f496ca9c80c1a0816846bfbd84a Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Mon, 1 Jul 2024 13:03:08 -0400
Subject: [PATCH 09/15] fix formatting
---
clang/lib/Format/ContinuationIndenter.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 965c112236e18..12cf57c95abda 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -150,7 +150,7 @@ static bool startsNextParameter(const FormatToken &Current,
static bool startsNextOperand(const FormatToken &Current) {
const FormatToken &Previous = *Current.Previous;
return Previous.is(TT_BinaryOperator) && !Current.isTrailingComment() &&
- (Previous.getPrecedence() > prec::Conditional) &&
+ (Previous.getPrecedence() > prec::Conditional) &&
(Previous.getPrecedence() < prec::PointerToMember);
}
>From 8eee170a8bee85059bffd9810ee59a8705f9bf75 Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Mon, 1 Jul 2024 14:43:11 -0400
Subject: [PATCH 10/15] Update ReleaseNotes.rst
---
clang/docs/ReleaseNotes.rst | 1 +
1 file changed, 1 insertion(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 90c2469c1c89a..9ec5ed1da0276 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1130,6 +1130,7 @@ clang-format
- Adds ``LeftWithLastLine`` suboption to ``AlignEscapedNewlines``.
- Adds ``KeepEmptyLines`` option to deprecate ``KeepEmptyLinesAtEOF``
and ``KeepEmptyLinesAtTheStartOfBlocks``.
+- Adds ``BinPackBinaryOperations`` option.
libclang
--------
>From daa3cf1760e983013ef318cc96c8377431b79c76 Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Wed, 10 Jul 2024 11:59:27 -0400
Subject: [PATCH 11/15] Review comments
---
clang/lib/Format/ContinuationIndenter.cpp | 12 +++++++-----
clang/unittests/Format/FormatTest.cpp | 10 ++++++++++
2 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 12cf57c95abda..ed30de63917bb 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -131,7 +131,8 @@ static bool startsSegmentOfBuilderTypeCall(const FormatToken &Tok) {
// Returns \c true if \c Current starts a new parameter.
static bool startsNextParameter(const FormatToken &Current,
const FormatStyle &Style) {
- const FormatToken &Previous = *Current.Previous;
+ assert(Current.Previous);
+ const auto &Previous = *Current.Previous;
if (Current.is(TT_CtorInitializerComma) &&
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma) {
return true;
@@ -146,12 +147,13 @@ static bool startsNextParameter(const FormatToken &Current,
Style.BreakInheritanceList != FormatStyle::BILS_BeforeComma));
}
-// Returns \c true if \c Current starts a new operand in a binary operation.
+// Returns \c true if \c Current starts the next operand in a binary operation.
static bool startsNextOperand(const FormatToken &Current) {
- const FormatToken &Previous = *Current.Previous;
+ assert(Current.Previous);
+ const auto &Previous = *Current.Previous;
return Previous.is(TT_BinaryOperator) && !Current.isTrailingComment() &&
- (Previous.getPrecedence() > prec::Conditional) &&
- (Previous.getPrecedence() < prec::PointerToMember);
+ Previous.getPrecedence() > prec::Conditional &&
+ Previous.getPrecedence() < prec::PointerToMember;
}
static bool opensProtoMessageField(const FormatToken &LessTok,
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 60dd2a0968694..661ae882eb373 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -27652,10 +27652,12 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
verifyFormat("const int result = loooooooongop1 + looooooooongop2 +\n"
" loooooooooooooooooooooongop3;\n",
Style);
+
verifyFormat("result = longOperand1 + longOperand2 -\n"
" (longOperand3 + longOperand4) -\n"
" longOperand5 * longOperand6;\n",
Style);
+
verifyFormat("const int result =\n"
" operand1 + operand2 - (operand3 + operand4);\n",
Style);
@@ -27666,6 +27668,7 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
verifyFormat("if (condition1 && condition2) {\n"
"}",
Style);
+
verifyFormat("if (condition1 && // comment\n"
" condition2 &&\n"
" (condition3 || condition4) && // comment\n"
@@ -27673,6 +27676,7 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
" condition6) {\n"
"}",
Style);
+
verifyFormat("if (loooooooooooooooooooooongcondition1 &&\n"
" loooooooooooooooooooooongcondition2) {\n"
"}",
@@ -27680,6 +27684,7 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
// Arithmetic
verifyFormat("const int result = lhs + rhs;\n", Style);
+
verifyFormat("result = loooooooooooooooooooooongop1 +\n"
" loooooooooooooooooooooongop2 +\n"
" loooooooooooooooooooooongop3;\n",
@@ -27695,6 +27700,7 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
" longOperand5 +\n"
" longOperand6;\n",
Style);
+
verifyFormat("result = operand1 +\n"
" operand2 -\n"
" operand3 +\n"
@@ -27705,6 +27711,7 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
// Ensure mixed precedence operations are handled properly
verifyFormat("result = op1 + op2 * op3 - op4;", Style);
+
verifyFormat("result = operand1 +\n"
" operand2 /\n"
" operand3 +\n"
@@ -27712,6 +27719,7 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
" operand5 *\n"
" operand6;\n",
Style);
+
verifyFormat("result = operand1 *\n"
" operand2 -\n"
" operand3 *\n"
@@ -27719,11 +27727,13 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
" operand5 +\n"
" operand6;\n",
Style);
+
verifyFormat("result = operand1 *\n"
" (operand2 - operand3 * operand4) -\n"
" operand5 +\n"
" operand6;\n",
Style);
+
verifyFormat("result = operand1.member *\n"
" (operand2.member() - operand3->mem * operand4) -\n"
" operand5.member() +\n"
>From 5520dc168126f249b5cb0becd6a9dd24883be8be Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Thu, 11 Jul 2024 11:25:42 -0400
Subject: [PATCH 12/15] Review comments
---
clang/lib/Format/TokenAnnotator.cpp | 4 ++--
clang/unittests/Format/ConfigParseTest.cpp | 1 +
clang/unittests/Format/FormatTest.cpp | 20 ++++++++++----------
3 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 8b6bd773e6063..bc7ec692b16ba 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -3154,8 +3154,8 @@ class ExpressionParser {
int CurrentPrecedence = getCurrentPrecedence();
if (!Style.BinPackBinaryOperations &&
- (CurrentPrecedence > prec::Conditional) &&
- (CurrentPrecedence < prec::PointerToMember)) {
+ CurrentPrecedence > prec::Conditional &&
+ CurrentPrecedence < prec::PointerToMember) {
// With BinPackBinaryOperations disabled,
// all operations will be on the same line or on individual lines.
// Override precedence to avoid adding fake parenthesis which could
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index cc044153b7c9b..1381b221bc725 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -160,6 +160,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
CHECK_PARSE_BOOL(AllowShortEnumsOnASingleLine);
CHECK_PARSE_BOOL(AllowShortLoopsOnASingleLine);
CHECK_PARSE_BOOL(BinPackArguments);
+ CHECK_PARSE_BOOL(BinPackBinaryOperations);
CHECK_PARSE_BOOL(BinPackParameters);
CHECK_PARSE_BOOL(BreakAdjacentStringLiterals);
CHECK_PARSE_BOOL(BreakAfterJavaFieldAnnotations);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 661ae882eb373..046c85c2d0a00 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -27650,12 +27650,12 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
verifyFormat("const int result = lhs + rhs;\n", Style);
verifyFormat("const int result = loooooooongop1 + looooooooongop2 +\n"
- " loooooooooooooooooooooongop3;\n",
+ " loooooooooooooooooooooongop3;",
Style);
verifyFormat("result = longOperand1 + longOperand2 -\n"
" (longOperand3 + longOperand4) -\n"
- " longOperand5 * longOperand6;\n",
+ " longOperand5 * longOperand6;",
Style);
verifyFormat("const int result =\n"
@@ -27687,18 +27687,18 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
verifyFormat("result = loooooooooooooooooooooongop1 +\n"
" loooooooooooooooooooooongop2 +\n"
- " loooooooooooooooooooooongop3;\n",
+ " loooooooooooooooooooooongop3;",
Style);
verifyFormat("const int result =\n"
- " operand1 + operand2 - (operand3 + operand4);\n",
+ " operand1 + operand2 - (operand3 + operand4);",
Style);
verifyFormat("result = longOperand1 +\n"
" longOperand2 -\n"
" (longOperand3 + longOperand4) -\n"
" longOperand5 +\n"
- " longOperand6;\n",
+ " longOperand6;",
Style);
verifyFormat("result = operand1 +\n"
@@ -27706,7 +27706,7 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
" operand3 +\n"
" operand4 -\n"
" operand5 +\n"
- " operand6;\n",
+ " operand6;",
Style);
// Ensure mixed precedence operations are handled properly
@@ -27717,7 +27717,7 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
" operand3 +\n"
" operand4 /\n"
" operand5 *\n"
- " operand6;\n",
+ " operand6;",
Style);
verifyFormat("result = operand1 *\n"
@@ -27725,19 +27725,19 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
" operand3 *\n"
" operand4 -\n"
" operand5 +\n"
- " operand6;\n",
+ " operand6;",
Style);
verifyFormat("result = operand1 *\n"
" (operand2 - operand3 * operand4) -\n"
" operand5 +\n"
- " operand6;\n",
+ " operand6;",
Style);
verifyFormat("result = operand1.member *\n"
" (operand2.member() - operand3->mem * operand4) -\n"
" operand5.member() +\n"
- " operand6->member;\n",
+ " operand6->member;",
Style);
}
>From 21bcfa51e77e4e03771ae22c0c5d3568ac263e35 Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Thu, 11 Jul 2024 11:28:14 -0400
Subject: [PATCH 13/15] missed a trailing newline
---
clang/unittests/Format/FormatTest.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 046c85c2d0a00..b0cb01f50e479 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -27647,7 +27647,7 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
Style);
// Arithmetic
- verifyFormat("const int result = lhs + rhs;\n", Style);
+ verifyFormat("const int result = lhs + rhs;", Style);
verifyFormat("const int result = loooooooongop1 + looooooooongop2 +\n"
" loooooooooooooooooooooongop3;",
>From e1f1cf22d668411879b1060072eb46540efdcdd6 Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Mon, 15 Jul 2024 08:44:53 -0400
Subject: [PATCH 14/15] missed trailing newlines
---
clang/unittests/Format/FormatTest.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index b0cb01f50e479..9caaa164288d7 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -27659,7 +27659,7 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
Style);
verifyFormat("const int result =\n"
- " operand1 + operand2 - (operand3 + operand4);\n",
+ " operand1 + operand2 - (operand3 + operand4);",
Style);
Style.BinPackBinaryOperations = false;
@@ -27683,7 +27683,7 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
Style);
// Arithmetic
- verifyFormat("const int result = lhs + rhs;\n", Style);
+ verifyFormat("const int result = lhs + rhs;", Style);
verifyFormat("result = loooooooooooooooooooooongop1 +\n"
" loooooooooooooooooooooongop2 +\n"
>From 33a6ef9585ff6c696d37daa6eb7eb0fbede3c86d Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Wed, 17 Jul 2024 11:56:09 -0400
Subject: [PATCH 15/15] Fixes for BreakBeforeBinaryOperators
---
clang/lib/Format/ContinuationIndenter.cpp | 29 ++++++++--
clang/unittests/Format/FormatTest.cpp | 69 +++++++++++++++++++++++
2 files changed, 93 insertions(+), 5 deletions(-)
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index ed30de63917bb..d3fd7620bf2dd 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -147,13 +147,31 @@ static bool startsNextParameter(const FormatToken &Current,
Style.BreakInheritanceList != FormatStyle::BILS_BeforeComma));
}
+// Returns \c true if \c Token in an alignable binary operator
+static bool isAlignableBinaryOperator(const FormatToken &Token) {
+ // No need to align binary operators that only have two operands.
+ bool HasTwoOperands = Token.OperatorIndex == 0 && !Token.NextOperator &&
+ Token.isNot(TT_ConditionalExpr);
+ return Token.is(TT_BinaryOperator) && !HasTwoOperands &&
+ Token.getPrecedence() > prec::Conditional &&
+ Token.getPrecedence() < prec::PointerToMember;
+}
+
// Returns \c true if \c Current starts the next operand in a binary operation.
static bool startsNextOperand(const FormatToken &Current) {
assert(Current.Previous);
const auto &Previous = *Current.Previous;
- return Previous.is(TT_BinaryOperator) && !Current.isTrailingComment() &&
- Previous.getPrecedence() > prec::Conditional &&
- Previous.getPrecedence() < prec::PointerToMember;
+ return isAlignableBinaryOperator(Previous) && !Current.isTrailingComment();
+}
+
+// Returns \c true if \c Current is a binary operation that must break.
+static bool mustBreakBinaryOperation(const FormatToken &Current,
+ const FormatStyle &Style) {
+ return !Style.BinPackBinaryOperations &&
+ ((isAlignableBinaryOperator(Current) &&
+ Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None) ||
+ (startsNextOperand(Current) &&
+ Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None));
}
static bool opensProtoMessageField(const FormatToken &LessTok,
@@ -847,7 +865,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
}
if (CurrentState.AvoidBinPacking && startsNextParameter(Current, Style))
CurrentState.NoLineBreak = true;
- if (!Style.BinPackBinaryOperations && startsNextOperand(Current))
+ if (mustBreakBinaryOperation(Current, Style))
CurrentState.NoLineBreak = true;
if (startsSegmentOfBuilderTypeCall(Current) &&
@@ -1216,8 +1234,9 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
}
}
- if (!Style.BinPackBinaryOperations && startsNextOperand(Current))
+ if (mustBreakBinaryOperation(Current, Style))
CurrentState.BreakBeforeParameter = true;
+
return Penalty;
}
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 9caaa164288d7..a358c53a5f6f8 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -27739,6 +27739,75 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
" operand5.member() +\n"
" operand6->member;",
Style);
+
+ Style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
+ // Logical operations
+ verifyFormat("if (condition1 && condition2) {\n"
+ "}",
+ Style);
+
+ verifyFormat("if (loooooooooooooooooooooongcondition1\n"
+ " && loooooooooooooooooooooongcondition2) {\n"
+ "}",
+ Style);
+
+ // Arithmetic
+ verifyFormat("const int result = lhs + rhs;", Style);
+
+ verifyFormat("result = loooooooooooooooooooooongop1\n"
+ " + loooooooooooooooooooooongop2\n"
+ " + loooooooooooooooooooooongop3;",
+ Style);
+
+ verifyFormat("const int result =\n"
+ " operand1 + operand2 - (operand3 + operand4);",
+ Style);
+
+ verifyFormat("result = longOperand1\n"
+ " + longOperand2\n"
+ " - (longOperand3 + longOperand4)\n"
+ " - longOperand5\n"
+ " + longOperand6;",
+ Style);
+
+ verifyFormat("result = operand1\n"
+ " + operand2\n"
+ " - operand3\n"
+ " + operand4\n"
+ " - operand5\n"
+ " + operand6;",
+ Style);
+
+ // Ensure mixed precedence operations are handled properly
+ verifyFormat("result = op1 + op2 * op3 - op4;", Style);
+
+ verifyFormat("result = operand1\n"
+ " + operand2\n"
+ " / operand3\n"
+ " + operand4\n"
+ " / operand5\n"
+ " * operand6;",
+ Style);
+
+ verifyFormat("result = operand1\n"
+ " * operand2\n"
+ " - operand3\n"
+ " * operand4\n"
+ " - operand5\n"
+ " + operand6;",
+ Style);
+
+ verifyFormat("result = operand1\n"
+ " * (operand2 - operand3 * operand4)\n"
+ " - operand5\n"
+ " + operand6;",
+ Style);
+
+ verifyFormat("std::uint32_t a = byte_buffer[0]\n"
+ " | (byte_buffer[1] << 8)\n"
+ " | (byte_buffer[2] << 16)\n"
+ " | (byte_buffer[3] << 24);",
+ Style);
}
} // namespace
More information about the cfe-commits
mailing list