[clang] 45e210d - [ASTMatchers] Make it possible to build mapAnyOf through the registry

Stephen Kelly via cfe-commits cfe-commits at lists.llvm.org
Sun Feb 7 07:37:26 PST 2021


Author: Stephen Kelly
Date: 2021-02-07T15:36:15Z
New Revision: 45e210dbebfae916b213e52be15c276032aeb60d

URL: https://github.com/llvm/llvm-project/commit/45e210dbebfae916b213e52be15c276032aeb60d
DIFF: https://github.com/llvm/llvm-project/commit/45e210dbebfae916b213e52be15c276032aeb60d.diff

LOG: [ASTMatchers] Make it possible to build mapAnyOf through the registry

Added: 
    

Modified: 
    clang/include/clang/ASTMatchers/Dynamic/Registry.h
    clang/lib/ASTMatchers/Dynamic/Marshallers.h
    clang/lib/ASTMatchers/Dynamic/Registry.cpp
    clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/ASTMatchers/Dynamic/Registry.h b/clang/include/clang/ASTMatchers/Dynamic/Registry.h
index 9ce77c33d6d8..f91f5fe01c4e 100644
--- a/clang/include/clang/ASTMatchers/Dynamic/Registry.h
+++ b/clang/include/clang/ASTMatchers/Dynamic/Registry.h
@@ -33,6 +33,23 @@ namespace internal {
 
 class MatcherDescriptor;
 
+/// A smart (owning) pointer for MatcherDescriptor. We can't use unique_ptr
+/// because MatcherDescriptor is forward declared
+class MatcherDescriptorPtr {
+public:
+  explicit MatcherDescriptorPtr(MatcherDescriptor *);
+  ~MatcherDescriptorPtr();
+  MatcherDescriptorPtr(MatcherDescriptorPtr &&) = default;
+  MatcherDescriptorPtr &operator=(MatcherDescriptorPtr &&) = default;
+  MatcherDescriptorPtr(const MatcherDescriptorPtr &) = delete;
+  MatcherDescriptorPtr &operator=(const MatcherDescriptorPtr &) = delete;
+
+  MatcherDescriptor *get() { return Ptr; }
+
+private:
+  MatcherDescriptor *Ptr;
+};
+
 } // namespace internal
 
 using MatcherCtor = const internal::MatcherDescriptor *;
@@ -68,6 +85,12 @@ class Registry {
 
   static ASTNodeKind nodeMatcherType(MatcherCtor);
 
+  static bool isBuilderMatcher(MatcherCtor Ctor);
+
+  static internal::MatcherDescriptorPtr
+  buildMatcherCtor(MatcherCtor, SourceRange NameRange,
+                   ArrayRef<ParserValue> Args, Diagnostics *Error);
+
   /// Look up a matcher in the registry by name,
   ///
   /// \return An opaque value which may be used to refer to the matcher

diff  --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/clang/lib/ASTMatchers/Dynamic/Marshallers.h
index 71d7443c91ca..3ffa0d6af217 100644
--- a/clang/lib/ASTMatchers/Dynamic/Marshallers.h
+++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -311,6 +311,14 @@ class MatcherDescriptor {
 
   virtual ASTNodeKind nodeMatcherType() const { return ASTNodeKind(); }
 
+  virtual bool isBuilderMatcher() const { return false; }
+
+  virtual std::unique_ptr<MatcherDescriptor>
+  buildMatcherCtor(SourceRange NameRange, ArrayRef<ParserValue> Args,
+                   Diagnostics *Error) const {
+    return {};
+  }
+
   /// Returns whether the matcher is variadic. Variadic matchers can take any
   /// number of arguments, but they must be of the same type.
   virtual bool isVariadic() const = 0;
@@ -996,6 +1004,62 @@ class MapAnyOfMatcherDescriptor : public MatcherDescriptor {
   }
 };
 
+class MapAnyOfBuilderDescriptor : public MatcherDescriptor {
+public:
+  VariantMatcher create(SourceRange, ArrayRef<ParserValue>,
+                        Diagnostics *) const override {
+    return {};
+  }
+
+  bool isBuilderMatcher() const override { return true; }
+
+  std::unique_ptr<MatcherDescriptor>
+  buildMatcherCtor(SourceRange, ArrayRef<ParserValue> Args,
+                   Diagnostics *) const override {
+
+    std::vector<ASTNodeKind> NodeKinds;
+    for (auto Arg : Args) {
+      if (!Arg.Value.isNodeKind())
+        return {};
+      NodeKinds.push_back(Arg.Value.getNodeKind());
+    }
+
+    if (NodeKinds.empty())
+      return {};
+
+    ASTNodeKind CladeNodeKind = NodeKinds.front().getCladeKind();
+
+    for (auto NK : NodeKinds)
+    {
+      if (!NK.getCladeKind().isSame(CladeNodeKind))
+        return {};
+    }
+
+    return std::make_unique<MapAnyOfMatcherDescriptor>(CladeNodeKind,
+                                                       NodeKinds);
+  }
+
+  bool isVariadic() const override { return true; }
+
+  unsigned getNumArgs() const override { return 0; }
+
+  void getArgKinds(ASTNodeKind ThisKind, unsigned,
+                   std::vector<ArgKind> &ArgKinds) const override {
+    ArgKinds.push_back(ArgKind::MakeNodeArg(ThisKind));
+    return;
+  }
+  bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity = nullptr,
+                       ASTNodeKind *LeastDerivedKind = nullptr) const override {
+    if (Specificity)
+      *Specificity = 1;
+    if (LeastDerivedKind)
+      *LeastDerivedKind = Kind;
+    return true;
+  }
+
+  bool isPolymorphic() const override { return false; }
+};
+
 /// Helper functions to select the appropriate marshaller functions.
 /// They detect the number of arguments, arguments types and return type.
 

