Author: ahmed mohamed kamel Date: 2026-08-25T19:02:47Z New Revision: f1363c60faea7c903683339c8c4f0d824f7cd9d7
URL: https://github.com/llvm/llvm-project/commit/f1363c60faea7c903683339c8c4f0d824f7cd9d7 DIFF: https://github.com/llvm/llvm-project/commit/f1363c60faea7c903683339c8c4f0d824f7cd9d7.diff LOG: [clang-format] Add BraceWrapping.AfterExportBlock option (#216892) ### Summary Adds the `BraceWrapping.AfterExportBlock` option to `clang-format`. This allows users configuring `BreakBeforeBraces: Custom` to specify whether the opening brace of a C++20 `export` block should be wrapped onto a new line. Fixes #216785 ### Examples ```c++ // BraceWrapping.AfterExportBlock = true export { int foo(); } // BraceWrapping.AfterExportBlock = false export { int foo(); } Added: Modified: clang/docs/ClangFormatStyleOptions.md clang/include/clang/Format/Format.h clang/lib/Format/Format.cpp clang/lib/Format/FormatToken.h clang/lib/Format/TokenAnnotator.h clang/lib/Format/UnwrappedLineFormatter.cpp clang/lib/Format/UnwrappedLineParser.cpp clang/unittests/Format/ConfigParseTest.cpp clang/unittests/Format/FormatTest.cpp clang/unittests/Format/TokenAnnotatorTest.cpp Removed: ################################################################################ diff --git a/clang/docs/ClangFormatStyleOptions.md b/clang/docs/ClangFormatStyleOptions.md index 5ee06983036c9..ee239f768cf2b 100644 --- a/clang/docs/ClangFormatStyleOptions.md +++ b/clang/docs/ClangFormatStyleOptions.md @@ -2582,6 +2582,16 @@ the configuration (without a prefix: `Auto`). } ``` + - `bool AfterExportBlock` Wrap export blocks. + + ```c++ + true: false: + export vs. export { + { int foo(); + int foo(); } + } + ``` + - `bool AfterExternBlock` Wrap extern blocks. ```c++ diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 554ebdab09442..0f91df5b1b32d 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -1535,6 +1535,15 @@ struct FormatStyle { /// } /// \endcode bool AfterUnion; + /// Wrap export blocks. + /// \code + /// true: false: + /// export vs. export { + /// { int foo(); + /// int foo(); } + /// } + /// \endcode + bool AfterExportBlock; /// Wrap extern blocks. /// \code /// true: diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index fa308086da5b5..e5533c32899a3 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -221,6 +221,7 @@ template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> { IO.mapOptional("AfterClass", Wrapping.AfterClass); IO.mapOptional("AfterControlStatement", Wrapping.AfterControlStatement); IO.mapOptional("AfterEnum", Wrapping.AfterEnum); + IO.mapOptional("AfterExportBlock", Wrapping.AfterExportBlock); IO.mapOptional("AfterExternBlock", Wrapping.AfterExternBlock); IO.mapOptional("AfterFunction", Wrapping.AfterFunction); IO.mapOptional("AfterNamespace", Wrapping.AfterNamespace); @@ -1726,6 +1727,7 @@ static void expandPresetsBraceWrapping(FormatStyle &Expanded) { /*AfterObjCDeclaration=*/false, /*AfterStruct=*/false, /*AfterUnion=*/false, + /*AfterExportBlock=*/false, /*AfterExternBlock=*/false, /*BeforeCatch=*/false, /*BeforeElse=*/false, @@ -1747,6 +1749,7 @@ static void expandPresetsBraceWrapping(FormatStyle &Expanded) { Expanded.BraceWrapping.AfterFunction = true; Expanded.BraceWrapping.AfterStruct = true; Expanded.BraceWrapping.AfterUnion = true; + Expanded.BraceWrapping.AfterExportBlock = true; Expanded.BraceWrapping.AfterExternBlock = true; Expanded.BraceWrapping.SplitEmptyFunction = true; Expanded.BraceWrapping.SplitEmptyRecord = false; @@ -1766,6 +1769,7 @@ static void expandPresetsBraceWrapping(FormatStyle &Expanded) { Expanded.BraceWrapping.AfterObjCDeclaration = true; Expanded.BraceWrapping.AfterStruct = true; Expanded.BraceWrapping.AfterUnion = true; + Expanded.BraceWrapping.AfterExportBlock = true; Expanded.BraceWrapping.AfterExternBlock = true; Expanded.BraceWrapping.BeforeCatch = true; Expanded.BraceWrapping.BeforeElse = true; @@ -1796,6 +1800,7 @@ static void expandPresetsBraceWrapping(FormatStyle &Expanded) { /*AfterObjCDeclaration=*/true, /*AfterStruct=*/true, /*AfterUnion=*/true, + /*AfterExportBlock=*/true, /*AfterExternBlock=*/true, /*BeforeCatch=*/true, /*BeforeElse=*/true, @@ -1898,6 +1903,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { /*AfterObjCDeclaration=*/false, /*AfterStruct=*/false, /*AfterUnion=*/false, + /*AfterExportBlock=*/false, /*AfterExternBlock=*/false, /*BeforeCatch=*/false, /*BeforeElse=*/false, diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 4a2982eaa3a17..691ecdd24f448 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -80,6 +80,7 @@ namespace format { TYPE(EnumLBrace) \ TYPE(EnumRBrace) \ TYPE(EnumUnderlyingTypeColon) \ + TYPE(ExportLBrace) \ TYPE(FatArrow) \ TYPE(ForEachMacro) \ TYPE(FunctionAnnotationRParen) \ diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h index 264f39b7b1d60..c909c39e92ea3 100644 --- a/clang/lib/Format/TokenAnnotator.h +++ b/clang/lib/Format/TokenAnnotator.h @@ -157,11 +157,6 @@ class AnnotatedLine { startsWith(tok::kw_export, tok::kw_namespace); } - /// \c true if this line starts a C++ export block. - bool startsWithExportBlock() const { - return startsWith(tok::kw_export, tok::l_brace); - } - FormatToken *getFirstNonComment() const { assert(First); return First->is(tok::comment) ? First->getNextNonComment() : First; diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index b783876b6da8f..33e6807dfe7dd 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -444,7 +444,8 @@ class LineJoiner { if (TheLine->Last->is(tok::l_brace) && FirstNonComment != TheLine->Last && (FirstNonComment->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for, TT_ForEachMacro) || - TheLine->startsWithExportBlock())) { + (TheLine->Last->is(TT_ExportLBrace) && + !Style.BraceWrapping.AfterExportBlock))) { return Style.AllowShortBlocksOnASingleLine != FormatStyle::SBS_Never ? tryMergeSimpleBlock(I, E, Limit) : 0; @@ -892,7 +893,7 @@ class LineJoiner { Line.First->isOneOf(tok::kw_try, tok::kw___try, tok::kw_catch, tok::kw___finally, tok::r_brace, Keywords.kw___except) || - Line.startsWithExportBlock()) { + Line.Last->is(TT_ExportLBrace)) { if (IsSplitBlock) return 0; // Don't merge when we can't except the case when @@ -937,6 +938,11 @@ class LineJoiner { } if (Line.endsWith(tok::l_brace)) { + if (Style.BraceWrapping.AfterExportBlock && + Line.First->is(TT_ExportLBrace)) { + return 0; + } + if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never && Line.First->is(TT_BlockLBrace)) { return 0; diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index da6465548bb3e..621804b060fad 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -3311,6 +3311,11 @@ void UnwrappedLineParser::parseNamespace() { } void UnwrappedLineParser::parseCppExportBlock() { + if (FormatTok->is(tok::l_brace)) { + FormatTok->setFinalizedType(TT_ExportLBrace); + if (Style.BraceWrapping.AfterExportBlock) + addUnwrappedLine(); + } parseNamespaceOrExportBlock(/*AddLevels=*/Style.IndentExportBlock ? 1 : 0); } diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index 9350ba7eb3de4..53fbec9806ca4 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -238,6 +238,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) { CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterCaseLabel); CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterClass); CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterEnum); + CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterExportBlock); CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterFunction); CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterNamespace); CHECK_PARSE_NESTED_BOOL(BraceWrapping, AfterObjCDeclaration); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 99561f12c51c8..ca9312ae40f1d 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -4931,6 +4931,26 @@ TEST_F(FormatTest, IndentExternBlockStyle) { Style); } +TEST_F(FormatTest, BraceWrappingAfterExportBlock) { + FormatStyle Style = getLLVMStyle(); + Style.BreakBeforeBraces = FormatStyle::BS_Custom; + Style.BraceWrapping.AfterExportBlock = true; + verifyFormat("export\n" + "{\n" + " int foo();\n" + "}", + "export {\n" + " int foo();\n" + "}", + Style); + + Style.BraceWrapping.AfterExportBlock = false; + verifyFormat("export {\n" + " int foo();\n" + "}", + Style); +} + TEST_F(FormatTest, FormatsInlineASM) { verifyFormat("asm(\"xyz\" : \"=a\"(a), \"=d\"(b) : \"a\"(data));"); verifyFormat("asm(\"nop\" ::: \"memory\");"); diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index ae9e0b6b8e74c..b71147aaf1bc2 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -694,6 +694,14 @@ TEST_F(TokenAnnotatorTest, UnderstandsEnums) { EXPECT_TOKEN(Tokens[3], tok::r_brace, TT_EnumRBrace); } +TEST_F(TokenAnnotatorTest, UnderstandsExportBlock) { + auto Tokens = annotate("export {\n" + "int foo();\n" + "}"); + ASSERT_EQ(Tokens.size(), 9u) << Tokens; + EXPECT_TOKEN(Tokens[1], tok::l_brace, TT_ExportLBrace); +} + TEST_F(TokenAnnotatorTest, UnderstandsDefaultedAndDeletedFunctions) { auto Tokens = annotate("auto operator<=>(const T &) const & = default;"); ASSERT_EQ(Tokens.size(), 14u) << Tokens; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
