Skip to content

Commit 2c26e66

Browse files
committed
[clang-format] Add option to omit wrapping for empty records
Currently, clang-format does not allow empty records to be formatted on a single line if the corresponding `BraceWrapping.After*` option is set to true. This results in unnecessarily wrapped code: struct foo { int i; }; struct bar { }; This patch adds the `BraceWrapping.WrapEmptyRecord` option, which allows `class`, `struct`, and `union` declarations with empty bodies to be formatted as one-liners, even when `AfterRecord: true`. As such, the following becomes possible: struct foo { int i; }; struct bar {};
1 parent 4431331 commit 2c26e66

File tree

5 files changed

+88
-12
lines changed

5 files changed

+88
-12
lines changed

clang/include/clang/Format/Format.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,6 +1355,32 @@ struct FormatStyle {
13551355
BWACS_Always
13561356
};
13571357

1358+
enum BraceWrapEmptyRecordStyle : int8_t {
1359+
/// Use default wrapping rules for records
1360+
/// (AfterClass,AfterStruct,AfterUnion)
1361+
/// \code
1362+
/// class foo
1363+
/// {
1364+
/// int foo;
1365+
/// };
1366+
///
1367+
/// class foo
1368+
/// {
1369+
/// };
1370+
/// \endcode
1371+
BWER_Default,
1372+
/// Override wrapping for empty records
1373+
/// \code
1374+
/// class foo
1375+
/// {
1376+
/// int foo;
1377+
/// };
1378+
///
1379+
/// class foo {};
1380+
/// \endcode
1381+
BWER_Never
1382+
};
1383+
13581384
/// Precise control over the wrapping of braces.
13591385
/// \code
13601386
/// # Should be declared this way:
@@ -1585,6 +1611,8 @@ struct FormatStyle {
15851611
/// \endcode
15861612
///
15871613
bool SplitEmptyNamespace;
1614+
/// Wrap empty record (``class``/``struct``/``union``).
1615+
BraceWrapEmptyRecordStyle WrapEmptyRecord;
15881616
};
15891617

15901618
/// Control of individual brace wrapping cases.

clang/lib/Format/Format.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
200200
IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
201201
IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord);
202202
IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
203+
IO.mapOptional("WrapEmptyRecord", Wrapping.WrapEmptyRecord);
203204
}
204205
};
205206

@@ -232,6 +233,15 @@ struct ScalarEnumerationTraits<
232233
}
233234
};
234235

236+
template <>
237+
struct ScalarEnumerationTraits<FormatStyle::BraceWrapEmptyRecordStyle> {
238+
static void enumeration(IO &IO,
239+
FormatStyle::BraceWrapEmptyRecordStyle &Value) {
240+
IO.enumCase(Value, "Default", FormatStyle::BWER_Default);
241+
IO.enumCase(Value, "Never", FormatStyle::BWER_Never);
242+
}
243+
};
244+
235245
template <>
236246
struct ScalarEnumerationTraits<
237247
FormatStyle::BreakBeforeConceptDeclarationsStyle> {
@@ -1392,7 +1402,8 @@ static void expandPresetsBraceWrapping(FormatStyle &Expanded) {
13921402
/*IndentBraces=*/false,
13931403
/*SplitEmptyFunction=*/true,
13941404
/*SplitEmptyRecord=*/true,
1395-
/*SplitEmptyNamespace=*/true};
1405+
/*SplitEmptyNamespace=*/true,
1406+
/*WrapEmptyRecord=*/FormatStyle::BWER_Default};
13961407
switch (Expanded.BreakBeforeBraces) {
13971408
case FormatStyle::BS_Linux:
13981409
Expanded.BraceWrapping.AfterClass = true;

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5935,10 +5935,11 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
59355935

59365936
// Don't attempt to interpret struct return types as structs.
59375937
if (Right.isNot(TT_FunctionLBrace)) {
5938-
return (Line.startsWith(tok::kw_class) &&
5939-
Style.BraceWrapping.AfterClass) ||
5940-
(Line.startsWith(tok::kw_struct) &&
5941-
Style.BraceWrapping.AfterStruct);
5938+
return ((Line.startsWith(tok::kw_class) &&
5939+
Style.BraceWrapping.AfterClass) ||
5940+
(Line.startsWith(tok::kw_struct) &&
5941+
Style.BraceWrapping.AfterStruct)) &&
5942+
Style.BraceWrapping.WrapEmptyRecord == FormatStyle::BWER_Default;
59425943
}
59435944
}
59445945

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -952,20 +952,26 @@ static bool isIIFE(const UnwrappedLine &Line,
952952
}
953953

