diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -1226,6 +1226,11 @@ +Matcher<Stmt>fixedPointLiteralMatcher<FixedPointLiteral>... +
Matches fixed point literals
+
+ + Matcher<Stmt>floatLiteralMatcher<FloatingLiteral>...
Matches float literals of all sizes / encodings, e.g.
 1.0, 1.0f, 1.0L and 1e10.
@@ -5219,6 +5224,43 @@
 
+Matcher<CXXBaseSpecifier>hasClassMatcher<CXXRecordDecl> InnerMatcher +
Matches if the Base specifier refers to the given class matcher.
+
+Example matches class Derived
+(matcher = cxxRecordDecl(hasAnyBase(hasClass(hasName("Base")))))
+class Base {};
+class Derived : Base {};
+
+ + +Matcher<CXXBaseSpecifier>hasClassOrClassTemplateMatcher<CXXRecordDecl> InnerMatcher +
Matches if the Base specifier refers to the given class or class template
+matcher.
+
+Example
+(matcher = cxxRecordDecl(hasAnyBase(
+              hasClassOrClassTemplate(hasAnyName("Base", "TBase")))))
+class Base {};
+template<class T> class TBase {};
+class A : Base {}; // Matches.
+class B : TBase<int> {}; // Matches.
+template <class T> C : TBase<C> {}; // Matches.
+
+ + +Matcher<CXXBaseSpecifier>hasClassTemplateMatcher<ClassTemplateDecl> InnerMatcher +
Matches if the Base specifier refers to the given class template matcher.
+
+Example
+(matcher = cxxRecordDecl(hasAnyBase(
+              hasClassTemplate(hasTemplatedDecl(hasName("Base"))))))
+template<class T> class Base {};
+template<class T> class Derived : Base<T>{}; // Matches.
+class NonDepDerived : Base<int> {}; // No match.
+
+ + Matcher<CXXBaseSpecifier>hasTypeMatcher<Decl> InnerMatcher
Overloaded to match the declaration of the expression's or value
 declaration's type.
@@ -5632,18 +5674,33 @@
 Matcher<CXXRecordDecl>hasAnyBaseMatcher<CXXBaseSpecifier> BaseSpecMatcher
 
Matches C++ classes that have a direct or indirect base matching BaseSpecMatcher.
 
-Example matches DirectlyDerived, IndirectlyDerived (BaseSpecMatcher ==
-hasType(cxxRecordDecl(hasName("SpecialBase")))) class Foo;
+Example:
+matcher hasAnyBase(hasClass(hasName("SpecialBase")))
+  class Foo;
   class Bar : Foo {};
   class Baz : Bar {};
   class SpecialBase;
-  class DirectlyDerived : SpecialBase {};  // directly derived
-  class IndirectlyDerived : DirectlyDerived {};  // indirectly derived
+  class Proxy : SpecialBase {};  // matches Proxy
+  class IndirectlyDerived : Proxy {};  //matches IndirectlyDerived
 
 FIXME: Refactor this and isDerivedFrom to reuse implementation.
 
+Matcher<CXXRecordDecl>hasDirectBaseMatcher<CXXBaseSpecifier> BaseSpecMatcher +
Matches C++ classes that have a direct base matching BaseSpecMatcher.
+
+Example:
+matcher hasDirectBase(hasClass(hasName("SpecialBase")))
+  class Foo;
+  class Bar : Foo {};
+  class Baz : Bar {};
+  class SpecialBase;
+  class Proxy : SpecialBase {};  // matches Proxy
+  class IndirectlyDerived : Proxy {};  // doesn't match
+
+ + Matcher<CXXRecordDecl>hasMethodMatcher<CXXMethodDecl> InnerMatcher
Matches the first method of a class or struct that satisfies InnerMatcher.
 
@@ -5868,6 +5925,14 @@
 
+Matcher<ClassTemplateDecl>hasTemplatedDeclMatcher<CXXRecordDecl> InnerMatcher +
Matches the underlying class declaration or a class template declaration.
+
+Using (matcher = classTemplateDecl(hasTemplatedDecl(hasName("A"))))
+  template<typename T> Class A {}; // matches
+
+ + Matcher<ClassTemplateSpecializationDecl>hasAnyTemplateArgumentMatcher<TemplateArgument> InnerMatcher
Matches classTemplateSpecializations, templateSpecializationType and
 functionDecl that have at least one TemplateArgument matching the given
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -694,6 +694,18 @@
           InnerMatcher.matches(*Decl, Finder, Builder));
 }
 
+/// Matches the underlying class declaration or a class template declaration.
+///
+/// Using (matcher = classTemplateDecl(hasTemplatedDecl(hasName("A"))))
+/// \code
+///   template Class A {}; // matches
+/// \endcode
+AST_MATCHER_P(ClassTemplateDecl, hasTemplatedDecl,
+              internal::Matcher, InnerMatcher) {
+  const CXXRecordDecl *RD = Node.getTemplatedDecl();
+  return RD && InnerMatcher.matches(*RD, Finder, Builder);
+}
+
 /// Matches a declaration that has been implicitly added
 /// by the compiler (eg. implicit default/copy constructors).
 AST_MATCHER(Decl, isImplicit) {
@@ -2864,7 +2876,7 @@
 /// BaseSpecMatcher.
 ///
 /// Example:
-/// matcher hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase")))))
+/// matcher hasAnyBase(hasClass(hasName("SpecialBase")))
 /// \code
 ///   class Foo;
 ///   class Bar : Foo {};
@@ -2880,6 +2892,27 @@
   return internal::matchesAnyBase(Node, BaseSpecMatcher, Finder, Builder);
 }
 
+/// Matches C++ classes that have a direct base matching \p BaseSpecMatcher.
+///
+/// Example:
+/// matcher hasDirectBase(hasClass(hasName("SpecialBase")))
+/// \code
+///   class Foo;
+///   class Bar : Foo {};
+///   class Baz : Bar {};
+///   class SpecialBase;
+///   class Proxy : SpecialBase {};  // matches Proxy
+///   class IndirectlyDerived : Proxy {};  // doesn't match
+/// \endcode
+AST_MATCHER_P(CXXRecordDecl, hasDirectBase, internal::Matcher,
+              BaseSpecMatcher) {
+
+  return Node.hasDefinition() &&
+         llvm::any_of(Node.bases(), [&](const CXXBaseSpecifier &Base) {
+           return BaseSpecMatcher.matches(Base, Finder, Builder);
+         });
+}
+
 /// Similar to \c isDerivedFrom(), but also matches classes that directly
 /// match \c Base.
 AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
@@ -3530,6 +3563,80 @@
   return false;
 }
 
+/// Matches if the Base specifier refers to the given class matcher.
+///
+/// Example matches class Derived
+/// (matcher = cxxRecordDecl(hasAnyBase(hasClass(hasName("Base")))))
+/// \code
+/// class Base {};
+/// class Derived : Base {};
+/// \endcode
+AST_MATCHER_P(CXXBaseSpecifier, hasClass, internal::Matcher,
+              InnerMatcher) {
+  QualType QT = Node.getType();
+  assert(!QT.isNull() && "CXXBaseSpecifier shouldn't have a null type");
+  if (auto *RD = QT->getAsCXXRecordDecl()) {
+    return InnerMatcher.matches(*RD, Finder, Builder);
+  }
+  return false;
+}
+
+/// Matches if the Base specifier refers to the given class template matcher.
+///
+/// Example
+/// (matcher = cxxRecordDecl(hasAnyBase(
+///               hasClassTemplate(hasTemplatedDecl(hasName("Base"))))))
+/// \code
+/// template class Base {};
+/// template class Derived : Base{}; // Matches.
+/// class NonDepDerived : Base {}; // No match.
+/// \endcode
+AST_MATCHER_P(CXXBaseSpecifier, hasClassTemplate,
+              internal::Matcher, InnerMatcher) {
+  QualType QT = Node.getType();
+  assert(!QT.isNull() && "CXXBaseSpecifier shouldn't have a null type");
+  if (const auto *TST = QT->getAs()) {
+    if (!TST->isDependentType())
+      return false;
+    if (const auto *TD = llvm::dyn_cast_or_null(
+            TST->getTemplateName().getAsTemplateDecl()))
+      return InnerMatcher.matches(*TD, Finder, Builder);
+  }
+  return false;
+}
+
+/// Matches if the Base specifier refers to the given class or class template
+/// matcher.
+///
+/// Example
+/// (matcher = cxxRecordDecl(hasAnyBase(
+///               hasClassOrClassTemplate(hasAnyName("Base", "TBase")))))
+/// \code
+/// class Base {};
+/// template class TBase {};
+/// class A : Base {}; // Matches.
+/// class B : TBase {}; // Matches.
+/// template  C : TBase {}; // Matches.
+/// \endcode
+AST_MATCHER_P(CXXBaseSpecifier, hasClassOrClassTemplate,
+              internal::Matcher, InnerMatcher) {
+  QualType QT = Node.getType();
+  QT->dump();
+  assert(!QT.isNull() && "CXXBaseSpecifier shouldn't have a null type");
+  if (auto *RD = QT->getAsCXXRecordDecl()) {
+    return InnerMatcher.matches(*RD, Finder, Builder);
+  } else if (const auto *TST = QT->getAs()) {
+    if (!TST->isDependentType())
+      return false;
+    if (const auto *TD = llvm::dyn_cast_or_null(
+            TST->getTemplateName().getAsTemplateDecl())) {
+      if (const CXXRecordDecl *RD = TD->getTemplatedDecl())
+        return InnerMatcher.matches(*RD, Finder, Builder);
+    }
+  }
+  return false;
+}
+
 /// Matches if the type location of the declarator decl's type matches
 /// the inner matcher.
 ///
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -261,6 +261,9 @@
   REGISTER_MATCHER(hasCanonicalType);
   REGISTER_MATCHER(hasCaseConstant);
   REGISTER_MATCHER(hasCastKind);
+  REGISTER_MATCHER(hasClass);
+  REGISTER_MATCHER(hasClassOrClassTemplate);
+  REGISTER_MATCHER(hasClassTemplate);
   REGISTER_MATCHER(hasCondition);
   REGISTER_MATCHER(hasConditionVariableStatement);
   REGISTER_MATCHER(hasDecayedType);
@@ -271,6 +274,7 @@
   REGISTER_MATCHER(hasDefinition);
   REGISTER_MATCHER(hasDescendant);
   REGISTER_MATCHER(hasDestinationType);
+  REGISTER_MATCHER(hasDirectBase);
   REGISTER_MATCHER(hasDynamicExceptionSpec);
   REGISTER_MATCHER(hasEitherOperand);
   REGISTER_MATCHER(hasElementType);
@@ -320,6 +324,7 @@
   REGISTER_MATCHER(hasSyntacticForm);
   REGISTER_MATCHER(hasTargetDecl);
   REGISTER_MATCHER(hasTemplateArgument);
+  REGISTER_MATCHER(hasTemplatedDecl);
   REGISTER_MATCHER(hasThen);
   REGISTER_MATCHER(hasThreadStorageDuration);
   REGISTER_MATCHER(hasTrailingReturn);
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2997,26 +2997,24 @@
 }
 
 TEST(HasAnyBase, DirectBase) {
-  EXPECT_TRUE(matches(
-      "struct Base {};"
-      "struct ExpectedMatch : Base {};",
-      cxxRecordDecl(hasName("ExpectedMatch"),
-                    hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))));
+  EXPECT_TRUE(matches("struct Base {};"
+                      "struct ExpectedMatch : Base {};",
+                      cxxRecordDecl(hasName("ExpectedMatch"),
+                                    hasAnyBase(hasClass(hasName("Base"))))));
 }
 
 TEST(HasAnyBase, IndirectBase) {
-  EXPECT_TRUE(matches(
-      "struct Base {};"
-      "struct Intermediate : Base {};"
-      "struct ExpectedMatch : Intermediate {};",
-      cxxRecordDecl(hasName("ExpectedMatch"),
-                    hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))));
+  EXPECT_TRUE(matches("struct Base {};"
+                      "struct Intermediate : Base {};"
+                      "struct ExpectedMatch : Intermediate {};",
+                      cxxRecordDecl(hasName("ExpectedMatch"),
+                                    hasAnyBase(hasClass(hasName("Base"))))));
 }
 
 TEST(HasAnyBase, NoBase) {
   EXPECT_TRUE(notMatches("struct Foo {};"
                          "struct Bar {};",
-                         cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl())))));
+                         cxxRecordDecl(hasAnyBase(hasClass(cxxRecordDecl())))));
 }
 
 TEST(IsPublicBase, Public) {
@@ -3117,5 +3115,94 @@
                          cxxRecordDecl(hasAnyBase(isVirtual()))));
 }
 
+TEST(BaseSpecifier, hasDirectBase) {
+  EXPECT_TRUE(matches(
+      R"cc(
+    class Base {};
+    class Derived : Base{};
+    )cc",
+      cxxRecordDecl(hasName("Derived"),
+                    hasDirectBase(hasClass(hasName("Base"))))));
+
+  StringRef MultiDerived = R"cc(
+    class Base {};
+    class Base2 {};
+    class Derived : Base, Base2{};
+    )cc";
+
+  EXPECT_TRUE(matches(MultiDerived,
+                      cxxRecordDecl(hasName("Derived"),
+                                    hasDirectBase(hasClass(hasName("Base"))))));
+  EXPECT_TRUE(matches(
+      MultiDerived, cxxRecordDecl(hasName("Derived"),
+                                  hasDirectBase(hasClass(hasName("Base2"))))));
+
+  StringRef Indirect = R"cc(
+    class Base {};
+    class Intermediate : Base {};
+    class Derived : Intermediate{};
+    )cc";
+
+  EXPECT_TRUE(
+      matches(Indirect,
+              cxxRecordDecl(hasName("Derived"),
+                            hasDirectBase(hasClass(hasName("Intermediate"))))));
+  EXPECT_TRUE(notMatches(
+      Indirect, cxxRecordDecl(hasName("Derived"),
+                              hasDirectBase(hasClass(hasName("Base"))))));
+}
+
+TEST(BaseSpecifier, HasClassTemplate) {
+  DeclarationMatcher Matcher = cxxRecordDecl(
+      hasDirectBase(hasClassTemplate(hasTemplatedDecl(hasName("Base")))));
+  EXPECT_TRUE(matches(R"cc(
+    template class Base {};
+    template class Derived : Base {};
+  )cc",
+                      Matcher));
+  EXPECT_FALSE(matches(R"cc(
+    template class Base {};
+    template class Derived : Base {};
+  )cc",
+                       Matcher));
+}
+
+TEST(BaseSpecifier, HasClassOrClassTemplate) {
+  DeclarationMatcher Matcher =
+      cxxRecordDecl(hasDirectBase(hasClassOrClassTemplate(hasName("Base"))));
+  EXPECT_TRUE(matches(R"cc(
+    template class Base {};
+    template class Derived : Base {};
+  )cc",
+                      Matcher));
+  EXPECT_TRUE(matches(R"cc(
+    template class Base {};
+    template class Derived : Base {};
+  )cc",
+                      Matcher));
+  EXPECT_TRUE(matches(R"cc(
+    template class Base {};
+    class Derived : Base {};
+  )cc",
+                      Matcher));
+  EXPECT_TRUE(matches(R"cc(
+    class Base {};
+    template class Derived : Base {};
+  )cc",
+                      Matcher));
+  EXPECT_TRUE(matches(R"cc(
+    class Base {};
+    class Derived : Base {};
+  )cc",
+                      Matcher));
+}
+
+TEST(ClassTemplateDecl, HasTemplatedDecl) {
+  DeclarationMatcher Matcher =
+      classTemplateDecl(hasTemplatedDecl(hasName("A")));
+  EXPECT_TRUE(matches("template class A {};", Matcher));
+  EXPECT_TRUE(notMatches("class A {};", Matcher));
+}
+
 } // namespace ast_matchers
 } // namespace clang