Skip to content

Commit be57057

Browse files
committed
[clang-format] fix namepsace format when the name is macro expansion
Originally filed at crbug.com/1184570. When the name of a namespace is a macro that takes arguments, - It fixed the indentation. - It fixed the namepsace end comments. Differential Revision: https://reviews.llvm.org/D120931
1 parent 9129743 commit be57057

File tree

4 files changed

+179
-4
lines changed

4 files changed

+179
-4
lines changed

clang/lib/Format/NamespaceEndCommentsFixer.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,32 @@ std::string computeName(const FormatToken *NamespaceTok) {
4040
Tok = Tok->getNextNonComment();
4141
}
4242
} else {
43+
// Skip attributes.
44+
if (Tok && Tok->is(tok::l_square)) {
45+
for (int NestLevel = 1; NestLevel > 0;) {
46+
Tok = Tok->getNextNonComment();
47+
if (!Tok)
48+
break;
49+
if (Tok->is(tok::l_square))
50+
++NestLevel;
51+
else if (Tok->is(tok::r_square))
52+
--NestLevel;
53+
}
54+
if (Tok)
55+
Tok = Tok->getNextNonComment();
56+
}
57+
58+
// Use the string after `namespace` as a name candidate until `{` or `::` or
59+
// `(`. If the name is empty, use the candicate.
60+
std::string FirstNSName;
4361
// For `namespace [[foo]] A::B::inline C {` or
4462
// `namespace MACRO1 MACRO2 A::B::inline C {`, returns "A::B::inline C".
45-
// Peek for the first '::' (or '{') and then return all tokens from one
46-
// token before that up until the '{'.
63+
// Peek for the first '::' (or '{' or '(')) and then return all tokens from
64+
// one token before that up until the '{'. A '(' might be a macro with
65+
// arguments.
4766
const FormatToken *FirstNSTok = Tok;
48-
while (Tok && !Tok->is(tok::l_brace) && !Tok->is(tok::coloncolon)) {
67+
while (Tok && !Tok->isOneOf(tok::l_brace, tok::coloncolon, tok::l_paren)) {
68+
FirstNSName += FirstNSTok->TokenText;
4969
FirstNSTok = Tok;
5070
Tok = Tok->getNextNonComment();
5171
}
@@ -57,6 +77,8 @@ std::string computeName(const FormatToken *NamespaceTok) {
5777
name += " ";
5878
Tok = Tok->getNextNonComment();
5979
}
80+
if (name.empty())
81+
name = FirstNSName;
6082
}
6183
return name;
6284
}

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2597,10 +2597,12 @@ void UnwrappedLineParser::parseNamespace() {
25972597
parseParens();
25982598
} else {
25992599
while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw_inline,
2600-
tok::l_square, tok::period) ||
2600+
tok::l_square, tok::period, tok::l_paren) ||
26012601
(Style.isCSharp() && FormatTok->is(tok::kw_union)))
26022602
if (FormatTok->is(tok::l_square))
26032603
parseSquare();
2604+
else if (FormatTok->is(tok::l_paren))
2605+
parseParens();
26042606
else
26052607
nextToken();
26062608
}

