diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -1368,6 +1368,58 @@ +.. _AlwaysBreakBeforeFunctionParameters: + +**AlwaysBreakBeforeFunctionParameters** (``FunctionParameterBreakingStyle``) :versionbadge:`clang-format 16.0` :ref:`¶ ` + The function parameter breaking style to use. + + Possible values: + + * ``FPBS_Leave`` (in configuration: ``Leave``) + Do nothing with line breaks before function parameters. + + .. code-block:: c++ + + original: + int someFunction( + int arg1, + int arg2); + int someFunction(int arg1, int arg2); + + formatted: + int someFunction( + int arg1, + int arg2); + int someFunction(int arg1, int arg2); + + * ``FPBS_Never`` (in configuration: ``Never``) + Never break after the return type. This removes breaks that are there. + + .. code-block:: c++ + + original: + int someFunction( + int arg1, + int arg2); + + formatted: + int someFunction(int arg1, int arg2); + + * ``FPBS_Always`` (in configuration: ``Always``) + Always break after the return type. + + .. code-block:: c++ + + original: + int someFunction(int arg1, int arg2); + + formatted: + int someFunction( + int arg1, + int arg2); + + + .. _AlwaysBreakBeforeMultilineStrings: **AlwaysBreakBeforeMultilineStrings** (``Boolean``) :versionbadge:`clang-format 3.4` :ref:`¶ ` diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -807,6 +807,53 @@ /// \version 3.8 ReturnTypeBreakingStyle AlwaysBreakAfterReturnType; + /// Different ways to break before the function parameters. + enum FunctionParameterBreakingStyle : int8_t { + /// Do nothing with line breaks before function parameters. + /// \code + /// original: + /// int someFunction( + /// int arg1, + /// int arg2); + /// int someFunction(int arg1, int arg2); + /// + /// formatted: + /// int someFunction( + /// int arg1, + /// int arg2); + /// int someFunction(int arg1, int arg2); + /// \endcode + FPBS_Leave, + + /// Never break after the return type. This removes breaks that are there. + /// \code + /// original: + /// int someFunction( + /// int arg1, + /// int arg2); + /// + /// formatted: + /// int someFunction(int arg1, int arg2); + /// \endcode + FPBS_Never, + + /// Always break after the return type. + /// \code + /// original: + /// int someFunction(int arg1, int arg2); + /// + /// formatted: + /// int someFunction( + /// int arg1, + /// int arg2); + /// \endcode + FPBS_Always, + }; + + /// The function parameter breaking style to use. + /// \version 16.0 + FunctionParameterBreakingStyle AlwaysBreakBeforeFunctionParameters; + /// If ``true``, always break before multiline string literals. /// /// This flag is mean to make cases where there are multiple multiline strings diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -354,6 +354,19 @@ auto LambdaBodyLength = getLengthToMatchingParen(Current, State.Stack); return LambdaBodyLength > getColumnLimit(State); } + // Check if we want to break before function parameters in declarations + if (startsNextParameter(Current, Style) && State.Line->MustBeDeclaration) { + switch (Style.AlwaysBreakBeforeFunctionParameters) { + case FormatStyle::FPBS_Always: + return true; + case FormatStyle::FPBS_Never: + return false; + case FormatStyle::FPBS_Leave: + if (Current.NewlinesBefore > 0) + return true; + break; + } + } if (Current.MustBreakBefore || (Current.is(TT_InlineASMColon) && (Style.BreakBeforeInlineASMColon == FormatStyle::BBIAS_Always || @@ -1055,7 +1068,9 @@ // If we are breaking after '(', '{', '<', or this is the break after a ':' // to start a member initializater list in a constructor, this should not // be considered bin packing unless the relevant AllowAll option is false or - // this is a dict/object literal. + // this is a dict/object literal. Break if + // AlwaysBreakBeforeFunctionParameters is Always and it's a function + // declaration. bool PreviousIsBreakingCtorInitializerColon = PreviousNonComment && PreviousNonComment->is(TT_CtorInitializerColon) && Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon; @@ -1070,7 +1085,13 @@ !State.Line->MustBeDeclaration) || (!AllowAllConstructorInitializersOnNextLine && PreviousIsBreakingCtorInitializerColon) || - Previous.is(TT_DictLiteral)) { + Previous.is(TT_DictLiteral) || + (((Style.AlwaysBreakBeforeFunctionParameters == + FormatStyle::FPBS_Always) || + ((Style.AlwaysBreakBeforeFunctionParameters == + FormatStyle::FPBS_Leave) && + Current.NewlinesBefore > 0)) && + State.Line->MustBeDeclaration)) { CurrentState.BreakBeforeParameter = true; } diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -334,6 +334,20 @@ } }; +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, + FormatStyle::FunctionParameterBreakingStyle &Value) { + IO.enumCase(Value, "Leave", FormatStyle::FPBS_Leave); + IO.enumCase(Value, "Never", FormatStyle::FPBS_Never); + IO.enumCase(Value, "Always", FormatStyle::FPBS_Always); + + // For backward compatibility. + IO.enumCase(Value, "false", FormatStyle::FPBS_Leave); + IO.enumCase(Value, "true", FormatStyle::FPBS_Always); + } +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, FormatStyle::IndentExternBlockStyle &Value) { @@ -871,6 +885,8 @@ Style.AlwaysBreakAfterDefinitionReturnType); IO.mapOptional("AlwaysBreakAfterReturnType", Style.AlwaysBreakAfterReturnType); + IO.mapOptional("AlwaysBreakBeforeFunctionParameters", + Style.AlwaysBreakBeforeFunctionParameters); IO.mapOptional("AlwaysBreakBeforeMultilineStrings", Style.AlwaysBreakBeforeMultilineStrings); IO.mapOptional("AlwaysBreakTemplateDeclarations", @@ -1331,6 +1347,7 @@ LLVMStyle.AllowShortLoopsOnASingleLine = false; LLVMStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None; + LLVMStyle.AlwaysBreakBeforeFunctionParameters = FormatStyle::FPBS_Leave; LLVMStyle.AlwaysBreakBeforeMultilineStrings = false; LLVMStyle.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_MultiLine; LLVMStyle.AttributeMacros.push_back("__capability"); diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -4840,6 +4840,22 @@ return true; } + // If AlwaysBreakBeforeFunctionParameters is true, we want to break before + // the next parameter, if there is one. + if (Left.is(tok::l_paren) && !Right.is(tok::r_paren) && Left.Previous && + Left.Previous->is(TT_FunctionDeclarationName)) { + switch (Style.AlwaysBreakBeforeFunctionParameters) { + case FormatStyle::FPBS_Always: + return true; + case FormatStyle::FPBS_Never: + return false; + case FormatStyle::FPBS_Leave: + if (Right.NewlinesBefore > 0) + return true; + break; + } + } + // If the last token before a '}', ']', or ')' is a comma or a trailing // comment, the intention is to insert a line break after it in order to make // shuffling around entries easier. Import statements, especially in diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -550,6 +550,14 @@ CHECK_PARSE("AllowShortLambdasOnASingleLine: true", AllowShortLambdasOnASingleLine, FormatStyle::SLS_All); + Style.AlwaysBreakBeforeFunctionParameters = FormatStyle::FPBS_Never; + CHECK_PARSE("AlwaysBreakBeforeFunctionParameters: Leave", + AlwaysBreakBeforeFunctionParameters, FormatStyle::FPBS_Leave); + CHECK_PARSE("AlwaysBreakBeforeFunctionParameters: Always", + AlwaysBreakBeforeFunctionParameters, FormatStyle::FPBS_Always); + CHECK_PARSE("AlwaysBreakBeforeFunctionParameters: Never", + AlwaysBreakBeforeFunctionParameters, FormatStyle::FPBS_Never); + Style.SpaceAroundPointerQualifiers = FormatStyle::SAPQ_Both; CHECK_PARSE("SpaceAroundPointerQualifiers: Default", SpaceAroundPointerQualifiers, FormatStyle::SAPQ_Default); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -25429,6 +25429,73 @@ verifyFormat("auto x = 5s .count() == 5;"); } +TEST_F(FormatTest, BreakBeforeParameterList) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(Style.AlwaysBreakBeforeFunctionParameters, FormatStyle::FPBS_Leave); + + // test Leave + + // verify that there is no break by default + verifyFormat("int function1();\n" // formatted + "int function2(int param1, int param2, int param3);\n" + "void function3(int param1, int param2, int param3) {}\n" + "int function4(\n" + " int param1,\n" + " int param2,\n" + " int param3);\n" + "int function5(int param1, int param2, int param3);\n", + "int function1();\n" // original + "int function2(int param1, int param2, int param3);\n" + "void function3(int param1, int param2, int param3) {}\n" + "int function4(\n" + " int param1,\n" + " int param2,\n" + " int param3);\n" + "int function5(int param1, int param2, int param3);\n", + Style); + + // test Always + // verify that there is a break when told to break + Style.AlwaysBreakBeforeFunctionParameters = FormatStyle::FPBS_Always; + verifyFormat("int function1(\n" + " int param1,\n" + " int param2,\n" + " int param3);\n" + "int function2();\n" + "void function3(\n" + " int param1,\n" + " int param2,\n" + " int param3) {}\n" + "int function4(\n" + " int param1,\n" + " int param2,\n" + " int param3);\n" + "int function5(\n" + " int param1,\n" + " int param2,\n" + " int param3);\n", + Style); + + // verify that having no parameters doesn't affect the parentheses + verifyFormat("void function1() {}\n", // the formatted part + "void function1() {}\n", // the original + Style); + + verifyFormat("void function1();\n", // the formatted part + "void function1();\n", // the original + Style); + + // test Never + Style.AlwaysBreakBeforeFunctionParameters = FormatStyle::FPBS_Never; + verifyFormat("int function1();\n" // the formatted part + "int function2(int param1, int param2, int param3);\n", + "int function1();\n" // the original + "int function2(\n" + " int param1,\n" + " int param2,\n" + " int param3);\n", + Style); +} } // namespace } // namespace test } // namespace format