[clang] be57057 - [clang-format] fix namepsace format when the name is macro expansion
Zequan Wu via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 4 16:01:27 PST 2022
Author: Zequan Wu
Date: 2022-03-04T16:01:17-08:00
New Revision: be5705767aad8d8eafd40225f7dba8e7e661c6b5
URL: https://github.com/llvm/llvm-project/commit/be5705767aad8d8eafd40225f7dba8e7e661c6b5
DIFF: https://github.com/llvm/llvm-project/commit/be5705767aad8d8eafd40225f7dba8e7e661c6b5.diff
LOG: [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
Added:
Modified:
clang/lib/Format/NamespaceEndCommentsFixer.cpp
clang/lib/Format/UnwrappedLineParser.cpp
clang/unittests/Format/FormatTest.cpp
clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp
Removed:
################################################################################
diff --git a/clang/lib/Format/NamespaceEndCommentsFixer.cpp b/clang/lib/Format/NamespaceEndCommentsFixer.cpp
index 65f965548da37..e527402e33074 100644
--- a/clang/lib/Format/NamespaceEndCommentsFixer.cpp
+++ b/clang/lib/Format/NamespaceEndCommentsFixer.cpp
@@ -40,12 +40,32 @@ std::string computeName(const FormatToken *NamespaceTok) {
Tok = Tok->getNextNonComment();
}
} else {
+ // Skip attributes.
+ if (Tok && Tok->is(tok::l_square)) {
+ for (int NestLevel = 1; NestLevel > 0;) {
+ Tok = Tok->getNextNonComment();
+ if (!Tok)
+ break;
+ if (Tok->is(tok::l_square))
+ ++NestLevel;
+ else if (Tok->is(tok::r_square))
+ --NestLevel;
+ }
+ if (Tok)
+ Tok = Tok->getNextNonComment();
+ }
+
+ // Use the string after `namespace` as a name candidate until `{` or `::` or
+ // `(`. If the name is empty, use the candicate.
+ std::string FirstNSName;
// For `namespace [[foo]] A::B::inline C {` or
// `namespace MACRO1 MACRO2 A::B::inline C {`, returns "A::B::inline C".
- // Peek for the first '::' (or '{') and then return all tokens from one
- // token before that up until the '{'.
+ // Peek for the first '::' (or '{' or '(')) and then return all tokens from
+ // one token before that up until the '{'. A '(' might be a macro with
+ // arguments.
const FormatToken *FirstNSTok = Tok;
- while (Tok && !Tok->is(tok::l_brace) && !Tok->is(tok::coloncolon)) {
+ while (Tok && !Tok->isOneOf(tok::l_brace, tok::coloncolon, tok::l_paren)) {
+ FirstNSName += FirstNSTok->TokenText;
FirstNSTok = Tok;
Tok = Tok->getNextNonComment();
}
@@ -57,6 +77,8 @@ std::string computeName(const FormatToken *NamespaceTok) {
name += " ";
Tok = Tok->getNextNonComment();
}
+ if (name.empty())
+ name = FirstNSName;
}
return name;
}
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 46562f7ae8b84..68b0e2a630bcd 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -2597,10 +2597,12 @@ void UnwrappedLineParser::parseNamespace() {
parseParens();
} else {
while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw_inline,
- tok::l_square, tok::period) ||
+ tok::l_square, tok::period, tok::l_paren) ||
(Style.isCSharp() && FormatTok->is(tok::kw_union)))
if (FormatTok->is(tok::l_square))
parseSquare();
+ else if (FormatTok->is(tok::l_paren))
+ parseParens();
else
nextToken();
}
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 6c2b00b97ed3c..f453a4f77f8b3 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -3738,6 +3738,36 @@ TEST_F(FormatTest, FormatsNamespaces) {
"void f() { f(); }\n"
"}",
LLVMWithNoNamespaceFix);
+ verifyFormat("#define M(x) x##x\n"
+ "namespace M(x) {\n"
+ "class A {};\n"
+ "void f() { f(); }\n"
+ "}",
+ LLVMWithNoNamespaceFix);
+ verifyFormat("#define M(x) x##x\n"
+ "namespace N::inline M(x) {\n"
+ "class A {};\n"
+ "void f() { f(); }\n"
+ "}",
+ LLVMWithNoNamespaceFix);
+ verifyFormat("#define M(x) x##x\n"
+ "namespace M(x)::inline N {\n"
+ "class A {};\n"
+ "void f() { f(); }\n"
+ "}",
+ LLVMWithNoNamespaceFix);
+ verifyFormat("#define M(x) x##x\n"
+ "namespace N::M(x) {\n"
+ "class A {};\n"
+ "void f() { f(); }\n"
+ "}",
+ LLVMWithNoNamespaceFix);
+ verifyFormat("#define M(x) x##x\n"
+ "namespace M::N(x) {\n"
+ "class A {};\n"
+ "void f() { f(); }\n"
+ "}",
+ LLVMWithNoNamespaceFix);
verifyFormat("namespace N::inline D {\n"
"class A {};\n"
"void f() { f(); }\n"
diff --git a/clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp b/clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp
index 925b0e3b2e4c9..e2ce6071c6e87 100644
--- a/clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp
+++ b/clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp
@@ -68,6 +68,127 @@ TEST_F(NamespaceEndCommentsFixerTest, AddsEndComment) {
"int i;\n"
"int j;\n"
"}"));
+ EXPECT_EQ("#define M(x) x##x\n"
+ "namespace M(x) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace M(x)",
+ fixNamespaceEndComments("#define M(x) x##x\n"
+ "namespace M(x) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}"));
+ EXPECT_EQ("#define M(x) x##x\n"
+ "namespace A::M(x) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace A::M(x)",
+ fixNamespaceEndComments("#define M(x) x##x\n"
+ "namespace A::M(x) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}"));
+ EXPECT_EQ("#define M(x) x##x\n"
+ "namespace M(x)::A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace M(x)::A",
+ fixNamespaceEndComments("#define M(x) x##x\n"
+ "namespace M(x)::A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}"));
+ EXPECT_EQ("#define M(x) x##x\n"
+ "namespace A::inline M(x)::B {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace A::inline M(x)::B",
+ fixNamespaceEndComments("#define M(x) x##x\n"
+ "namespace A::inline M(x)::B {\n"
+ "int i;\n"
+ "int j;\n"
+ "}"));
+ EXPECT_EQ("#define M(x) x##x\n"
+ "namespace [[deprecated(\"foo\")]] A::inline M(x)::A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace A::inline M(x)::A",
+ fixNamespaceEndComments(
+ "#define M(x) x##x\n"
+ "namespace [[deprecated(\"foo\")]] A::inline M(x)::A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}"));
+ EXPECT_EQ(
+ "namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace A",
+ fixNamespaceEndComments(
+ "namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}"));
+ EXPECT_EQ("namespace /* comment */ [[deprecated(\"foo\")]] A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace A",
+ fixNamespaceEndComments(
+ "namespace /* comment */ [[deprecated(\"foo\")]] A {\n"
+ "int i;\n"
+ "int j;\n"
+ "}"));
+ EXPECT_EQ(
+ "#define M(x) x##x\n"
+ "namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ M(x) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace M(x)",
+ fixNamespaceEndComments("#define M(x) x##x\n"
+ "namespace /* comment */ "
+ "[[deprecated(\"foo\")]] /* comment */ M(x) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}"));
+ EXPECT_EQ("#define M(x) x##x\n"
+ "namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ "
+ "A::M(x) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace A::M(x)",
+ fixNamespaceEndComments(
+ "#define M(x) x##x\n"
+ "namespace /* comment */ "
+ "[[deprecated(\"foo\")]] /* comment */ A::M(x) {\n"
+ "int i;\n"
+ "int j;\n"
+ "}"));
+ EXPECT_EQ("#define M(x) x##x\n"
+ "namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ "
+ "M(x) /* comment */ {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace M(x)",
+ fixNamespaceEndComments(
+ "#define M(x) x##x\n"
+ "namespace /* comment */ [[deprecated(\"foo\")]] /* comment "
+ "*/ M(x) /* comment */ {\n"
+ "int i;\n"
+ "int j;\n"
+ "}"));
+ EXPECT_EQ("#define M(x) x##x\n"
+ "namespace /* comment */ [[deprecated(\"foo\")]] /* comment */ "
+ "A::M(x) /* comment */ {\n"
+ "int i;\n"
+ "int j;\n"
+ "}// namespace A::M(x)",
+ fixNamespaceEndComments(
+ "#define M(x) x##x\n"
+ "namespace /* comment */ [[deprecated(\"foo\")]] /* comment "
+ "*/ A::M(x) /* comment */ {\n"
+ "int i;\n"
+ "int j;\n"
+ "}"));
EXPECT_EQ("inline namespace A {\n"
"int i;\n"
"int j;\n"
More information about the cfe-commits
mailing list