Index: docs/LibASTMatchersReference.html =================================================================== --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -410,7 +410,7 @@ Given typedef int X; - using Y = int; + using Y = int; typeAliasDecl() matches "using Y = int", but not "typedef int X" @@ -421,7 +421,7 @@ Given typedef int X; - using Y = int; + using Y = int; typedefDecl() matches "typedef int X", but not "using Y = int" @@ -432,7 +432,7 @@ Given typedef int X; - using Y = int; + using Y = int; typedefNameDecl() matches "typedef int X" and "using Y = int" @@ -3836,6 +3836,30 @@ +
Matches each method overriden by the given method. This matcher may
+produce multiple matches.
+
+Given
+ class A { virtual void f(); };
+ class B : public A { void f(); };
+ class C : public B { void f(); };
+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.
+ class A1 { virtual void f(); };
+ class A2 { virtual void f(); };
+ class C : public A1, public A2 { void f(); };
+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".
+Matches the class declaration that the given method declaration
belongs to.
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -821,6 +821,7 @@
overridden_methods_end(const CXXMethodDecl *Method) const;
unsigned overridden_methods_size(const CXXMethodDecl *Method) const;
+ const CXXMethodVector *overridden_methods(const CXXMethodDecl *Method) const;
/// \brief Note that the given C++ \p Method overrides the given \p
/// Overridden method.
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h
+++ include/clang/AST/DeclCXX.h
@@ -23,6 +23,7 @@
#include "clang/AST/LambdaCapture.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Support/Compiler.h"
namespace clang {
@@ -1827,6 +1828,7 @@
method_iterator begin_overridden_methods() const;
method_iterator end_overridden_methods() const;
unsigned size_overridden_methods() const;
+ const llvm::TinyPtrVector *overridden_methods() const;
/// Returns the parent of this method declaration, which
/// is the class in which this method is defined.
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -3693,6 +3693,50 @@
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, InnerMatcher) {
+ if (Node.overridden_methods() == nullptr) {
+ return false;
+ }
+ BoundNodesTreeBuilder Result;
+ bool Matched = false;
+ for (const auto* Overridden : *Node.overridden_methods()) {
+ BoundNodesTreeBuilder OverriddenBuilder(*Builder);
+ const bool OverriddenMatched =
+ InnerMatcher.matches(*Overridden, 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
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -1259,32 +1259,30 @@
ASTContext::overridden_cxx_method_iterator
ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const {
- llvm::DenseMap::const_iterator Pos
- = OverriddenMethods.find(Method->getCanonicalDecl());
- if (Pos == OverriddenMethods.end())
- return nullptr;
-
- return Pos->second.begin();
+ const auto* Overridden = overridden_methods(Method);
+ return Overridden == nullptr ? nullptr : Overridden->begin();
}
ASTContext::overridden_cxx_method_iterator
ASTContext::overridden_methods_end(const CXXMethodDecl *Method) const {
- llvm::DenseMap::const_iterator Pos
- = OverriddenMethods.find(Method->getCanonicalDecl());
- if (Pos == OverriddenMethods.end())
- return nullptr;
-
- return Pos->second.end();
+ const auto* Overridden = overridden_methods(Method);
+ return Overridden == nullptr ? nullptr : Overridden->end();
}
unsigned
ASTContext::overridden_methods_size(const CXXMethodDecl *Method) const {
+ const auto* Overridden = overridden_methods(Method);
+ return Overridden == nullptr ? 0 : Overridden->size();
+}
+
+const ASTContext::CXXMethodVector *
+ASTContext::overridden_methods(const CXXMethodDecl *Method) const {
llvm::DenseMap::const_iterator Pos
= OverriddenMethods.find(Method->getCanonicalDecl());
if (Pos == OverriddenMethods.end())
- return 0;
+ return nullptr;
- return Pos->second.size();
+ return &Pos->second;
}
void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method,
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp
+++ lib/AST/DeclCXX.cpp
@@ -1622,6 +1622,12 @@
return getASTContext().overridden_methods_size(this);
}
+const llvm::TinyPtrVector *
+CXXMethodDecl::overridden_methods() const {
+ if (isa(this)) return nullptr;
+ return getASTContext().overridden_methods(this);
+}
+
QualType CXXMethodDecl::getThisType(ASTContext &C) const {
// C++ 9.3.2p1: The type of this in a member function of a class X is X*.
// If the member function is declared const, the type of this is const X*,
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: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -2085,6 +2085,50 @@
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"),
+ llvm::make_unique>("override", "f", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Code1, ForEachOverriddenInClass("C"),
+ llvm::make_unique>("overridden", "f",
+ 1)));
+ // B::f overrides A::f.
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Code1, ForEachOverriddenInClass("B"),
+ llvm::make_unique>("override", "f", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Code1, ForEachOverriddenInClass("B"),
+ llvm::make_unique>("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"),
+ llvm::make_unique>("override", "f", 2)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ Code2, ForEachOverriddenInClass("B"),
+ llvm::make_unique>("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"))));