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

>From 25d45a4ffce718a6a4086d3cd5802d8ff7972164 Mon Sep 17 00:00:00 2001
From: Lidong Yan <yldhome...@gmail.com>
Date: Tue, 5 Aug 2025 15:49:41 +0800
Subject: [PATCH] [clang-format] allow short function body on a single line

clang-format doesn't put short function body on a single line even if
user asks to put short blocks on a single line and do not put a whole
function on a single line. Add tryMergeSimpleBlocks() if we find user
want to put short function body on a single line.

Signed-off-by: Lidong Yan <yldhome...@gmail.com>
---
 clang/docs/ClangFormatStyleOptions.rst      | 19 ++++++++++++
 clang/include/clang/Format/Format.h         | 19 ++++++++++++
 clang/lib/Format/ContinuationIndenter.cpp   |  7 +++++
 clang/lib/Format/Format.cpp                 |  7 +++++
 clang/lib/Format/UnwrappedLineFormatter.cpp | 32 ++++++++++++++++++---
 clang/lib/Format/UnwrappedLineParser.cpp    |  4 +++
 clang/unittests/Format/FormatTest.cpp       | 30 +++++++++++++++++++
 7 files changed, 114 insertions(+), 4 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst 
b/clang/docs/ClangFormatStyleOptions.rst
index 02986a94a656c..b33abee391fab 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -5405,6 +5405,25 @@ the configuration (without a prefix: ``Auto``).
 
 
 
+.. _PutShortFunctionBodiesOnASingleLine:
+
+**PutShortFunctionBodiesOnASingleLine** (``Boolean``) 
:versionbadge:`clang-format 20` :ref:`¶ <PutShortFunctionBodiesOnASingleLine>`
+  Dependent on the value, function body can be put on a single line.
+  Automatically enabled when
+  `AllowShortFunctionsOnASingleLine` is set to `None` and
+  `AllowShortBlocksOnASingleLine` is set to `Always`.
+
+  .. code-block:: c++
+
+    true:
+    int f()
+    { return 0; }
+
+    false:
+    int f() {
+      return 0;
+    }
+
 .. _QualifierAlignment:
 
 **QualifierAlignment** (``QualifierAlignmentStyle``) 
