From 13be0d4a34c421607a5c082ec39dad2cbd6d506f Mon Sep 17 00:00:00 2001 From: Ameer J <52414509+ameerj@users.noreply.github.com> Date: Tue, 2 Apr 2024 15:00:51 -0400 Subject: [PATCH] [clang-format] Add BreakFunctionDefinitionParameters option (#84988) This adds an option to break function definition parameters, putting them on the next line after the function's opening paren. This was a missing step towards allowing styles which require all function definition parameters be on their own lines. Closes #62963 --- clang/docs/ClangFormatStyleOptions.rst | 15 +++++++++++ clang/include/clang/Format/Format.h | 16 +++++++++++ clang/lib/Format/Format.cpp | 3 +++ clang/lib/Format/FormatToken.h | 3 +++ clang/lib/Format/TokenAnnotator.cpp | 7 +++++ clang/unittests/Format/FormatTest.cpp | 37 ++++++++++++++++++++++++++ 6 files changed, 81 insertions(+) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 2ee36f24d7ce4b..39f7cded36edbf 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -3295,6 +3295,21 @@ the configuration (without a prefix: ``Auto``). +.. _BreakFunctionDefinitionParameters: + +**BreakFunctionDefinitionParameters** (``Boolean``) :versionbadge:`clang-format 19` :ref:`¶ ` + If ``true``, clang-format will always break before function definition + parameters. + + .. code-block:: c++ + + true: + void functionDefinition( + int A, int B) {} + + false: + void functionDefinition(int A, int B) {} + .. _BreakInheritanceList: **BreakInheritanceList** (``BreakInheritanceListStyle``) :versionbadge:`clang-format 7` :ref:`¶ ` diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 0720c8283cd75c..48f5fb44157570 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -2223,6 +2223,20 @@ struct FormatStyle { /// \version 5 BreakConstructorInitializersStyle BreakConstructorInitializers; + /// If ``true``, clang-format will always break before function definition + /// parameters. + /// \code + /// true: + /// void functionDefinition( + /// int A, int B) {} + /// + /// false: + /// void functionDefinition(int A, int B) {} + /// + /// \endcode + /// \version 19 + bool BreakFunctionDefinitionParameters; + /// Break after each annotation on a field in Java files. /// \code{.java} /// true: false: @@ -4938,6 +4952,8 @@ struct FormatStyle { BreakBeforeInlineASMColon == R.BreakBeforeInlineASMColon && BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators && BreakConstructorInitializers == R.BreakConstructorInitializers && + BreakFunctionDefinitionParameters == + R.BreakFunctionDefinitionParameters && BreakInheritanceList == R.BreakInheritanceList && BreakStringLiterals == R.BreakStringLiterals && BreakTemplateDeclarations == R.BreakTemplateDeclarations && diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 46ed5baaeacead..e41cf2902a6818 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -955,6 +955,8 @@ template <> struct MappingTraits { Style.BreakBeforeTernaryOperators); IO.mapOptional("BreakConstructorInitializers", Style.BreakConstructorInitializers); + IO.mapOptional("BreakFunctionDefinitionParameters", + Style.BreakFunctionDefinitionParameters); IO.mapOptional("BreakInheritanceList", Style.BreakInheritanceList); IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals); IO.mapOptional("BreakTemplateDeclarations", @@ -1465,6 +1467,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline; LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; + LLVMStyle.BreakFunctionDefinitionParameters = false; LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon; LLVMStyle.BreakStringLiterals = true; LLVMStyle.BreakTemplateDeclarations = FormatStyle::BTDS_MultiLine; diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 2ddcd5259446f6..48b6a9092a8c09 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -574,6 +574,9 @@ struct FormatToken { /// Is optional and can be removed. bool Optional = false; + /// Might be function declaration open/closing paren. + bool MightBeFunctionDeclParen = false; + /// Number of optional braces to be inserted after this token: /// -1: a single left brace /// 0: no braces diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index b9144cf55452e2..a405a348403bdf 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1550,6 +1550,7 @@ class AnnotatingParser { (!Previous->isAttribute() && !Previous->isOneOf(TT_RequiresClause, TT_LeadingJavaAnnotation))) { Line.MightBeFunctionDecl = true; + Tok->MightBeFunctionDeclParen = true; } } break; @@ -5392,6 +5393,12 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, if (Right.NewlinesBefore > 1 && Style.MaxEmptyLinesToKeep > 0) return true; + if (Style.BreakFunctionDefinitionParameters && Line.MightBeFunctionDecl && + Line.mightBeFunctionDefinition() && Left.MightBeFunctionDeclParen && + Left.ParameterCount > 0) { + return true; + } + if (Style.isCSharp()) { if (Left.is(TT_FatArrow) && Right.is(tok::l_brace) && Style.BraceWrapping.AfterFunction) { diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 33dec7dae319f0..ec0267da468ab2 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -7976,6 +7976,43 @@ TEST_F(FormatTest, AllowAllArgumentsOnNextLineDontAlign) { Input, Style); } +TEST_F(FormatTest, BreakFunctionDefinitionParameters) { + FormatStyle Style = getLLVMStyle(); + EXPECT_FALSE(Style.BreakFunctionDefinitionParameters); + StringRef Input = "void functionDecl(paramA, paramB, paramC);\n" + "void emptyFunctionDefinition() {}\n" + "void functionDefinition(int A, int B, int C) {}\n" + "Class::Class(int A, int B) : m_A(A), m_B(B) {}\n"; + verifyFormat(StringRef("void functionDecl(paramA, paramB, paramC);\n" + "void emptyFunctionDefinition() {}\n" + "void functionDefinition(int A, int B, int C) {}\n" + "Class::Class(int A, int B) : m_A(A), m_B(B) {}\n"), + Input, Style); + Style.BreakFunctionDefinitionParameters = true; + verifyFormat(StringRef("void functionDecl(paramA, paramB, paramC);\n" + "void emptyFunctionDefinition() {}\n" + "void functionDefinition(\n" + " int A, int B, int C) {}\n" + "Class::Class(\n" + " int A, int B)\n" + " : m_A(A), m_B(B) {}\n"), + Input, Style); + // Test the style where all parameters are on their own lines + Style.AllowAllParametersOfDeclarationOnNextLine = false; + Style.BinPackParameters = false; + verifyFormat(StringRef("void functionDecl(paramA, paramB, paramC);\n" + "void emptyFunctionDefinition() {}\n" + "void functionDefinition(\n" + " int A,\n" + " int B,\n" + " int C) {}\n" + "Class::Class(\n" + " int A,\n" + " int B)\n" + " : m_A(A), m_B(B) {}\n"), + Input, Style); +} + TEST_F(FormatTest, BreakBeforeInlineASMColon) { FormatStyle Style = getLLVMStyle(); Style.BreakBeforeInlineASMColon = FormatStyle::BBIAS_Never;