[clang] [clang-format] Add per-operator granularity for BreakBinaryOperations (PR #181051)

Sergey Subbotin via cfe-commits cfe-commits at lists.llvm.org
Sun Feb 15 14:23:13 PST 2026


================
@@ -28625,6 +28627,89 @@ TEST_F(FormatTest, BreakBinaryOperations) {
                Style);
 }
 
+TEST_F(FormatTest, BreakBinaryOperationsPerOperator) {
+  auto Style = getLLVMStyleWithColumns(60);
+
+  // Per-operator override: && and || are OnePerLine, rest is Never (default).
+  FormatStyle::BinaryOperationBreakRule LogicalRule;
+  LogicalRule.Operators = {"&&", "||"};
+  LogicalRule.Style = FormatStyle::BBO_OnePerLine;
+  LogicalRule.MinChainLength = 0;
+
+  Style.BreakBinaryOperations.Default = FormatStyle::BBO_Never;
+  Style.BreakBinaryOperations.PerOperator = {LogicalRule};
+
+  // Logical operators break one-per-line when line is too long.
+  verifyFormat("bool x = loooooooooooooongcondition1 &&\n"
+               "         loooooooooooooongcondition2 &&\n"
+               "         loooooooooooooongcondition3;",
+               Style);
+
+  // Arithmetic operators stay with default (Never) — no forced break.
+  verifyFormat("int x = loooooooooooooongop1 + looooooooongop2 +\n"
+               "        loooooooooooooooooooooongop3;",
+               Style);
+
+  // Short logical chain that fits on one line stays on one line.
+  verifyFormat("bool x = a && b && c;", Style);
+
+  // Multiple PerOperator groups: && and || plus | operators.
+  FormatStyle::BinaryOperationBreakRule BitwiseOrRule;
+  BitwiseOrRule.Operators = {"|"};
+  BitwiseOrRule.Style = FormatStyle::BBO_OnePerLine;
+  BitwiseOrRule.MinChainLength = 0;
+
+  Style.BreakBinaryOperations.PerOperator = {LogicalRule, BitwiseOrRule};
+
+  // | operators should break one-per-line.
+  verifyFormat("int x = loooooooooooooooooongval1 |\n"
+               "        loooooooooooooooooongval2 |\n"
+               "        loooooooooooooooooongval3;",
+               Style);
+
+  // && still works in multi-group configuration.
+  verifyFormat("bool x = loooooooooooooongcondition1 &&\n"
+               "         loooooooooooooongcondition2 &&\n"
+               "         loooooooooooooongcondition3;",
+               Style);
+
+  // + operators stay with default (Never) even with multi-group.
+  verifyFormat("int x = loooooooooooooongop1 + looooooooongop2 +\n"
+               "        loooooooooooooooooooooongop3;",
+               Style);
+}
+
+TEST_F(FormatTest, BreakBinaryOperationsMinChainLength) {
+  auto Style = getLLVMStyleWithColumns(60);
+
+  // MinChainLength = 3: chains shorter than 3 don't force breaks.
+  FormatStyle::BinaryOperationBreakRule LogicalRule;
+  LogicalRule.Operators = {"&&", "||"};
+  LogicalRule.Style = FormatStyle::BBO_OnePerLine;
+  LogicalRule.MinChainLength = 3;
+
+  Style.BreakBinaryOperations.Default = FormatStyle::BBO_Never;
+  Style.BreakBinaryOperations.PerOperator = {LogicalRule};
+
+  // Chain of 2 — should NOT force one-per-line (below MinChainLength).
+  verifyFormat("bool x = loooooooooooooongcondition1 &&\n"
----------------
ssubbotin wrote:

Good point — replaced `loooooong` names with realistic ones in commit 258f4f3. Tests now use names like `isConnectionReady()`, `isSessionNotExpired()`, `hasRequiredPermission()`, `unitBasePrice`, `shippingCostPerItem`, `OPTION_VERBOSE_OUTPUT`, etc.

https://github.com/llvm/llvm-project/pull/181051


More information about the cfe-commits mailing list