[PATCH] Re-introduce MatchFinder::addDynamicMatcher.

Peter Collingbourne peter at pcc.me.uk
Wed Nov 6 16:31:50 PST 2013


Hi klimek, sbenza,

http://llvm-reviews.chandlerc.com/D2114

Files:
  include/clang/ASTMatchers/ASTMatchFinder.h
  lib/ASTMatchers/ASTMatchFinder.cpp
  unittests/ASTMatchers/ASTMatchersTest.cpp
  unittests/ASTMatchers/ASTMatchersTest.h

Index: include/clang/ASTMatchers/ASTMatchFinder.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchFinder.h
+++ include/clang/ASTMatchers/ASTMatchFinder.h
@@ -136,6 +136,17 @@
                   MatchCallback *Action);
   /// @}
 
+  /// \brief Adds a matcher to execute when running over the AST.
+  ///
+  /// This is similar to \c addMatcher(), but it uses the dynamic interface. It
+  /// is more flexible, but the lost type information enables a caller to pass
+  /// a matcher that cannot match anything.
+  ///
+  /// \returns \c true if the matcher is a valid top-level matcher, \c false
+  ///   otherwise.
+  bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
+                         MatchCallback *Action);
+
   /// \brief Creates a clang ASTConsumer that finds all matches.
   clang::ASTConsumer *newASTConsumer();
 
Index: lib/ASTMatchers/ASTMatchFinder.cpp
===================================================================
--- lib/ASTMatchers/ASTMatchFinder.cpp
+++ lib/ASTMatchers/ASTMatchFinder.cpp
@@ -811,6 +811,30 @@
   MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action));
 }
 
+bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
+                                    MatchCallback *Action) {
+  if (NodeMatch.canConvertTo<Decl>()) {
+    addMatcher(NodeMatch.convertTo<Decl>(), Action);
+    return true;
+  } else if (NodeMatch.canConvertTo<QualType>()) {
+    addMatcher(NodeMatch.convertTo<QualType>(), Action);
+    return true;
+  } else if (NodeMatch.canConvertTo<Stmt>()) {
+    addMatcher(NodeMatch.convertTo<Stmt>(), Action);
+    return true;
+  } else if (NodeMatch.canConvertTo<NestedNameSpecifier>()) {
+    addMatcher(NodeMatch.convertTo<NestedNameSpecifier>(), Action);
+    return true;
+  } else if (NodeMatch.canConvertTo<NestedNameSpecifierLoc>()) {
+    addMatcher(NodeMatch.convertTo<NestedNameSpecifierLoc>(), Action);
+    return true;
+  } else if (NodeMatch.canConvertTo<TypeLoc>()) {
+    addMatcher(NodeMatch.convertTo<TypeLoc>(), Action);
+    return true;
+  }
+  return false;
+}
+
 ASTConsumer *MatchFinder::newASTConsumer() {
   return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone);
 }
Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -40,6 +40,18 @@
 }
 #endif
 
+TEST(Finder, DynamicOnlyAcceptsSomeMatchers) {
+  MatchFinder Finder;
+  EXPECT_TRUE(Finder.addDynamicMatcher(decl(), NULL));
+  EXPECT_TRUE(Finder.addDynamicMatcher(callExpr(), NULL));
+  EXPECT_TRUE(Finder.addDynamicMatcher(constantArrayType(hasSize(42)), NULL));
+
+  // Do not accept non-toplevel matchers.
+  EXPECT_FALSE(Finder.addDynamicMatcher(isArrow(), NULL));
+  EXPECT_FALSE(Finder.addDynamicMatcher(hasSize(2), NULL));
+  EXPECT_FALSE(Finder.addDynamicMatcher(hasName("x"), NULL));
+}
+
 TEST(Decl, MatchesDeclarations) {
   EXPECT_TRUE(notMatches("", decl(usingDecl())));
   EXPECT_TRUE(matches("namespace x { class X {}; } using x::X;",
@@ -651,11 +663,18 @@
       : Id(Id), ExpectedCount(ExpectedCount), Count(0),
         ExpectedName(ExpectedName) {}
 
-  ~VerifyIdIsBoundTo() {
+  void onEndOfTranslationUnit() LLVM_OVERRIDE {
     if (ExpectedCount != -1)
       EXPECT_EQ(ExpectedCount, Count);
     if (!ExpectedName.empty())
       EXPECT_EQ(ExpectedName, Name);
+    Count = 0;
+    Name.clear();
+  }
+
+  ~VerifyIdIsBoundTo() {
+    EXPECT_EQ(0, Count);
+    EXPECT_EQ("", Name);
   }
 
   virtual bool run(const BoundNodes *Nodes) {
Index: unittests/ASTMatchers/ASTMatchersTest.h
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.h
+++ unittests/ASTMatchers/ASTMatchersTest.h
@@ -26,6 +26,7 @@
   virtual ~BoundNodesCallback() {}
   virtual bool run(const BoundNodes *BoundNodes) = 0;
   virtual bool run(const BoundNodes *BoundNodes, ASTContext *Context) = 0;
+  virtual void onEndOfTranslationUnit() {}
 };
 
 // If 'FindResultVerifier' is not NULL, sets *Verified to the result of
@@ -44,6 +45,11 @@
     }
   }
 
+  void onEndOfTranslationUnit() LLVM_OVERRIDE {
+    if (FindResultReviewer)
+      FindResultReviewer->onEndOfTranslationUnit();
+  }
+
 private:
   bool *const Verified;
   BoundNodesCallback *const FindResultReviewer;
@@ -54,15 +60,23 @@
                                               const T &AMatcher,
                                               bool ExpectMatch,
                                               llvm::StringRef CompileArg) {
-  bool Found = false;
+  bool Found = false, DynamicFound = false;
   MatchFinder Finder;
   Finder.addMatcher(AMatcher, new VerifyMatch(0, &Found));
+  if (!Finder.addDynamicMatcher(AMatcher, new VerifyMatch(0, &DynamicFound)))
+    return testing::AssertionFailure() << "Could not add dynamic matcher";
   OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
   // Some tests use typeof, which is a gnu extension.
   std::vector<std::string> Args(1, CompileArg);
   if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
     return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
   }
+  if (Found != DynamicFound) {
+    return testing::AssertionFailure() << "Dynamic match result ("
+                                       << DynamicFound
+                                       << ") does not match static result ("
+                                       << Found << ")";
+  }
   if (!Found && ExpectMatch) {
     return testing::AssertionFailure()
       << "Could not find match in \"" << Code << "\"";
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D2114.1.patch
Type: text/x-patch
Size: 5740 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131106/dafd775a/attachment.bin>


More information about the cfe-commits mailing list