:versionbadge:`clang-format 14` :ref:`¶ <QualifierAlignment>`
diff --git a/clang/include/clang/Format/Format.h 
b/clang/include/clang/Format/Format.h
index 31582a40de866..010dc622822c6 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -3829,6 +3829,23 @@ struct FormatStyle {
   /// \version 13
   int PPIndentWidth;
 
+  /// Dependent on the value, function body can be put on a single line.
+  /// Automatically enabled when
+  /// `AllowShortFunctionsOnASingleLine` is set to `None` and
+  /// `AllowShortBlocksOnASingleLine` is set to `Always`.
+  /// \code
+  ///   true:
+  ///   int f()
+  ///   { return 0; }
+  ///
+  ///   false:
+  ///   int f() {
+  ///     return 0;
+  ///   }
+  /// \endcode
+  /// \version 20
+  bool PutShortFunctionBodiesOnASingleLine;
+
   /// Different specifiers and qualifiers alignment styles.
   enum QualifierAlignmentStyle : int8_t {
     /// Don't change specifiers/qualifiers to either Left or Right alignment
@@ -5461,6 +5478,8 @@ struct FormatStyle {
            PenaltyExcessCharacter == R.PenaltyExcessCharacter &&
            PenaltyReturnTypeOnItsOwnLine == R.PenaltyReturnTypeOnItsOwnLine &&
            PointerAlignment == R.PointerAlignment &&
+           PutShortFunctionBodiesOnASingleLine ==
+               R.PutShortFunctionBodiesOnASingleLine &&
            QualifierAlignment == R.QualifierAlignment &&
            QualifierOrder == R.QualifierOrder &&
            RawStringFormats == R.RawStringFormats &&
diff --git a/clang/lib/Format/ContinuationIndenter.cpp 
b/clang/lib/Format/ContinuationIndenter.cpp
index 9a10403b858f9..57624edd60c0d 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -390,6 +390,13 @@ bool ContinuationIndenter::canBreak(const LineState 
&State) {
     return true;
   }
 
+  // `PutShortFunctionBodiesOnASingleLine = true` will wrap left brace into
+  // a new line, do not break before the left brace.
+  if (Current.is(TT_FunctionLBrace) && !Style.BraceWrapping.AfterFunction &&
+      Style.PutShortFunctionBodiesOnASingleLine) {
+    return false;
+  }
+
   return !State.NoLineBreak && !CurrentState.NoLineBreak;
 }
 
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 063780721423f..da1e5937e3720 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1144,6 +1144,8 @@ template <> struct MappingTraits<FormatStyle> {
                    Style.PenaltyReturnTypeOnItsOwnLine);
     IO.mapOptional("PointerAlignment", Style.PointerAlignment);
     IO.mapOptional("PPIndentWidth", Style.PPIndentWidth);
+    IO.mapOptional("PutShortFunctionBodiesOnASingleLine",
+                   Style.PutShortFunctionBodiesOnASingleLine);
     IO.mapOptional("QualifierAlignment", Style.QualifierAlignment);
     // Default Order for Left/Right based Qualifier alignment.
     if (Style.QualifierAlignment == FormatStyle::QAS_Right)
@@ -1643,6 +1645,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind 
Language) {
   LLVMStyle.PackConstructorInitializers = FormatStyle::PCIS_BinPack;
   LLVMStyle.PointerAlignment = FormatStyle::PAS_Right;
   LLVMStyle.PPIndentWidth = -1;
+  LLVMStyle.PutShortFunctionBodiesOnASingleLine = false;
   LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave;
   LLVMStyle.ReferenceAlignment = FormatStyle::RAS_Pointer;
   LLVMStyle.ReflowComments = FormatStyle::RCS_Always;
@@ -3828,6 +3831,10 @@ reformat(const FormatStyle &Style, StringRef Code,
   default:
     break;
   }
+  if (Expanded.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_None &&
+      Expanded.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Always) {
+    Expanded.PutShortFunctionBodiesOnASingleLine = true;
+  }
 
   if (Expanded.DisableFormat)
     return {tooling::Replacements(), 0};
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp 
b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 0adf7ee9ed543..d42689b66f049 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -242,13 +242,13 @@ class LineJoiner {
     if (Style.ColumnLimit > 0 && Indent > Style.ColumnLimit)
       return 0;
 
-    unsigned Limit =
+    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 &&
@@ -257,6 +257,12 @@ class LineJoiner {
       return tryMergeSimpleBlock(I, E, Limit);
     }
 
+    if (TheLine->Last->is(TT_FunctionLBrace) &&
+        TheLine->First == TheLine->Last &&
+        Style.PutShortFunctionBodiesOnASingleLine) {
+      return tryMergeSimpleBlock(I, E, Limit);
+    }
+
     const auto *PreviousLine = I != AnnotatedLines.begin() ? I[-1] : nullptr;
     // Handle empty record blocks where the brace has already been wrapped.
     if (PreviousLine && TheLine->Last->is(tok::l_brace) &&
@@ -532,6 +538,24 @@ class LineJoiner {
       }
       return MergedLines;
     }
+
+    // UnwrappedLineParser would move the left brace to a new line when
+    // PutShortFunctionBodiesOnASingleLine is enabled. However, if the
+    // function body cannot fit on a single line, and
+    // Style.BraceWrapping.AfterFunction is false, we should merge the
+    // function name and the left brace back onto the same line.
+    if (NextLine.First->is(TT_FunctionLBrace) &&
+        Style.PutShortFunctionBodiesOnASingleLine &&
+        !Style.BraceWrapping.AfterFunction) {
+      unsigned MergedLines = 0;
+      unsigned NextLineLimit =
+          NextLine.Last->TotalLength > LimitStripIndent
+              ? 0
+              : LimitStripIndent - NextLine.Last->TotalLength;
+      MergedLines = tryMergeSimpleBlock(I + 1, E, NextLineLimit);
+      return MergedLines > 0 ? 0 : 1;
+    }
+
     auto IsElseLine = [&TheLine]() -> bool {
       const FormatToken *First = TheLine->First;
       if (First->is(tok::kw_else))
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp 
b/clang/lib/Format/UnwrappedLineParser.cpp
index 91b8fdc8a3c38..09e1e671d7220 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -1921,6 +1921,10 @@ void UnwrappedLineParser::parseStructuralElement(
           }
         } else if (Style.BraceWrapping.AfterFunction) {
           addUnwrappedLine();
+        } else if (Style.PutShortFunctionBodiesOnASingleLine) {
+          // Wrap the left brace here; we'll try to merge it back
+          // later if needed.
+          addUnwrappedLine();
         }
         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 9c5aa11d6e58f..f4028626c4783 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -14941,11 +14941,24 @@ TEST_F(FormatTest, 
PullTrivialFunctionDefinitionsIntoSingleLine) {
   FormatStyle DoNotMerge = getLLVMStyle();
   DoNotMerge.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
 
+  FormatStyle MergeBodyOnly = getLLVMStyle();
+  MergeBodyOnly.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
+  MergeBodyOnly.PutShortFunctionBodiesOnASingleLine = true;
+
+  FormatStyle MergeBodyIfPossible = getLLVMStyleWithColumns(20);
+  MergeBodyIfPossible.PutShortFunctionBodiesOnASingleLine = true;
+
   verifyFormat("void f() { return 42; }");
   verifyFormat("void f() {\n"
                "  return 42;\n"
                "}",
                DoNotMerge);
+  verifyFormat("void f()\n"
+               "{ return 42; }",
+               MergeBodyOnly);
+  verifyFormat("void long_function_name()\n"
+               "{ return 42; }",
+               MergeBodyIfPossible);
   verifyFormat("void f() {\n"
                "  // Comment\n"
                "}");
@@ -14966,6 +14979,23 @@ TEST_F(FormatTest, 
PullTrivialFunctionDefinitionsIntoSingleLine) {
                "  int a;\n"
                "} // comment",
                DoNotMerge);
+  verifyFormat("void f()\n"
+               "{} // comment",
+               MergeBodyOnly);
+  verifyFormat("void f()\n"
+               "{ int a; } // comment",
+               MergeBodyOnly);
+  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() {\n"
                "} // comment",
                getLLVMStyleWithColumns(15));

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to