[PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet created this revision. courbet added a subscriber: cfe-commits. Herald added a subscriber: klimek. Matches methods overridden by the given method. 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("override", "f", 1))); + EXPECT_TRUE(matchAndVerifyResultTrue( + Code1, ForEachOverriddenInClass("C"), + new VerifyIdIsBoundTo("overridden", "f", 1))); + // B::f overrides A::f. + EXPECT_TRUE(matchAndVerifyResultTrue( + Code1, ForEachOverriddenInClass("B"), + new VerifyIdIsBoundTo("override", "f", 1))); + EXPECT_TRUE(matchAndVerifyResultTrue( + Code1, ForEachOverriddenInClass("B"), + new VerifyIdIsBoundTo("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("override", "f", 2))); + EXPECT_TRUE(matchAndVerifyResultTrue( + Code2, ForEachOverriddenInClass("B"), + new VerifyIdIsBoundTo("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", and +AST_MATCHER_P(CXXMethodDecl, forEachOverridden, + internal::Matcher, 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 Match
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet updated this revision to Diff 57462. courbet added a comment. Use iterator_range instead of ArrayRef for overridden_methods 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>("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"; 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(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_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_iterator Pos -= OverriddenMethods.find(Method->getCanonicalDecl()); + = OverriddenMethods.find(Method->getCanonicalDecl()); if (Pos == OverriddenMethods.end()) return nullptr; - return Pos->second.end(); } unsigned
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
aaron.ballman accepted this revision. aaron.ballman added a comment. This revision is now accepted and ready to land. LGTM, with one minor nit. Thank you for working on this! Comment at: include/clang/ASTMatchers/ASTMatchers.h:3724 @@ +3723,3 @@ + bool Matched = false; + for (const auto* Overridden : Node.overridden_methods()) { +BoundNodesTreeBuilder OverriddenBuilder(*Builder); Nit: the * should bind to Overridden instead of auto. (May just want to clang-format the patch.) http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet added a comment. Thanks. Could please you submit this for me ? Comment at: include/clang/ASTMatchers/ASTMatchers.h:3724 @@ +3723,3 @@ + bool Matched = false; + for (const auto *Overridden : Node.overridden_methods()) { +BoundNodesTreeBuilder OverriddenBuilder(*Builder); Thanks for the catch. Unfortunately there are a lot of errors in the file that prevent me to run clang-format. Any hint to handle that efficiently ? http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
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>("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"; 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(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_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_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 CXXMethodDe
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
aaron.ballman added inline comments. Comment at: include/clang/ASTMatchers/ASTMatchers.h:3724 @@ +3723,3 @@ + bool Matched = false; + for (const auto *Overridden : Node.overridden_methods()) { +BoundNodesTreeBuilder OverriddenBuilder(*Builder); courbet wrote: > Thanks for the catch. Unfortunately there are a lot of errors in the file > that prevent me to run clang-format. Any hint to handle that efficiently ? There's a script that you can use to reformat just the contents of a diff: http://clang.llvm.org/docs/ClangFormat.html#script-for-patch-reformatting http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet updated this revision to Diff 57756. courbet added a comment. Rebase on HEAD. 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 unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp === --- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -1975,5 +1975,49 @@ EXPECT_TRUE(notMatches(CppString2, returnStmt(forFunction(hasName("F"); } +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"))); +} + } // namespace ast_matchers } // namespace clang Index: lib/AST/DeclCXX.cpp === --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -1632,6 +1632,13 @@ return getASTContext().overridden_methods_size(this); } +CXXMethodDecl::overridden_method_range +CXXMethodDecl::overridden_methods() const { + if (isa(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 @@ -1255,33 +1255,36 @@ ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { llvm::DenseMap::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_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_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,
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet updated this revision to Diff 57757. courbet added a comment. clang-format diff 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 unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp === --- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -1975,5 +1975,49 @@ EXPECT_TRUE(notMatches(CppString2, returnStmt(forFunction(hasName("F"); } +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"))); +} + } // namespace ast_matchers } // namespace clang Index: lib/AST/DeclCXX.cpp === --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -1632,6 +1632,13 @@ return getASTContext().overridden_methods_size(this); } +CXXMethodDecl::overridden_method_range +CXXMethodDecl::overridden_methods() const { + if (isa(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 @@ -1254,34 +1254,37 @@ ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { - llvm::DenseMap::const_iterator Pos -= OverriddenMethods.find(Method->getCanonicalDecl()); + llvm::DenseMap::const_iterator Pos = + 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_iterator Pos -= OverriddenMethods.find(Method->getCanonicalDecl()); + llvm::DenseMap::const_iterator Pos = + 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_iterator Pos -= OverriddenMethods.find(Method->getCanonicalDecl()); + llvm::DenseMap::const_iterator Pos = + 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_metho
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet added inline comments. Comment at: include/clang/ASTMatchers/ASTMatchers.h:3776 @@ +3775,3 @@ + bool Matched = false; + for (const auto *Overridden : Node.overridden_methods()) { +BoundNodesTreeBuilder OverriddenBuilder(*Builder); Thanks for the pointer ! http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet marked 10 inline comments as done. courbet added a comment. http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
sbenza added inline comments. Comment at: include/clang/AST/ASTContext.h:824 @@ -823,1 +823,3 @@ unsigned overridden_methods_size(const CXXMethodDecl *Method) const; + typedef llvm::iterator_range + overridden_method_range; Sure. Sorry about that. The main idea was to use a range-like API instead of returning a nullable pointer to a range. http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
mgrang added a subscriber: mgrang. Comment at: include/clang/ASTMatchers/ASTMatchers.h:3719 @@ +3718,3 @@ +/// 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", and +AST_MATCHER_P(CXXMethodDecl, forEachOverridden, Extraneous ", and" at the end of comment. http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
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("override", "f", 1))); + EXPECT_TRUE(matchAndVerifyResultTrue( + Code1, ForEachOverriddenInClass("C"), + new VerifyIdIsBoundTo("overridden", "f", 1))); + // B::f overrides A::f. + EXPECT_TRUE(matchAndVerifyResultTrue( + Code1, ForEachOverriddenInClass("B"), + new VerifyIdIsBoundTo("override", "f", 1))); + EXPECT_TRUE(matchAndVerifyResultTrue( + Code1, ForEachOverriddenInClass("B"), + new VerifyIdIsBoundTo("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("override", "f", 2))); + EXPECT_TRUE(matchAndVerifyResultTrue( + Code2, ForEachOverriddenInClass("B"), + new VerifyIdIsBoundTo("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, 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
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
aaron.ballman added a subscriber: aaron.ballman. aaron.ballman added a reviewer: aaron.ballman. aaron.ballman added a comment. Please run clang\docs\tools\dump_ast_matchers.py to regenerate the documentation as well. Comment at: include/clang/ASTMatchers/ASTMatchers.h:3724 @@ +3723,3 @@ + bool Matched = false; + for (auto It = Node.begin_overridden_methods(); + It != Node.end_overridden_methods(); ++It) { Can you range-ify this for loop? Comment at: unittests/ASTMatchers/ASTMatchersTest.cpp:2084 @@ +2083,3 @@ + Code1, ForEachOverriddenInClass("C"), + new VerifyIdIsBoundTo("override", "f", 1))); + EXPECT_TRUE(matchAndVerifyResultTrue( Can you write the tests such that they don't leak? http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet added inline comments. Comment at: unittests/ASTMatchers/ASTMatchersTest.cpp:2084 @@ +2083,3 @@ + Code1, ForEachOverriddenInClass("C"), + new VerifyIdIsBoundTo("override", "f", 1))); + EXPECT_TRUE(matchAndVerifyResultTrue( aaron.ballman wrote: > Can you write the tests such that they don't leak? matchAndVerifyResultConditionally deletes them: ``` template testing::AssertionResult matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher, BoundNodesCallback *FindResultVerifier, bool ExpectResult) { std::unique_ptr ScopedVerifier(FindResultVerifier); ``` I'll send you a (separate) patch for taking a unique_ptr in. http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet added inline comments. Comment at: include/clang/ASTMatchers/ASTMatchers.h:3724 @@ +3723,3 @@ + bool Matched = false; + for (auto It = Node.begin_overridden_methods(); + It != Node.end_overridden_methods(); ++It) { aaron.ballman wrote: > Can you range-ify this for loop? I could do that , but it would require adding: ```const CXXMethodVector* ASTContext::overridden_methods() const;``` And plumbing it through. (or did I miss something ?) Let me know what you think. http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
aaron.ballman added inline comments. Comment at: include/clang/ASTMatchers/ASTMatchers.h:3724 @@ +3723,3 @@ + bool Matched = false; + for (auto It = Node.begin_overridden_methods(); + It != Node.end_overridden_methods(); ++It) { courbet wrote: > aaron.ballman wrote: > > Can you range-ify this for loop? > I could do that , but it would require adding: > > ```const CXXMethodVector* ASTContext::overridden_methods() const;``` > > And plumbing it through. (or did I miss something ?) > > Let me know what you think. I think it's an oversight that we don't have the range form of that function, and this seems like a reasonable use case to add it. http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet updated this revision to Diff 54512. courbet marked 4 inline comments as done. courbet added a comment. - add overridden_methods() to CXXMethodDecl and plumbing. - Use range-based for loop for iterating over overridden methods. http://reviews.llvm.org/D19324 Files: 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>("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"; 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: 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/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(); +
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet marked an inline comment as done. courbet added a comment. http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet updated this revision to Diff 54514. courbet added a comment. Regenerate doc. 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>("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"; 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: 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/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
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
sbenza added inline comments. Comment at: lib/AST/ASTContext.cpp:1279 @@ -1282,1 +1278,3 @@ +const ASTContext::CXXMethodVector * +ASTContext::overridden_methods(const CXXMethodDecl *Method) const { llvm::DenseMap::const_iterator Pos It would be simpler to return `ArrayRef`. That way the caller doesn't need to deal with a potential null pointer or with the custom vector type. http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet updated this revision to Diff 54830. courbet marked an inline comment as done. courbet added a comment. overridden_methods return ArrayRef instead of TinyPtrVector* 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>("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"; 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: lib/AST/DeclCXX.cpp === --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -1622,6 +1622,12 @@ return getASTContext().overridden_methods_size(this); } +const ArrayRef +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/AST/ASTContext.cpp === --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -1260,31 +1260,30 @@ ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { llvm::DenseMap::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_iterator Pos -= OverriddenMethods.find(Method->getCanonicalDecl()); + = OverriddenMethods.find(Method->getCanonicalDecl()); if (Pos == OverriddenMethods.end()) return nullptr; - return Pos->second.end(); } unsigned ASTContext::overridden_met
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
sbenza added inline comments. Comment at: include/clang/AST/DeclCXX.h:1830 @@ -1829,2 +1829,3 @@ unsigned size_overridden_methods() const; + const ArrayRef overridden_methods() const; Return type should have have toplevel `const`. Comment at: lib/AST/ASTContext.cpp:1262 @@ -1261,2 +1261,3 @@ ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { llvm::DenseMap::const_iterator Pos + = OverriddenMethods.find(Method->getCanonicalDecl()); I would invert the calls here. That is, make overridden_methods_begin/_end call overridden_methods() instead, and have overridden_methods() be the one that does the lookup. This way we have a single place where the lookup happens. It would also make overridden_methods() faster. http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet updated this revision to Diff 56006. courbet marked an inline comment as done. courbet added a comment. implement overridden_methods_begin()/end() in terms of overridden_methods(). 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>("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"; 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: lib/AST/DeclCXX.cpp === --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -1622,6 +1622,12 @@ return getASTContext().overridden_methods_size(this); } +const ArrayRef +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/AST/ASTContext.cpp === --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -1259,32 +1259,26 @@ 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(); + return overridden_methods(Method).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(); + return overridden_methods(Method).end(); } unsigned ASTContext::overridden_methods_size(cons
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
aaron.ballman added inline comments. Comment at: include/clang/AST/ASTContext.h:824 @@ -823,1 +823,3 @@ unsigned overridden_methods_size(const CXXMethodDecl *Method) const; + const ArrayRef overridden_methods( + const CXXMethodDecl *Method) const; This is too tight of a coupling to the underlying datatype. It should return `iterator_range` Comment at: include/clang/AST/DeclCXX.h:1830 @@ -1829,2 +1829,3 @@ unsigned size_overridden_methods() const; + const ArrayRef overridden_methods() const; This should return `iterator_range` http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet added inline comments. Comment at: include/clang/AST/ASTContext.h:824 @@ -823,1 +823,3 @@ unsigned overridden_methods_size(const CXXMethodDecl *Method) const; + const ArrayRef overridden_methods( + const CXXMethodDecl *Method) const; aaron.ballman wrote: > This is too tight of a coupling to the underlying datatype. It should return > `iterator_range` This is the exact opposite of the change that Samuel just requested (implementing the iterators in term of the ArrayRef getter). I don't have a strong opinion on this, but could you two agree on the desired API ? http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
aaron.ballman added inline comments. Comment at: include/clang/AST/ASTContext.h:824 @@ -823,1 +823,3 @@ unsigned overridden_methods_size(const CXXMethodDecl *Method) const; + const ArrayRef overridden_methods( + const CXXMethodDecl *Method) const; courbet wrote: > aaron.ballman wrote: > > This is too tight of a coupling to the underlying datatype. It should > > return `iterator_range` > This is the exact opposite of the change that Samuel just requested > (implementing the iterators in term of the ArrayRef getter). I don't have a > strong opinion on this, but could you two agree on the desired API ? I hadn't noticed that we disagreed, sorry for the conflicting advice. However, I strongly think that we should use an abstraction, and that ArrayRef is too concrete. FWIW, we use iterator_range in almost every other case in the code base when we refactored to rangify code. http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet added inline comments. Comment at: include/clang/AST/ASTContext.h:824 @@ -823,1 +823,3 @@ unsigned overridden_methods_size(const CXXMethodDecl *Method) const; + const ArrayRef overridden_methods( + const CXXMethodDecl *Method) const; aaron.ballman wrote: > courbet wrote: > > aaron.ballman wrote: > > > This is too tight of a coupling to the underlying datatype. It should > > > return `iterator_range` > > This is the exact opposite of the change that Samuel just requested > > (implementing the iterators in term of the ArrayRef getter). I don't have a > > strong opinion on this, but could you two agree on the desired API ? > I hadn't noticed that we disagreed, sorry for the conflicting advice. > However, I strongly think that we should use an abstraction, and that > ArrayRef is too concrete. FWIW, we use iterator_range in almost every other > case in the code base when we refactored to rangify code. Samuel, are you OK with this (reverting the last change and using iterator_range instead of ArrayRef) ? http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet updated this revision to Diff 59502. courbet added a comment. Rebase on origin/master 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 unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Index: unittests/ASTMatchers/ASTMatchersTraversalTest.cpp === --- unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -1997,5 +1997,49 @@ EXPECT_TRUE(notMatches(CppString2, returnStmt(forFunction(hasName("F"); } +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"))); +} + } // namespace ast_matchers } // namespace clang Index: lib/AST/DeclCXX.cpp === --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -1635,6 +1635,13 @@ return getASTContext().overridden_methods_size(this); } +CXXMethodDecl::overridden_method_range +CXXMethodDecl::overridden_methods() const { + if (isa(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 @@ -1254,34 +1254,37 @@ ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { - llvm::DenseMap::const_iterator Pos -= OverriddenMethods.find(Method->getCanonicalDecl()); + llvm::DenseMap::const_iterator Pos = + 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_iterator Pos -= OverriddenMethods.find(Method->getCanonicalDecl()); + llvm::DenseMap::const_iterator Pos = + 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_iterator Pos -= OverriddenMethods.find(Method->getCanonicalDecl()); + llvm::DenseMap::const_iterator Pos = + 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
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet added a comment. @sbenza @aaron.ballman I don't have write access. Can one of you submit this on my behalf ? Thanks ! http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet added a comment. That could work :) I'm not sure my commit history is considered a "track record of submitting high quality patches" but I'll give it a try. http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
Just ask Chris for the access :) 03.06.2016 11:26 AM "Clement Courbet via cfe-commits" < cfe-commits@lists.llvm.org> napisaĆ(a): > courbet added a comment. > > @sbenza @aaron.ballman I don't have write access. Can one of you submit > this on my behalf ? Thanks ! > > > http://reviews.llvm.org/D19324 > > > > ___ > cfe-commits mailing list > cfe-commits@lists.llvm.org > http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits > ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
Re: [PATCH] D19324: [ASTMatchers] new forEachOverriden matcher
courbet closed this revision. courbet added a comment. This was submitted as r272386. http://reviews.llvm.org/D19324 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits