Index: docs/LibASTMatchersReference.html =================================================================== --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -307,6 +307,15 @@ +
Matches Objective-C interface declarations. + +Example matches Foo + @interface Foo + @end +
Matches parameter variable declarations. @@ -364,6 +373,22 @@
Matches unresolved using value declarations that involve the +typename. + +Given + template <typename T> + struct Base { typedef T Foo; }; + + template<typename T> + struct S : private Base<T> { + using typename Base<T>::Foo; + }; +unresolvedUsingTypenameDecl() + matches using Base<T>::Foo
Matches unresolved using value declarations. @@ -1254,6 +1279,18 @@
Matches injected class name types. + +Example matches S s, but not S<T> s. + (matcher = parmVarDecl(hasType(injectedClassNameType()))) + template <typename T> struct S { + void f(S s); + void g(S<T> s); + }; +
Matches lvalue reference types. @@ -1281,6 +1318,21 @@
Matches an Objective-C object pointer type, which is different from +a pointer type, despite being syntactically similar. + +Given + int *a; + + @interface Foo + @end + Foo *f; +pointerType() + matches "Foo *f", but does not match "int *a". +
Matches ParenType nodes. @@ -1294,14 +1346,19 @@- Matcher<Type> pointerType Matcher<PointerType>... + Matches pointer types. +@@ -1382,6 +1439,15 @@ Matches pointer types, but does not match Objective-C object pointer +types. Given int *a; int &b = *a; int c = 5; + + @interface Foo + @end + Foo *f; pointerType() - matches "int *a" + matches "int *a", but does not match "Foo *f".+ Matcher<Type> templateTypeParmType Matcher<TemplateTypeParmType>... + + Matches template type parameter types. + +Example matches T, but not int. + (matcher = templateTypeParmType()) + template <typename T> void f(int i); +Matcher<Type> type Matcher<Type>... @@ -2280,7 +2346,7 @@ Matches Types in the clang AST.Matcher<ObjCMessageExpr> numSelectorArgs unsigned N Matches when the selector has the specified number of arguments - matcher = objCMessageExpr(numSelectorArgs(1)); + matcher = objCMessageExpr(numSelectorArgs(0)); matches self.bodyView in the code below matcher = objCMessageExpr(numSelectorArgs(2)); Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -904,6 +904,16 @@ Stmt, ObjCMessageExpr> objcMessageExpr; +/// \brief Matches Objective-C interface declarations. +/// +/// Example matches Foo +/// \code +/// @interface Foo +/// @end +/// \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + ObjCInterfaceDecl> objcInterfaceDecl; /// \brief Matches expressions that introduce cleanups to be run at the end /// of the sub-expression's evaluation. @@ -978,6 +988,25 @@ Decl, UnresolvedUsingValueDecl> unresolvedUsingValueDecl; +/// \brief Matches unresolved using value declarations that involve the +/// typename. +/// +/// Given +/// \code +/// template+/// struct Base { typedef T Foo; }; +/// +/// template +/// struct S : private Base { +/// using typename Base ::Foo; +/// }; +/// \endcode +/// unresolvedUsingTypenameDecl() +/// matches \code using Base ::Foo \endcode +const internal::VariadicDynCastAllOfMatcher< + Decl, + UnresolvedUsingTypenameDecl> unresolvedUsingTypenameDecl; + /// \brief Matches constructor call expressions (including implicit ones). /// /// Example matches string(ptr, n) and ptr within arguments of f @@ -2282,7 +2311,7 @@ AST_MATCHER_P( QualType, pointsTo, internal::Matcher , InnerMatcher) { - return (!Node.isNull() && Node->isPointerType() && + return (!Node.isNull() && Node->isAnyPointerType() && InnerMatcher.matches(Node->getPointeeType(), Finder, Builder)); } @@ -3754,7 +3783,8 @@ /// matches "A::* ptr" AST_TYPE_MATCHER(MemberPointerType, memberPointerType); -/// \brief Matches pointer types. +/// \brief Matches pointer types, but does not match Objective-C object pointer +/// types. /// /// Given /// \code @@ -3761,11 +3791,30 @@ /// int *a; /// int &b = *a; /// int c = 5; +/// +/// @interface Foo +/// @end +/// Foo *f; /// \endcode /// pointerType() -/// matches "int *a" +/// matches "int *a", but does not match "Foo *f". AST_TYPE_MATCHER(PointerType, pointerType); +/// \brief Matches an Objective-C object pointer type, which is different from +/// a pointer type, despite being syntactically similar. +/// +/// Given +/// \code +/// int *a; +/// +/// @interface Foo +/// @end +/// Foo *f; +/// \endcode +/// pointerType() +/// matches "Foo *f", but does not match "int *a". +AST_TYPE_MATCHER(ObjCObjectPointerType, objcObjectPointerType); + /// \brief Matches both lvalue and rvalue reference types. /// /// Given @@ -3963,6 +4012,27 @@ /// \c substTemplateTypeParmType() matches the type of 't' but not '1' AST_TYPE_MATCHER(SubstTemplateTypeParmType, substTemplateTypeParmType); +/// \brief Matches template type parameter types. +/// +/// Example matches T, but not int. +/// (matcher = templateTypeParmType()) +/// \code +/// template void f(int i); +/// \endcode +AST_TYPE_MATCHER(TemplateTypeParmType, templateTypeParmType); + +/// \brief Matches injected class name types. +/// +/// Example matches S s, but not S s. +/// (matcher = parmVarDecl(hasType(injectedClassNameType()))) +/// \code +/// template struct S { +/// void f(S s); +/// void g(S s); +/// }; +/// \endcode +AST_TYPE_MATCHER(InjectedClassNameType, injectedClassNameType); + /// \brief Matches declarations whose declaration context, interpreted as a /// Decl, matches \c InnerMatcher. /// Index: include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- include/clang/ASTMatchers/ASTMatchersInternal.h +++ include/clang/ASTMatchers/ASTMatchersInternal.h @@ -672,10 +672,26 @@ /// matcher matches on it. bool matchesSpecialized(const QualType &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { - /// FIXME: Add other ways to convert... if (Node.isNull()) return false; - return matchesDecl(Node->getAsTagDecl(), Finder, Builder); + + if (auto *TD = Node->getAsTagDecl()) + return matchesDecl(TD, Finder, Builder); + else if (auto *TT = Node->getAs ()) + return matchesDecl(TT->getDecl(), Finder, Builder); + // Do not use getAs instead of the direct dyn_cast. + // Calling getAs will return the canonical type, but that type does not + // store a TemplateTypeParmDecl. We *need* the uncanonical type, if it is + // available, and using dyn_cast ensures that. + else if (auto *TTP = dyn_cast (Node.getTypePtr())) + return matchesDecl(TTP->getDecl(), Finder, Builder); + else if (auto *OCIT = Node->getAs ()) + return matchesDecl(OCIT->getDecl(), Finder, Builder); + else if (auto *UUT = Node->getAs ()) + return matchesDecl(UUT->getDecl(), Finder, Builder); + else if (auto *ICNT = Node->getAs ()) + return matchesDecl(ICNT->getDecl(), Finder, Builder); + return false; } /// \brief Gets the TemplateDecl from a TemplateSpecializationType Index: lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- lib/ASTMatchers/Dynamic/Registry.cpp +++ lib/ASTMatchers/Dynamic/Registry.cpp @@ -238,6 +238,7 @@ REGISTER_MATCHER(implicitCastExpr); REGISTER_MATCHER(incompleteArrayType); REGISTER_MATCHER(initListExpr); + REGISTER_MATCHER(injectedClassNameType); REGISTER_MATCHER(innerType); REGISTER_MATCHER(integerLiteral); REGISTER_MATCHER(isAnonymous); @@ -298,7 +299,9 @@ REGISTER_MATCHER(nullStmt); REGISTER_MATCHER(numSelectorArgs); REGISTER_MATCHER(ofClass); + REGISTER_MATCHER(objcInterfaceDecl); REGISTER_MATCHER(objcMessageExpr); + REGISTER_MATCHER(objcObjectPointerType); REGISTER_MATCHER(on); REGISTER_MATCHER(onImplicitObjectArgument); REGISTER_MATCHER(operatorCallExpr); @@ -334,6 +337,7 @@ REGISTER_MATCHER(templateArgument); REGISTER_MATCHER(templateArgumentCountIs); REGISTER_MATCHER(templateSpecializationType); + REGISTER_MATCHER(templateTypeParmType); REGISTER_MATCHER(temporaryObjectExpr); REGISTER_MATCHER(thisExpr); REGISTER_MATCHER(throughUsingDecl); @@ -350,6 +354,7 @@ REGISTER_MATCHER(unaryTransformType); REGISTER_MATCHER(unless); REGISTER_MATCHER(unresolvedConstructExpr); + REGISTER_MATCHER(unresolvedUsingTypenameDecl); REGISTER_MATCHER(unresolvedUsingValueDecl); REGISTER_MATCHER(userDefinedLiteral); REGISTER_MATCHER(usingDecl); Index: unittests/ASTMatchers/ASTMatchersTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersTest.cpp +++ unittests/ASTMatchers/ASTMatchersTest.cpp @@ -924,6 +924,54 @@ varDecl(hasType(namedDecl(hasName("S")))))); } +TEST(TypeMatcher, MatchesDeclTypes) { + // TypedefType -> TypedefNameDecl + EXPECT_TRUE(matches("typedef int I; void f(I i);", + parmVarDecl(hasType(namedDecl(hasName("I")))))); + // ObjCObjectPointerType + EXPECT_TRUE(matchesObjC("@interface Foo @end void f(Foo *f);", + parmVarDecl(hasType(objcObjectPointerType())))); + // ObjCObjectPointerType -> ObjCInterfaceType -> ObjCInterfaceDecl + EXPECT_TRUE(matchesObjC( + "@interface Foo @end void f(Foo *f);", + parmVarDecl(hasType(pointsTo(objcInterfaceDecl(hasName("Foo"))))))); + // TemplateTypeParmType + EXPECT_TRUE(matches("template void f(T t);", + parmVarDecl(hasType(templateTypeParmType())))); + // TemplateTypeParmType -> TemplateTypeParmDecl + EXPECT_TRUE(matches("template void f(T t);", + parmVarDecl(hasType(namedDecl(hasName("T")))))); + // InjectedClassNameType + EXPECT_TRUE(matches("template struct S {" + " void f(S s);" + "};", + parmVarDecl(hasType(injectedClassNameType())))); + EXPECT_TRUE(notMatches("template struct S {" + " void g(S s);" + "};", + parmVarDecl(hasType(injectedClassNameType())))); + // InjectedClassNameType -> CXXRecordDecl + EXPECT_TRUE(matches("template struct S {" + " void f(S s);" + "};", + parmVarDecl(hasType(namedDecl(hasName("S")))))); + + static const char Using[] = "template " + "struct Base {" + " typedef T Foo;" + "};" + "" + "template " + "struct S : private Base {" + " using typename Base ::Foo;" + " void f(Foo);" + "};"; + // UnresolvedUsingTypenameDecl + EXPECT_TRUE(matches(Using, unresolvedUsingTypenameDecl(hasName("Foo")))); + // UnresolvedUsingTypenameType -> UnresolvedUsingTypenameDecl + EXPECT_TRUE(matches(Using, parmVarDecl(hasType(namedDecl(hasName("Foo")))))); +} + TEST(Matcher, BindMatchedNodes) { DeclarationMatcher ClassX = has(recordDecl(hasName("::X")).bind("x"));