https://github.com/brandb97 updated 
https://github.com/llvm/llvm-project/pull/151428

>From 0c5bc1a66d35cda6f09c118652f3cf529c28c200 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    |  6 +++
 clang/unittests/Format/FormatTest.cpp       | 32 ++++++++++++
 4 files changed, 86 insertions(+), 14 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..a38cb3fe9a21b 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -1921,6 +1921,12 @@ void UnwrappedLineParser::parseStructuralElement(
           }
         } else if (Style.BraceWrapping.AfterFunction) {
           addUnwrappedLine();
+        } else if (Style.AllowShortBlocksOnASingleLine >=
+                   FormatStyle::SBS_Empty) {
+          // 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);
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

Reply via email to