https://github.com/rudolflovrencic updated https://github.com/llvm/llvm-project/pull/196021
From ff25f62c2082373fac7229a41718f4cd8aadae42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rudolf=20Lovren=C4=8Di=C4=87?= <[email protected]> Date: Wed, 6 May 2026 10:00:04 +0200 Subject: [PATCH 1/2] [clang-format] Disable short blocks if brace is on the new line If the opening brace of control statement blocks, record block, and function blocks is not on the same line, the block can never be short (the closing brace is always placed into a separate line). The format options AllowShortIfStatementsOnASingleLine and AllowShortLoopsOnASingleLine now correctly control only the braceless variants of these statements. Fixes #183705 and #187993 --- clang/lib/Format/UnwrappedLineFormatter.cpp | 32 ++++++------ clang/unittests/Format/FormatTest.cpp | 54 ++++++++++----------- 2 files changed, 42 insertions(+), 44 deletions(-) diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index 42eabc065b1a8..f02ae5b5fecb8 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -264,13 +264,10 @@ class LineJoiner { : Limit - TheLine->Last->TotalLength; if (TheLine->Last->is(TT_FunctionLBrace) && - TheLine->First == TheLine->Last) { - const bool EmptyFunctionBody = NextLine.First->is(tok::r_brace); - if ((EmptyFunctionBody && !Style.BraceWrapping.SplitEmptyFunction) || - (!EmptyFunctionBody && - Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Always)) { - return tryMergeSimpleBlock(I, E, Limit); - } + TheLine->First == TheLine->Last && + !Style.BraceWrapping.SplitEmptyFunction && + NextLine.First->is(tok::r_brace)) { + return tryMergeSimpleBlock(I, E, Limit); } // Try merging record blocks that have had their left brace wrapped into @@ -647,11 +644,8 @@ class LineJoiner { const bool IsEmptyBlock = Line->Last->is(tok::l_brace) && NextLine->First->is(tok::r_brace); - if ((IsEmptyBlock && !Style.BraceWrapping.SplitEmptyRecord) || - (!IsEmptyBlock && - Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Always)) { + if (IsEmptyBlock && !Style.BraceWrapping.SplitEmptyRecord) return tryMergeSimpleBlock(I, E, Limit); - } } return 0; @@ -895,9 +889,12 @@ class LineJoiner { Line.startsWithExportBlock()) { if (IsSplitBlock) return 0; + const bool BracedBlocksAlwaysOnSingleLine = + Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Always; // Don't merge when we can't except the case when // the control statement block is empty - if (!Style.AllowShortIfStatementsOnASingleLine && + if (!BracedBlocksAlwaysOnSingleLine && + !Style.AllowShortIfStatementsOnASingleLine && Line.First->isOneOf(tok::kw_if, tok::kw_else) && !Style.BraceWrapping.AfterControlStatement && I[1]->First->isNot(tok::r_brace)) { @@ -910,7 +907,8 @@ class LineJoiner { I + 2 != E && I[2]->First->isNot(tok::r_brace)) { return 0; } - if (!Style.AllowShortLoopsOnASingleLine && + if (!BracedBlocksAlwaysOnSingleLine && + !Style.AllowShortLoopsOnASingleLine && Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for, TT_ForEachMacro) && !Style.BraceWrapping.AfterControlStatement && @@ -988,9 +986,11 @@ class LineJoiner { if (I[1]->Last->is(TT_LineComment)) return 0; do { - if (Tok->isOneOf(tok::l_brace, tok::r_brace) && - Tok->isNot(BK_BracedInit)) { - return 0; + if (Tok->isOneOf(tok::l_brace, tok::r_brace)) { + const FormatToken *Open = + Tok->is(tok::l_brace) ? Tok : Tok->MatchingParen; + if (!Open || Open->isNot(BK_BracedInit)) + return 0; } Tok = Tok->Next; } while (Tok); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 1f243fe967fd1..6327aad7c7b08 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -1607,10 +1607,7 @@ TEST_F(FormatTest, FormatShortBracedStatements) { AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; verifyFormat("if (true) {}", AllowSimpleBracedStatements); - verifyFormat("if (true) {\n" - " f();\n" - "}", - AllowSimpleBracedStatements); + verifyFormat("if (true) { f(); }", AllowSimpleBracedStatements); verifyFormat("if (true) {\n" " f();\n" "} else {\n" @@ -1618,10 +1615,7 @@ TEST_F(FormatTest, FormatShortBracedStatements) { "}", AllowSimpleBracedStatements); verifyFormat("MYIF (true) {}", AllowSimpleBracedStatements); - verifyFormat("MYIF (true) {\n" - " f();\n" - "}", - AllowSimpleBracedStatements); + verifyFormat("MYIF (true) { f(); }", AllowSimpleBracedStatements); verifyFormat("MYIF (true) {\n" " f();\n" "} else {\n" @@ -1631,19 +1625,11 @@ TEST_F(FormatTest, FormatShortBracedStatements) { AllowSimpleBracedStatements.AllowShortLoopsOnASingleLine = false; verifyFormat("while (true) {}", AllowSimpleBracedStatements); - verifyFormat("while (true) {\n" - " f();\n" - "}", - AllowSimpleBracedStatements); + verifyFormat("while (true) { f(); }", AllowSimpleBracedStatements); verifyFormat("for (;;) {}", AllowSimpleBracedStatements); - verifyFormat("for (;;) {\n" - " f();\n" - "}", - AllowSimpleBracedStatements); + verifyFormat("for (;;) { f(); }", AllowSimpleBracedStatements); verifyFormat("BOOST_FOREACH (int v, vec) {}", AllowSimpleBracedStatements); - verifyFormat("BOOST_FOREACH (int v, vec) {\n" - " f();\n" - "}", + verifyFormat("BOOST_FOREACH (int v, vec) { f(); }", AllowSimpleBracedStatements); AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine = @@ -2432,12 +2418,8 @@ TEST_F(FormatTest, ForEachLoops) { " int j = 1;\n" " Q_FOREACH (int &v, vec)\n" " v *= 2;\n" - " for (;;) {\n" - " int j = 1;\n" - " }\n" - " Q_FOREACH (int &v, vec) {\n" - " int j = 1;\n" - " }\n" + " for (;;) { int j = 1; }\n" + " Q_FOREACH (int &v, vec) { int j = 1; }\n" "}", ShortBlocks); @@ -15564,7 +15546,19 @@ TEST_F(FormatTest, MergeShortFunctionBody) { Style.BraceWrapping.AfterFunction = true; verifyFormat("int foo()\n" - "{ return 1; }", + "{\n" + " return 1;\n" + "}\n", + Style); + verifyFormat("int foo()\n" + "{\n" + " if (true) { return 42; };\n" + "}\n", + Style); + verifyFormat("int foo()\n" + "{\n" + " static constexpr auto lambda = []() -> int { return 42; };\n" + "}\n", Style); } @@ -15913,11 +15907,15 @@ TEST_F(FormatTest, AllowShortRecordOnASingleLine) { Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Never; verifyFormat("class foo\n" - "{ int i; };", + "{\n" + " int i;\n" + "};", Style); Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Empty; verifyFormat("class foo\n" - "{ int i; };", + "{\n" + " int i;\n" + "};", Style); Style.AllowShortRecordOnASingleLine = FormatStyle::SRS_Always; verifyFormat("class foo\n" From a967e19f409906004c8b8dbc8609b0c066c4543d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rudolf=20Lovren=C4=8Di=C4=87?= <[email protected]> Date: Tue, 12 May 2026 21:30:20 +0200 Subject: [PATCH 2/2] [clang-format] Disable short blocks if brace is on the new line If the opening brace of control statement blocks, record block, and function blocks is not on the same line, the block can never be short (the closing brace is always placed into a separate line). Fixes #183705 and #187993 --- clang/docs/ClangFormatStyleOptions.rst | 5 ++++ clang/include/clang/Format/Format.h | 5 ++++ clang/lib/Format/UnwrappedLineFormatter.cpp | 13 ++++---- clang/unittests/Format/FormatTest.cpp | 33 ++++++++++++++++----- 4 files changed, 43 insertions(+), 13 deletions(-) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 7b1b7a7384b07..497c452aca41a 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -1827,6 +1827,11 @@ the configuration (without a prefix: ``Auto``). Dependent on the value, ``while (true) { continue; }`` can be put on a single line. + The construct-specific options ``AllowShortIfStatementsOnASingleLine`` and + ``AllowShortLoopsOnASingleLine`` take precedence over this option: an + ``if`` statement or a loop whose corresponding option disallows putting it + on a single line is not merged even when this option is ``Always``. + Possible values: * ``SBS_Never`` (in configuration: ``Never``) diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 27b2d8f4a405b..ebcc416ba3af7 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -767,6 +767,11 @@ struct FormatStyle { /// Dependent on the value, ``while (true) { continue; }`` can be put on a /// single line. + /// + /// The construct-specific options ``AllowShortIfStatementsOnASingleLine`` and + /// ``AllowShortLoopsOnASingleLine`` take precedence over this option: an + /// ``if`` statement or a loop whose corresponding option disallows putting it + /// on a single line is not merged even when this option is ``Always``. /// \version 3.5 ShortBlockStyle AllowShortBlocksOnASingleLine; diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index f02ae5b5fecb8..7847a8dcb40f7 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -889,12 +889,14 @@ class LineJoiner { Line.startsWithExportBlock()) { if (IsSplitBlock) return 0; - const bool BracedBlocksAlwaysOnSingleLine = - Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Always; + // The construct-specific options AllowShortIfStatementsOnASingleLine and + // AllowShortLoopsOnASingleLine take precedence over + // AllowShortBlocksOnASingleLine: a statement whose specific option + // disallows merging is not put on a single line even when short blocks + // are always allowed. // Don't merge when we can't except the case when // the control statement block is empty - if (!BracedBlocksAlwaysOnSingleLine && - !Style.AllowShortIfStatementsOnASingleLine && + if (!Style.AllowShortIfStatementsOnASingleLine && Line.First->isOneOf(tok::kw_if, tok::kw_else) && !Style.BraceWrapping.AfterControlStatement && I[1]->First->isNot(tok::r_brace)) { @@ -907,8 +909,7 @@ class LineJoiner { I + 2 != E && I[2]->First->isNot(tok::r_brace)) { return 0; } - if (!BracedBlocksAlwaysOnSingleLine && - !Style.AllowShortLoopsOnASingleLine && + if (!Style.AllowShortLoopsOnASingleLine && Line.First->isOneOf(tok::kw_while, tok::kw_do, tok::kw_for, TT_ForEachMacro) && !Style.BraceWrapping.AfterControlStatement && diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 6327aad7c7b08..21db0b867b300 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -1607,7 +1607,10 @@ TEST_F(FormatTest, FormatShortBracedStatements) { AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_Never; verifyFormat("if (true) {}", AllowSimpleBracedStatements); - verifyFormat("if (true) { f(); }", AllowSimpleBracedStatements); + verifyFormat("if (true) {\n" + " f();\n" + "}", + AllowSimpleBracedStatements); verifyFormat("if (true) {\n" " f();\n" "} else {\n" @@ -1615,7 +1618,10 @@ TEST_F(FormatTest, FormatShortBracedStatements) { "}", AllowSimpleBracedStatements); verifyFormat("MYIF (true) {}", AllowSimpleBracedStatements); - verifyFormat("MYIF (true) { f(); }", AllowSimpleBracedStatements); + verifyFormat("MYIF (true) {\n" + " f();\n" + "}", + AllowSimpleBracedStatements); verifyFormat("MYIF (true) {\n" " f();\n" "} else {\n" @@ -1625,11 +1631,19 @@ TEST_F(FormatTest, FormatShortBracedStatements) { AllowSimpleBracedStatements.AllowShortLoopsOnASingleLine = false; verifyFormat("while (true) {}", AllowSimpleBracedStatements); - verifyFormat("while (true) { f(); }", AllowSimpleBracedStatements); + verifyFormat("while (true) {\n" + " f();\n" + "}", + AllowSimpleBracedStatements); verifyFormat("for (;;) {}", AllowSimpleBracedStatements); - verifyFormat("for (;;) { f(); }", AllowSimpleBracedStatements); + verifyFormat("for (;;) {\n" + " f();\n" + "}", + AllowSimpleBracedStatements); verifyFormat("BOOST_FOREACH (int v, vec) {}", AllowSimpleBracedStatements); - verifyFormat("BOOST_FOREACH (int v, vec) { f(); }", + verifyFormat("BOOST_FOREACH (int v, vec) {\n" + " f();\n" + "}", AllowSimpleBracedStatements); AllowSimpleBracedStatements.AllowShortIfStatementsOnASingleLine = @@ -2418,8 +2432,12 @@ TEST_F(FormatTest, ForEachLoops) { " int j = 1;\n" " Q_FOREACH (int &v, vec)\n" " v *= 2;\n" - " for (;;) { int j = 1; }\n" - " Q_FOREACH (int &v, vec) { int j = 1; }\n" + " for (;;) {\n" + " int j = 1;\n" + " }\n" + " Q_FOREACH (int &v, vec) {\n" + " int j = 1;\n" + " }\n" "}", ShortBlocks); @@ -15542,6 +15560,7 @@ TEST_F(FormatTest, MergeShortFunctionBody) { auto Style = getLLVMStyle(); Style.AllowShortFunctionsOnASingleLine = FormatStyle::ShortFunctionStyle(); Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Always; + Style.AllowShortIfStatementsOnASingleLine = FormatStyle::SIS_WithoutElse; Style.BreakBeforeBraces = FormatStyle::BS_Custom; Style.BraceWrapping.AfterFunction = true; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
