summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClement Courbet <courbet@google.com>2016-06-10 11:54:43 +0000
committerClement Courbet <courbet@google.com>2016-06-10 11:54:43 +0000
commit8251ebfac6559739a9238053a74a816dbdc54b21 (patch)
tree5226b4480583f132c446ddaf419195a6211f77ed
parentb16907f17abaa49469a5a6538a938127f247d31f (diff)
downloadbcm5719-llvm-8251ebfac6559739a9238053a74a816dbdc54b21.tar.gz
bcm5719-llvm-8251ebfac6559739a9238053a74a816dbdc54b21.zip
[ASTMatchers] New forEachOverriden matcher.
Matches methods overridden by the given method. llvm-svn: 272386
-rw-r--r--clang/docs/LibASTMatchersReference.html24
-rw-r--r--clang/include/clang/AST/ASTContext.h3
-rw-r--r--clang/include/clang/AST/DeclCXX.h3
-rw-r--r--clang/include/clang/ASTMatchers/ASTMatchers.h41
-rw-r--r--clang/lib/AST/ASTContext.cpp21
-rw-r--r--clang/lib/AST/DeclCXX.cpp7
-rw-r--r--clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp44
7 files changed, 134 insertions, 9 deletions
diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html
index 3606367d2fd..5ab35568907 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -3968,6 +3968,30 @@ matcher, or is a pointer to a type that matches the InnerMatcher.
</pre></td></tr>
+<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;</td><td class="name" onclick="toggle('forEachOverridden0')"><a name="forEachOverridden0Anchor">forEachOverridden</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt; 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&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt;</td><td class="name" onclick="toggle('ofClass0')"><a name="ofClass0Anchor">ofClass</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="ofClass0"><pre>Matches the class declaration that the given method declaration
belongs to.
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 47f89c63613..e3fc4643445 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -821,6 +821,9 @@ public:
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.
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 755542c04a1..e540f072e13 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/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"
@@ -1828,6 +1829,8 @@ public:
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.
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 712eef0d3ca..778b993bc83 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -3770,6 +3770,47 @@ AST_MATCHER_P(CXXMethodDecl, ofClass,
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
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index fa46b24e57c..67024e7c391 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1254,34 +1254,37 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst,
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());
+ llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::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 CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
- = OverriddenMethods.find(Method->getCanonicalDecl());
+ llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::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 CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
- = OverriddenMethods.find(Method->getCanonicalDecl());
+ llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::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_methods_end(Method));
+}
+
void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method,
const CXXMethodDecl *Overridden) {
assert(Method->isCanonicalDecl() && Overridden->isCanonicalDecl());
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 2a1fac8509e..83c7db88f4d 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -1635,6 +1635,13 @@ unsigned CXXMethodDecl::size_overridden_methods() const {
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*,
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index cc5cf715a70..aa861f4e4da 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1997,5 +1997,49 @@ TEST(StatementMatcher, ForFunction) {
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<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")));
+}
+
} // namespace ast_matchers
} // namespace clang
OpenPOWER on IntegriCloud