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() +
Matches template arguments. + +Given + template <typename T> struct C {}; + C<int> c; +templateArgument() + matches 'int' in C<int>. +
Matches TypeLocs in the clang AST.
Matches if the number of template arguments equals N. + +Given + template<typename T> struct C {}; + C<int> c; +classTemplateSpecializationDecl(templateArgumentCountIs(1)) + matches C<int>. +
Checks that a compound statement contains a specific number of child statements. @@ -1638,6 +1660,19 @@ by the compiler (eg. implicit defaultcopy constructors).
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) {...}'. +
Matches private C++ declarations. @@ -1955,6 +1990,22 @@ and reference to that variable declaration within a compound statement.
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. +
Matches if a declaration has a body attached. @@ -1970,6 +2021,46 @@ Usable as: Matcher<TemplateArgument>
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>. +
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. +
Matches if the number of template arguments equals N. + +Given + template<typename T> struct C {}; + C<int> c; +classTemplateSpecializationDecl(templateArgumentCountIs(1)) + matches C<int>. +
Matches if a node equals a previously bound node. @@ -3630,6 +3721,18 @@ classTemplateSpecializationDecl(hasAnyTemplateArgument(
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>. +
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::VariadicAllOfMatcherctorInitializer; +/// \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(