Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2579,6 +2579,36 @@ the configuration (without a prefix: ``Auto``).
{} {
}

* ``BraceWrapEmptyRecordStyle WrapEmptyRecord``
Wrap empty record (``class``/``struct``/``union``).

Possible values:

* ``BWËR_Never`` (in configuration: ``Never``)
Never wrap braces of empty records.

.. code-block:: c++

class foo
{
int foo;
};

class foo{};

* ``BWER_Default`` (in configuration: ``MultiLine``)
Use default wrapping rules for records. (``AfterClass``, ``AfterStruct``, ``AfterUnion``)

.. code-block:: c++

class foo
{
int foo;
};

class foo
{
};

.. _BracedInitializerIndentWidth:

Expand Down
28 changes: 28 additions & 0 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -1355,6 +1355,32 @@ struct FormatStyle {
BWACS_Always
};

enum BraceWrapEmptyRecordStyle : int8_t {
/// Use default wrapping rules for records
/// (AfterClass,AfterStruct,AfterUnion)
/// \code
/// class foo
/// {
/// int foo;
/// };
///
/// class foo
/// {
/// };
/// \endcode
BWER_Default,
/// Override wrapping for empty records
/// \code
/// class foo
/// {
/// int foo;
/// };
///
/// class foo {};
/// \endcode
BWER_Never
};

/// Precise control over the wrapping of braces.
/// \code
/// # Should be declared this way:
Expand Down Expand Up @@ -1585,6 +1611,8 @@ struct FormatStyle {
/// \endcode
///
bool SplitEmptyNamespace;
/// Wrap empty record (``class``/``struct``/``union``).
BraceWrapEmptyRecordStyle WrapEmptyRecord;
};

/// Control of individual brace wrapping cases.
Expand Down
13 changes: 12 additions & 1 deletion clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord);
IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
IO.mapOptional("WrapEmptyRecord", Wrapping.WrapEmptyRecord);
}
};

Expand Down Expand Up @@ -232,6 +233,15 @@ struct ScalarEnumerationTraits<
}
};

template <>
struct ScalarEnumerationTraits<FormatStyle::BraceWrapEmptyRecordStyle> {
static void enumeration(IO &IO,
FormatStyle::BraceWrapEmptyRecordStyle &Value) {
IO.enumCase(Value, "Default", FormatStyle::BWER_Default);
IO.enumCase(Value, "Never", FormatStyle::BWER_Never);
}
};

template <>
struct ScalarEnumerationTraits<
FormatStyle::BreakBeforeConceptDeclarationsStyle> {
Expand Down Expand Up @@ -1392,7 +1402,8 @@ static void expandPresetsBraceWrapping(FormatStyle &Expanded) {
/*IndentBraces=*/false,
/*SplitEmptyFunction=*/true,
/*SplitEmptyRecord=*/true,
/*SplitEmptyNamespace=*/true};
/*SplitEmptyNamespace=*/true,
/*WrapEmptyRecord=*/FormatStyle::BWER_Default};
switch (Expanded.BreakBeforeBraces) {
case FormatStyle::BS_Linux:
Expanded.BraceWrapping.AfterClass = true;
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5935,10 +5935,11 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,

// Don't attempt to interpret struct return types as structs.
if (Right.isNot(TT_FunctionLBrace)) {
return (Line.startsWith(tok::kw_class) &&
Style.BraceWrapping.AfterClass) ||
(Line.startsWith(tok::kw_struct) &&
Style.BraceWrapping.AfterStruct);
return ((Line.startsWith(tok::kw_class) &&
Style.BraceWrapping.AfterClass) ||
(Line.startsWith(tok::kw_struct) &&
Style.BraceWrapping.AfterStruct)) &&
Style.BraceWrapping.WrapEmptyRecord == FormatStyle::BWER_Default;
}
}

Expand Down
20 changes: 13 additions & 7 deletions clang/lib/Format/UnwrappedLineParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -952,20 +952,26 @@ static bool isIIFE(const UnwrappedLine &Line,
}

