]> granicus.if.org Git - clang/commitdiff
Re-introduce MatchFinder::addDynamicMatcher.
authorPeter Collingbourne <peter@pcc.me.uk>
Thu, 7 Nov 2013 22:30:32 +0000 (22:30 +0000)
committerPeter Collingbourne <peter@pcc.me.uk>
Thu, 7 Nov 2013 22:30:32 +0000 (22:30 +0000)
Differential Revision: http://llvm-reviews.chandlerc.com/D2114

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@194222 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 8817d3eb0c39cd3982a0d526dc27e7d7323141c3..eddc7ca3ac8d090d9e2d79f4aa500a8fb03137b2 100644 (file)
@@ -136,6 +136,17 @@ public:
                   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 fbb696f4644d7b50b695b3c9c61cdeba68d0d2f8..6ca5afc2496fad35f7f640303d7812c7e704098c 100644 (file)
@@ -811,6 +811,30 @@ void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch,
   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 a848d55f989ee9f04c983e608777628d536f39fa..5649ad897e825c9dd906cf732cb1269916de2f4b 100644 (file)
@@ -40,6 +40,18 @@ TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) {
 }
 #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 @@ public:
       : 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 5fed85bb30bb6a78d9c1b6d55f6b6640588b7250..e65d8e792df596666b9f1843b9093db0f9501e0b 100644 (file)
@@ -26,6 +26,7 @@ public:
   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 @@ public:
     }
   }
 
+  void onEndOfTranslationUnit() LLVM_OVERRIDE {
+    if (FindResultReviewer)
+      FindResultReviewer->onEndOfTranslationUnit();
+  }
+
 private:
   bool *const Verified;
   BoundNodesCallback *const FindResultReviewer;
@@ -54,15 +60,23 @@ testing::AssertionResult matchesConditionally(const std::string &Code,
                                               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 << "\"";