aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h18
-rw-r--r--lib/ASTMatchers/ASTMatchFinder.cpp12
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.cpp14
3 files changed, 31 insertions, 13 deletions
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 23743e529b..91a3ecfd49 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -1108,11 +1108,11 @@ AST_MATCHER_P(CXXOperatorCallExpr,
/// \brief Matches C++ classes that are directly or indirectly derived from
/// a class matching \c Base.
///
-/// Note that a class is considered to be also derived from itself.
+/// Note that a class is not considered to be derived from itself.
///
-/// Example matches X, Y, Z, C (Base == hasName("X"))
+/// Example matches Y, Z, C (Base == hasName("X"))
/// \code
-/// class X; // A class is considered to be derived from itself
+/// class X;
/// class Y : public X {}; // directly derived
/// class Z : public Y {}; // indirectly derived
/// typedef X A;
@@ -1137,6 +1137,18 @@ inline internal::Matcher<CXXRecordDecl> isDerivedFrom(StringRef BaseName) {
return isDerivedFrom(hasName(BaseName));
}
+/// \brief Similar to \c isDerivedFrom(), but also matches classes that directly
+/// match \c Base.
+inline internal::Matcher<CXXRecordDecl> isA(internal::Matcher<NamedDecl> Base) {
+ return anyOf(Base, isDerivedFrom(Base));
+}
+
+/// \brief Overloaded method as shortcut for \c isA(hasName(...)).
+inline internal::Matcher<CXXRecordDecl> isA(StringRef BaseName) {
+ assert(!BaseName.empty());
+ return isA(hasName(BaseName));
+}
+
/// \brief Matches AST nodes that have child AST nodes that match the
/// provided matcher.
///
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
index 54b05b3939..afab1df4a6 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -277,7 +277,7 @@ public:
bool VisitTypedefDecl(TypedefDecl *DeclNode) {
// When we see 'typedef A B', we add name 'B' to the set of names
// A's canonical type maps to. This is necessary for implementing
- // IsDerivedFrom(x) properly, where x can be the name of the base
+ // isDerivedFrom(x) properly, where x can be the name of the base
// class or any of its aliases.
//
// In general, the is-alias-of (as defined by typedefs) relation
@@ -298,7 +298,7 @@ public:
// `- E
//
// It is wrong to assume that the relation is a chain. A correct
- // implementation of IsDerivedFrom() needs to recognize that B and
+ // implementation of isDerivedFrom() needs to recognize that B and
// E are aliases, even though neither is a typedef of the other.
// Therefore, we cannot simply walk through one typedef chain to
// find out whether the type name matches.
@@ -468,13 +468,11 @@ private:
};
// Returns true if the given class is directly or indirectly derived
-// from a base type with the given name. A class is considered to be
-// also derived from itself.
+// from a base type with the given name. A class is not considered to be
+// derived from itself.
bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
const Matcher<NamedDecl> &Base,
BoundNodesTreeBuilder *Builder) {
- if (Base.matches(*Declaration, this, Builder))
- return true;
if (!Declaration->hasDefinition())
return false;
typedef CXXRecordDecl::base_class_const_iterator BaseIterator;
@@ -523,6 +521,8 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
}
assert(ClassDecl != NULL);
assert(ClassDecl != Declaration);
+ if (Base.matches(*ClassDecl, this, Builder))
+ return true;
if (classIsDerivedFrom(ClassDecl, Base, Builder))
return true;
}
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index 7adc71837d..55e22e927a 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -101,12 +101,19 @@ TEST(DeclarationMatcher, ClassIsDerived) {
DeclarationMatcher IsDerivedFromX = recordDecl(isDerivedFrom("X"));
EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsDerivedFromX));
- EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsDerivedFromX));
- EXPECT_TRUE(matches("class X {};", IsDerivedFromX));
- EXPECT_TRUE(matches("class X;", IsDerivedFromX));
+ EXPECT_TRUE(notMatches("class X {};", IsDerivedFromX));
+ EXPECT_TRUE(notMatches("class X;", IsDerivedFromX));
EXPECT_TRUE(notMatches("class Y;", IsDerivedFromX));
EXPECT_TRUE(notMatches("", IsDerivedFromX));
+ DeclarationMatcher IsAX = recordDecl(isA("X"));
+
+ EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsAX));
+ EXPECT_TRUE(matches("class X {};", IsAX));
+ EXPECT_TRUE(matches("class X;", IsAX));
+ EXPECT_TRUE(notMatches("class Y;", IsAX));
+ EXPECT_TRUE(notMatches("", IsAX));
+
DeclarationMatcher ZIsDerivedFromX =
recordDecl(hasName("Z"), isDerivedFrom("X"));
EXPECT_TRUE(
@@ -458,7 +465,6 @@ TEST(DeclarationMatcher, MatchNot) {
DeclarationMatcher NotClassX =
recordDecl(
isDerivedFrom("Y"),
- unless(hasName("Y")),
unless(hasName("X")));
EXPECT_TRUE(notMatches("", NotClassX));
EXPECT_TRUE(notMatches("class Y {};", NotClassX));