From 7735e40a87a002dc0ea50085709b0c1bfd03aff2 Mon Sep 17 00:00:00 2001 From: Manuel Klimek Date: Thu, 9 Oct 2014 13:06:22 +0000 Subject: [PATCH] Implement various matchers around template argument handling. llvm-svn: 219408 --- clang/docs/LibASTMatchersReference.html | 103 ++++++++++++++++++ clang/include/clang/ASTMatchers/ASTMatchers.h | 81 ++++++++++++++ clang/lib/ASTMatchers/Dynamic/Registry.cpp | 31 +++--- .../unittests/ASTMatchers/ASTMatchersTest.cpp | 58 ++++++++++ 4 files changed, 260 insertions(+), 13 deletions(-) diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index 2c2b68de93f9..2eabff49cff0 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -1020,6 +1020,17 @@ whileStmt() +Matcher<TemplateArgument>templateArgumentMatcher<TemplateArgument>... +
Matches template arguments.
+
+Given
+  template <typename T> struct C {};
+  C<int> c;
+templateArgument()
+  matches 'int' in C<int>.
+
+ + Matcher<TypeLoc>typeLocMatcher<TypeLoc>...
Matches TypeLocs in the clang AST.
 
@@ -1562,6 +1573,17 @@ Usable as: Matcher<ClassTemplateSpecializationDecl>templateArgumentCountIsunsigned N +
Matches if the number of template arguments equals N.
+
+Given
+  template<typename T> struct C {};
+  C<int> c;
+classTemplateSpecializationDecl(templateArgumentCountIs(1))
+  matches C<int>.
+
+ + Matcher<CompoundStmt>statementCountIsunsigned N
Checks that a compound statement contains a specific number of
 child statements.
@@ -1638,6 +1660,19 @@ by the compiler (eg. implicit defaultcopy constructors).
 
+Matcher<Decl>isInstantiated +
Matches declarations that are template instantiations or are inside
+template instantiations.
+
+Given
+  template<typename T> void A(T t) { T i; }
+  A(0);
+  A(0U);
+functionDecl(isInstantiated())
+  matches 'A(int) {...};' and 'A(unsigned) {...}'.
+
+ + Matcher<Decl>isPrivate
Matches private C++ declarations.
 
@@ -1955,6 +1990,22 @@ and reference to that variable declaration within a compound statement.
 
+Matcher<Stmt>isInTemplateInstantiation +
Matches statements inside of a template instantiation.
+
+Given
+  int j;
+  template<typename T> void A(T t) { T i; j += 42;}
+  A(0);
+  A(0U);
+declStmt(isInTemplateInstantiation())
+  matches 'int i;' and 'unsigned i'.
+unless(stmt(isInTemplateInstantiation()))
+  will NOT match j += 42; as it's shared between the template definition and
+  instantiation.
+
+ + Matcher<TagDecl>isDefinition
Matches if a declaration has a body attached.
 
@@ -1970,6 +2021,46 @@ Usable as: Matcher<TemplateArgument>equalsIntegralValuestd::string Value
+
Matches a TemplateArgument of integral type with a given value.
+
+Note that 'Value' is a string as the template argument's value is
+an arbitrary precision integer. 'Value' must be euqal to the canonical
+representation of that integral value in base 10.
+
+Given
+  template<int T> struct A {};
+  C<42> c;
+classTemplateSpecializationDecl(
+  hasAnyTemplateArgument(equalsIntegralValue("42")))
+  matches the implicit instantiation of C in C<42>.
+
+ + +Matcher<TemplateArgument>isIntegral +
Matches a TemplateArgument that is an integral value.
+
+Given
+  template<int T> struct A {};
+  C<42> c;
+classTemplateSpecializationDecl(
+  hasAnyTemplateArgument(isIntegral()))
+  matches the implicit instantiation of C in C<42>
+  with isIntegral() matching 42.
+
+ + +Matcher<TemplateSpecializationType>templateArgumentCountIsunsigned N +
Matches if the number of template arguments equals N.
+
+Given
+  template<typename T> struct C {};
+  C<int> c;
+classTemplateSpecializationDecl(templateArgumentCountIs(1))
+  matches C<int>.
+
+ + Matcher<Type>equalsBoundNodestd::string ID
Matches if a node equals a previously bound node.
 
