Make the isDerivedFrom matcher more generic.

It now accepts an arbitrary inner matcher but is fully backwards
compatible.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@160348 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index fceea21..d2ff604 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -839,14 +839,11 @@
 }
 
 /// \brief Matches C++ classes that are directly or indirectly derived from
-/// the given base class.
+/// a class matching \c Base.
 ///
 /// Note that a class is considered to be also derived from itself.
-/// The parameter specified the name of the base type (either a class or a
-/// typedef), and does not allow structural matches for namespaces or template
-/// type parameters.
 ///
-/// Example matches X, Y, Z, C (Base == "X")
+/// Example matches X, Y, Z, C (Base == hasName("X"))
 ///   class X;                // A class is considered to be derived from itself
 ///   class Y : public X {};  // directly derived
 ///   class Z : public Y {};  // indirectly derived
@@ -854,13 +851,19 @@
 ///   typedef A B;
 ///   class C : public B {};  // derived from a typedef of X
 ///
-/// In the following example, Bar matches isDerivedFrom("X"):
+/// In the following example, Bar matches isDerivedFrom(hasName("X")):
 ///   class Foo;
 ///   typedef Foo X;
 ///   class Bar : public Foo {};  // derived from a type that X is a typedef of
-AST_MATCHER_P(CXXRecordDecl, isDerivedFrom, std::string, Base) {
-  assert(!Base.empty());
-  return Finder->classIsDerivedFrom(&Node, Base);
+AST_MATCHER_P(CXXRecordDecl, isDerivedFrom,
+              internal::Matcher<NamedDecl>, Base) {
+  return Finder->classIsDerivedFrom(&Node, Base, Builder);
+}
+
+/// \brief Overloaded method as shortcut for \c isDerivedFrom(hasName(...)).
+inline internal::Matcher<CXXRecordDecl> isDerivedFrom(StringRef BaseName) {
+  assert(!BaseName.empty());
+  return isDerivedFrom(hasName(BaseName));
 }
 
 /// \brief Matches AST nodes that have child AST nodes that match the
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index 5039c52..4d04401 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -411,11 +411,12 @@
   virtual ~ASTMatchFinder() {}
 
   /// \brief Returns true if the given class is directly or indirectly derived
-  /// from a base type with the given name.
+  /// from a base type matching \c base.
   ///
   /// A class is considered to be also derived from itself.
   virtual bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
-                                  StringRef BaseName) const = 0;
+                                  const Matcher<NamedDecl> &Base,
+                                  BoundNodesTreeBuilder *Builder) = 0;
 
   // FIXME: Implement for other base nodes.
   virtual bool matchesChildOf(const Decl &DeclNode,
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
index 8aad8dd..a58d4f0 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -27,15 +27,6 @@
 namespace internal {
 namespace {
 
-// Returns the value that 'AMap' maps 'Key' to, or NULL if 'Key' is
-// not in 'AMap'.
-template <typename Map>
-static const typename Map::mapped_type *
-find(const Map &AMap, const typename Map::key_type &Key) {
-  typename Map::const_iterator It = AMap.find(Key);
-  return It == AMap.end() ? NULL : &It->second;
-}
-
 // We use memoization to avoid running the same matcher on the same
 // AST node twice.  This pair is the key for looking up match
 // result.  It consists of an ID of the MatcherInterface (for
@@ -244,8 +235,7 @@
     const Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();
     const Type *CanonicalType =  // root of the typedef tree
         ActiveASTContext->getCanonicalType(TypeNode);
-    TypeToUnqualifiedAliases[CanonicalType].insert(
-        DeclNode->getName().str());
+    TypeAliases[CanonicalType].insert(DeclNode);
     return true;
   }
 
@@ -289,7 +279,8 @@
   }
 
   virtual bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
-                                  StringRef BaseName) const;
+                                  const Matcher<NamedDecl> &Base,
+                                  BoundNodesTreeBuilder *Builder);
 
   // Implements ASTMatchFinder::MatchesChildOf.
   virtual bool matchesChildOf(const Decl &DeclNode,
@@ -347,16 +338,20 @@
     MatchFinder::MatchCallback* Callback;
   };
 
