diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index d492f2364cf74..61f27bcf9dbbc 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -3858,6 +3858,21 @@ the configuration (without a prefix: ``Auto``). +.. _BreakFunctionDeclarationParameters: + +**BreakFunctionDeclarationParameters** (``Boolean``) :versionbadge:`clang-format 23` :ref:`¶ ` + If ``true``, clang-format will always break before function declaration + parameters. + + .. code-block:: c++ + + true: + void functionDeclaration( + int A, int B); + + false: + void functionDeclaration(int A, int B); + .. _BreakFunctionDefinitionParameters: **BreakFunctionDefinitionParameters** (``Boolean``) :versionbadge:`clang-format 19` :ref:`¶ ` diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index ac462e3bf4732..24d72e8ab48b4 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -738,6 +738,8 @@ clang-format - Extend ``BreakBinaryOperations`` to accept a structured configuration with per-operator break rules and minimum chain length gating via ``PerOperator``. - Add ``AllowShortRecordOnASingleLine`` option and set it to ``EmptyAndAttached`` for LLVM style. +- Add ``BreakFunctionDeclarationParameters`` option to always break before function + declaration parameters. libclang -------- diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 98400a1609b6a..0e883837ac0e9 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -2644,6 +2644,20 @@ struct FormatStyle { /// \version 5 BreakConstructorInitializersStyle BreakConstructorInitializers; + /// If ``true``, clang-format will always break before function declaration + /// parameters. + /// \code + /// true: + /// void functionDeclaration( + /// int A, int B); + /// + /// false: + /// void functionDeclaration(int A, int B); + /// + /// \endcode + /// \version 23 + bool BreakFunctionDeclarationParameters; + /// If ``true``, clang-format will always break before function definition /// parameters. /// \code @@ -6076,6 +6090,8 @@ struct FormatStyle { BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators && BreakBinaryOperations == R.BreakBinaryOperations && BreakConstructorInitializers == R.BreakConstructorInitializers && + BreakFunctionDeclarationParameters == + R.BreakFunctionDeclarationParameters && BreakFunctionDefinitionParameters == R.BreakFunctionDefinitionParameters && BreakInheritanceList == R.BreakInheritanceList && diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 2147a812e27c1..74b31810843fc 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1318,6 +1318,8 @@ template <> struct MappingTraits { IO.mapOptional("BreakBinaryOperations", Style.BreakBinaryOperations); IO.mapOptional("BreakConstructorInitializers", Style.BreakConstructorInitializers); + IO.mapOptional("BreakFunctionDeclarationParameters", + Style.BreakFunctionDeclarationParameters); IO.mapOptional("BreakFunctionDefinitionParameters", Style.BreakFunctionDefinitionParameters); IO.mapOptional("BreakInheritanceList", Style.BreakInheritanceList); @@ -1885,6 +1887,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakBinaryOperations = {FormatStyle::BBO_Never, {}}; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; + LLVMStyle.BreakFunctionDeclarationParameters = false; LLVMStyle.BreakFunctionDefinitionParameters = false; LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon; LLVMStyle.BreakStringLiterals = true; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 898759cb8ea1b..640f03a4ac130 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -5758,6 +5758,12 @@ bool TokenAnnotator::mustBreakBefore(AnnotatedLine &Line, const FormatToken &Left = *Right.Previous; + if (Style.BreakFunctionDeclarationParameters && Line.MightBeFunctionDecl && + !Line.mightBeFunctionDefinition() && Left.MightBeFunctionDeclParen && + Left.ParameterCount > 0) { + return true; + } + if (Style.BreakFunctionDefinitionParameters && Line.MightBeFunctionDecl && Line.mightBeFunctionDefinition() && Left.MightBeFunctionDeclParen && Left.ParameterCount > 0) { diff --git a/clang/unittests/Format/AlignBracketsTest.cpp b/clang/unittests/Format/AlignBracketsTest.cpp index cd314305751e7..fcfcae20e3e11 100644 --- a/clang/unittests/Format/AlignBracketsTest.cpp +++ b/clang/unittests/Format/AlignBracketsTest.cpp @@ -731,6 +731,15 @@ TEST_F(AlignBracketsTest, FormatsDefinitionBreakAlways) { "}", BreakAlways); + // Ensure BreakFunctionDeclarationParameters interacts correctly when + // PackParameters.BinPack is set to BPPS_AlwaysOnePerLine. + BreakAlways.BreakFunctionDeclarationParameters = true; + verifyFormat("void f(\n" + " int a,\n" + " int b);", + BreakAlways); + BreakAlways.BreakFunctionDeclarationParameters = false; + // Ensure BreakFunctionDefinitionParameters interacts correctly when // PackParameters.BinPack is set to BPPS_AlwaysOnePerLine. BreakAlways.BreakFunctionDefinitionParameters = true; diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index 64b0e8702872c..ccb9c837d8362 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -183,6 +183,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) { CHECK_PARSE_BOOL(BreakBeforeCloseBracketSwitch); CHECK_PARSE_BOOL(BreakBeforeTemplateCloser); CHECK_PARSE_BOOL(BreakBeforeTernaryOperators); + CHECK_PARSE_BOOL(BreakFunctionDeclarationParameters); CHECK_PARSE_BOOL(BreakStringLiterals); CHECK_PARSE_BOOL(CompactNamespaces); CHECK_PARSE_BOOL(DerivePointerAlignment); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index f5e496652e15e..4245bd1c58153 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -8119,6 +8119,33 @@ TEST_F(FormatTest, AllowAllArgumentsOnNextLine) { Style); } +TEST_F(FormatTest, BreakFunctionDeclarationParameters) { + StringRef Input = "void functionDecl(int A, int B, int C);\n" + "void emptyFunctionDecl();\n" + "void functionDefinition(int A, int B, int C) {}"; + verifyFormat(Input); + + FormatStyle Style = getLLVMStyle(); + EXPECT_FALSE(Style.BreakFunctionDeclarationParameters); + Style.BreakFunctionDeclarationParameters = true; + verifyFormat("void functionDecl(\n" + " int A, int B, int C);\n" + "void emptyFunctionDecl();\n" + "void functionDefinition(int A, int B, int C) {}", + Input, Style); + + // Test the style where all parameters are on their own lines. + Style.AllowAllParametersOfDeclarationOnNextLine = false; + Style.PackParameters.BinPack = FormatStyle::BPPS_OnePerLine; + verifyFormat("void functionDecl(\n" + " int A,\n" + " int B,\n" + " int C);\n" + "void emptyFunctionDecl();\n" + "void functionDefinition(int A, int B, int C) {}", + Input, Style); +} + TEST_F(FormatTest, BreakFunctionDefinitionParameters) { StringRef Input = "void functionDecl(paramA, paramB, paramC);\n" "void emptyFunctionDefinition() {}\n"