@@ -3630,6 +3721,18 @@ classTemplateSpecializationDecl(hasAnyTemplateArgument(
 
+Matcher<TemplateArgument>refersToIntegralTypeMatcher<QualType> InnerMatcher +
Matches a TemplateArgument that referes to an integral type.
+
+Given
+  template<int T> struct A {};
+  C<42> c;
+classTemplateSpecializationDecl(
+  hasAnyTemplateArgument(refersToIntegralType(asString("int"))))
+  matches the implicit instantiation of C in C<42>.
+
+ + Matcher<TemplateArgument>refersToTypeMatcher<QualType> InnerMatcher
Matches a TemplateArgument that refers to a certain type.
 
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 23edcc675646..7d268ead2b09 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -274,6 +274,17 @@ const internal::VariadicDynCastAllOfMatcher<
 /// \endcode
 const internal::VariadicAllOfMatcher ctorInitializer;
 
+/// \brief Matches template arguments.
+///
+/// Given
+/// \code
+///   template  struct C {};
+///   C c;
+/// \endcode
+/// templateArgument()
+///   matches 'int' in C.
+const internal::VariadicAllOfMatcher templateArgument;
+
 /// \brief Matches public C++ declarations.
 ///
 /// Given
@@ -452,6 +463,23 @@ AST_POLYMORPHIC_MATCHER_P2(
   return InnerMatcher.matches(List[N], Finder, Builder);
 }
 
+/// \brief Matches if the number of template arguments equals \p N.
+///
+/// Given
+/// \code
+///   template struct C {};
+///   C c;
+/// \endcode
+/// classTemplateSpecializationDecl(templateArgumentCountIs(1))
+///   matches C.
+AST_POLYMORPHIC_MATCHER_P(
+    templateArgumentCountIs,
+    AST_POLYMORPHIC_SUPPORTED_TYPES_2(ClassTemplateSpecializationDecl,
+                                      TemplateSpecializationType),
+    unsigned, N) {
+  return internal::getTemplateSpecializationArgs(Node).size() == N;
+}
+
 /// \brief Matches a TemplateArgument that refers to a certain type.
 ///
 /// Given
@@ -508,6 +536,59 @@ AST_MATCHER_P(TemplateArgument, isExpr, internal::Matcher, InnerMatcher) {
   return false;
 }
 
+/// \brief Matches a TemplateArgument that is an integral value.
+///
+/// Given
+/// \code
+///   template struct A {};
+///   C<42> c;
+/// \endcode
+/// classTemplateSpecializationDecl(
+///   hasAnyTemplateArgument(isIntegral()))
+///   matches the implicit instantiation of C in C<42>
+///   with isIntegral() matching 42.
+AST_MATCHER(TemplateArgument, isIntegral) {
+  return Node.getKind() == TemplateArgument::Integral;
+}
+
+/// \brief Matches a TemplateArgument that referes to an integral type.
+///
+/// Given
+/// \code
+///   template struct A {};
+///   C<42> c;
+/// \endcode
+/// classTemplateSpecializationDecl(
+///   hasAnyTemplateArgument(refersToIntegralType(asString("int"))))
+///   matches the implicit instantiation of C in C<42>.
+AST_MATCHER_P(TemplateArgument, refersToIntegralType,
+              internal::Matcher, InnerMatcher) {
+  if (Node.getKind() != TemplateArgument::Integral)
+    return false;
+  return InnerMatcher.matches(Node.getIntegralType(), Finder, Builder);
+}
+
+/// \brief Matches a TemplateArgument of integral type with a given value.
+///
+/// Note that 'Value' is a string as the template argument's value is
+/// an arbitrary precision integer. 'Value' must be euqal to the canonical
+/// representation of that integral value in base 10.
+///
+/// Given
+/// \code
+///   template struct A {};
+///   C<42> c;
+/// \endcode
+/// classTemplateSpecializationDecl(
+///   hasAnyTemplateArgument(equalsIntegralValue("42")))
+///   matches the implicit instantiation of C in C<42>.
+AST_MATCHER_P(TemplateArgument, equalsIntegralValue,
+              std::string, Value) {
+  if (Node.getKind() != TemplateArgument::Integral)
+    return false;
+  return Node.getAsIntegral().toString(10) == Value;
+}
+
 /// \brief Matches C++ constructor declarations.
 ///
 /// Example matches Foo::Foo() and Foo::Foo(int)
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 9fb72e6d5e5a..5672169d3dc5 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -93,7 +93,6 @@ RegistryMaps::RegistryMaps() {
   REGISTER_OVERLOADED_2(references);
   REGISTER_OVERLOADED_2(thisPointerType);
 
-  REGISTER_MATCHER(CUDAKernelCallExpr);
   REGISTER_MATCHER(accessSpecDecl);
   REGISTER_MATCHER(alignOfExpr);
   REGISTER_MATCHER(allOf);
@@ -102,8 +101,8 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(argumentCountIs);
   REGISTER_MATCHER(arraySubscriptExpr);
   REGISTER_MATCHER(arrayType);
-  REGISTER_MATCHER(asString);
   REGISTER_MATCHER(asmStmt);
+  REGISTER_MATCHER(asString);
   REGISTER_MATCHER(atomicType);
   REGISTER_MATCHER(autoType);
   REGISTER_MATCHER(binaryOperator);
@@ -112,7 +111,6 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(boolLiteral);
   REGISTER_MATCHER(breakStmt);
   REGISTER_MATCHER(builtinType);
-  REGISTER_MATCHER(cStyleCastExpr);
   REGISTER_MATCHER(callExpr);
   REGISTER_MATCHER(caseStmt);
   REGISTER_MATCHER(castExpr);
@@ -124,18 +122,20 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(compoundLiteralExpr);
   REGISTER_MATCHER(compoundStmt);
   REGISTER_MATCHER(conditionalOperator);
-  REGISTER_MATCHER(constCastExpr);
   REGISTER_MATCHER(constantArrayType);
+  REGISTER_MATCHER(constCastExpr);
   REGISTER_MATCHER(constructExpr);
   REGISTER_MATCHER(constructorDecl);
   REGISTER_MATCHER(containsDeclaration);
   REGISTER_MATCHER(continueStmt);
+  REGISTER_MATCHER(cStyleCastExpr);
   REGISTER_MATCHER(ctorInitializer);
+  REGISTER_MATCHER(CUDAKernelCallExpr);
   REGISTER_MATCHER(decl);
+  REGISTER_MATCHER(declaratorDecl);
   REGISTER_MATCHER(declCountIs);
   REGISTER_MATCHER(declRefExpr);
   REGISTER_MATCHER(declStmt);
-  REGISTER_MATCHER(declaratorDecl);
   REGISTER_MATCHER(defaultArgExpr);
   REGISTER_MATCHER(defaultStmt);
   REGISTER_MATCHER(deleteExpr);
@@ -148,6 +148,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(enumConstantDecl);
   REGISTER_MATCHER(enumDecl);
   REGISTER_MATCHER(equalsBoundNode);
+  REGISTER_MATCHER(equalsIntegralValue);
   REGISTER_MATCHER(explicitCastExpr);
   REGISTER_MATCHER(expr);
   REGISTER_MATCHER(exprWithCleanups);
@@ -161,10 +162,10 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(forRangeStmt);
   REGISTER_MATCHER(forStmt);
   REGISTER_MATCHER(friendDecl);
+  REGISTER_MATCHER(functionalCastExpr);
   REGISTER_MATCHER(functionDecl);
   REGISTER_MATCHER(functionTemplateDecl);
   REGISTER_MATCHER(functionType);
-  REGISTER_MATCHER(functionalCastExpr);
   REGISTER_MATCHER(gotoStmt);
   REGISTER_MATCHER(has);
   REGISTER_MATCHER(hasAncestor);
@@ -183,8 +184,8 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(hasCaseConstant);
   REGISTER_MATCHER(hasCondition);
   REGISTER_MATCHER(hasConditionVariableStatement);
-  REGISTER_MATCHER(hasDeclContext);
   REGISTER_MATCHER(hasDeclaration);
+  REGISTER_MATCHER(hasDeclContext);
   REGISTER_MATCHER(hasDeducedType);
   REGISTER_MATCHER(hasDescendant);
   REGISTER_MATCHER(hasDestinationType);
@@ -210,8 +211,8 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(hasParameter);
   REGISTER_MATCHER(hasParent);
   REGISTER_MATCHER(hasQualifier);
-  REGISTER_MATCHER(hasRHS);
   REGISTER_MATCHER(hasRangeInit);
+  REGISTER_MATCHER(hasRHS);
   REGISTER_MATCHER(hasSingleDecl);
   REGISTER_MATCHER(hasSize);
   REGISTER_MATCHER(hasSizeExpr);
@@ -243,6 +244,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(isImplicit);
   REGISTER_MATCHER(isInstantiated);
   REGISTER_MATCHER(isInteger);
+  REGISTER_MATCHER(isIntegral);
   REGISTER_MATCHER(isInTemplateInstantiation);
   REGISTER_MATCHER(isListInitialization);
   REGISTER_MATCHER(isOverride);
@@ -253,9 +255,9 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(isTemplateInstantiation);
   REGISTER_MATCHER(isVirtual);
   REGISTER_MATCHER(isWritten);
-  REGISTER_MATCHER(lValueReferenceType);
   REGISTER_MATCHER(labelStmt);
   REGISTER_MATCHER(lambdaExpr);
+  REGISTER_MATCHER(lValueReferenceType);
   REGISTER_MATCHER(matchesName);
   REGISTER_MATCHER(materializeTemporaryExpr);
   REGISTER_MATCHER(member);
@@ -264,8 +266,8 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(memberPointerType);
   REGISTER_MATCHER(methodDecl);
   REGISTER_MATCHER(namedDecl);
-  REGISTER_MATCHER(namesType);
   REGISTER_MATCHER(namespaceDecl);
+  REGISTER_MATCHER(namesType);
   REGISTER_MATCHER(nestedNameSpecifier);
   REGISTER_MATCHER(nestedNameSpecifierLoc);
   REGISTER_MATCHER(newExpr);
@@ -281,15 +283,16 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(pointee);
   REGISTER_MATCHER(pointerType);
   REGISTER_MATCHER(qualType);
-  REGISTER_MATCHER(rValueReferenceType);
   REGISTER_MATCHER(recordDecl);
   REGISTER_MATCHER(recordType);
   REGISTER_MATCHER(referenceType);
   REGISTER_MATCHER(refersToDeclaration);
+  REGISTER_MATCHER(refersToIntegralType);
   REGISTER_MATCHER(refersToType);
   REGISTER_MATCHER(reinterpretCastExpr);
-  REGISTER_MATCHER(returnStmt);
   REGISTER_MATCHER(returns);
+  REGISTER_MATCHER(returnStmt);
+  REGISTER_MATCHER(rValueReferenceType);
   REGISTER_MATCHER(sizeOfExpr);
   REGISTER_MATCHER(specifiesNamespace);
   REGISTER_MATCHER(specifiesType);
@@ -301,6 +304,8 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(substNonTypeTemplateParmExpr);
   REGISTER_MATCHER(switchCase);
   REGISTER_MATCHER(switchStmt);
+  REGISTER_MATCHER(templateArgument);
+  REGISTER_MATCHER(templateArgumentCountIs);
   REGISTER_MATCHER(templateSpecializationType);
   REGISTER_MATCHER(temporaryObjectExpr);
   REGISTER_MATCHER(thisExpr);
@@ -309,8 +314,8 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(to);
   REGISTER_MATCHER(tryStmt);
   REGISTER_MATCHER(type);
-  REGISTER_MATCHER(typeLoc);
   REGISTER_MATCHER(typedefType);
+  REGISTER_MATCHER(typeLoc);
   REGISTER_MATCHER(unaryExprOrTypeTraitExpr);
   REGISTER_MATCHER(unaryOperator);
   REGISTER_MATCHER(unaryTransformType);
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp
index a7969340ba8a..2195604799bc 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -1658,6 +1658,64 @@ TEST(Matcher, MatchesSpecificArgument) {
           1, refersToType(asString("int"))))));
 }
 