-  // Returns true if 'TypeNode' is also known by the name 'Name'.  In other
-  // words, there is a type (including typedef) with the name 'Name'
-  // that is equal to 'TypeNode'.
-  bool typeHasAlias(const Type *TypeNode,
-                    StringRef Name) const {
+  // Returns true if 'TypeNode' has an alias that matches the given matcher.
+  bool typeHasMatchingAlias(const Type *TypeNode,
+                            const Matcher<NamedDecl> Matcher,
+                            BoundNodesTreeBuilder *Builder) {
     const Type *const CanonicalType =
       ActiveASTContext->getCanonicalType(TypeNode);
-    const std::set<std::string> *UnqualifiedAlias =
-      find(TypeToUnqualifiedAliases, CanonicalType);
-    return UnqualifiedAlias != NULL && UnqualifiedAlias->count(Name) > 0;
+    const std::set<const TypedefDecl*> &Aliases = TypeAliases[CanonicalType];
+    for (std::set<const TypedefDecl*>::const_iterator
+           It = Aliases.begin(), End = Aliases.end();
+         It != End; ++It) {
+      if (Matcher.matches(**It, this, Builder))
+        return true;
+    }
+    return false;
   }
 
   // Matches all registered matchers on the given node and calls the
@@ -380,9 +375,8 @@
                MatchFinder::MatchCallback*> > *const Triggers;
   ASTContext *ActiveASTContext;
 
-  // Maps a canonical type to the names of its typedefs.
-  llvm::DenseMap<const Type*, std::set<std::string> >
-    TypeToUnqualifiedAliases;
+  // Maps a canonical type to its TypedefDecls.
+  llvm::DenseMap<const Type*, std::set<const TypedefDecl*> > TypeAliases;
 
   // Maps (matcher, node) -> the match result for memoization.
   typedef llvm::DenseMap<UntypedMatchInput, MemoizedMatchResult> MemoizationMap;
@@ -392,39 +386,36 @@
 // 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.
-bool
-MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
-                                    StringRef BaseName) const {
-  if (Declaration->getName() == BaseName) {
+bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
+                                         const Matcher<NamedDecl> &Base,
+                                         BoundNodesTreeBuilder *Builder) {
+  if (Base.matches(*Declaration, this, Builder))
     return true;
-  }
-  if (!Declaration->hasDefinition()) {
+  if (!Declaration->hasDefinition())
     return false;
-  }
   typedef CXXRecordDecl::base_class_const_iterator BaseIterator;
   for (BaseIterator It = Declaration->bases_begin(),
                     End = Declaration->bases_end(); It != End; ++It) {
     const Type *TypeNode = It->getType().getTypePtr();
 
-    if (typeHasAlias(TypeNode, BaseName))
+    if (typeHasMatchingAlias(TypeNode, Base, Builder))
       return true;
 
     // Type::getAs<...>() drills through typedefs.
     if (TypeNode->getAs<DependentNameType>() != NULL ||
-        TypeNode->getAs<TemplateTypeParmType>() != NULL) {
+        TypeNode->getAs<TemplateTypeParmType>() != NULL)
       // Dependent names and template TypeNode parameters will be matched when
       // the template is instantiated.
       continue;
-    }
     CXXRecordDecl *ClassDecl = NULL;
     TemplateSpecializationType const *TemplateType =
       TypeNode->getAs<TemplateSpecializationType>();
     if (TemplateType != NULL) {
-      if (TemplateType->getTemplateName().isDependent()) {
+      if (TemplateType->getTemplateName().isDependent())
         // Dependent template specializations will be matched when the
         // template is instantiated.
         continue;
-      }
+
       // For template specialization types which are specializing a template
       // declaration which is an explicit or partial specialization of another
       // template declaration, getAsCXXRecordDecl() returns the corresponding
@@ -448,9 +439,8 @@
     }
     assert(ClassDecl != NULL);
     assert(ClassDecl != Declaration);
-    if (classIsDerivedFrom(ClassDecl, BaseName)) {
+    if (classIsDerivedFrom(ClassDecl, Base, Builder))
       return true;
-    }
   }
   return false;
 }
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index 597cf6f..5791932 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -245,7 +245,7 @@
       variable(
           hasName("z_char"),
           hasInitializer(hasType(record(isDerivedFrom("Base1"),
-                                       isDerivedFrom("Base2")))))));
+                                        isDerivedFrom("Base2")))))));
 
   const char *RecursiveTemplateTwoParameters =
       "class Base1 {}; class Base2 {};"
@@ -273,7 +273,17 @@
       variable(
           hasName("z_char"),
           hasInitializer(hasType(record(isDerivedFrom("Base1"),
-                                       isDerivedFrom("Base2")))))));
+                                        isDerivedFrom("Base2")))))));
+  EXPECT_TRUE(matches(
+      "namespace ns { class X {}; class Y : public X {}; }",
+      record(isDerivedFrom("::ns::X"))));
+  EXPECT_TRUE(notMatches(
+      "class X {}; class Y : public X {};",
+      record(isDerivedFrom("::ns::X"))));
+
+  EXPECT_TRUE(matches(
+      "class X {}; class Y : public X {};",
+      record(isDerivedFrom(id("test", record(hasName("X")))))));
 }
 
 TEST(AllOf, AllOverloadsWork) {