diff  --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 908a9ee8ae62..ef5fd64a3666 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -102,6 +102,9 @@ RegistryMaps::RegistryMaps() {
   // Other:
   // equalsNode
 
+  registerMatcher("mapAnyOf",
+                  std::make_unique<internal::MapAnyOfBuilderDescriptor>());
+
   REGISTER_OVERLOADED_2(callee);
   REGISTER_OVERLOADED_2(hasAnyCapture);
   REGISTER_OVERLOADED_2(hasPrefix);
@@ -566,6 +569,22 @@ ASTNodeKind Registry::nodeMatcherType(MatcherCtor Ctor) {
   return Ctor->nodeMatcherType();
 }
 
+internal::MatcherDescriptorPtr::MatcherDescriptorPtr(MatcherDescriptor *Ptr)
+    : Ptr(Ptr) {}
+
+internal::MatcherDescriptorPtr::~MatcherDescriptorPtr() { delete Ptr; }
+
+bool Registry::isBuilderMatcher(MatcherCtor Ctor) {
+  return Ctor->isBuilderMatcher();
+}
+
+internal::MatcherDescriptorPtr
+Registry::buildMatcherCtor(MatcherCtor Ctor, SourceRange NameRange,
+                           ArrayRef<ParserValue> Args, Diagnostics *Error) {
+  return internal::MatcherDescriptorPtr(
+      Ctor->buildMatcherCtor(NameRange, Args, Error).release());
+}
+
 // static
 llvm::Optional<MatcherCtor> Registry::lookupMatcherCtor(StringRef MatcherName) {
   auto it = RegistryData->constructors().find(MatcherName);

diff  --git a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
index 386fd523bb24..a7368d819ccd 100644
--- a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -497,6 +497,20 @@ TEST_F(RegistryTest, Completion) {
       "Matcher<CXXRecordDecl> isSameOrDerivedFrom(string|Matcher<NamedDecl>)"));
 }
 
+TEST_F(RegistryTest, MatcherBuilder) {
+  auto Ctor = *lookupMatcherCtor("mapAnyOf");
+  EXPECT_TRUE(Registry::isBuilderMatcher(Ctor));
+  auto BuiltCtor = Registry::buildMatcherCtor(Ctor, {}, Args(ASTNodeKind::getFromNodeKind<WhileStmt>(), ASTNodeKind::getFromNodeKind<ForStmt>()), nullptr);
+  EXPECT_TRUE(BuiltCtor.get());
+  auto LoopMatcher = Registry::constructMatcher(BuiltCtor.get(), SourceRange(), Args(), nullptr).getTypedMatcher<Stmt>();
+  EXPECT_TRUE(matches("void f() { for (;;) {} }", LoopMatcher));
+  EXPECT_TRUE(matches("void f() { while (true) {} }", LoopMatcher));
+  EXPECT_FALSE(matches("void f() { if (true) {} }", LoopMatcher));
+
+  auto NotBuiltCtor = Registry::buildMatcherCtor(Ctor, {}, Args(ASTNodeKind::getFromNodeKind<FunctionDecl>(), ASTNodeKind::getFromNodeKind<ForStmt>()), nullptr);
+  EXPECT_FALSE(NotBuiltCtor.get());
+}
+
 TEST_F(RegistryTest, NodeType) {
   EXPECT_TRUE(Registry::nodeMatcherType(*lookupMatcherCtor("callExpr")).isSame(ASTNodeKind::getFromNodeKind<CallExpr>()));
   EXPECT_TRUE(Registry::nodeMatcherType(*lookupMatcherCtor("has")).isNone());


        


More information about the cfe-commits mailing list