From 2a81ca8d610b5bdccee0bc75f73980ab395712ba Mon Sep 17 00:00:00 2001 From: Francois Ferrand Date: Tue, 13 Jun 2017 07:02:43 +0000 Subject: [PATCH] clang-format: add option to merge empty function body Summary: This option supplements the AllowShortFunctionsOnASingleLine flag, to merge empty function body at the beginning of the line: e.g. when the function is not short-enough and breaking braces after function. int f() {} Reviewers: krasimir, djasper Reviewed By: djasper Subscribers: klimek, cfe-commits Differential Revision: https://reviews.llvm.org/D33447 llvm-svn: 305272 --- clang/include/clang/Format/Format.h | 12 ++ clang/lib/Format/Format.cpp | 8 +- clang/lib/Format/UnwrappedLineFormatter.cpp | 11 +- clang/unittests/Format/FormatTest.cpp | 125 ++++++++++++++++++++ 4 files changed, 152 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 7ec3e22ca4d7..4081e2131c70 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -688,6 +688,18 @@ struct FormatStyle { bool BeforeElse; /// \brief Indent the wrapped braces themselves. bool IndentBraces; + /// \brief If ``false``, empty function body can be put on a single line. + /// This option is used only if the opening brace of the function has + /// already been wrapped, i.e. the `AfterFunction` brace wrapping mode is + /// set, and the function could/should not be put on a single line (as per + /// `AllowShortFunctionsOnASingleLine` and constructor formatting options). + /// \code + /// int f() vs. inf f() + /// {} { + /// } + /// \endcode + /// + bool SplitEmptyFunctionBody; }; /// \brief Control of individual brace wrapping cases. diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 2ef6516e02ee..0eaf44d2048a 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -410,6 +410,7 @@ template <> struct MappingTraits { IO.mapOptional("BeforeCatch", Wrapping.BeforeCatch); IO.mapOptional("BeforeElse", Wrapping.BeforeElse); IO.mapOptional("IndentBraces", Wrapping.IndentBraces); + IO.mapOptional("SplitEmptyFunctionBody", Wrapping.SplitEmptyFunctionBody); } }; @@ -485,7 +486,7 @@ static FormatStyle expandPresets(const FormatStyle &Style) { return Style; FormatStyle Expanded = Style; Expanded.BraceWrapping = {false, false, false, false, false, false, - false, false, false, false, false}; + false, false, false, false, false, true}; switch (Style.BreakBeforeBraces) { case FormatStyle::BS_Linux: Expanded.BraceWrapping.AfterClass = true; @@ -498,6 +499,7 @@ static FormatStyle expandPresets(const FormatStyle &Style) { Expanded.BraceWrapping.AfterFunction = true; Expanded.BraceWrapping.AfterStruct = true; Expanded.BraceWrapping.AfterUnion = true; + Expanded.BraceWrapping.SplitEmptyFunctionBody = false; break; case FormatStyle::BS_Stroustrup: Expanded.BraceWrapping.AfterFunction = true; @@ -517,7 +519,7 @@ static FormatStyle expandPresets(const FormatStyle &Style) { break; case FormatStyle::BS_GNU: Expanded.BraceWrapping = {true, true, true, true, true, true, - true, true, true, true, true}; + true, true, true, true, true, true}; break; case FormatStyle::BS_WebKit: Expanded.BraceWrapping.AfterFunction = true; @@ -554,7 +556,7 @@ FormatStyle getLLVMStyle() { LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; LLVMStyle.BraceWrapping = {false, false, false, false, false, false, - false, false, false, false, false}; + false, false, false, false, false, true}; LLVMStyle.BreakAfterJavaFieldAnnotations = false; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; LLVMStyle.BreakBeforeInheritanceComma = false; diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index 01504da0a29b..eb8de6598ebb 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -186,6 +186,12 @@ private: ? 0 : Limit - TheLine->Last->TotalLength; + if (TheLine->Last->is(TT_FunctionLBrace) && + TheLine->First == TheLine->Last && + !Style.BraceWrapping.SplitEmptyFunctionBody && + I[1]->First->is(tok::r_brace)) + return tryMergeSimpleBlock(I, E, Limit); + // FIXME: TheLine->Level != 0 might or might not be the right check to do. // If necessary, change to something smarter. bool MergeShortFunctions = @@ -215,7 +221,10 @@ private: Limit -= 2; unsigned MergedLines = 0; - if (MergeShortFunctions) { + if (MergeShortFunctions || + (Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty && + I[1]->First == I[1]->Last && I + 2 != E && + I[2]->First->is(tok::r_brace))) { MergedLines = tryMergeSimpleBlock(I + 1, E, Limit); // If we managed to merge the block, count the function header, which is // on a separate line. diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 64e963db4cfd..783fe450427b 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -6239,6 +6239,35 @@ TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) { getLLVMStyleWithColumns(23)); } +TEST_F(FormatTest, PullEmptyFunctionDefinitionsIntoSingleLine) { + FormatStyle MergeEmptyOnly = getLLVMStyle(); + MergeEmptyOnly.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; + verifyFormat("class C {\n" + " int f() {}\n" + "};", + MergeEmptyOnly); + verifyFormat("class C {\n" + " int f() {\n" + " return 42;\n" + " }\n" + "};", + MergeEmptyOnly); + verifyFormat("int f() {}", MergeEmptyOnly); + verifyFormat("int f() {\n" + " return 42;\n" + "}", + MergeEmptyOnly); + + // Also verify behavior when BraceWrapping.AfterFunction = true + MergeEmptyOnly.BreakBeforeBraces = FormatStyle::BS_Custom; + MergeEmptyOnly.BraceWrapping.AfterFunction = true; + verifyFormat("int f() {}", MergeEmptyOnly); + verifyFormat("class C {\n" + " int f() {}\n" + "};", + MergeEmptyOnly); +} + TEST_F(FormatTest, PullInlineFunctionDefinitionsIntoSingleLine) { FormatStyle MergeInlineOnly = getLLVMStyle(); MergeInlineOnly.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; @@ -6250,6 +6279,101 @@ TEST_F(FormatTest, PullInlineFunctionDefinitionsIntoSingleLine) { " return 42;\n" "}", MergeInlineOnly); + + // SFS_Inline implies SFS_Empty + verifyFormat("class C {\n" + " int f() {}\n" + "};", + MergeInlineOnly); + verifyFormat("int f() {}", MergeInlineOnly); + + // Also verify behavior when BraceWrapping.AfterFunction = true + MergeInlineOnly.BreakBeforeBraces = FormatStyle::BS_Custom; + MergeInlineOnly.BraceWrapping.AfterFunction = true; + verifyFormat("class C {\n" + " int f() { return 42; }\n" + "};", + MergeInlineOnly); + verifyFormat("int f()\n" + "{\n" + " return 42;\n" + "}", + MergeInlineOnly); + + // SFS_Inline implies SFS_Empty + verifyFormat("int f() {}", MergeInlineOnly); + verifyFormat("class C {\n" + " int f() {}\n" + "};", + MergeInlineOnly); +} + +TEST_F(FormatTest, SplitEmptyFunctionBody) { + FormatStyle Style = getLLVMStyle(); + Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None; + Style.BreakBeforeBraces = FormatStyle::BS_Custom; + Style.BraceWrapping.AfterFunction = true; + Style.BraceWrapping.SplitEmptyFunctionBody = false; + Style.ColumnLimit = 40; + + verifyFormat("int f()\n" + "{}", + Style); + verifyFormat("int f()\n" + "{\n" + " return 42;\n" + "}", + Style); + verifyFormat("int f()\n" + "{\n" + " // some comment\n" + "}", + Style); + + Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; + verifyFormat("int f() {}", Style); + verifyFormat("int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n" + "{}", + Style); + verifyFormat("int f()\n" + "{\n" + " return 0;\n" + "}", + Style); + + Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; + verifyFormat("class Foo {\n" + " int f() {}\n" + "};\n", + Style); + verifyFormat("class Foo {\n" + " int f() { return 0; }\n" + "};\n", + Style); + verifyFormat("class Foo {\n" + " int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n" + " {}\n" + "};\n", + Style); + verifyFormat("class Foo {\n" + " int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n" + " {\n" + " return 0;\n" + " }\n" + "};\n", + Style); + + Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All; + verifyFormat("int f() {}", Style); + verifyFormat("int f() { return 0; }", Style); + verifyFormat("int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n" + "{}", + Style); + verifyFormat("int aaaaaaaaaaaaaa(int bbbbbbbbbbbbbb)\n" + "{\n" + " return 0;\n" + "}", + Style); } TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) { @@ -8960,6 +9084,7 @@ TEST_F(FormatTest, ParsesConfigurationBools) { CHECK_PARSE_NESTED_BOOL(BraceWrapping, BeforeCatch); CHECK_PARSE_NESTED_BOOL(BraceWrapping, BeforeElse); CHECK_PARSE_NESTED_BOOL(BraceWrapping, IndentBraces); + CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyFunctionBody); } #undef CHECK_PARSE_BOOL