From 8456ae602783b615019a42f7d5c6f0e71639b11b Mon Sep 17 00:00:00 2001 From: Dmitri Gribenko Date: Fri, 17 Aug 2012 18:42:47 +0000 Subject: [PATCH] AST Matchers: introduce functionTemplate(), classTemplate() and isExplicitTemplateSpecialization() matchers which do what their name says. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162115 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/ASTMatchers/ASTMatchers.h | 30 ++++++ .../clang/ASTMatchers/ASTMatchersInternal.h | 17 ++++ unittests/ASTMatchers/ASTMatchersTest.cpp | 91 +++++++++++++++++++ 3 files changed, 138 insertions(+) diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index 33ef3dc8d6..55f0772bd8 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/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/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h index 3f5568521c..a94e925d59 100644 --- a/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/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/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp index adf0e9479f..dcebbc9f3d 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/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 -- 2.40.0