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,24 @@ +.. _AlwaysBreakBeforeFunctionParameters: + +**AlwaysBreakBeforeFunctionParameters** (``Boolean``) :versionbadge:`clang-format 16` :ref:`¶ ` + If ``true``, always break before function parameters in a declaration. + + This flag is meant to align function parameters starting on the line following + a function declaration or definition. Thus, it will only take effect if a + function declares a parameter (or multiple parameters). Example uses + ``AlwaysBreakAfterReturnType`` set to ``All``. + + .. code-block:: c++ + + true: false: + int vs. int + someFunction( someFunction(int argument1, int argument2); + int argument1, + int argument2); + .. _AlwaysBreakBeforeMultilineStrings: **AlwaysBreakBeforeMultilineStrings** (``Boolean``) :versionbadge:`clang-format 3.4` :ref:`¶ ` @@ -3642,6 +3660,43 @@ **MacroBlockEnd** (``String``) :versionbadge:`clang-format 3.7` :ref:`¶ ` A regular expression matching macros that end a block. +.. _Macros: + +**Macros** (``List of Strings``) :ref:`¶ ` + A list of macros of the form ``=`` . + + Code will be parsed with macros expanded, in order to determine how to + interpret and format the macro arguments. + + For example, the code: + + .. code-block:: c++ + + A(a*b); + will usually be interpreted as a call to a function A, and the + multiplication expression will be formatted as `a * b`. + + If we specify the macro definition: + + .. code-block:: c++ + + Macros: + - A(x)=x + the code will now be parsed as a declaration of the variable b of type a*, + and formatted as `a* b` (depending on pointer-binding rules). + + Features and restrictions: + * Both function-like macros and object-like macros are supported. + * Macro arguments must be used exactly once in the expansion. + * No recursive expansion; macros referencing other macros will be + ignored. + * Overloading by arity is supported: for example, given the macro + definitions A=x, A()=y, A(a)=a, + 'A;' -> 'x;' + 'A();' -> 'y;' + 'A(z);' -> 'z;' + 'A(a, b) will not be expanded. + .. _MaxEmptyLinesToKeep: **MaxEmptyLinesToKeep** (``Unsigned``) :versionbadge:`clang-format 3.7` :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,22 @@ /// \version 3.8 ReturnTypeBreakingStyle AlwaysBreakAfterReturnType; + /// If ``true``, always break before function parameters in a declaration. + /// + /// This flag is meant to align function parameters starting on the line following + /// a function declaration or definition. Thus, it will only take effect if a + /// function declares a parameter (or multiple parameters). Example uses + /// ``AlwaysBreakAfterReturnType`` set to ``All``. + /// \code + /// true: false: + /// int vs. int + /// someFunction( someFunction(int argument1, int argument2); + /// int argument1, + /// int argument2); + /// \endcode + /// \version 16 + bool 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,11 @@ 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) && + Style.AlwaysBreakBeforeFunctionParameters && + State.Line->MustBeDeclaration) + return true; if (Current.MustBreakBefore || (Current.is(TT_InlineASMColon) && (Style.BreakBeforeInlineASMColon == FormatStyle::BBIAS_Always || @@ -1055,7 +1060,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 true and it's a function + // declaration. bool PreviousIsBreakingCtorInitializerColon = PreviousNonComment && PreviousNonComment->is(TT_CtorInitializerColon) && Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon; @@ -1070,7 +1077,9 @@ !State.Line->MustBeDeclaration) || (!AllowAllConstructorInitializersOnNextLine && PreviousIsBreakingCtorInitializerColon) || - Previous.is(TT_DictLiteral)) { + Previous.is(TT_DictLiteral) || + (Style.AlwaysBreakBeforeFunctionParameters && + 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 @@ -870,6 +870,8 @@ Style.AlwaysBreakAfterReturnType); IO.mapOptional("AlwaysBreakBeforeMultilineStrings", Style.AlwaysBreakBeforeMultilineStrings); + IO.mapOptional("AlwaysBreakBeforeFunctionParameters", + Style.AlwaysBreakBeforeFunctionParameters); IO.mapOptional("AlwaysBreakTemplateDeclarations", Style.AlwaysBreakTemplateDeclarations); IO.mapOptional("AttributeMacros", Style.AttributeMacros); @@ -1325,6 +1327,7 @@ LLVMStyle.AllowShortLoopsOnASingleLine = false; LLVMStyle.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; LLVMStyle.AlwaysBreakAfterDefinitionReturnType = FormatStyle::DRTBS_None; + LLVMStyle.AlwaysBreakBeforeFunctionParameters = false; 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 @@ -4737,6 +4737,16 @@ return true; } + // If AlwaysBreakBeforeFunctionParameters is true, we want to break before + // the next parameter, if there is one. + if (Left.is(tok::l_paren) && Style.AlwaysBreakBeforeFunctionParameters && + !Right.is(tok::r_paren) && Left.Previous) { + const FormatToken &TwoPrevious = *Left.Previous; + if (TwoPrevious.is(TT_FunctionDeclarationName)) { + return true; + } + } + // 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/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -25350,6 +25350,27 @@ verifyFormat("auto x = 5s .count() == 5;"); } +TEST_F(FormatTest, BreakBeforeParameterList) { + FormatStyle Style = getLLVMStyle(); + EXPECT_EQ(Style.AlwaysBreakBeforeFunctionParameters, false); + + const StringRef Code("int function1(int param1, int param2, int param3);\n" + "int function2();\n"); + + // verify that there is no break by default + verifyFormat("int function1(int param1, int param2, int param3);\n" + "int function2();\n", + Code, Style); + + // verify that there is a break when told to break + Style.AlwaysBreakBeforeFunctionParameters = true; + verifyFormat("int function1(\n" + " int param1,\n" + " int param2,\n" + " int param3);\n" + "int function2();\n", + Code, Style); +} } // namespace } // namespace test } // namespace format