zequanwu updated this revision to Diff 414149.
zequanwu marked an inline comment as done.
zequanwu added a comment.

Add a test for `namespace A B {`.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D121269/new/

https://reviews.llvm.org/D121269

Files:
  clang/lib/Format/NamespaceEndCommentsFixer.cpp
  clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp

Index: clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp
===================================================================
--- clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp
+++ clang/unittests/Format/NamespaceEndCommentsFixerTest.cpp
@@ -189,6 +189,38 @@
                 "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 B __attribute__((availability(macos, introduced=10.15)))\n"
+      "namespace A B {\n"
+      "int i;\n"
+      "int j;\n"
+      "}// namespace A B",
+      fixNamespaceEndComments(
+          "#define B __attribute__((availability(macos, introduced=10.15)))\n"
+          "namespace A B {\n"
+          "int i;\n"
+          "int j;\n"
+          "}"));
+  EXPECT_EQ("#define M(x) x##x\n"
+            "namespace A::B M(x) {\n"
+            "int i;\n"
+            "int j;\n"
+            "}// namespace A::B",
+            fixNamespaceEndComments("#define M(x) x##x\n"
+                                    "namespace A::B M(x) {\n"
+                                    "int i;\n"
+                                    "int j;\n"
+                                    "}"));
   EXPECT_EQ("inline namespace A {\n"
             "int i;\n"
             "int j;\n"
Index: clang/lib/Format/NamespaceEndCommentsFixer.cpp
===================================================================
--- clang/lib/Format/NamespaceEndCommentsFixer.cpp
+++ clang/lib/Format/NamespaceEndCommentsFixer.cpp
@@ -55,30 +55,72 @@
         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 '{' 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;
+    const FormatToken *FirstNSTok = nullptr;
     while (Tok && !Tok->isOneOf(tok::l_brace, tok::coloncolon, tok::l_paren)) {
-      FirstNSName += FirstNSTok->TokenText;
+      if (FirstNSTok)
+        FirstNSName += FirstNSTok->TokenText;
       FirstNSTok = Tok;
       Tok = Tok->getNextNonComment();
     }
 
-    Tok = FirstNSTok;
-    while (Tok && !Tok->is(tok::l_brace)) {
+    bool IsPrevColoncolon = false;
+    bool HasColoncolon = false;
+    bool IsPrevInline = false;
+    bool NameFinished = false;
+    if (FirstNSTok)
+      Tok = FirstNSTok;
+    FirstNSTok = nullptr;
+    // Add everything from '(' to ')'.
+    auto AddMacro = [&name](const FormatToken *Tok) {
+      if (!Tok->is(tok::l_paren))
+        return Tok;
       name += Tok->TokenText;
-      if (Tok->is(tok::kw_inline))
-        name += " ";
+      Tok = Tok->getNextNonComment();
+      for (int NestLevel = 1; Tok && NestLevel > 0;) {
+        if (Tok->is(tok::l_paren))
+          ++NestLevel;
+        else if (Tok->is(tok::r_paren))
+          --NestLevel;
+        name += Tok->TokenText;
+        Tok = Tok->getNextNonComment();
+      }
+      return Tok;
+    };
+    // If we found '::' in name, then it's the name. Otherwise, we can't tell
+    // which one is name. For example, `namespace A B {`.
+    while (Tok && !Tok->is(tok::l_brace)) {
+      if (FirstNSTok) {
+        if (!IsPrevInline && HasColoncolon && !IsPrevColoncolon) {
+          if (FirstNSTok->is(tok::l_paren)) {
+            FirstNSTok = Tok = AddMacro(FirstNSTok);
+            continue;
+          }
+          if (!FirstNSTok->is(tok::coloncolon)) {
+            NameFinished = true;
+            break;
+          }
+        }
+        name += FirstNSTok->TokenText;
+        IsPrevColoncolon = FirstNSTok->is(tok::coloncolon);
+        HasColoncolon |= IsPrevColoncolon;
+        if (FirstNSTok->is(tok::kw_inline)) {
+          name += " ";
+          IsPrevInline = true;
+        }
+      }
+      FirstNSTok = Tok;
       Tok = Tok->getNextNonComment();
     }
-    if (name.empty())
-      name = FirstNSName;
+    if (!NameFinished && FirstNSTok && !FirstNSTok->is(tok::l_brace))
+      name += FirstNSTok->TokenText;
+    if (!FirstNSName.empty() && !HasColoncolon)
+      name = FirstNSName + " " + name;
   }
   return name;
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to