Skip to content

Commit 3794413

Browse files
committed
clang-format: Fix namespace end comments for namespaces with attributes and macros.
Fixes PR39247. While here, also make C++20 `namespace A::inline B::inline C` nested inline namespaced definitions work. Before: #define DEPRECATE_WOOF [[deprecated("meow")]] namespace DEPRECATE_WOOF woof { void f() {} } // namespace DEPRECATE_WOOFwoof namespace [[deprecated("meow")]] woof { void f() {} } // namespace [[deprecated("meow")]]woof namespace woof::inline bark { void f() {} } // namespace woof::inlinebark Now: #define DEPRECATE_WOOF [[deprecated("meow")]] namespace DEPRECATE_WOOF woof { void f() {} } // namespace woof namespace [[deprecated("meow")]] woof { void f() {} } // namespace woof namespace woof::inline bark { void f() {} } // namespace woof::inline bark (In addition to the fixed namespace end comments, also note the correct indent of the namespace contents.) Differential Revision: https://reviews.llvm.org/D65125 llvm-svn: 366831
1 parent 93f5059 commit 3794413

File tree

4 files changed

+76
-5
lines changed

4 files changed

+76
-5
lines changed

clang/lib/Format/NamespaceEndCommentsFixer.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,29 @@ std::string computeName(const FormatToken *NamespaceTok) {
3636
const FormatToken *Tok = NamespaceTok->getNextNonComment();
3737
if (NamespaceTok->is(TT_NamespaceMacro)) {
3838
// Collects all the non-comment tokens between opening parenthesis
39-
// and closing parenthesis or comma
39+
// and closing parenthesis or comma.
4040
assert(Tok && Tok->is(tok::l_paren) && "expected an opening parenthesis");
4141
Tok = Tok->getNextNonComment();
4242
while (Tok && !Tok->isOneOf(tok::r_paren, tok::comma)) {
4343
name += Tok->TokenText;
4444
Tok = Tok->getNextNonComment();
4545
}
4646
} else {
47-
// Collects all the non-comment tokens between 'namespace' and '{'.
47+
// For `namespace [[foo]] A::B::inline C {` or
48+
// `namespace MACRO1 MACRO2 A::B::inline C {`, returns "A::B::inline C".
49+
// Peek for the first '::' (or '{') and then return all tokens from one
50+
// token before that up until the '{'.
51+
const FormatToken *FirstNSTok = Tok;
52+
while (Tok && !Tok->is(tok::l_brace) && !Tok->is(tok::coloncolon)) {
53+
FirstNSTok = Tok;
54+
Tok = Tok->getNextNonComment();
55+
}
56+
57+
Tok = FirstNSTok;
4858
while (Tok && !Tok->is(tok::l_brace)) {
4959
name += Tok->TokenText;
60+
if (Tok->is(tok::kw_inline))
61+
name += " ";
5062
Tok = Tok->getNextNonComment();
5163
}
5264
}

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1873,8 +1873,13 @@ void UnwrappedLineParser::parseNamespace() {
18731873
if (InitialToken.is(TT_NamespaceMacro)) {
18741874
parseParens();
18751875
} else {
1876-
while (FormatTok->isOneOf(tok::identifier, tok::coloncolon))
1877-
nextToken();
1876+
while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw_inline,
1877+
tok::l_square)) {
1878+
if (FormatTok->is(tok::l_square))
1879+
parseSquare();
1880+
else
1881+
nextToken();
1882+
}
18781883
}
18791884
if (FormatTok->Tok.is(tok::l_brace)) {
18801885
if (ShouldBreakBeforeBrace(Style, InitialToken))

clang/unittests/Format/FormatTest.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1782,6 +1782,21 @@ TEST_F(FormatTest, FormatsNamespaces) {
17821782
"void f() { f(); }\n"
17831783
"}",
17841784
LLVMWithNoNamespaceFix);
1785+
verifyFormat("namespace N::inline D {\n"
1786+
"class A {};\n"
1787+
"void f() { f(); }\n"
1788+
"}",
1789+
LLVMWithNoNamespaceFix);
1790+
verifyFormat("namespace N::inline D::E {\n"
1791+
"class A {};\n"
1792+
"void f() { f(); }\n"
1793+
"}",
1794+
LLVMWithNoNamespaceFix);
1795+
verifyFormat("namespace [[deprecated(\"foo[bar\")]] some_namespace {\n"
1796+
"class A {};\n"
1797+
"void f() { f(); }\n"
1798+
"}",
1799+
LLVMWithNoNamespaceFix);
17851800
verifyFormat("/* something */ namespace some_namespace {\n"
17861801
"class A {};\n"
17871802
"void f() { f(); }\n"

clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,44 @@ TEST_F(NamespaceEndCommentsFixerTest, AddsEndComment) {
7777
"int i;\n"
7878
"int j;\n"
7979
"}"));
80+
81+
EXPECT_EQ("namespace [[deprecated(\"foo\")]] A::B {\n"
82+
"int i;\n"
83+
"int j;\n"
84+
"}// namespace A::B",
85+
fixNamespaceEndComments("namespace [[deprecated(\"foo\")]] A::B {\n"
86+
"int i;\n"
87+
"int j;\n"
88+
"}"));
89+
90+
EXPECT_EQ("namespace [[deprecated(\"foo\")]] A::inline B::inline C {\n"
91+
"int i;\n"
92+
"int j;\n"
93+
"}// namespace A::inline B::inline C",
94+
fixNamespaceEndComments(
95+
"namespace [[deprecated(\"foo\")]] A::inline B::inline C {\n"
96+
"int i;\n"
97+
"int j;\n"
98+
"}"));
99+
100+
EXPECT_EQ("namespace DEPRECATED A::B {\n"
101+
"int i;\n"
102+
"int j;\n"
103+
"}// namespace A::B",
104+
fixNamespaceEndComments("namespace DEPRECATED A::B {\n"
105+
"int i;\n"
106+
"int j;\n"
107+
"}"));
108+
109+
EXPECT_EQ("inline namespace [[deprecated]] A {\n"
110+
"int i;\n"
111+
"int j;\n"
112+
"}// namespace A",
113+
fixNamespaceEndComments("inline namespace [[deprecated]] A {\n"
114+
"int i;\n"
115+
"int j;\n"
116+
"}"));
117+
80118
EXPECT_EQ("namespace ::A {\n"
81119
"int i;\n"
82120
"int j;\n"
@@ -410,7 +448,8 @@ TEST_F(NamespaceEndCommentsFixerTest, DoesNotAddCommentAfterUnaffectedRBrace) {
410448
/*Ranges=*/{1, tooling::Range(16, 3)}));
411449
}
412450

413-
TEST_F(NamespaceEndCommentsFixerTest, DoesNotAddCommentAfterRBraceInPPDirective) {
451+
TEST_F(NamespaceEndCommentsFixerTest,
452+
DoesNotAddCommentAfterRBraceInPPDirective) {
414453
EXPECT_EQ("#define SAD \\\n"
415454
"namespace A { \\\n"
416455
"int i; \\\n"

0 commit comments

Comments
 (0)