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
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index adf0e94..dcebbc9 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -292,6 +292,32 @@
       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 @@
                  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 @@
       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