Skip to content

Commit 72d57e0

Browse files
author
Galen Elias
committed
Re-work interaction with 'CompactNamespaces' option
- Disable recursive merging of nested namespaces onto a single line unless 'CompactNamespaces' is enabled. - Fix off-by-one error in CompactNamespaces code. For nested namespaces with 3 or more namespaces, it was incorrectly compacting lines which were 1 or two spaces over the ColumnLimit, leading to incorrect formatting results. - Add release notes mention. - Re-generate Style Options documentation
1 parent 0dcdacd commit 72d57e0

File tree

4 files changed

+60
-50
lines changed

4 files changed

+60
-50
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2091,8 +2091,7 @@ the configuration (without a prefix: ``Auto``).
20912091
.. _AllowShortNamespacesOnASingleLine:
20922092

20932093
**AllowShortNamespacesOnASingleLine** (``Boolean``) :versionbadge:`clang-format 20` :ref:`<AllowShortNamespacesOnASingleLine>`
2094-
If ``true``, ``namespace a { class b; }`` can be put on a single a single
2095-
line.
2094+
If ``true``, ``namespace a { class b; }`` can be put on a single line.
20962095

20972096
.. _AlwaysBreakAfterDefinitionReturnType:
20982097

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,8 @@ clang-format
11221122
- Adds ``RemoveEmptyLinesInUnwrappedLines`` option.
11231123
- Adds ``KeepFormFeed`` option and set it to ``true`` for ``GNU`` style.
11241124

1125+
- Adds ``AllowShortNamespacesOnASingleLine`` option.
1126+
11251127
libclang
11261128
--------
11271129
- Add ``clang_isBeforeInTranslationUnit``. Given two source locations, it determines

