Add code complete support for mapAnyOf
authorStephen Kelly <steveire@gmail.com>
Sun, 7 Feb 2021 00:28:20 +0000 (00:28 +0000)
committerStephen Kelly <steveire@gmail.com>
Sun, 7 Feb 2021 16:03:05 +0000 (16:03 +0000)
clang/lib/ASTMatchers/Dynamic/Registry.cpp
clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp

index ef5fd64..4300eb8 100644 (file)
@@ -656,20 +656,40 @@ Registry::getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes) {
     bool IsPolymorphic = Matcher.isPolymorphic();
     std::vector<std::vector<ArgKind>> ArgsKinds(NumArgs);
     unsigned MaxSpecificity = 0;
+    bool NodeArgs = false;
     for (const ArgKind& Kind : AcceptedTypes) {
-      if (Kind.getArgKind() != Kind.AK_Matcher)
+      if (Kind.getArgKind() != Kind.AK_Matcher &&
+          Kind.getArgKind() != Kind.AK_Node) {
         continue;
-      unsigned Specificity;
-      ASTNodeKind LeastDerivedKind;
-      if (Matcher.isConvertibleTo(Kind.getMatcherKind(), &Specificity,
-                                  &LeastDerivedKind)) {
-        if (MaxSpecificity < Specificity)
-          MaxSpecificity = Specificity;
-        RetKinds.insert(LeastDerivedKind);
-        for (unsigned Arg = 0; Arg != NumArgs; ++Arg)
-          Matcher.getArgKinds(Kind.getMatcherKind(), Arg, ArgsKinds[Arg]);
-        if (IsPolymorphic)
-          break;
+      }
+
+      if (Kind.getArgKind() == Kind.AK_Node) {
+        NodeArgs = true;
+        unsigned Specificity;
+        ASTNodeKind LeastDerivedKind;
+        if (Matcher.isConvertibleTo(Kind.getNodeKind(), &Specificity,
+                                    &LeastDerivedKind)) {
+          if (MaxSpecificity < Specificity)
+            MaxSpecificity = Specificity;
+          RetKinds.insert(LeastDerivedKind);
+          for (unsigned Arg = 0; Arg != NumArgs; ++Arg)
+            Matcher.getArgKinds(Kind.getNodeKind(), Arg, ArgsKinds[Arg]);
+          if (IsPolymorphic)
+            break;
+        }
+      } else {
+        unsigned Specificity;
+        ASTNodeKind LeastDerivedKind;
+        if (Matcher.isConvertibleTo(Kind.getMatcherKind(), &Specificity,
+                                    &LeastDerivedKind)) {
+          if (MaxSpecificity < Specificity)
+            MaxSpecificity = Specificity;
+          RetKinds.insert(LeastDerivedKind);
+          for (unsigned Arg = 0; Arg != NumArgs; ++Arg)
+            Matcher.getArgKinds(Kind.getMatcherKind(), Arg, ArgsKinds[Arg]);
+          if (IsPolymorphic)
+            break;
+        }
       }
     }
 
@@ -677,42 +697,49 @@ Registry::getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes) {
       std::string Decl;
       llvm::raw_string_ostream OS(Decl);
 
-      if (IsPolymorphic) {
-        OS << "Matcher<T> " << Name << "(Matcher<T>";
+      std::string TypedText = std::string(Name);
+
+      if (NodeArgs) {
+        OS << Name;
       } else {
-        OS << "Matcher<" << RetKinds << "> " << Name << "(";
-        for (const std::vector<ArgKind> &Arg : ArgsKinds) {
-          if (&Arg != &ArgsKinds[0])
-            OS << ", ";
-
-          bool FirstArgKind = true;
-          std::set<ASTNodeKind> MatcherKinds;
-          // Two steps. First all non-matchers, then matchers only.
-          for (const ArgKind &AK : Arg) {
-            if (AK.getArgKind() == ArgKind::AK_Matcher) {
-              MatcherKinds.insert(AK.getMatcherKind());
-            } else {
+
+        if (IsPolymorphic) {
+          OS << "Matcher<T> " << Name << "(Matcher<T>";
+        } else {
+          OS << "Matcher<" << RetKinds << "> " << Name << "(";
+          for (const std::vector<ArgKind> &Arg : ArgsKinds) {
+            if (&Arg != &ArgsKinds[0])
+              OS << ", ";
+
+            bool FirstArgKind = true;
+            std::set<ASTNodeKind> MatcherKinds;
+            // Two steps. First all non-matchers, then matchers only.
+            for (const ArgKind &AK : Arg) {
+              if (AK.getArgKind() == ArgKind::AK_Matcher) {
+                MatcherKinds.insert(AK.getMatcherKind());
+              } else {
+                if (!FirstArgKind)
+                  OS << "|";
+                FirstArgKind = false;
+                OS << AK.asString();
+              }
+            }
+            if (!MatcherKinds.empty()) {
               if (!FirstArgKind) OS << "|";
-              FirstArgKind = false;
-              OS << AK.asString();
+              OS << "Matcher<" << MatcherKinds << ">";
             }
           }
-          if (!MatcherKinds.empty()) {
-            if (!FirstArgKind) OS << "|";
-            OS << "Matcher<" << MatcherKinds << ">";
-          }
         }
+        if (Matcher.isVariadic())
+          OS << "...";
+        OS << ")";
+
+        TypedText += "(";
+        if (ArgsKinds.empty())
+          TypedText += ")";
+        else if (ArgsKinds[0][0].getArgKind() == ArgKind::AK_String)
+          TypedText += "\"";
       }
-      if (Matcher.isVariadic())
-        OS << "...";
-      OS << ")";
-
-      std::string TypedText = std::string(Name);
-      TypedText += "(";
-      if (ArgsKinds.empty())
-        TypedText += ")";
-      else if (ArgsKinds[0][0].getArgKind() == ArgKind::AK_String)
-        TypedText += "\"";
 
       Completions.emplace_back(TypedText, OS.str(), MaxSpecificity);
     }
index 744be79..255432d 100644 (file)
@@ -541,6 +541,29 @@ TEST(ParserTest, CompletionRegistry) {
   ASSERT_EQ(1u, Comps.size());
   EXPECT_EQ("bind(\"", Comps[0].TypedText);
   EXPECT_EQ("bind", Comps[0].MatcherDecl);
+
+  Code = "mapAny";
+  Comps = Parser::completeExpression(Code, 6);
+  ASSERT_EQ(1u, Comps.size());
+  EXPECT_EQ("Of(", Comps[0].TypedText);
+  EXPECT_EQ("Matcher<NestedNameSpecifierLoc|QualType|TypeLoc|...> "
+            "mapAnyOf(NestedNameSpecifierLoc|QualType|TypeLoc|"
+            "NestedNameSpecifier|Decl|Stmt|Type...)",
+            Comps[0].MatcherDecl);
+
+  Code = "mapAnyOf(ifStmt).";
+  Comps = Parser::completeExpression(Code, 17);
+  ASSERT_EQ(2u, Comps.size());
+  EXPECT_EQ("bind(\"", Comps[0].TypedText);
+  EXPECT_EQ("bind", Comps[0].MatcherDecl);
+  EXPECT_EQ("with(", Comps[1].TypedText);
+  EXPECT_EQ("with", Comps[1].MatcherDecl);
+
+  Code = "mapAnyOf(ifS";
+  Comps = Parser::completeExpression(Code, 12);
+  ASSERT_EQ(1u, Comps.size());
+  EXPECT_EQ("tmt", Comps[0].TypedText);
+  EXPECT_EQ("ifStmt", Comps[0].MatcherDecl);
 }
 
 TEST(ParserTest, CompletionNamedValues) {