[clang] [clang-format] Add BreakBinaryOperations configuration (PR #95013)

Ameer J via cfe-commits cfe-commits at lists.llvm.org
Mon Aug 5 09:20:59 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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/19] 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

>From 5b091ff1c04ba4cc32a8f965899b2586810f0bd6 Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Wed, 17 Jul 2024 13:26:08 -0400
Subject: [PATCH 16/19] Rename BinPackBinaryOperations -> BreakBinaryOperations
 enum

---
 clang/docs/ClangFormatStyleOptions.rst     | 57 ++++++++++++------
 clang/docs/ReleaseNotes.rst                |  2 +-
 clang/include/clang/Format/Format.h        | 52 +++++++++++------
 clang/lib/Format/ContinuationIndenter.cpp  |  2 +-
 clang/lib/Format/Format.cpp                | 15 ++++-
 clang/lib/Format/TokenAnnotator.cpp        |  4 +-
 clang/unittests/Format/ConfigParseTest.cpp |  9 ++-
 clang/unittests/Format/FormatTest.cpp      | 67 ++++++++++++++++++++--
 8 files changed, 163 insertions(+), 45 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 1d9d58c01cad5..6a533ec30afd2 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -2065,23 +2065,6 @@ 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>`
@@ -3317,6 +3300,46 @@ the configuration (without a prefix: ``Auto``).
          firstValue :
          SecondValueVeryVeryVeryVeryLong;
 
+.. _BreakBinaryOperations:
+
+**BreakBinaryOperations** (``BreakBinaryOperationsStyle``) :versionbadge:`clang-format 19` :ref:`¶ <BreakBinaryOperations>`
+  The break constructor initializers style to use.
+
+  Possible values:
+
+  * ``BBO_Never`` (in configuration: ``Never``)
+    Don't break binary operations
+
+    .. code-block:: c++
+
+       aaa + bbbb * ccccc - ddddd +
+       eeeeeeeeeeeeeeee;
+
+  * ``BBO_BreakAll`` (in configuration: ``BreakAll``)
+    Binary operations will either be all on the same line, or each operation
+    will have one line each.
+
+    .. code-block:: c++
+
+       aaa +
+       bbbb *
+       ccccc -
+       ddddd +
+       eeeeeeeeeeeeeeee;
+
+  * ``BBO_BreakRespectPrecedence`` (in configuration: ``BreakRespectPrecedence``)
+    Binary operations of a particular precedence that go beyond the column
+    limit will have one line each.
+
+    .. code-block:: c++
+
+       aaa +
+       bbbb * ccccc -
+       ddddd +
+       eeeeeeeeeeeeeeee;
+
+
+
 .. _BreakConstructorInitializers:
 
 **BreakConstructorInitializers** (``BreakConstructorInitializersStyle``) :versionbadge:`clang-format 5` :ref:`¶ <BreakConstructorInitializers>`
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 31478f73ffcfc..fa2c80a846d00 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1143,7 +1143,7 @@ clang-format
 - Adds ``LeftWithLastLine`` suboption to ``AlignEscapedNewlines``.
 - Adds ``KeepEmptyLines`` option to deprecate ``KeepEmptyLinesAtEOF``
   and ``KeepEmptyLinesAtTheStartOfBlocks``.
-- Adds ``BinPackBinaryOperations`` option.
+- Adds ``BreakBinaryOperations`` option.
 - Add ``ExceptDoubleParentheses`` sub-option for ``SpacesInParensOptions``
   to override addition of spaces between multiple, non-redundant parentheses
   similar to the rules used for ``RemoveParentheses``.
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 6c5b44904131e..7c98c848484af 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1192,21 +1192,6 @@ 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
@@ -2246,6 +2231,41 @@ struct FormatStyle {
   /// \version 3.7
   bool BreakBeforeTernaryOperators;
 
+  /// Different ways to break binary operations.
+  enum BreakBinaryOperationsStyle : int8_t {
+    /// Don't break binary operations
+    /// \code
+    ///    aaa + bbbb * ccccc - ddddd +
+    ///    eeeeeeeeeeeeeeee;
+    /// \endcode
+    BBO_Never,
+
+    /// Binary operations will either be all on the same line, or each operation
+    /// will have one line each.
+    /// \code
+    ///    aaa +
+    ///    bbbb *
+    ///    ccccc -
+    ///    ddddd +
+    ///    eeeeeeeeeeeeeeee;
+    /// \endcode
+    BBO_BreakAll,
+
+    /// Binary operations of a particular precedence that go beyond the column
+    /// limit will have one line each.
+    /// \code
+    ///    aaa +
+    ///    bbbb * ccccc -
+    ///    ddddd +
+    ///    eeeeeeeeeeeeeeee;
+    /// \endcode
+    BBO_BreakRespectPrecedence
+  };
+
+  /// The break constructor initializers style to use.
+  /// \version 19
+  BreakBinaryOperationsStyle BreakBinaryOperations;
+
   /// Different ways to break initializers.
   enum BreakConstructorInitializersStyle : int8_t {
     /// Break constructor initializers before the colon and after the commas.
@@ -5039,7 +5059,6 @@ struct FormatStyle {
                R.AlwaysBreakBeforeMultilineStrings &&
            AttributeMacros == R.AttributeMacros &&
            BinPackArguments == R.BinPackArguments &&
-           BinPackBinaryOperations == R.BinPackBinaryOperations &&
            BinPackParameters == R.BinPackParameters &&
            BitFieldColonSpacing == R.BitFieldColonSpacing &&
            BracedInitializerIndentWidth == R.BracedInitializerIndentWidth &&
@@ -5053,6 +5072,7 @@ struct FormatStyle {
            BreakBeforeConceptDeclarations == R.BreakBeforeConceptDeclarations &&
            BreakBeforeInlineASMColon == R.BreakBeforeInlineASMColon &&
            BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators &&
+           BreakBinaryOperations == R.BreakBinaryOperations &&
            BreakConstructorInitializers == R.BreakConstructorInitializers &&
            BreakFunctionDefinitionParameters ==
                R.BreakFunctionDefinitionParameters &&
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index d3fd7620bf2dd..27b7ae1365bda 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -167,7 +167,7 @@ static bool startsNextOperand(const FormatToken &Current) {
 // 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 &&
+  return Style.BreakBinaryOperations != FormatStyle::BBO_Never &&
          ((isAlignableBinaryOperator(Current) &&
            Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None) ||
           (startsNextOperand(Current) &&
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index c03d91fc8c2da..088c4cfe2b403 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -244,6 +244,17 @@ struct ScalarEnumerationTraits<FormatStyle::BreakBeforeInlineASMColonStyle> {
   }
 };
 
+template <>
+struct ScalarEnumerationTraits<FormatStyle::BreakBinaryOperationsStyle> {
+  static void enumeration(IO &IO,
+                          FormatStyle::BreakBinaryOperationsStyle &Value) {
+    IO.enumCase(Value, "Never", FormatStyle::BBO_Never);
+    IO.enumCase(Value, "BreakAll", FormatStyle::BBO_BreakAll);
+    IO.enumCase(Value, "BreakRespectPrecedence",
+                FormatStyle::BBO_BreakRespectPrecedence);
+  }
+};
+
 template <>
 struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> {
   static void
@@ -947,7 +958,6 @@ 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",
@@ -969,6 +979,7 @@ template <> struct MappingTraits<FormatStyle> {
                    Style.BreakBeforeInlineASMColon);
     IO.mapOptional("BreakBeforeTernaryOperators",
                    Style.BreakBeforeTernaryOperators);
+    IO.mapOptional("Style.BreakBinaryOperations", Style.BreakBinaryOperations);
     IO.mapOptional("BreakConstructorInitializers",
                    Style.BreakConstructorInitializers);
     IO.mapOptional("BreakFunctionDefinitionParameters",
@@ -1450,7 +1461,6 @@ 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;
@@ -1482,6 +1492,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
   LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always;
   LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline;
   LLVMStyle.BreakBeforeTernaryOperators = true;
+  LLVMStyle.BreakBinaryOperations = FormatStyle::BBO_Never;
   LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
   LLVMStyle.BreakFunctionDefinitionParameters = false;
   LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon;
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index bc7ec692b16ba..f4226f441c9a4 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -3153,10 +3153,10 @@ class ExpressionParser {
       parse(Precedence + 1);
 
       int CurrentPrecedence = getCurrentPrecedence();
-      if (!Style.BinPackBinaryOperations &&
+      if (Style.BreakBinaryOperations == FormatStyle::BBO_BreakAll &&
           CurrentPrecedence > prec::Conditional &&
           CurrentPrecedence < prec::PointerToMember) {
-        // With BinPackBinaryOperations disabled,
+        // When BreakBinaryOperations is set to BreakAll,
         // 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
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 1381b221bc725..eb4c354e08a9b 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -160,7 +160,6 @@ 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);
@@ -405,6 +404,14 @@ TEST(ConfigParseTest, ParsesConfiguration) {
   CHECK_PARSE("BreakBeforeBinaryOperators: true", BreakBeforeBinaryOperators,
               FormatStyle::BOS_All);
 
+  Style.BreakBinaryOperations = FormatStyle::BBO_Never;
+  CHECK_PARSE("BreakBinaryOperations: BreakAll", BreakBinaryOperations,
+              FormatStyle::BBO_BreakAll);
+  CHECK_PARSE("BreakBinaryOperations: BreakRespectPrecedence",
+              BreakBinaryOperations, FormatStyle::BBO_BreakRespectPrecedence);
+  CHECK_PARSE("BreakBinaryOperations: Never", BreakBinaryOperations,
+              FormatStyle::BBO_Never);
+
   Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
   CHECK_PARSE("BreakConstructorInitializers: BeforeComma",
               BreakConstructorInitializers, FormatStyle::BCIS_BeforeComma);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index a358c53a5f6f8..fee77a9927adb 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -27628,7 +27628,7 @@ TEST_F(FormatTest, SpaceBetweenKeywordAndLiteral) {
   verifyFormat("return sizeof \"5\";");
 }
 
-TEST_F(FormatTest, BinPackBinaryOperations) {
+TEST_F(FormatTest, BreakBinaryOperations) {
   auto Style = getLLVMStyleWithColumns(60);
   // Logical operations
   verifyFormat("if (condition1 && condition2) {\n"
@@ -27662,7 +27662,7 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
                "    operand1 + operand2 - (operand3 + operand4);",
                Style);
 
-  Style.BinPackBinaryOperations = false;
+  Style.BreakBinaryOperations = FormatStyle::BBO_BreakAll;
 
   // Logical operations
   verifyFormat("if (condition1 && condition2) {\n"
@@ -27710,6 +27710,7 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
                Style);
 
   // Ensure mixed precedence operations are handled properly
+  Style.BreakBinaryOperations = FormatStyle::BBO_BreakAll;
   verifyFormat("result = op1 + op2 * op3 - op4;", Style);
 
   verifyFormat("result = operand1 +\n"
@@ -27740,7 +27741,34 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
                "         operand6->member;",
                Style);
 
+  Style.BreakBinaryOperations = FormatStyle::BBO_BreakRespectPrecedence;
+  verifyFormat("result = op1 + op2 * op3 - op4;", Style);
+
+  verifyFormat("result = operand1 +\n"
+               "         operand2 / operand3 +\n"
+               "         operand4 / operand5 * operand6;",
+               Style);
+
+  verifyFormat("result = operand1 * operand2 -\n"
+               "         operand3 * operand4 -\n"
+               "         operand5 +\n"
+               "         operand6;",
+               Style);
+
+  verifyFormat("result = operand1 * (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);
+
+  Style.BreakBinaryOperations = FormatStyle::BBO_BreakAll;
   Style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
+
   // Logical operations
   verifyFormat("if (condition1 && condition2) {\n"
                "}",
@@ -27779,6 +27807,7 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
                Style);
 
   // Ensure mixed precedence operations are handled properly
+  Style.BreakBinaryOperations = FormatStyle::BBO_BreakAll;
   verifyFormat("result = op1 + op2 * op3 - op4;", Style);
 
   verifyFormat("result = operand1\n"
@@ -27804,9 +27833,37 @@ TEST_F(FormatTest, BinPackBinaryOperations) {
                Style);
 
   verifyFormat("std::uint32_t a = byte_buffer[0]\n"
-               "                  | (byte_buffer[1] << 8)\n"
-               "                  | (byte_buffer[2] << 16)\n"
-               "                  | (byte_buffer[3] << 24);",
+               "                  | byte_buffer[1]\n"
+               "                  << 8\n"
+               "                  | byte_buffer[2]\n"
+               "                  << 16\n"
+               "                  | byte_buffer[3]\n"
+               "                  << 24;",
+               Style);
+
+  Style.BreakBinaryOperations = FormatStyle::BBO_BreakRespectPrecedence;
+  verifyFormat("result = op1 + op2 * op3 - op4;", Style);
+
+  verifyFormat("result = operand1\n"
+               "         + operand2 / operand3\n"
+               "         + operand4 / operand5 * operand6;",
+               Style);
+
+  verifyFormat("result = operand1 * operand2\n"
+               "         - operand3 * operand4\n"
+               "         - operand5\n"
+               "         + operand6;",
+               Style);
+
+  verifyFormat("result = operand1 * (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);
 }
 

>From 066520888ca438bf40d8c4479a901bdebac630e4 Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Mon, 22 Jul 2024 10:35:30 -0400
Subject: [PATCH 17/19] Fix typo in config parsing

---
 clang/lib/Format/Format.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 088c4cfe2b403..f2fc4f10c1299 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -979,7 +979,7 @@ template <> struct MappingTraits<FormatStyle> {
                    Style.BreakBeforeInlineASMColon);
     IO.mapOptional("BreakBeforeTernaryOperators",
                    Style.BreakBeforeTernaryOperators);
-    IO.mapOptional("Style.BreakBinaryOperations", Style.BreakBinaryOperations);
+    IO.mapOptional("BreakBinaryOperations", Style.BreakBinaryOperations);
     IO.mapOptional("BreakConstructorInitializers",
                    Style.BreakConstructorInitializers);
     IO.mapOptional("BreakFunctionDefinitionParameters",

>From e062cffcfdba146b8418f6bb94b91ba7e5799db2 Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Tue, 23 Jul 2024 11:05:07 -0400
Subject: [PATCH 18/19] clang-format version 20

---
 clang/docs/ClangFormatStyleOptions.rst | 2 +-
 clang/include/clang/Format/Format.h    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 6a533ec30afd2..c2e3846e31314 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3302,7 +3302,7 @@ the configuration (without a prefix: ``Auto``).
 
 .. _BreakBinaryOperations:
 
-**BreakBinaryOperations** (``BreakBinaryOperationsStyle``) :versionbadge:`clang-format 19` :ref:`¶ <BreakBinaryOperations>`
+**BreakBinaryOperations** (``BreakBinaryOperationsStyle``) :versionbadge:`clang-format 20` :ref:`¶ <BreakBinaryOperations>`
   The break constructor initializers style to use.
 
   Possible values:
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 7c98c848484af..f6e7aaa382a99 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2263,7 +2263,7 @@ struct FormatStyle {
   };
 
   /// The break constructor initializers style to use.
-  /// \version 19
+  /// \version 20
   BreakBinaryOperationsStyle BreakBinaryOperations;
 
   /// Different ways to break initializers.

>From 66b866e97a6d97ff996b9c92d82ecbd0ab7f486d Mon Sep 17 00:00:00 2001
From: ameerj <ameerj99 at outlook.com>
Date: Mon, 5 Aug 2024 12:19:54 -0400
Subject: [PATCH 19/19] Review feedback

---
 clang/docs/ClangFormatStyleOptions.rst     |  6 +++---
 clang/include/clang/Format/Format.h        |  6 +++---
 clang/lib/Format/ContinuationIndenter.cpp  | 10 ++++------
 clang/lib/Format/Format.cpp                |  5 ++---
 clang/lib/Format/TokenAnnotator.cpp        |  2 +-
 clang/unittests/Format/ConfigParseTest.cpp |  8 ++++----
 clang/unittests/Format/FormatTest.cpp      | 12 ++++++------
 7 files changed, 23 insertions(+), 26 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index c2e3846e31314..ab38c9a04e459 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3315,7 +3315,7 @@ the configuration (without a prefix: ``Auto``).
        aaa + bbbb * ccccc - ddddd +
        eeeeeeeeeeeeeeee;
 
-  * ``BBO_BreakAll`` (in configuration: ``BreakAll``)
+  * ``BBO_OnePerLine`` (in configuration: ``OnePerLine``)
     Binary operations will either be all on the same line, or each operation
     will have one line each.
 
@@ -3327,8 +3327,8 @@ the configuration (without a prefix: ``Auto``).
        ddddd +
        eeeeeeeeeeeeeeee;
 
-  * ``BBO_BreakRespectPrecedence`` (in configuration: ``BreakRespectPrecedence``)
-    Binary operations of a particular precedence that go beyond the column
+  * ``BBO_RespectPrecedence`` (in configuration: ``RespectPrecedence``)
+    Binary operations of a particular precedence that exceed the column
     limit will have one line each.
 
     .. code-block:: c++
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index f6e7aaa382a99..ab8d412c08fb9 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2249,9 +2249,9 @@ struct FormatStyle {
     ///    ddddd +
     ///    eeeeeeeeeeeeeeee;
     /// \endcode
-    BBO_BreakAll,
+    BBO_OnePerLine,
 
-    /// Binary operations of a particular precedence that go beyond the column
+    /// Binary operations of a particular precedence that exceed the column
     /// limit will have one line each.
     /// \code
     ///    aaa +
@@ -2259,7 +2259,7 @@ struct FormatStyle {
     ///    ddddd +
     ///    eeeeeeeeeeeeeeee;
     /// \endcode
-    BBO_BreakRespectPrecedence
+    BBO_RespectPrecedence
   };
 
   /// The break constructor initializers style to use.
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 27b7ae1365bda..53d14a599d504 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -150,8 +150,7 @@ static bool startsNextParameter(const FormatToken &Current,
 // 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);
+  bool HasTwoOperands = Token.OperatorIndex == 0 && !Token.NextOperator;
   return Token.is(TT_BinaryOperator) && !HasTwoOperands &&
          Token.getPrecedence() > prec::Conditional &&
          Token.getPrecedence() < prec::PointerToMember;
@@ -168,10 +167,9 @@ static bool startsNextOperand(const FormatToken &Current) {
 static bool mustBreakBinaryOperation(const FormatToken &Current,
                                      const FormatStyle &Style) {
   return Style.BreakBinaryOperations != FormatStyle::BBO_Never &&
-         ((isAlignableBinaryOperator(Current) &&
-           Style.BreakBeforeBinaryOperators != FormatStyle::BOS_None) ||
-          (startsNextOperand(Current) &&
-           Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None));
+         (Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None
+              ? startsNextOperand
+              : isAlignableBinaryOperator)(Current);
 }
 
 static bool opensProtoMessageField(const FormatToken &LessTok,
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 061cf689d443c..5358b35c19de2 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -249,9 +249,8 @@ struct ScalarEnumerationTraits<FormatStyle::BreakBinaryOperationsStyle> {
   static void enumeration(IO &IO,
                           FormatStyle::BreakBinaryOperationsStyle &Value) {
     IO.enumCase(Value, "Never", FormatStyle::BBO_Never);
-    IO.enumCase(Value, "BreakAll", FormatStyle::BBO_BreakAll);
-    IO.enumCase(Value, "BreakRespectPrecedence",
-                FormatStyle::BBO_BreakRespectPrecedence);
+    IO.enumCase(Value, "OnePerLine", FormatStyle::BBO_OnePerLine);
+    IO.enumCase(Value, "RespectPrecedence", FormatStyle::BBO_RespectPrecedence);
   }
 };
 
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index a9417617b85f1..492e50ed8b58d 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -3164,7 +3164,7 @@ class ExpressionParser {
       parse(Precedence + 1);
 
       int CurrentPrecedence = getCurrentPrecedence();
-      if (Style.BreakBinaryOperations == FormatStyle::BBO_BreakAll &&
+      if (Style.BreakBinaryOperations == FormatStyle::BBO_OnePerLine &&
           CurrentPrecedence > prec::Conditional &&
           CurrentPrecedence < prec::PointerToMember) {
         // When BreakBinaryOperations is set to BreakAll,
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index eb4c354e08a9b..2ee0df99353ff 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -405,10 +405,10 @@ TEST(ConfigParseTest, ParsesConfiguration) {
               FormatStyle::BOS_All);
 
   Style.BreakBinaryOperations = FormatStyle::BBO_Never;
-  CHECK_PARSE("BreakBinaryOperations: BreakAll", BreakBinaryOperations,
-              FormatStyle::BBO_BreakAll);
-  CHECK_PARSE("BreakBinaryOperations: BreakRespectPrecedence",
-              BreakBinaryOperations, FormatStyle::BBO_BreakRespectPrecedence);
+  CHECK_PARSE("BreakBinaryOperations: OnePerLine", BreakBinaryOperations,
+              FormatStyle::BBO_OnePerLine);
+  CHECK_PARSE("BreakBinaryOperations: RespectPrecedence", BreakBinaryOperations,
+              FormatStyle::BBO_RespectPrecedence);
   CHECK_PARSE("BreakBinaryOperations: Never", BreakBinaryOperations,
               FormatStyle::BBO_Never);
 
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 91763a9ff35db..c7e7515675f67 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -27632,6 +27632,8 @@ TEST_F(FormatTest, SpaceBetweenKeywordAndLiteral) {
 
 TEST_F(FormatTest, BreakBinaryOperations) {
   auto Style = getLLVMStyleWithColumns(60);
+  EXPECT_EQ(Style.BreakBinaryOperations, FormatStyle::BBO_Never);
+
   // Logical operations
   verifyFormat("if (condition1 && condition2) {\n"
                "}",
@@ -27664,7 +27666,7 @@ TEST_F(FormatTest, BreakBinaryOperations) {
                "    operand1 + operand2 - (operand3 + operand4);",
                Style);
 
-  Style.BreakBinaryOperations = FormatStyle::BBO_BreakAll;
+  Style.BreakBinaryOperations = FormatStyle::BBO_OnePerLine;
 
   // Logical operations
   verifyFormat("if (condition1 && condition2) {\n"
@@ -27712,7 +27714,6 @@ TEST_F(FormatTest, BreakBinaryOperations) {
                Style);
 
   // Ensure mixed precedence operations are handled properly
-  Style.BreakBinaryOperations = FormatStyle::BBO_BreakAll;
   verifyFormat("result = op1 + op2 * op3 - op4;", Style);
 
   verifyFormat("result = operand1 +\n"
@@ -27743,7 +27744,7 @@ TEST_F(FormatTest, BreakBinaryOperations) {
                "         operand6->member;",
                Style);
 
-  Style.BreakBinaryOperations = FormatStyle::BBO_BreakRespectPrecedence;
+  Style.BreakBinaryOperations = FormatStyle::BBO_RespectPrecedence;
   verifyFormat("result = op1 + op2 * op3 - op4;", Style);
 
   verifyFormat("result = operand1 +\n"
@@ -27768,7 +27769,7 @@ TEST_F(FormatTest, BreakBinaryOperations) {
                "                  byte_buffer[3] << 24;",
                Style);
 
-  Style.BreakBinaryOperations = FormatStyle::BBO_BreakAll;
+  Style.BreakBinaryOperations = FormatStyle::BBO_OnePerLine;
   Style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
 
   // Logical operations
@@ -27809,7 +27810,6 @@ TEST_F(FormatTest, BreakBinaryOperations) {
                Style);
 
   // Ensure mixed precedence operations are handled properly
-  Style.BreakBinaryOperations = FormatStyle::BBO_BreakAll;
   verifyFormat("result = op1 + op2 * op3 - op4;", Style);
 
   verifyFormat("result = operand1\n"
@@ -27843,7 +27843,7 @@ TEST_F(FormatTest, BreakBinaryOperations) {
                "                  << 24;",
                Style);
 
-  Style.BreakBinaryOperations = FormatStyle::BBO_BreakRespectPrecedence;
+  Style.BreakBinaryOperations = FormatStyle::BBO_RespectPrecedence;
   verifyFormat("result = op1 + op2 * op3 - op4;", Style);
 
   verifyFormat("result = operand1\n"



More information about the cfe-commits mailing list