clang/unittests/Format/FormatTest.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3738,6 +3738,36 @@ TEST_F(FormatTest, FormatsNamespaces) {
37383738
"void f() { f(); }\n"
37393739
"}",
37403740
LLVMWithNoNamespaceFix);
3741+
verifyFormat("#define M(x) x##x\n"
3742+
"namespace M(x) {\n"
3743+
"class A {};\n"
3744+
"void f() { f(); }\n"
3745+
"}",
3746+
LLVMWithNoNamespaceFix);
3747+
verifyFormat("#define M(x) x##x\n"
3748+
"namespace N::inline M(x) {\n"
3749+
"class A {};\n"
3750+
"void f() { f(); }\n"
3751+
"}",
3752+
LLVMWithNoNamespaceFix);
3753+
verifyFormat("#define M(x) x##x\n"
3754+
"namespace M(x)::inline N {\n"
3755+
"class A {};\n"
3756+
"void f() { f(); }\n"
3757+
"}",
3758+
LLVMWithNoNamespaceFix);
3759+
verifyFormat("#define M(x) x##x\n"
3760+
"namespace N::M(x) {\n"
3761+
"class A {};\n"
3762+
"void f() { f(); }\n"
3763+
"}",
3764+
LLVMWithNoNamespaceFix);
3765+
verifyFormat("#define M(x) x##x\n"
3766+
"namespace M::N(x) {\n"
3767+
"class A {};\n"
3768+
"void f() { f(); }\n"
3769+
"}",
3770+
LLVMWithNoNamespaceFix);
37413771
verifyFormat("namespace N::inline D {\n"
37423772
"class A {};\n"
37433773
"void f() { f(); }\n"

clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,127 @@ TEST_F(NamespaceEndCommentsFixerTest, AddsEndComment) {
6868
"int i;\n"
6969
"int j;\n"
7070
"}"));
71+
EXPECT_EQ("#define M(x) x##x\n"
72+
"namespace M(x) {\n"
73+
"int i;\n"
74+
"int j;\n"
75+
"}// namespace M(x)",
76+
fixNamespaceEndComments("#define M(x) x##x\n"
77+
"namespace M(x) {\n"
78+
"int i;\n"
79+
"int j;\n"
80+
"}"));
81+
EXPECT_EQ("#define M(x) x##x\n"
82+
"namespace A::M(x) {\n"
83+
"int i;\n"
84+
"int j;\n"
85+
"}// namespace A::M(x)",
86+
fixNamespaceEndComments("#define M(x) x##x\n"
87+
"namespace A::M(x) {\n"
88+
"int i;\n"
89+
"int j;\n"
90+
"}"));
91+
EXPECT_EQ("#define M(x) x##x\n"
92+
"namespace M(x)::A {\n"
93+
"int i;\n"
94+
"int j;\n"
95+
"}// namespace M(x)::A",
96+
fixNamespaceEndComments("#define M(x) x##x\n"
97+
"namespace M(x)::A {\n"
98+
"int i;\n"
99+
"int j;\n"
100+
"}"));
101+
EXPECT_EQ("#define M(x) x##x\n"
102+
"namespace A::inline M(x)::B {\n"
103+
"int i;\n"
104+
"int j;\n"
105+
"}// namespace A::inline M(x)::B",
106+
fixNamespaceEndComments("#define M(x) x##x\n"
107+
"namespace A::inline M(x)::B {\n"
108+
"int i;\n"
109+
"int j;\n"
110+
"}"));
111+
EXPECT_EQ("#define M(x) x##x\n"
112+
"namespace [[deprecated(\"foo\")]] A::inline M(x)::A {\n"
113+
"int i;\n"
114+
"int j;\n"
115+
"}// namespace A::inline M(x)::A",
116+
fixNamespaceEndComments(
117+
"#define M(x) x##x\n"
118+
"namespace [[deprecated(\"foo\")]] A::inline M(x)::A {\n"
119+
"int i;\n"
120+
"int j;\n"
121+
"}"));
122+
EXPECT_EQ(
123+
"namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ A {\n"
124+
"int i;\n"
125+
"int j;\n"
126+
"}// namespace A",
127+
fixNamespaceEndComments(
128+
"namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ A {\n"
129+
"int i;\n"
130+
"int j;\n"
131+
"}"));
132+
EXPECT_EQ("namespace /* comment */ [[deprecated(\"foo\")]] A {\n"
133+
"int i;\n"
134+
"int j;\n"
135+
"}// namespace A",
136+
fixNamespaceEndComments(
137+
"namespace /* comment */ [[deprecated(\"foo\")]] A {\n"
138+
"int i;\n"
139+
"int j;\n"
140+
"}"));
141+
EXPECT_EQ(
142+
"#define M(x) x##x\n"
143+
"namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ M(x) {\n"
144+
"int i;\n"
145+
"int j;\n"
146+
"}// namespace M(x)",
147+
fixNamespaceEndComments("#define M(x) x##x\n"
148+
"namespace /* comment */ "
149+
"[[deprecated(\"foo\")]] /* comment */ M(x) {\n"
150+
"int i;\n"
151+
"int j;\n"
152+
"}"));
153+
EXPECT_EQ("#define M(x) x##x\n"
154+
"namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ "
155+
"A::M(x) {\n"
156+
"int i;\n"
157+
"int j;\n"
158+
"}// namespace A::M(x)",
159+
fixNamespaceEndComments(
160+
"#define M(x) x##x\n"
161+
"namespace /* comment */ "
162+
"[[deprecated(\"foo\")]] /* comment */ A::M(x) {\n"
163+
"int i;\n"
164+
"int j;\n"
165+
"}"));
166+
EXPECT_EQ("#define M(x) x##x\n"
167+
"namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ "
168+
"M(x) /* comment */ {\n"
169+
"int i;\n"
170+
"int j;\n"
171+
"}// namespace M(x)",
172+
fixNamespaceEndComments(
173+
"#define M(x) x##x\n"
174+
"namespace /* comment */ [[deprecated(\"foo\")]] /* comment "
175+
"*/ M(x) /* comment */ {\n"
176+
"int i;\n"
177+
"int j;\n"
178+
"}"));
179+
EXPECT_EQ("#define M(x) x##x\n"
180+
"namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ "
181+
"A::M(x) /* comment */ {\n"
182+
"int i;\n"
183+
"int j;\n"
184+
"}// namespace A::M(x)",
185+
fixNamespaceEndComments(
186+
"#define M(x) x##x\n"
187+
"namespace /* comment */ [[deprecated(\"foo\")]] /* comment "
188+
"*/ A::M(x) /* comment */ {\n"
189+
"int i;\n"
190+
"int j;\n"
191+
"}"));
71192
EXPECT_EQ("inline namespace A {\n"
72193
"int i;\n"
73194
"int j;\n"

0 commit comments

Comments
 (0)