courbet updated this revision to Diff 54462.
courbet marked an inline comment as done.
courbet added a comment.

Fix typo in doc.


http://reviews.llvm.org/D19324

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

Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -2069,6 +2069,47 @@
       notMatches("class X { virtual void f(); };", cxxMethodDecl(isFinal())));
 }
 
+TEST(Matcher, ForEachOverriden) {
+  const auto ForEachOverriddenInClass = [](const char *ClassName) {
+    return cxxMethodDecl(ofClass(hasName(ClassName)), isVirtual(),
+                         forEachOverridden(cxxMethodDecl().bind("overridden")))
+        .bind("override");
+  };
+  constexpr const char Code1[] = "class A { virtual void f(); };"
+                                 "class B : public A { void f(); };"
+                                 "class C : public B { void f(); };";
+  // C::f overrides A::f.
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Code1, ForEachOverriddenInClass("C"),
+      new VerifyIdIsBoundTo<CXXMethodDecl>("override", "f", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Code1, ForEachOverriddenInClass("C"),
+      new VerifyIdIsBoundTo<CXXMethodDecl>("overridden", "f", 1)));
+  // B::f overrides A::f.
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Code1, ForEachOverriddenInClass("B"),
+      new VerifyIdIsBoundTo<CXXMethodDecl>("override", "f", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Code1, ForEachOverriddenInClass("B"),
+      new VerifyIdIsBoundTo<CXXMethodDecl>("overridden", "f", 1)));
+  // A::f overrides nothing.
+  EXPECT_TRUE(notMatches(Code1, ForEachOverriddenInClass("A")));
+
+  constexpr const char Code2[] =
+      "class A1 { virtual void f(); };"
+      "class A2 { virtual void f(); };"
+      "class B : public A1, public A2 { void f(); };";
+  // B::f overrides A1::f and A2::f. This produces two matches.
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Code2, ForEachOverriddenInClass("B"),
+      new VerifyIdIsBoundTo<CXXMethodDecl>("override", "f", 2)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Code2, ForEachOverriddenInClass("B"),
+      new VerifyIdIsBoundTo<CXXMethodDecl>("overridden", "f", 2)));
+  // A1::f overrides nothing.
+  EXPECT_TRUE(notMatches(Code2, ForEachOverriddenInClass("A1")));
+}
+
 TEST(Matcher, MatchesVirtualMethod) {
   EXPECT_TRUE(matches("class X { virtual int f(); };",
                       cxxMethodDecl(isVirtual(), hasName("::X::f"))));
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -182,6 +182,7 @@
   REGISTER_MATCHER(forEachArgumentWithParam);
   REGISTER_MATCHER(forEachConstructorInitializer);
   REGISTER_MATCHER(forEachDescendant);
+  REGISTER_MATCHER(forEachOverridden);
   REGISTER_MATCHER(forEachSwitchCase);
   REGISTER_MATCHER(forField);
   REGISTER_MATCHER(forStmt);
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -3693,6 +3693,48 @@
           InnerMatcher.matches(*Parent, Finder, Builder));
 }
 
+/// \brief Matches each method overriden by the given method. This matcher may
+/// produce multiple matches.
+///
+/// Given
+/// \code
+///   class A { virtual void f(); };
+///   class B : public A { void f(); };
+///   class C : public B { void f(); };
+/// \endcode
+/// cxxMethodDecl(ofClass(hasName("C")),
+///               forEachOverridden(cxxMethodDecl().bind("b"))).bind("d")
+///   matches once, with "b" binding "A::f" and "d" binding "C::f" (Note
+///   that B::f is not overridden by C::f).
+///
+/// The check can produce multiple matches in case of multiple inheritance, e.g.
+/// \code
+///   class A1 { virtual void f(); };
+///   class A2 { virtual void f(); };
+///   class C : public A1, public A2 { void f(); };
+/// \endcode
+/// cxxMethodDecl(ofClass(hasName("C")),
+///               forEachOverridden(cxxMethodDecl().bind("b"))).bind("d")
+///   matches twice, once with "b" binding "A1::f" and "d" binding "C::f", and
+///   once with "b" binding "A2::f" and "d" binding "C::f".
+AST_MATCHER_P(CXXMethodDecl, forEachOverridden,
+              internal::Matcher<CXXMethodDecl>, InnerMatcher) {
+  BoundNodesTreeBuilder Result;
+  bool Matched = false;
+  for (auto It = Node.begin_overridden_methods();
+       It != Node.end_overridden_methods(); ++It) {
+    BoundNodesTreeBuilder OverriddenBuilder(*Builder);
+    const bool OverriddenMatched =
+        InnerMatcher.matches(**It, Finder, &OverriddenBuilder);
+    if (OverriddenMatched) {
+      Matched = true;
+      Result.addMatch(OverriddenBuilder);
+    }
+  }
+  *Builder = std::move(Result);
+  return Matched;
+}
+
 /// \brief Matches if the given method declaration is virtual.
 ///
 /// Given
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to