courbet updated this revision to Diff 57473. courbet added a comment. cometics
http://reviews.llvm.org/D19324 Files: docs/LibASTMatchersReference.html include/clang/AST/ASTContext.h include/clang/AST/DeclCXX.h include/clang/ASTMatchers/ASTMatchers.h lib/AST/ASTContext.cpp lib/AST/DeclCXX.cpp lib/ASTMatchers/Dynamic/Registry.cpp unittests/ASTMatchers/ASTMatchersTest.cpp
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<VerifyIdIsBoundTo<CXXMethodDecl>>("override", "f", 1))); + EXPECT_TRUE(matchAndVerifyResultTrue( + Code1, ForEachOverriddenInClass("C"), + llvm::make_unique<VerifyIdIsBoundTo<CXXMethodDecl>>("overridden", "f", + 1))); + // B::f overrides A::f. + EXPECT_TRUE(matchAndVerifyResultTrue( + Code1, ForEachOverriddenInClass("B"), + llvm::make_unique<VerifyIdIsBoundTo<CXXMethodDecl>>("override", "f", 1))); + EXPECT_TRUE(matchAndVerifyResultTrue( + Code1, ForEachOverriddenInClass("B"), + llvm::make_unique<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"), + llvm::make_unique<VerifyIdIsBoundTo<CXXMethodDecl>>("override", "f", 2))); + EXPECT_TRUE(matchAndVerifyResultTrue( + Code2, ForEachOverriddenInClass("B"), + llvm::make_unique<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(forFunction); Index: lib/AST/DeclCXX.cpp =================================================================== --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -1622,6 +1622,13 @@ return getASTContext().overridden_methods_size(this); } +CXXMethodDecl::overridden_method_range +CXXMethodDecl::overridden_methods() const { + if (isa<CXXConstructorDecl>(this)) + return overridden_method_range(nullptr, 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/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -1260,33 +1260,36 @@ ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos - = OverriddenMethods.find(Method->getCanonicalDecl()); + = OverriddenMethods.find(Method->getCanonicalDecl()); if (Pos == OverriddenMethods.end()) return nullptr; - return Pos->second.begin(); } ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_end(const CXXMethodDecl *Method) const { llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos - = OverriddenMethods.find(Method->getCanonicalDecl()); + = OverriddenMethods.find(Method->getCanonicalDecl()); if (Pos == OverriddenMethods.end()) return nullptr; - return Pos->second.end(); } unsigned ASTContext::overridden_methods_size(const CXXMethodDecl *Method) const { llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos - = OverriddenMethods.find(Method->getCanonicalDecl()); + = OverriddenMethods.find(Method->getCanonicalDecl()); if (Pos == OverriddenMethods.end()) return 0; - return Pos->second.size(); } +ASTContext::overridden_method_range +ASTContext::overridden_methods(const CXXMethodDecl *Method) const { + return overridden_method_range(overridden_methods_begin(Method), + overridden_methods_end(Method)); +} + void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method, const CXXMethodDecl *Overridden) { assert(Method->isCanonicalDecl() && Overridden->isCanonicalDecl()); Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -3693,6 +3693,47 @@ 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 (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: include/clang/AST/DeclCXX.h =================================================================== --- include/clang/AST/DeclCXX.h +++ include/clang/AST/DeclCXX.h @@ -16,6 +16,7 @@ #ifndef LLVM_CLANG_AST_DECLCXX_H #define LLVM_CLANG_AST_DECLCXX_H +#include "clang/AST/ASTContext.h" #include "clang/AST/ASTUnresolvedSet.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" @@ -1827,6 +1828,8 @@ method_iterator begin_overridden_methods() const; method_iterator end_overridden_methods() const; unsigned size_overridden_methods() const; + typedef ASTContext::overridden_method_range overridden_method_range; + overridden_method_range overridden_methods() const; /// Returns the parent of this method declaration, which /// is the class in which this method is defined. Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -821,6 +821,9 @@ overridden_methods_end(const CXXMethodDecl *Method) const; unsigned overridden_methods_size(const CXXMethodDecl *Method) const; + typedef llvm::iterator_range<overridden_cxx_method_iterator> + overridden_method_range; + overridden_method_range overridden_methods(const CXXMethodDecl *Method) const; /// \brief Note that the given C++ \p Method overrides the given \p /// Overridden method. Index: docs/LibASTMatchersReference.html =================================================================== --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -3867,6 +3867,30 @@ </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('forEachOverridden0')"><a name="forEachOverridden0Anchor">forEachOverridden</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="forEachOverridden0"><pre>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". +</pre></td></tr> + + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('ofClass0')"><a name="ofClass0Anchor">ofClass</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="ofClass0"><pre>Matches the class declaration that the given method declaration belongs to.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits