Skip to content

[clang-format] allow short function body on a single line #151428

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

brandb97
Copy link
Contributor

@brandb97 brandb97 commented Jul 31, 2025

Fix issue #145161

@llvmbot
Copy link
Member

llvmbot commented Jul 31, 2025

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-format

Author: Lidong Yan (brandb97)

Changes

Fix issue #145161


Full diff: https://github.com/llvm/llvm-project/pull/151428.diff

4 Files Affected:

  • (modified) clang/include/clang/Format/Format.h (+6)
  • (modified) clang/lib/Format/Format.cpp (+3)
  • (modified) clang/lib/Format/UnwrappedLineFormatter.cpp (+20)
  • (modified) clang/lib/Format/UnwrappedLineParser.cpp (+4)
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 31582a40de866..e13df9df83e18 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -878,6 +878,12 @@ struct FormatStyle {
   /// \version 3.5
   ShortFunctionStyle AllowShortFunctionsOnASingleLine;
 
+  /// Dependent on the value, function body like ``{ return 0; }`` can be
+  /// put on a single line. Only when AllowShortFunctionsOnASingleLine = None
+  /// and AllowShortBlocksOnASingleLine != Never, the value of this option
+  /// is true.
+  bool AllowShortFunctionBodiesOnASingleLine;
+
   /// Different styles for handling short if statements.
   enum ShortIfStyle : int8_t {
     /// Never put short ifs on the same line.
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 063780721423f..61c0d399ca796 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -3828,6 +3828,9 @@ reformat(const FormatStyle &Style, StringRef Code,
   default:
     break;
   }
+  Expanded.AllowShortFunctionBodiesOnASingleLine =
+      Expanded.AllowShortFunctionsOnASingleLine == FormatStyle::SFS_None &&
+      Expanded.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never;
 
   if (Expanded.DisableFormat)
     return {tooling::Replacements(), 0};
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 0adf7ee9ed543..44c767a0db9b8 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -257,6 +257,12 @@ class LineJoiner {
       return tryMergeSimpleBlock(I, E, Limit);
     }
 
+    if (TheLine->Last->is(TT_FunctionLBrace) &&
+        TheLine->First == TheLine->Last &&
+        Style.AllowShortFunctionBodiesOnASingleLine) {
+      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,20 @@ class LineJoiner {
       }
       return MergedLines;
     }
+
+    // Previously, UnwrappedLineParser would move the left brace to a new line
+    // when AllowShortFunctionBodiesOnASingleLine 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.AllowShortFunctionBodiesOnASingleLine &&
+        !Style.BraceWrapping.AfterFunction) {
+      unsigned MergedLines = 0;
+      MergedLines = tryMergeSimpleBlock(I + 1, E, Limit);
+      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..7dd59c1cbd678 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.AllowShortFunctionBodiesOnASingleLine) {
+          // 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);

Copy link

github-actions bot commented Jul 31, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Contributor

@HazardyKnusperkeks HazardyKnusperkeks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are missing unit tests. clang/unittests/Format/FromatTest.cpp.

@@ -1921,6 +1921,10 @@ void UnwrappedLineParser::parseStructuralElement(
}
} else if (Style.BraceWrapping.AfterFunction) {
addUnwrappedLine();
} else if (Style.AllowShortFunctionBodiesOnASingleLine) {
// Wrap the left brace here; we'll try to merge it back
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed? It seems wrong to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Style.AllowShortFunctionBodiesOnSingleLine = true, I modified UnwrappedLineParser to parse

int main() {
  //...
}

into unwrapped lines ["int main()", "{", ..., "}"], not ["int main() {", ..., "}"] as usual. If clang-format can't put function body on a single line, I want to merge "int main()" and "{" back if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I parse the { in void foo() { as an unwrapped line is to allow merging the { and the function body into one line when the function body is very short.

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 <yldhome2d2@gmail.com>
@llvmbot llvmbot added the clang Clang issues not falling into any other category label Aug 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang Clang issues not falling into any other category clang-format
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants