diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 33ef3dc8d6e0..55f0772bd80a 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -164,6 +164,14 @@ const internal::VariadicDynCastAllOfMatcher< Decl, CXXRecordDecl> record; +/// \brief Matches C++ class template declarations. +/// +/// Example matches Z +/// template class Z {}; +const internal::VariadicDynCastAllOfMatcher< + Decl, + ClassTemplateDecl> classTemplate; + /// \brief Matches C++ class template specializations. /// /// Given @@ -385,6 +393,13 @@ const internal::VariadicDynCastAllOfMatcher field; /// void f(); const internal::VariadicDynCastAllOfMatcher function; +/// \brief Matches C++ function template declarations. +/// +/// Example matches f +/// template void f(T t) {} +const internal::VariadicDynCastAllOfMatcher< + Decl, + FunctionTemplateDecl> functionTemplate; /// \brief Matches statements. /// @@ -1941,6 +1956,21 @@ isTemplateInstantiation() { internal::IsTemplateInstantiationMatcher>(); } +/// \brief Matches explicit template specializations of function, class, or +/// static member variable template instantiations. +/// +/// Given +/// template void A(T t) { } +/// template<> void A(int N) { } +/// function(isExplicitSpecialization()) +/// matches the specialization A(). +inline internal::PolymorphicMatcherWithParam0< + internal::IsExplicitTemplateSpecializationMatcher> +isExplicitTemplateSpecialization() { + return internal::PolymorphicMatcherWithParam0< + internal::IsExplicitTemplateSpecializationMatcher>(); +} + } // end namespace ast_matchers } // end namespace clang diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index 3f5568521c0e..a94e925d5954 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -858,6 +858,23 @@ class IsTemplateInstantiationMatcher : public MatcherInterface { } }; +/// \brief Matches on explicit template specializations for FunctionDecl, +/// VarDecl or CXXRecordDecl nodes. +template +class IsExplicitTemplateSpecializationMatcher : public MatcherInterface { + TOOLING_COMPILE_ASSERT((llvm::is_base_of::value) || + (llvm::is_base_of::value) || + (llvm::is_base_of::value), + requires_getTemplateSpecializationKind_method); + public: + virtual bool matches(const T& Node, + ASTMatchFinder* Finder, + BoundNodesTreeBuilder* Builder) const { + return (Node.getTemplateSpecializationKind() == TSK_ExplicitSpecialization); + } +}; + + class IsArrowMatcher : public SingleNodeMatcherInterface { public: virtual bool matchesNode(const MemberExpr &Node) const { diff --git a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp index adf0e9479f08..dcebbc9f3d6e 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -292,6 +292,32 @@ TEST(DeclarationMatcher, ClassIsDerived) { record(isDerivedFrom(record(hasName("X")).bind("test"))))); } +TEST(ClassTemplate, DoesNotMatchClass) { + DeclarationMatcher ClassX = classTemplate(hasName("X")); + EXPECT_TRUE(notMatches("class X;", ClassX)); + EXPECT_TRUE(notMatches("class X {};", ClassX)); +} + +TEST(ClassTemplate, MatchesClassTemplate) { + DeclarationMatcher ClassX = classTemplate(hasName("X")); + EXPECT_TRUE(matches("template class X {};", ClassX)); + EXPECT_TRUE(matches("class Z { template class X {}; };", ClassX)); +} + +TEST(ClassTemplate, DoesNotMatchClassTemplateExplicitSpecialization) { + EXPECT_TRUE(notMatches("template class X { };" + "template<> class X { int a; };", + classTemplate(hasName("X"), + hasDescendant(field(hasName("a")))))); +} + +TEST(ClassTemplate, DoesNotMatchClassTemplatePartialSpecialization) { + EXPECT_TRUE(notMatches("template class X { };" + "template class X { int a; };", + classTemplate(hasName("X"), + hasDescendant(field(hasName("a")))))); +} + TEST(AllOf, AllOverloadsWork) { const char Program[] = "struct T { }; int f(int, T*); void g(int x) { T t; f(x, &t); }"; @@ -1017,6 +1043,27 @@ TEST(Function, MatchesFunctionDeclarations) { CallFunctionF)); } +TEST(FunctionTemplate, MatchesFunctionTemplateDeclarations) { + EXPECT_TRUE( + matches("template void f(T t) {}", + functionTemplate(hasName("f")))); +} + +TEST(FunctionTemplate, DoesNotMatchFunctionDeclarations) { + EXPECT_TRUE( + notMatches("void f(double d); void f(int t) {}", + functionTemplate(hasName("f")))); +} + +TEST(FunctionTemplate, DoesNotMatchFunctionTemplateSpecializations) { + EXPECT_TRUE( + notMatches("void g(); template void f(T t) {}" + "template <> void f(int t) { g(); }", + functionTemplate(hasName("f"), + hasDescendant(declarationReference( + to(function(hasName("g")))))))); +} + TEST(Matcher, Argument) { StatementMatcher CallArgumentY = expression(call( hasArgument(0, declarationReference(to(variable(hasName("y"))))))); @@ -2565,5 +2612,49 @@ TEST(IsTemplateInstantiation, DoesNotMatchNonTemplate) { record(isTemplateInstantiation()))); } +TEST(IsExplicitTemplateSpecialization, + DoesNotMatchPrimaryTemplate) { + EXPECT_TRUE(notMatches( + "template class X {};", + record(isExplicitTemplateSpecialization()))); + EXPECT_TRUE(notMatches( + "template void f(T t);", + function(isExplicitTemplateSpecialization()))); +} + +TEST(IsExplicitTemplateSpecialization, + DoesNotMatchExplicitTemplateInstantiations) { + EXPECT_TRUE(notMatches( + "template class X {};" + "template class X; extern template class X;", + record(isExplicitTemplateSpecialization()))); + EXPECT_TRUE(notMatches( + "template void f(T t) {}" + "template void f(int t); extern template void f(long t);", + function(isExplicitTemplateSpecialization()))); +} + +TEST(IsExplicitTemplateSpecialization, + DoesNotMatchImplicitTemplateInstantiations) { + EXPECT_TRUE(notMatches( + "template class X {}; X x;", + record(isExplicitTemplateSpecialization()))); + EXPECT_TRUE(notMatches( + "template void f(T t); void g() { f(10); }", + function(isExplicitTemplateSpecialization()))); +} + +TEST(IsExplicitTemplateSpecialization, + MatchesExplicitTemplateSpecializations) { + EXPECT_TRUE(matches( + "template class X {};" + "template<> class X {};", + record(isExplicitTemplateSpecialization()))); + EXPECT_TRUE(matches( + "template void f(T t) {}" + "template<> void f(int t) {}", + function(isExplicitTemplateSpecialization()))); +} + } // end namespace ast_matchers } // end namespace clang