[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