]> granicus.if.org Git - clang/commitdiff
AST Matchers: introduce functionTemplate(), classTemplate() and
authorDmitri Gribenko <gribozavr@gmail.com>
Fri, 17 Aug 2012 18:42:47 +0000 (18:42 +0000)
committerDmitri Gribenko <gribozavr@gmail.com>
Fri, 17 Aug 2012 18:42:47 +0000 (18:42 +0000)
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
include/clang/ASTMatchers/ASTMatchersInternal.h
unittests/ASTMatchers/ASTMatchersTest.cpp

index 33ef3dc8d6e0cb5fd3270b5362ba474a37410c41..55f0772bd80a2386cdae11116032d0db3cb36d5a 100644 (file)
@@ -164,6 +164,14 @@ const internal::VariadicDynCastAllOfMatcher<
   Decl,
   CXXRecordDecl> record;
 
+/// \brief Matches C++ class template declarations.
+///
+/// Example matches Z
+///   template<class T> class Z {};
+const internal::VariadicDynCastAllOfMatcher<
+  Decl,
+  ClassTemplateDecl> classTemplate;
+
 /// \brief Matches C++ class template specializations.
 ///
 /// Given
@@ -385,6 +393,13 @@ const internal::VariadicDynCastAllOfMatcher<Decl, FieldDecl> field;
 ///   void f();
 const internal::VariadicDynCastAllOfMatcher<Decl, FunctionDecl> function;
 
+/// \brief Matches C++ function template declarations.
+///
+/// Example matches f
+///   template<class T> 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<typename T> void A(T t) { }
+///   template<> void A(int N) { }
+/// function(isExplicitSpecialization())
+///   matches the specialization A<int>().
+inline internal::PolymorphicMatcherWithParam0<
+  internal::IsExplicitTemplateSpecializationMatcher>
+isExplicitTemplateSpecialization() {
+  return internal::PolymorphicMatcherWithParam0<
+    internal::IsExplicitTemplateSpecializationMatcher>();
+}
+
 } // end namespace ast_matchers
 } // end namespace clang
 
index 3f5568521c0e02a8ac92470469e8f0ab0f3974b6..a94e925d59545d967618b011111fe2a68f2d59b6 100644 (file)
@@ -858,6 +858,23 @@ class IsTemplateInstantiationMatcher : public MatcherInterface<T> {
   }
 };
 
+/// \brief Matches on explicit template specializations for FunctionDecl,
+/// VarDecl or CXXRecordDecl nodes.
+template <typename T>
+class IsExplicitTemplateSpecializationMatcher : public MatcherInterface<T> {
+  TOOLING_COMPILE_ASSERT((llvm::is_base_of<FunctionDecl, T>::value) ||
+                         (llvm::is_base_of<VarDecl, T>::value) ||
+                         (llvm::is_base_of<CXXRecordDecl, T>::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<MemberExpr> {
 public:
   virtual bool matchesNode(const MemberExpr &Node) const {
index adf0e9479f08b0b43972c832f34fda936ed7bb9b..dcebbc9f3d6e290129259242c1b46bb79bf1fa56 100644 (file)
@@ -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<typename T> class X {};", ClassX));
+  EXPECT_TRUE(matches("class Z { template<class T> class X {}; };", ClassX));
+}
+
+TEST(ClassTemplate, DoesNotMatchClassTemplateExplicitSpecialization) {
+  EXPECT_TRUE(notMatches("template<typename T> class X { };"
+                         "template<> class X<int> { int a; };",
+              classTemplate(hasName("X"),
+                            hasDescendant(field(hasName("a"))))));
+}
+
+TEST(ClassTemplate, DoesNotMatchClassTemplatePartialSpecialization) {
+  EXPECT_TRUE(notMatches("template<typename T, typename U> class X { };"
+                         "template<typename T> class X<T, int> { 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 <typename T> 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 <typename T> 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 <typename T> class X {};",
+      record(isExplicitTemplateSpecialization())));
+  EXPECT_TRUE(notMatches(
+      "template <typename T> void f(T t);",
+      function(isExplicitTemplateSpecialization())));
+}
+
+TEST(IsExplicitTemplateSpecialization,
+     DoesNotMatchExplicitTemplateInstantiations) {
+  EXPECT_TRUE(notMatches(
+      "template <typename T> class X {};"
+      "template class X<int>; extern template class X<long>;",
+      record(isExplicitTemplateSpecialization())));
+  EXPECT_TRUE(notMatches(
+      "template <typename T> void f(T t) {}"
+      "template void f(int t); extern template void f(long t);",
+      function(isExplicitTemplateSpecialization())));
+}
+
+TEST(IsExplicitTemplateSpecialization,
+     DoesNotMatchImplicitTemplateInstantiations) {
+  EXPECT_TRUE(notMatches(
+      "template <typename T> class X {}; X<int> x;",
+      record(isExplicitTemplateSpecialization())));
+  EXPECT_TRUE(notMatches(
+      "template <typename T> void f(T t); void g() { f(10); }",
+      function(isExplicitTemplateSpecialization())));
+}
+
+TEST(IsExplicitTemplateSpecialization,
+     MatchesExplicitTemplateSpecializations) {
+  EXPECT_TRUE(matches(
+      "template <typename T> class X {};"
+      "template<> class X<int> {};",
+      record(isExplicitTemplateSpecialization())));
+  EXPECT_TRUE(matches(
+      "template <typename T> void f(T t) {}"
+      "template<> void f(int t) {}",
+      function(isExplicitTemplateSpecialization())));
+}
+
 } // end namespace ast_matchers
 } // end namespace clang