Skip to content

Conversation

brandb97
Copy link
Contributor

@brandb97 brandb97 commented Jul 31, 2025

Fix #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.

@llvmbot llvmbot added the clang Clang issues not falling into any other category label Aug 5, 2025
@brandb97
Copy link
Contributor Author

ping

@owenca
Copy link
Contributor

owenca commented Aug 19, 2025

Can we fix the bug instead of adding an option?

@brandb97
Copy link
Contributor Author

Sorry, I promised to add enum PutShortFunctionBodiesOnASingleLine option, but I haven’t touched this code in quite a while (due to summer vacation). It seems the requirements have changed since then, so maybe it was a good thing I didn’t write it after all? ;-)

@brandb97
Copy link
Contributor Author

I can just fix the bug by moving PutShortFunctionBodiesOnASingleLine to private area in FormatStyle and set PutShortFunctionBodiesOnASingleLine to Always if and only if AllowShortFunctionsOnASingleLine is Never and AllowShortBlocksOnASingleLine is Always. Is that what I should do?

@brandb97
Copy link
Contributor Author

@owenca I actually think adding a new option would be better. The reason is that when users want to specify putting function bodies on a single line, without a new option, they would have to set
AllowShortFunctionsOnASingleLine: Never
AllowShortBlocksOnASingleLine: Always
But such a setting would also cause shorter if and while blocks to be placed on a single line, which users might not want. With a new option, this problem wouldn’t occur.

@owenca
Copy link
Contributor

owenca commented Aug 20, 2025

Sorry, I promised to add enum PutShortFunctionBodiesOnASingleLine option, but I haven’t touched this code in quite a while (due to summer vacation). It seems the requirements have changed since then, so maybe it was a good thing I didn’t write it after all? ;-)

I don't think the requirements have changed from my perspective. See #145161 (comment).

@owenca I actually think adding a new option would be better. The reason is that when users want to specify putting function bodies on a single line, without a new option, they would have to set AllowShortFunctionsOnASingleLine: Never AllowShortBlocksOnASingleLine: Always But such a setting would also cause shorter if and while blocks to be placed on a single line, which users might not want. With a new option, this problem wouldn’t occur.

We can't keep adding all kinds of options people can come up with. See https://clang.llvm.org/docs/ClangFormatStyleOptions.html#adding-additional-style-options.

@brandb97
Copy link
Contributor Author

I see, I’ll rewrite this part of the code.

@brandb97
Copy link
Contributor Author

brandb97 commented Aug 22, 2025

@owenca Could you help review my code? Thank you very much.

@brandb97 brandb97 force-pushed the fix-clang-format branch 2 times, most recently from e5a880b to 7cdbee9 Compare August 25, 2025 05:20
@brandb97 brandb97 force-pushed the fix-clang-format branch 2 times, most recently from 0c5bc1a to 8df95ae Compare August 25, 2025 11:42
@owenca
Copy link
Contributor

owenca commented Aug 26, 2025

See #145161 (comment). Sorry about that! Hopefully this requirement change makes the fix much simpler.

@brandb97
Copy link
Contributor Author

@owenca That's totally fine, I will try to simplify my code.

@brandb97 brandb97 requested a review from owenca August 29, 2025 00:54
@owenca owenca removed their request for review August 29, 2025 02:50
@brandb97
Copy link
Contributor Author

brandb97 commented Aug 29, 2025 via email

When set AllowShortBlocksOnASingleLine to Always and short function
cannot be put on a single line, clang-format doesn't tries to put
the function body on a seperate new single line. Add
tryMergeSimpleBlocks() to put short function body on a single line if
possible.

Signed-off-by: Lidong Yan <[email protected]>
@brandb97 brandb97 requested a review from owenca August 29, 2025 02:57
@owenca owenca changed the title [clang-format] allow short function body on a single line [clang-format] Allow short function body on a single line Aug 29, 2025
@owenca owenca removed the clang Clang issues not falling into any other category label Aug 30, 2025
@owenca owenca merged commit 81035c3 into llvm:main Aug 30, 2025
9 checks passed
@llvm llvm deleted a comment from llvm-ci Aug 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add clang-format option for formatting single statement function on one line with braces
4 participants