clang/lib/Format/UnwrappedLineFormatter.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ class LineJoiner {
383383
ClosingLineIndex == I[J]->MatchingClosingBlockLineIndex &&
384384
I[J]->Last->TotalLength < Limit;
385385
++J, --ClosingLineIndex) {
386-
Limit -= I[J]->Last->TotalLength;
386+
Limit -= I[J]->Last->TotalLength + 1;
387387

388388
// Reduce indent level for bodies of namespaces which were compacted,
389389
// but only if their content was indented in the first place.
@@ -647,9 +647,10 @@ class LineJoiner {
647647
// Check if it's a namespace inside a namespace, and call recursively if so.
648648
// '3' is the sizes of the whitespace and closing brace for " _inner_ }".
649649
if (I[1]->First->is(tok::kw_namespace)) {
650-
if (I[1]->Last->is(tok::comment))
650+
if (I[1]->Last->is(tok::comment) || !Style.CompactNamespaces)
651651
return 0;
652652

653+
assert(Limit >= I[1]->Last->TotalLength + 3);
653654
const unsigned InnerLimit = Limit - I[1]->Last->TotalLength - 3;
654655
const unsigned MergedLines = tryMergeNamespace(I + 1, E, InnerLimit);
655656
if (!MergedLines)
@@ -661,7 +662,7 @@ class LineJoiner {
661662
// Check that the line after the inner result starts with a closing brace
662663
// which we are permitted to merge into one line.
663664
if (I[N]->First->is(tok::r_brace) && !I[N]->First->MustBreakBefore &&
664-
!I[MergedLines + 1]->Last->is(tok::comment) &&
665+
I[MergedLines + 1]->Last->isNot(tok::comment) &&
665666
nextNLinesFitInto(I, I + N + 1, Limit)) {
666667
return N;
667668
}

clang/unittests/Format/FormatTest.cpp

Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4484,7 +4484,7 @@ TEST_F(FormatTest, FormatsCompactNamespaces) {
44844484
"} // namespace A",
44854485
Style);
44864486

4487-
Style.ColumnLimit = 40;
4487+
Style.ColumnLimit = 41;
44884488
verifyFormat("namespace aaaaaaaaaa {\n"
44894489
"namespace bbbbbbbbbb {\n"
44904490
"}} // namespace aaaaaaaaaa::bbbbbbbbbb",
@@ -4504,6 +4504,16 @@ TEST_F(FormatTest, FormatsCompactNamespaces) {
45044504
"} // namespace bbbbbb\n"
45054505
"} // namespace aaaaaa",
45064506
Style);
4507+
4508+
verifyFormat("namespace a { namespace b { namespace c {\n"
4509+
"}}} // namespace a::b::c",
4510+
Style);
4511+
4512+
verifyFormat("namespace a { namespace b {\n"
4513+
"namespace cc {\n"
4514+
"}}} // namespace a::b::cc",
4515+
Style);
4516+
45074517
Style.ColumnLimit = 80;
45084518

45094519
// Extra semicolon after 'inner' closing brace prevents merging
@@ -28318,6 +28328,7 @@ TEST_F(FormatTest, ShortNamespacesOption) {
2831828328
auto BaseStyle = getLLVMStyle();
2831928329
BaseStyle.AllowShortNamespacesOnASingleLine = true;
2832028330
BaseStyle.FixNamespaceComments = false;
28331+
BaseStyle.CompactNamespaces = true;
2832128332

2832228333
auto Style = BaseStyle;
2832328334

@@ -28332,8 +28343,9 @@ TEST_F(FormatTest, ShortNamespacesOption) {
2833228343
Style);
2833328344

2833428345
// Trailing comments prevent merging.
28335-
verifyFormat("namespace foo {\n"
28336-
"namespace baz { class qux; } // comment\n"
28346+
verifyFormat("namespace foo { namespace baz {\n"
28347+
"class qux;\n"
28348+
"} // comment\n"
2833728349
"}",
2833828350
Style);
2833928351

@@ -28348,12 +28360,23 @@ TEST_F(FormatTest, ShortNamespacesOption) {
2834828360

2834928361
// Nested namespaces.
2835028362
verifyFormat("namespace foo { namespace bar { class baz; } }", Style);
28363+
28364+
// Without CompactNamespaces, we won't merge consecutive namespace
28365+
// declarations
28366+
Style.CompactNamespaces = false;
28367+
verifyFormat("namespace foo {\n"
28368+
"namespace bar { class baz; }\n"
28369+
"}",
28370+
Style);
28371+
2835128372
verifyFormat("namespace foo {\n"
2835228373
"namespace bar { class baz; }\n"
2835328374
"namespace qux { class quux; }\n"
2835428375
"}",
2835528376
Style);
2835628377

28378+
Style = BaseStyle;
28379+
2835728380
// Varying inner content.
2835828381
verifyFormat("namespace foo {\n"
2835928382
"int f() { return 5; }\n"
@@ -28362,7 +28385,7 @@ TEST_F(FormatTest, ShortNamespacesOption) {
2836228385
verifyFormat("namespace foo { template <T> struct bar; }", Style);
2836328386
verifyFormat("namespace foo { constexpr int num = 42; }", Style);
2836428387

28365-
// Validate wrapping scenarios around the ColumnLimit.
28388+
// Validate nested namespace wrapping scenarios around the ColumnLimit.
2836628389
Style.ColumnLimit = 64;
2836728390

2836828391
// Validate just under the ColumnLimit.
@@ -28371,22 +28394,24 @@ TEST_F(FormatTest, ShortNamespacesOption) {
2837128394
Style);
2837228395

2837328396
// Validate just over the ColumnLimit.
28374-
verifyFormat("namespace foo {\n"
28375-
"namespace bar { namespace baz { class quux; } }\n"
28376-
"}",
28397+
verifyFormat("namespace foo { namespace baar { namespace baaz {\n"
28398+
"class quux;\n"
28399+
"}}}",
2837728400
Style);
2837828401

28379-
verifyFormat("namespace foo {\n"
28380-
"namespace bar {\n"
28381-
"namespace baz { namespace qux { class quux; } }\n"
28382-
"}\n"
28383-
"}",
28384-
Style);
28402+
verifyFormat(
28403+
"namespace foo { namespace bar { namespace baz { namespace qux {\n"
28404+
"class quux;\n"
28405+
"}}}}",
28406+
Style);
2838528407

2838628408
// Validate that the ColumnLimit logic accounts for trailing content as well.
28387-
verifyFormat("namespace foo {\n"
28388-
"namespace bar { namespace baz { class qux; } }\n"
28389-
"} // extra",
28409+
verifyFormat("namespace foo { namespace bar { class qux; } } // extra",
28410+
Style);
28411+
28412+
verifyFormat("namespace foo { namespace bar { namespace baz {\n"
28413+
"class qux;\n"
28414+
"}}} // extra",
2839028415
Style);
2839128416

2839228417
// No ColumnLimit, allows long nested one-liners, but also leaves multi-line
@@ -28401,41 +28426,24 @@ TEST_F(FormatTest, ShortNamespacesOption) {
2840128426
"}",
2840228427
Style);
2840328428

28404-
Style = BaseStyle;
28405-
Style.CompactNamespaces = true;
2840628429
verifyFormat("namespace foo { namespace bar { class baz; } }", Style);
2840728430

28408-
// If we can't merge an outer nested namespaces, but can merge an inner
28409-
// nested namespace, then CompactNamespaces will merge the outer namespace
28410-
// first, preventing the merging of the inner namespace.
28411-
verifyFormat("namespace foo { namespace baz {\n"
28412-
"class qux;\n"
28413-
"} // comment\n"
28414-
"}",
28415-
Style);
28416-
28417-
// This option doesn't really work with FixNamespaceComments and nested
28418-
// namespaces. Code should use the concatenated namespace syntax. e.g.
28419-
// 'namespace foo::bar'.
28431+
// FIXME: Ideally AllowShortNamespacesOnASingleLine would disable the trailing
28432+
// namespace comment from 'FixNamespaceComments', as it's not really necessary
28433+
// in this scenario, but the two options work at very different layers of the
28434+
// formatter, so I'm not sure how to make them interact.
28435+
//
28436+
// As it stands, the trailing comment will be added and likely make the line
28437+
// too long to fit within the ColumnLimit, reducing the how likely the line
28438+
// will still fit on a single line. The recommendation for now is to use the
28439+
// concatenated namespace syntax instead. e.g. 'namespace foo::bar'
2842028440
Style = BaseStyle;
2842128441
Style.FixNamespaceComments = true;
2842228442

2842328443
verifyFormat(
28424-
"namespace foo {\n"
28425-
"namespace bar { namespace baz { class qux; } } // namespace bar\n"
28426-
"} // namespace foo",
28427-
"namespace foo { namespace bar { namespace baz { class qux; } } }",
28428-
Style);
28429-
28430-
// This option doesn't really make any sense with ShortNamespaceLines = 0.
28431-
Style.ShortNamespaceLines = 0;
28432-
28433-
verifyFormat(
28434-
"namespace foo {\n"
28435-
"namespace bar {\n"
28436-
"namespace baz { class qux; } // namespace baz\n"
28437-
"} // namespace bar\n"
28438-
"} // namespace foo",
28444+
"namespace foo { namespace bar { namespace baz {\n"
28445+
"class qux;\n"
28446+
"}}} // namespace foo::bar::baz",
2843928447
"namespace foo { namespace bar { namespace baz { class qux; } } }",
2844028448
Style);
2844128449
}

0 commit comments

Comments
 (0)