+TEST(TemplateArgument, Matches) {
+  EXPECT_TRUE(matches("template struct C {}; C c;",
+                      classTemplateSpecializationDecl(
+                          hasAnyTemplateArgument(templateArgument()))));
+  EXPECT_TRUE(matches(
+      "template struct C {}; C c;",
+      templateSpecializationType(hasAnyTemplateArgument(templateArgument()))));
+}
+
+TEST(TemplateArgumentCountIs, Matches) {
+  EXPECT_TRUE(
+      matches("template struct C {}; C c;",
+              classTemplateSpecializationDecl(templateArgumentCountIs(1))));
+  EXPECT_TRUE(
+      notMatches("template struct C {}; C c;",
+                 classTemplateSpecializationDecl(templateArgumentCountIs(2))));
+
+  EXPECT_TRUE(matches("template struct C {}; C c;",
+                      templateSpecializationType(templateArgumentCountIs(1))));
+  EXPECT_TRUE(
+      notMatches("template struct C {}; C c;",
+                 templateSpecializationType(templateArgumentCountIs(2))));
+}
+
+TEST(IsIntegral, Matches) {
+  EXPECT_TRUE(matches("template struct C {}; C<42> c;",
+                      classTemplateSpecializationDecl(
+                          hasAnyTemplateArgument(isIntegral()))));
+  EXPECT_TRUE(notMatches("template struct C {}; C c;",
+                         classTemplateSpecializationDecl(hasAnyTemplateArgument(
+                             templateArgument(isIntegral())))));
+}
+
+TEST(RefersToIntegralType, Matches) {
+  EXPECT_TRUE(matches("template struct C {}; C<42> c;",
+                      classTemplateSpecializationDecl(
+                          hasAnyTemplateArgument(refersToIntegralType(
+                              asString("int"))))));
+  EXPECT_TRUE(notMatches("template struct C {}; C<42> c;",
+                         classTemplateSpecializationDecl(hasAnyTemplateArgument(
+                             refersToIntegralType(asString("int"))))));
+}
+
+TEST(EqualsIntegralValue, Matches) {
+  EXPECT_TRUE(matches("template struct C {}; C<42> c;",
+                      classTemplateSpecializationDecl(
+                          hasAnyTemplateArgument(equalsIntegralValue("42")))));
+  EXPECT_TRUE(matches("template struct C {}; C<-42> c;",
+                      classTemplateSpecializationDecl(
+                          hasAnyTemplateArgument(equalsIntegralValue("-42")))));
+  EXPECT_TRUE(matches("template struct C {}; C<-0042> c;",
+                      classTemplateSpecializationDecl(
+                          hasAnyTemplateArgument(equalsIntegralValue("-34")))));
+  EXPECT_TRUE(notMatches("template struct C {}; C<42> c;",
+                         classTemplateSpecializationDecl(hasAnyTemplateArgument(
+                             equalsIntegralValue("0042")))));
+}
+
 TEST(Matcher, MatchesAccessSpecDecls) {
   EXPECT_TRUE(matches("class C { public: int i; };", accessSpecDecl()));
   EXPECT_TRUE(