static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
const FormatToken &InitialToken) {
const FormatToken &InitialToken,
const FormatToken &NextToken) {
tok::TokenKind Kind = InitialToken.Tok.getKind();
if (InitialToken.is(TT_NamespaceMacro))
Kind = tok::kw_namespace;

bool IsEmptyBlock = NextToken.is(tok::r_brace);
bool WrapRecordAllowed =
!(IsEmptyBlock &&
Style.BraceWrapping.WrapEmptyRecord == FormatStyle::BWER_Never);

switch (Kind) {
case tok::kw_namespace:
return Style.BraceWrapping.AfterNamespace;
case tok::kw_class:
return Style.BraceWrapping.AfterClass;
return Style.BraceWrapping.AfterClass && WrapRecordAllowed;
case tok::kw_union:
return Style.BraceWrapping.AfterUnion;
return Style.BraceWrapping.AfterUnion && WrapRecordAllowed;
case tok::kw_struct:
return Style.BraceWrapping.AfterStruct;
return Style.BraceWrapping.AfterStruct && WrapRecordAllowed;
case tok::kw_enum:
return Style.BraceWrapping.AfterEnum;
default:
Expand Down Expand Up @@ -3191,7 +3197,7 @@ void UnwrappedLineParser::parseNamespace() {
if (FormatTok->is(tok::l_brace)) {
FormatTok->setFinalizedType(TT_NamespaceLBrace);

if (ShouldBreakBeforeBrace(Style, InitialToken))
if (ShouldBreakBeforeBrace(Style, InitialToken, *Tokens->peekNextToken()))
addUnwrappedLine();

unsigned AddLevels =
Expand Down Expand Up @@ -3856,7 +3862,7 @@ bool UnwrappedLineParser::parseEnum() {
}

if (!Style.AllowShortEnumsOnASingleLine &&
ShouldBreakBeforeBrace(Style, InitialToken)) {
ShouldBreakBeforeBrace(Style, InitialToken, *Tokens->peekNextToken())) {
addUnwrappedLine();
}
// Parse enum body.
Expand Down Expand Up @@ -4151,7 +4157,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr, bool IsJavaRecord) {
if (ParseAsExpr) {
parseChildBlock();
} else {
if (ShouldBreakBeforeBrace(Style, InitialToken))
if (ShouldBreakBeforeBrace(Style, InitialToken, *Tokens->peekNextToken()))
addUnwrappedLine();

unsigned AddLevels = Style.IndentAccessModifiers ? 2u : 1u;
Expand Down
30 changes: 30 additions & 0 deletions clang/unittests/Format/FormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15615,6 +15615,36 @@ TEST_F(FormatTest, NeverMergeShortRecords) {
Style);
}

TEST_F(FormatTest, WrapEmptyRecords) {
FormatStyle Style = getLLVMStyle();

Style.BreakBeforeBraces = FormatStyle::BS_Custom;
Style.BraceWrapping.AfterStruct = true;
Style.BraceWrapping.AfterClass = true;
Style.BraceWrapping.AfterUnion = true;
Style.BraceWrapping.SplitEmptyRecord = false;

verifyFormat("class foo\n{\n void bar();\n};", Style);
verifyFormat("class foo\n{};", Style);

verifyFormat("struct foo\n{\n int bar;\n};", Style);
verifyFormat("struct foo\n{};", Style);

verifyFormat("union foo\n{\n int bar;\n};", Style);
verifyFormat("union foo\n{};", Style);

Style.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_Never;

verifyFormat("class foo\n{\n void bar();\n};", Style);
verifyFormat("class foo {};", Style);

verifyFormat("struct foo\n{\n int bar;\n};", Style);
verifyFormat("struct foo {};", Style);

verifyFormat("union foo\n{\n int bar;\n};", Style);
verifyFormat("union foo {};", Style);
}

TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
// Elaborate type variable declarations.
verifyFormat("struct foo a = {bar};\nint n;");
Expand Down
Loading