954954
static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
955-
const FormatToken &InitialToken) {
955+
const FormatToken &InitialToken,
956+
const FormatToken &NextToken) {
956957
tok::TokenKind Kind = InitialToken.Tok.getKind();
957958
if (InitialToken.is(TT_NamespaceMacro))
958959
Kind = tok::kw_namespace;
959960

961+
bool IsEmptyBlock = NextToken.is(tok::r_brace);
962+
bool WrapRecordAllowed =
963+
!(IsEmptyBlock &&
964+
Style.BraceWrapping.WrapEmptyRecord == FormatStyle::BWER_Never);
965+
960966
switch (Kind) {
961967
case tok::kw_namespace:
962968
return Style.BraceWrapping.AfterNamespace;
963969
case tok::kw_class:
964-
return Style.BraceWrapping.AfterClass;
970+
return Style.BraceWrapping.AfterClass && WrapRecordAllowed;
965971
case tok::kw_union:
966-
return Style.BraceWrapping.AfterUnion;
972+
return Style.BraceWrapping.AfterUnion && WrapRecordAllowed;
967973
case tok::kw_struct:
968-
return Style.BraceWrapping.AfterStruct;
974+
return Style.BraceWrapping.AfterStruct && WrapRecordAllowed;
969975
case tok::kw_enum:
970976
return Style.BraceWrapping.AfterEnum;
971977
default:
@@ -3191,7 +3197,7 @@ void UnwrappedLineParser::parseNamespace() {
31913197
if (FormatTok->is(tok::l_brace)) {
31923198
FormatTok->setFinalizedType(TT_NamespaceLBrace);
31933199

3194-
if (ShouldBreakBeforeBrace(Style, InitialToken))
3200+
if (ShouldBreakBeforeBrace(Style, InitialToken, *Tokens->peekNextToken()))
31953201
addUnwrappedLine();
31963202

31973203
unsigned AddLevels =
@@ -3856,7 +3862,7 @@ bool UnwrappedLineParser::parseEnum() {
38563862
}
38573863

38583864
if (!Style.AllowShortEnumsOnASingleLine &&
3859-
ShouldBreakBeforeBrace(Style, InitialToken)) {
3865+
ShouldBreakBeforeBrace(Style, InitialToken, *Tokens->peekNextToken())) {
38603866
addUnwrappedLine();
38613867
}
38623868
// Parse enum body.
@@ -4151,7 +4157,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr, bool IsJavaRecord) {
41514157
if (ParseAsExpr) {
41524158
parseChildBlock();
41534159
} else {
4154-
if (ShouldBreakBeforeBrace(Style, InitialToken))
4160+
if (ShouldBreakBeforeBrace(Style, InitialToken, *Tokens->peekNextToken()))
41554161
addUnwrappedLine();
41564162

41574163
unsigned AddLevels = Style.IndentAccessModifiers ? 2u : 1u;

clang/unittests/Format/FormatTest.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15615,6 +15615,36 @@ TEST_F(FormatTest, NeverMergeShortRecords) {
1561515615
Style);
1561615616
}
1561715617

15618+
TEST_F(FormatTest, WrapEmptyRecords) {
15619+
FormatStyle Style = getLLVMStyle();
15620+
15621+
Style.BreakBeforeBraces = FormatStyle::BS_Custom;
15622+
Style.BraceWrapping.AfterStruct = true;
15623+
Style.BraceWrapping.AfterClass = true;
15624+
Style.BraceWrapping.AfterUnion = true;
15625+
Style.BraceWrapping.SplitEmptyRecord = false;
15626+
15627+
verifyFormat("class foo\n{\n void bar();\n};", Style);
15628+
verifyFormat("class foo\n{};", Style);
15629+
15630+
verifyFormat("struct foo\n{\n int bar;\n};", Style);
15631+
verifyFormat("struct foo\n{};", Style);
15632+
15633+
verifyFormat("union foo\n{\n int bar;\n};", Style);
15634+
verifyFormat("union foo\n{};", Style);
15635+
15636+
Style.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_Never;
15637+
15638+
verifyFormat("class foo\n{\n void bar();\n};", Style);
15639+
verifyFormat("class foo {};", Style);
15640+
15641+
verifyFormat("struct foo\n{\n int bar;\n};", Style);
15642+
verifyFormat("struct foo {};", Style);
15643+
15644+
verifyFormat("union foo\n{\n int bar;\n};", Style);
15645+
verifyFormat("union foo {};", Style);
15646+
}
15647+
1561815648
TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
1561915649
// Elaborate type variable declarations.
1562015650
verifyFormat("struct foo a = {bar};\nint n;");

0 commit comments

Comments
 (0)