[clang] [clang-format] Add MaxParametersOnLine formatting option (PR #181281)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Feb 16 19:23:32 PST 2026
https://github.com/Ezlanding1 updated https://github.com/llvm/llvm-project/pull/181281
>From a2a04832e3f93b879f3bee4b235c4e3ab5b94400 Mon Sep 17 00:00:00 2001
From: Ezlanding1 <113404035+Ezlanding1 at users.noreply.github.com>
Date: Thu, 12 Feb 2026 19:55:05 -0500
Subject: [PATCH 1/6] Add MaxParametersOnLine format option
---
clang/docs/ClangFormatStyleOptions.rst | 31 ++++++++++++++++++++++++++
clang/include/clang/Format/Format.h | 30 +++++++++++++++++++++++++
clang/lib/Format/Format.cpp | 1 +
3 files changed, 62 insertions(+)
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 5ba117c231ad5..592f94c99010b 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -5252,6 +5252,37 @@ the configuration (without a prefix: ``Auto``).
return i;
}
+.. _MaxParametersOnLine:
+
+**MaxParametersOnLine** (``Unsigned``) :versionbadge:`clang-format 23` :ref:`¶ <MaxParametersOnLine>`
+ The maximum amount of parameters that may appear on a single line in a
+ function declaration. This option can be used with ``BPPS_OnePerLine`` to
+ put every parameter on its own line if the function has more than
+ ``MaxParametersOnLine`` parameters. If this option is 0, there is no maximum.
+
+ .. code-block:: c++
+
+ MaxParametersOnLine: 3
+ BinPackParameters: BPPS_BinPack
+
+ void foo(int a, int b, int c);
+
+ void foo(int a, int b, int c,
+ int d);
+
+ void foo(int a, int b, int c,
+ int d, int e, int f,
+ int g, int h, int i);
+
+ BinPackParameters: BPPS_OnePerLine
+
+ void foo(int a, int b, int c);
+
+ void foo(int a,
+ int b,
+ int c,
+ int d);
+
.. _NamespaceIndentation:
**NamespaceIndentation** (``NamespaceIndentationKind``) :versionbadge:`clang-format 3.7` :ref:`¶ <NamespaceIndentation>`
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 43bea4b80cb8a..0073ad96239cb 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1254,6 +1254,35 @@ struct FormatStyle {
/// \version 3.7
BinPackParametersStyle BinPackParameters;
+ /// The maximum amount of parameters that may appear on a single line in a
+ /// function declaration. This option can be used with \c BPPS_OnePerLine to
+ /// put every parameter on its own line if the function has more than
+ /// \c MaxParametersOnLine parameters. If this option is 0, there is no maximum.
+ /// \code
+ /// MaxParametersOnLine: 3
+ /// BinPackParameters: BPPS_BinPack
+ ///
+ /// void foo(int a, int b, int c);
+ ///
+ /// void foo(int a, int b, int c,
+ /// int d);
+ ///
+ /// void foo(int a, int b, int c,
+ /// int d, int e, int f,
+ /// int g, int h, int i);
+ ///
+ /// BinPackParameters: BPPS_OnePerLine
+ ///
+ /// void foo(int a, int b, int c);
+ ///
+ /// void foo(int a,
+ /// int b,
+ /// int c,
+ /// int d);
+ /// \endcode
+ /// \version 23
+ unsigned MaxParametersOnLine;
+
/// Styles for adding spacing around ``:`` in bitfield definitions.
enum BitFieldColonSpacingStyle : int8_t {
/// Add one space on each side of the ``:``
@@ -5694,6 +5723,7 @@ struct FormatStyle {
BinPackArguments == R.BinPackArguments &&
BinPackLongBracedList == R.BinPackLongBracedList &&
BinPackParameters == R.BinPackParameters &&
+ MaxParametersOnLine == R.MaxParametersOnLine &&
BitFieldColonSpacing == R.BitFieldColonSpacing &&
BracedInitializerIndentWidth == R.BracedInitializerIndentWidth &&
BreakAdjacentStringLiterals == R.BreakAdjacentStringLiterals &&
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 1e68de531791f..6a68012525144 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1355,6 +1355,7 @@ template <> struct MappingTraits<FormatStyle> {
Style.WhitespaceSensitiveMacros);
IO.mapOptional("WrapNamespaceBodyWithEmptyLines",
Style.WrapNamespaceBodyWithEmptyLines);
+ IO.mapOptional("MaxParametersOnLine", Style.MaxParametersOnLine);
// If AlwaysBreakAfterDefinitionReturnType was specified but
// BreakAfterReturnType was not, initialize the latter from the former for
>From 3d7741fde79127c386139ced866f6d932d04583b Mon Sep 17 00:00:00 2001
From: Ezlanding1 <113404035+Ezlanding1 at users.noreply.github.com>
Date: Thu, 12 Feb 2026 20:08:02 -0500
Subject: [PATCH 2/6] Implement MaxParametersOnLine format option
---
clang/lib/Format/TokenAnnotator.cpp | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index b1c1afbf8684d..516c997e75cfc 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -4246,6 +4246,26 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
ChildSize + Current->SpacesRequiredBefore;
}
+ if (Style.MaxParametersOnLine > 0 &&
+ Current->is(TT_FunctionDeclarationLParen) &&
+ Current->ParameterCount > Style.MaxParametersOnLine) {
+ const auto *RParen = Current->MatchingParen;
+ unsigned CurrentParamNum = 0;
+ for (auto *ParamTok = Current->Next; ParamTok && ParamTok != RParen;
+ ParamTok = ParamTok->Next) {
+ if (ParamTok->opensScope()) {
+ ParamTok = ParamTok->MatchingParen;
+ continue;
+ }
+
+ if (ParamTok->is(tok::comma) && ParamTok->Next &&
+ (++CurrentParamNum % Style.MaxParametersOnLine) == 0) {
+ ParamTok->Next->MustBreakBefore = true;
+ ParamTok->Next->CanBreakBefore = true;
+ }
+ }
+ }
+
if (Current->is(TT_ControlStatementLBrace)) {
if (Style.ColumnLimit > 0 &&
Style.BraceWrapping.AfterControlStatement ==
>From caffe220d477bd8813c09bb67912544b7a24ce08 Mon Sep 17 00:00:00 2001
From: Ezlanding1 <113404035+Ezlanding1 at users.noreply.github.com>
Date: Mon, 16 Feb 2026 16:07:52 -0500
Subject: [PATCH 3/6] Improve parameter check with startsNextParameter()
---
clang/lib/Format/TokenAnnotator.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 516c997e75cfc..a1d7ba49d3aad 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -4258,10 +4258,10 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
continue;
}
- if (ParamTok->is(tok::comma) && ParamTok->Next &&
+ if (startsNextParameter(*ParamTok, Style) &&
(++CurrentParamNum % Style.MaxParametersOnLine) == 0) {
- ParamTok->Next->MustBreakBefore = true;
- ParamTok->Next->CanBreakBefore = true;
+ ParamTok->MustBreakBefore = true;
+ ParamTok->CanBreakBefore = true;
}
}
}
>From 99c3f842e78e007c39d31ce9ba42c352c34519c8 Mon Sep 17 00:00:00 2001
From: Ezlanding1 <113404035+Ezlanding1 at users.noreply.github.com>
Date: Mon, 16 Feb 2026 16:43:31 -0500
Subject: [PATCH 4/6] Apply MaxParametersOnLine option to all parenthesized
parameter lists
---
clang/lib/Format/TokenAnnotator.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index a1d7ba49d3aad..236c6e7ea89f7 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -4247,7 +4247,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
}
if (Style.MaxParametersOnLine > 0 &&
- Current->is(TT_FunctionDeclarationLParen) &&
+ Current->is(tok::l_paren) &&
Current->ParameterCount > Style.MaxParametersOnLine) {
const auto *RParen = Current->MatchingParen;
unsigned CurrentParamNum = 0;
>From ad23bb5edf114bb12b69151218c5a6f214c30bdf Mon Sep 17 00:00:00 2001
From: Ezlanding1 <113404035+Ezlanding1 at users.noreply.github.com>
Date: Mon, 16 Feb 2026 16:49:00 -0500
Subject: [PATCH 5/6] Break every parameter and rename to BreakParametersAfter
---
clang/docs/ClangFormatStyleOptions.rst | 62 +++++++++++++-------------
clang/include/clang/Format/Format.h | 60 ++++++++++++-------------
clang/lib/Format/Format.cpp | 2 +-
clang/lib/Format/TokenAnnotator.cpp | 8 ++--
4 files changed, 65 insertions(+), 67 deletions(-)
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 592f94c99010b..a0673cb8dcbc2 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3752,6 +3752,37 @@ the configuration (without a prefix: ``Auto``).
+.. _BreakParametersAfter:
+
+**BreakParametersAfter** (``Unsigned``) :versionbadge:`clang-format 23` :ref:`¶ <BreakParametersAfter>`
+ If set to a value greater than 0, any parenthesized parameter or argument
+ list with more parameters than the specified number will be formatted with
+ one parameter per line. This applies to all parameter-like lists enclosed
+ in parentheses, including function declarations, function definitions,
+ function calls, and comma expressions.
+
+ .. code-block:: c++
+
+ BreakParametersAfter: 3
+
+ void foo(int a);
+
+ void bar(int a, int b, int c);
+
+ void baz(int a,
+ int b,
+ int c,
+ int d);
+
+ foo(1);
+
+ bar(1, 2, 3);
+
+ baz(1,
+ 2,
+ 3,
+ 4);
+
.. _BreakStringLiterals:
**BreakStringLiterals** (``Boolean``) :versionbadge:`clang-format 3.9` :ref:`¶ <BreakStringLiterals>`
@@ -5252,37 +5283,6 @@ the configuration (without a prefix: ``Auto``).
return i;
}
-.. _MaxParametersOnLine:
-
-**MaxParametersOnLine** (``Unsigned``) :versionbadge:`clang-format 23` :ref:`¶ <MaxParametersOnLine>`
- The maximum amount of parameters that may appear on a single line in a
- function declaration. This option can be used with ``BPPS_OnePerLine`` to
- put every parameter on its own line if the function has more than
- ``MaxParametersOnLine`` parameters. If this option is 0, there is no maximum.
-
- .. code-block:: c++
-
- MaxParametersOnLine: 3
- BinPackParameters: BPPS_BinPack
-
- void foo(int a, int b, int c);
-
- void foo(int a, int b, int c,
- int d);
-
- void foo(int a, int b, int c,
- int d, int e, int f,
- int g, int h, int i);
-
- BinPackParameters: BPPS_OnePerLine
-
- void foo(int a, int b, int c);
-
- void foo(int a,
- int b,
- int c,
- int d);
-
.. _NamespaceIndentation:
**NamespaceIndentation** (``NamespaceIndentationKind``) :versionbadge:`clang-format 3.7` :ref:`¶ <NamespaceIndentation>`
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 0073ad96239cb..25ad43d588485 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1254,35 +1254,6 @@ struct FormatStyle {
/// \version 3.7
BinPackParametersStyle BinPackParameters;
- /// The maximum amount of parameters that may appear on a single line in a
- /// function declaration. This option can be used with \c BPPS_OnePerLine to
- /// put every parameter on its own line if the function has more than
- /// \c MaxParametersOnLine parameters. If this option is 0, there is no maximum.
- /// \code
- /// MaxParametersOnLine: 3
- /// BinPackParameters: BPPS_BinPack
- ///
- /// void foo(int a, int b, int c);
- ///
- /// void foo(int a, int b, int c,
- /// int d);
- ///
- /// void foo(int a, int b, int c,
- /// int d, int e, int f,
- /// int g, int h, int i);
- ///
- /// BinPackParameters: BPPS_OnePerLine
- ///
- /// void foo(int a, int b, int c);
- ///
- /// void foo(int a,
- /// int b,
- /// int c,
- /// int d);
- /// \endcode
- /// \version 23
- unsigned MaxParametersOnLine;
-
/// Styles for adding spacing around ``:`` in bitfield definitions.
enum BitFieldColonSpacingStyle : int8_t {
/// Add one space on each side of the ``:``
@@ -2638,6 +2609,35 @@ struct FormatStyle {
/// \version 7
BreakInheritanceListStyle BreakInheritanceList;
+ /// If set to a value greater than 0, any parenthesized parameter or argument
+ /// list with more parameters than the specified number will be formatted with
+ /// one parameter per line. This applies to all parameter-like lists enclosed
+ /// in parentheses, including function declarations, function definitions,
+ /// function calls, and comma expressions.
+ /// \code
+ /// BreakParametersAfter: 3
+ ///
+ /// void foo(int a);
+ ///
+ /// void bar(int a, int b, int c);
+ ///
+ /// void baz(int a,
+ /// int b,
+ /// int c,
+ /// int d);
+ ///
+ /// foo(1);
+ ///
+ /// bar(1, 2, 3);
+ ///
+ /// baz(1,
+ /// 2,
+ /// 3,
+ /// 4);
+ /// \endcode
+ /// \version 23
+ unsigned BreakParametersAfter;
+
/// The template declaration breaking style to use.
/// \version 19
BreakTemplateDeclarationsStyle BreakTemplateDeclarations;
@@ -5723,7 +5723,6 @@ struct FormatStyle {
BinPackArguments == R.BinPackArguments &&
BinPackLongBracedList == R.BinPackLongBracedList &&
BinPackParameters == R.BinPackParameters &&
- MaxParametersOnLine == R.MaxParametersOnLine &&
BitFieldColonSpacing == R.BitFieldColonSpacing &&
BracedInitializerIndentWidth == R.BracedInitializerIndentWidth &&
BreakAdjacentStringLiterals == R.BreakAdjacentStringLiterals &&
@@ -5755,6 +5754,7 @@ struct FormatStyle {
BreakFunctionDefinitionParameters ==
R.BreakFunctionDefinitionParameters &&
BreakInheritanceList == R.BreakInheritanceList &&
+ BreakParametersAfter == R.BreakParametersAfter &&
BreakStringLiterals == R.BreakStringLiterals &&
BreakTemplateDeclarations == R.BreakTemplateDeclarations &&
ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas &&
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 6a68012525144..1409028e73731 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1355,7 +1355,7 @@ template <> struct MappingTraits<FormatStyle> {
Style.WhitespaceSensitiveMacros);
IO.mapOptional("WrapNamespaceBodyWithEmptyLines",
Style.WrapNamespaceBodyWithEmptyLines);
- IO.mapOptional("MaxParametersOnLine", Style.MaxParametersOnLine);
+ IO.mapOptional("BreakParametersAfter", Style.BreakParametersAfter);
// If AlwaysBreakAfterDefinitionReturnType was specified but
// BreakAfterReturnType was not, initialize the latter from the former for
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 236c6e7ea89f7..e9b07a1578e49 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -4246,11 +4246,10 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
ChildSize + Current->SpacesRequiredBefore;
}
- if (Style.MaxParametersOnLine > 0 &&
+ if (Style.BreakParametersAfter > 0 &&
Current->is(tok::l_paren) &&
- Current->ParameterCount > Style.MaxParametersOnLine) {
+ Current->ParameterCount > Style.BreakParametersAfter) {
const auto *RParen = Current->MatchingParen;
- unsigned CurrentParamNum = 0;
for (auto *ParamTok = Current->Next; ParamTok && ParamTok != RParen;
ParamTok = ParamTok->Next) {
if (ParamTok->opensScope()) {
@@ -4258,8 +4257,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
continue;
}
- if (startsNextParameter(*ParamTok, Style) &&
- (++CurrentParamNum % Style.MaxParametersOnLine) == 0) {
+ if (startsNextParameter(*ParamTok, Style)) {
ParamTok->MustBreakBefore = true;
ParamTok->CanBreakBefore = true;
}
>From da2af2419140b4d76a8ca7f993b1968bf933ad40 Mon Sep 17 00:00:00 2001
From: Ezlanding1 <113404035+Ezlanding1 at users.noreply.github.com>
Date: Mon, 16 Feb 2026 22:22:03 -0500
Subject: [PATCH 6/6] Add unit tests for BreakParametersAfter
---
clang/lib/Format/Format.cpp | 1 +
clang/unittests/Format/ConfigParseTest.cpp | 1 +
clang/unittests/Format/FormatTest.cpp | 80 ++++++++++++++++++++++
3 files changed, 82 insertions(+)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 1409028e73731..e0388a17f2ef0 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1729,6 +1729,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
LLVMStyle.BreakFunctionDefinitionParameters = false;
LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon;
+ LLVMStyle.BreakParametersAfter = 0;
LLVMStyle.BreakStringLiterals = true;
LLVMStyle.BreakTemplateDeclarations = FormatStyle::BTDS_MultiLine;
LLVMStyle.ColumnLimit = 80;
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 0a116b770f52a..ef442a17a7a8f 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -283,6 +283,7 @@ TEST(ConfigParseTest, ParsesConfigurationIntegers) {
CHECK_PARSE_INT(BracedInitializerIndentWidth);
CHECK_PARSE_INT(PPIndentWidth);
+ CHECK_PARSE_UNSIGNED(BreakParametersAfter);
CHECK_PARSE_UNSIGNED(ColumnLimit);
CHECK_PARSE_UNSIGNED(ConstructorInitializerIndentWidth);
CHECK_PARSE_UNSIGNED(ContinuationIndentWidth);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 33836e28289b4..18b33e3869dc7 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -8164,6 +8164,86 @@ TEST_F(FormatTest, BreakFunctionDefinitionParameters) {
" int B)\n"
" : m_A(A), m_B(B) {}",
Input, Style);
+
+ Style.BinPackParameters = FormatStyle::BPPS_BinPack;
+ Style.BreakFunctionDefinitionParameters = false;
+ Style.BreakParametersAfter = 2;
+ verifyFormat("void functionDecl(paramA, paramB);\n"
+ "void functionDecl(paramA,\n"
+ " paramB,\n"
+ " paramC);\n"
+ "void functionDecl(paramA,\n"
+ " paramB,\n"
+ " paramC,\n"
+ " paramD,\n"
+ " paramE);\n"
+ "void functionDefinition(int A, int B) {}\n"
+ "void functionDefinition(int A,\n"
+ " int B,\n"
+ " int C) {}\n"
+ "Class::Class(int A, int B) {}\n"
+ "Class::Class(int A,\n"
+ " int B,\n"
+ " int C) {}\n"
+ "call(a, b);\n"
+ "call(a,\n"
+ " b,\n"
+ " c);\n"
+ "new Class(a, b);\n"
+ "new Class(a,\n"
+ " b,\n"
+ " c);\n"
+ "int x = (a, b);\n"
+ "int y = (a,\n"
+ " b,\n"
+ " c);",
+ Style);
+ Style.BreakParametersAfter = 4;
+ verifyFormat("void functionDecl(paramA);\n"
+ "void functionDecl(paramA, paramB);\n"
+ "void functionDecl(paramA, paramB, paramC);\n"
+ "void functionDecl(paramA, paramB, paramC, paramD);\n"
+ "void functionDecl(paramA,\n"
+ " paramB,\n"
+ " paramC,\n"
+ " paramD,\n"
+ " paramE);\n"
+ "void functionDecl(paramA,\n"
+ " paramB,\n"
+ " paramC,\n"
+ " paramD,\n"
+ " paramE,\n"
+ " paramF);\n"
+ "void functionDefinition(int A, int B, int C, int D) {}\n"
+ "void functionDefinition(int A,\n"
+ " int B,\n"
+ " int C,\n"
+ " int D,\n"
+ " int E) {}\n"
+ "Class::Class(int A, int B) {}\n"
+ "Class::Class(int A, int B, int C, int D) {}\n"
+ "Class::Class(int A,\n"
+ " int B,\n"
+ " int C,\n"
+ " int D,\n"
+ " int E) {}\n"
+ "call(a,\n"
+ " b,\n"
+ " c,\n"
+ " d,\n"
+ " e);\n"
+ "new Class(a,\n"
+ " b,\n"
+ " c,\n"
+ " d,\n"
+ " e);\n"
+ "int y = (a,\n"
+ " b,\n"
+ " c,\n"
+ " d,\n"
+ " e);",
+ Style);
+ Style.BreakParametersAfter = 0;
}
TEST_F(FormatTest, BreakBeforeInlineASMColon) {
More information about the cfe-commits
mailing list