https://github.com/brandb97 updated https://github.com/llvm/llvm-project/pull/151428
>From 8df95ae522547ba1c4fdd61481bbfcbfa902eec6 Mon Sep 17 00:00:00 2001 From: Lidong Yan <yldhome...@gmail.com> Date: Mon, 25 Aug 2025 13:19:22 +0800 Subject: [PATCH] [clang-format] allow short function bodies on a single line When set AllowShortBlocksOnASingleLine as Empty or Always and we can't put the whole function on a single line, clang-format doesn't tries to put the function body on a seperate line from function signature. Add tryMergeLines to put function bodies on a single line if possible. Signed-off-by: Lidong Yan <yldhome...@gmail.com> --- clang/lib/Format/FormatToken.h | 4 ++ clang/lib/Format/UnwrappedLineFormatter.cpp | 58 ++++++++++++++++----- clang/lib/Format/UnwrappedLineParser.cpp | 11 +++- clang/unittests/Format/FormatTest.cpp | 32 ++++++++++++ 4 files changed, 89 insertions(+), 16 deletions(-) diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 9252a795a0b5e..4b10ec57c828d 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -360,6 +360,10 @@ struct FormatToken { /// \c true if it is allowed to break before this token. unsigned CanBreakBefore : 1; + /// \c true if line breaks should not occur when joining this token with + /// the previous line. + unsigned NoBreakDuringJoinLines : 1; + /// \c true if this is the ">" of "template<..>". unsigned ClosesTemplateDeclaration : 1; diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index c938ff3965f9e..1bdf69e74c713 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -242,19 +242,24 @@ class LineJoiner { if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit) return 0; - unsigned Limit = + const unsigned LimitStripIndent = Style.ColumnLimit == 0 ? UINT_MAX : Style.ColumnLimit - Indent; // If we already exceed the column limit, we set 'Limit' to 0. The different // tryMerge..() functions can then decide whether to still do merging. - Limit = TheLine->Last->TotalLength > Limit - ? 0 - : Limit - TheLine->Last->TotalLength; + unsigned Limit = TheLine->Last->TotalLength > LimitStripIndent + ? 0 + : LimitStripIndent - TheLine->Last->TotalLength; if (TheLine->Last->is(TT_FunctionLBrace) && - TheLine->First == TheLine->Last && - !Style.BraceWrapping.SplitEmptyFunction && - NextLine.First->is(tok::r_brace)) { - return tryMergeSimpleBlock(I, E, Limit); + TheLine->First == TheLine->Last) { + if (!Style.BraceWrapping.SplitEmptyFunction && + NextLine.First->is(tok::r_brace)) { + return tryMergeSimpleBlock(I, E, Limit); + } + if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Always && + I + 2 != E && I[2]->First->is(tok::r_brace)) { + return tryMergeSimpleBlock(I, E, Limit); + } } const auto *PreviousLine = I != AnnotatedLines.begin() ? I[-1] : nullptr; @@ -510,27 +515,51 @@ class LineJoiner { // Try to merge a function block with left brace wrapped. if (NextLine.First->is(TT_FunctionLBrace) && - Style.BraceWrapping.AfterFunction) { + (Style.BraceWrapping.AfterFunction || + Style.AllowShortBlocksOnASingleLine >= FormatStyle::SBS_Empty)) { if (NextLine.Last->is(TT_LineComment)) return 0; // Check for Limit <= 2 to account for the " {". if (Limit <= 2 || (Style.ColumnLimit == 0 && containsMustBreak(TheLine))) - return 0; + if (Style.BraceWrapping.AfterFunction) + return 0; Limit -= 2; unsigned MergedLines = 0; + const bool NextEmptyBlock = NextLine.First == NextLine.Last && + I + 2 != E && I[2]->First->is(tok::r_brace); + const bool NextShortBlock = NextLine.First == NextLine.Last && + I + 2 != E && I + 3 != E && + I[3]->First->is(tok::r_brace); if (MergeShortFunctions || (Style.AllowShortFunctionsOnASingleLine >= FormatStyle::SFS_Empty && - NextLine.First == NextLine.Last && I + 2 != E && - I[2]->First->is(tok::r_brace))) { + NextEmptyBlock) || + (Style.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_All && + NextShortBlock)) { MergedLines = tryMergeSimpleBlock(I + 1, E, Limit); // If we managed to merge the block, count the function header, which is // on a separate line. if (MergedLines > 0) ++MergedLines; } - return MergedLines; + // Return early if we shouldn't merge left brace back to function header. + if (Style.BraceWrapping.AfterFunction || MergedLines) + return MergedLines; + + // If we can't put function body on a single line, we should merge left + // brace back to function header. + const unsigned NextLineLimit = + NextLine.Last->TotalLength > LimitStripIndent + ? 0 + : LimitStripIndent - NextLine.Last->TotalLength; + if ((NextShortBlock && + Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Always) || + (NextEmptyBlock && + Style.AllowShortBlocksOnASingleLine >= FormatStyle::SBS_Empty)) { + MergedLines = tryMergeSimpleBlock(I + 1, E, NextLineLimit); + } + return MergedLines ? 0 : 1; } auto IsElseLine = [&TheLine]() -> bool { const FormatToken *First = TheLine->First; @@ -992,7 +1021,8 @@ class LineJoiner { } A.Last->Next = B.First; B.First->Previous = A.Last; - B.First->CanBreakBefore = true; + if (!B.First->NoBreakDuringJoinLines) + B.First->CanBreakBefore = true; unsigned LengthA = A.Last->TotalLength + B.First->SpacesRequiredBefore; for (FormatToken *Tok = B.First; Tok; Tok = Tok->Next) { Tok->TotalLength += LengthA; diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 91b8fdc8a3c38..3582a599e2959 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -1907,6 +1907,8 @@ void UnwrappedLineParser::parseStructuralElement( FormatTok->setFinalizedType(TT_BracedListLBrace); if (!tryToParsePropertyAccessor() && !tryToParseBracedList()) { IsDecltypeAutoFunction = Line->SeenDecltypeAuto; + if (!Previous || Previous->isNot(TT_TypeDeclarationParen)) + FormatTok->setFinalizedType(TT_FunctionLBrace); // A block outside of parentheses must be the last part of a // structural element. // FIXME: Figure out cases where this is not true, and add projections @@ -1921,9 +1923,14 @@ void UnwrappedLineParser::parseStructuralElement( } } else if (Style.BraceWrapping.AfterFunction) { addUnwrappedLine(); + } else if (Style.AllowShortBlocksOnASingleLine >= + FormatStyle::SBS_Empty && + FormatTok->is(TT_FunctionLBrace)) { + // Wrap left brace here in case that we want + // to merge function body on a single line. + addUnwrappedLine(); + FormatTok->NoBreakDuringJoinLines = true; } - if (!Previous || Previous->isNot(TT_TypeDeclarationParen)) - FormatTok->setFinalizedType(TT_FunctionLBrace); parseBlock(); IsDecltypeAutoFunction = false; addUnwrappedLine(); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 83c664c3b81f3..fef7607c30587 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -14953,11 +14953,25 @@ TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) { FormatStyle DoNotMerge = getLLVMStyle(); DoNotMerge.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None; + FormatStyle MergeBodyAlways = getLLVMStyle(); + MergeBodyAlways.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None; + MergeBodyAlways.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Always; + + FormatStyle MergeBodyIfPossible = getLLVMStyleWithColumns(20); + MergeBodyIfPossible.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None; + MergeBodyIfPossible.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Always; + verifyFormat("void f() { return 42; }"); verifyFormat("void f() {\n" " return 42;\n" "}", DoNotMerge); + verifyFormat("void f()\n" + "{ return 42; }", + MergeBodyAlways); + verifyFormat("void long_function_name()\n" + "{ return 42; }", + MergeBodyIfPossible); verifyFormat("void f() {\n" " // Comment\n" "}"); @@ -14982,6 +14996,24 @@ TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) { "} // comment", getLLVMStyleWithColumns(15)); + verifyFormat("void f()\n" + "{} // comment", + MergeBodyAlways); + verifyFormat("void f()\n" + "{ int a; } // comment", + MergeBodyAlways); + verifyFormat("void long_function_name()\n" + "{} // comment", + MergeBodyIfPossible); + verifyFormat("void f() {\n" + " int a;\n" + "} // comment", + MergeBodyIfPossible); + MergeBodyIfPossible.ColumnLimit = 21; + verifyFormat("void f()\n" + "{ int a; } // comment", + MergeBodyIfPossible); + verifyFormat("void f() { return 42; }", getLLVMStyleWithColumns(23)); verifyFormat("void f() {\n return 42;\n}", getLLVMStyleWithColumns(22)); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits