njames93 updated this revision to Diff 270000. njames93 added a comment. - Added back `hasType` overload for `CXXBaseSpecifier` - Added `hasClassTemplate` and `hasClassOrClassTemplate` matcher for `CXXBaseSpecifier` - Added `hasTemplatedDecl` for `ClassTemplateDecl`
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D81552/new/ https://reviews.llvm.org/D81552 Files: clang/docs/LibASTMatchersReference.html clang/include/clang/ASTMatchers/ASTMatchers.h clang/lib/ASTMatchers/Dynamic/Registry.cpp clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ 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<typename T> class Base {}; + template<typename T> class Derived : Base<T> {}; + )cc", + Matcher)); + EXPECT_FALSE(matches(R"cc( + template<typename T> class Base {}; + template<typename T> class Derived : Base<int> {}; + )cc", + Matcher)); +} + +TEST(BaseSpecifier, HasClassOrClassTemplate) { + DeclarationMatcher Matcher = + cxxRecordDecl(hasDirectBase(hasClassOrClassTemplate(hasName("Base")))); + EXPECT_TRUE(matches(R"cc( + template<typename T> class Base {}; + template<typename T> class Derived : Base<T> {}; + )cc", + Matcher)); + EXPECT_TRUE(matches(R"cc( + template<typename T> class Base {}; + template<typename T> class Derived : Base<int> {}; + )cc", + Matcher)); + EXPECT_TRUE(matches(R"cc( + template<typename T> class Base {}; + class Derived : Base<int> {}; + )cc", + Matcher)); + EXPECT_TRUE(matches(R"cc( + class Base {}; + template<typename T> 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 T> class A {};", Matcher)); + EXPECT_TRUE(notMatches("class A {};", Matcher)); +} + } // namespace ast_matchers } // namespace clang Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ 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); Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ 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<typename T> Class A {}; // matches +/// \endcode +AST_MATCHER_P(ClassTemplateDecl, hasTemplatedDecl, + internal::Matcher<CXXRecordDecl>, 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<CXXBaseSpecifier>, + 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<CXXRecordDecl>, + 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 T> class Base {}; +/// template<class T> class Derived : Base<T>{}; // Matches. +/// class NonDepDerived : Base<int> {}; // No match. +/// \endcode +AST_MATCHER_P(CXXBaseSpecifier, hasClassTemplate, + internal::Matcher<ClassTemplateDecl>, InnerMatcher) { + QualType QT = Node.getType(); + assert(!QT.isNull() && "CXXBaseSpecifier shouldn't have a null type"); + if (const auto *TST = QT->getAs<TemplateSpecializationType>()) { + if (!TST->isDependentType()) + return false; + if (const auto *TD = llvm::dyn_cast_or_null<ClassTemplateDecl>( + 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 T> class TBase {}; +/// class A : Base {}; // Matches. +/// class B : TBase<int> {}; // Matches. +/// template <class T> C : TBase<C> {}; // Matches. +/// \endcode +AST_MATCHER_P(CXXBaseSpecifier, hasClassOrClassTemplate, + internal::Matcher<CXXRecordDecl>, 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<TemplateSpecializationType>()) { + if (!TST->isDependentType()) + return false; + if (const auto *TD = llvm::dyn_cast_or_null<ClassTemplateDecl>( + 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. /// Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -1226,6 +1226,11 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('fixedPointLiteral0')"><a name="fixedPointLiteral0Anchor">fixedPointLiteral</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FixedPointLiteral.html">FixedPointLiteral</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="fixedPointLiteral0"><pre>Matches fixed point literals +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('floatLiteral0')"><a name="floatLiteral0Anchor">floatLiteral</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>...</td></tr> <tr><td colspan="4" class="doc" id="floatLiteral0"><pre>Matches float literals of all sizes / encodings, e.g. 1.0, 1.0f, 1.0L and 1e10. @@ -5219,6 +5224,43 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>></td><td class="name" onclick="toggle('hasClass0')"><a name="hasClass0Anchor">hasClass</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasClass0"><pre>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 {}; +</pre></td></tr> + + +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>></td><td class="name" onclick="toggle('hasClassOrClassTemplate0')"><a name="hasClassOrClassTemplate0Anchor">hasClassOrClassTemplate</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasClassOrClassTemplate0"><pre>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. +</pre></td></tr> + + +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>></td><td class="name" onclick="toggle('hasClassTemplate0')"><a name="hasClassTemplate0Anchor">hasClassTemplate</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ClassTemplateDecl.html">ClassTemplateDecl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasClassTemplate0"><pre>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. +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>></td><td class="name" onclick="toggle('hasType7')"><a name="hasType7Anchor">hasType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="hasType7"><pre>Overloaded to match the declaration of the expression's or value declaration's type. @@ -5632,18 +5674,33 @@ <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('hasAnyBase0')"><a name="hasAnyBase0Anchor">hasAnyBase</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>> BaseSpecMatcher</td></tr> <tr><td colspan="4" class="doc" id="hasAnyBase0"><pre>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. </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('hasDirectBase0')"><a name="hasDirectBase0Anchor">hasDirectBase</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>> BaseSpecMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasDirectBase0"><pre>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 +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('hasMethod0')"><a name="hasMethod0Anchor">hasMethod</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="hasMethod0"><pre>Matches the first method of a class or struct that satisfies InnerMatcher. @@ -5868,6 +5925,14 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ClassTemplateDecl.html">ClassTemplateDecl</a>></td><td class="name" onclick="toggle('hasTemplatedDecl0')"><a name="hasTemplatedDecl0Anchor">hasTemplatedDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasTemplatedDecl0"><pre>Matches the underlying class declaration or a class template declaration. + +Using (matcher = classTemplateDecl(hasTemplatedDecl(hasName("A")))) + template<typename T> Class A {}; // matches +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ClassTemplateSpecializationDecl.html">ClassTemplateSpecializationDecl</a>></td><td class="name" onclick="toggle('hasAnyTemplateArgument0')"><a name="hasAnyTemplateArgument0Anchor">hasAnyTemplateArgument</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="hasAnyTemplateArgument0"><pre>Matches classTemplateSpecializations, templateSpecializationType and functionDecl that have at least one TemplateArgument matching the given
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits