Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -45,9 +45,11 @@ #ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H #define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H +#include "clang/AST/DeclTemplate.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" #include "clang/ASTMatchers/ASTMatchersMacros.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/Regex.h" namespace clang { namespace ast_matchers { @@ -78,8 +80,8 @@ private: /// \brief Create BoundNodes from a pre-filled map of bindings. - BoundNodes(const std::map &DeclBindings, - const std::map &StmtBindings) + BoundNodes(const std::map &DeclBindings, + const std::map &StmtBindings) : DeclBindings(DeclBindings), StmtBindings(StmtBindings) {} template @@ -91,8 +93,8 @@ return llvm::dyn_cast(It->second); } - std::map DeclBindings; - std::map StmtBindings; + std::map DeclBindings; + std::map StmtBindings; friend class internal::BoundNodesTree; }; @@ -109,9 +111,9 @@ /// \brief Types of matchers for the top-level classes in the AST class /// hierarchy. /// @{ -typedef internal::Matcher DeclarationMatcher; -typedef internal::Matcher TypeMatcher; -typedef internal::Matcher StatementMatcher; +typedef internal::Matcher DeclarationMatcher; +typedef internal::Matcher TypeMatcher; +typedef internal::Matcher StatementMatcher; /// @} /// \brief Matches any node. @@ -138,8 +140,8 @@ /// } U; /// }; const internal::VariadicDynCastAllOfMatcher< - clang::Decl, - clang::NamedDecl> nameableDeclaration; + Decl, + NamedDecl> nameableDeclaration; /// \brief Matches C++ class declarations. /// @@ -147,8 +149,91 @@ /// class X; /// template class Z {}; const internal::VariadicDynCastAllOfMatcher< - clang::Decl, - clang::CXXRecordDecl> record; + Decl, + CXXRecordDecl> record; + +/// \brief Matches C++ class template specializations. +/// +/// Given +/// template class A {}; +/// template<> class A {}; +/// A a; +/// classTemplateSpecialization() +/// matches the specializations \c A and \c A +const internal::VariadicDynCastAllOfMatcher< + Decl, + ClassTemplateSpecializationDecl> classTemplateSpecialization; + +/// \brief Matches classTemplateSpecializations that have at least one +/// TemplateArgument matching the given Matcher. +/// +/// Given +/// template class A {}; +/// template<> class A {}; +/// A a; +/// classTemplateSpecialization(hasAnyTemplateArgument( +/// refersToType(asString("int")))) +/// matches the specialization \c A +AST_MATCHER_P(ClassTemplateSpecializationDecl, hasAnyTemplateArgument, + internal::Matcher, Matcher) { + const TemplateArgumentList &List = Node.getTemplateArgs(); + for (unsigned i = 0; i < List.size(); ++i) { + if (Matcher.matches(List.get(i), Finder, Builder)) + return true; + } + return false; +} + +/// \brief Matches classTemplateSpecializations where the n'th TemplateArgument +/// matches the given Matcher. +/// +/// Given +/// template class A {}; +/// A b; +/// A c; +/// classTemplateSpecialization(hasTemplateArgument( +/// 1, refersToType(asString("int")))) +/// matches the specialization \c A +AST_MATCHER_P2(ClassTemplateSpecializationDecl, hasTemplateArgument, + unsigned, N, internal::Matcher, Matcher) { + const TemplateArgumentList &List = Node.getTemplateArgs(); + if (List.size() <= N) + return false; + return Matcher.matches(List.get(N), Finder, Builder); +} + +/// \brief Matches a TemplateArgument that refers to a certain type. +/// +/// Given +/// struct X {}; +/// template struct A {}; +/// A a; +/// classTemplateSpecialization(hasAnyTemplateArgument( +/// refersToType(class(hasName("X"))))) +/// matches the specialization \c A +AST_MATCHER_P(TemplateArgument, refersToType, + internal::Matcher, Matcher) { + if (Node.getKind() != TemplateArgument::Type) + return false; + return Matcher.matches(Node.getAsType(), Finder, Builder); +} + +/// \brief Matches a TemplateArgument that refers to a certain declaration. +/// +/// Given +/// template struct A {}; +/// struct B { B* next; }; +/// A<&B::next> a; +/// classTemplateSpecialization(hasAnyTemplateArgument( +/// refersToDeclaration(field(hasName("next")))) +/// matches the specialization \c A<&B::next> with \c field(...) matching +/// \c B::next +AST_MATCHER_P(TemplateArgument, refersToDeclaration, + internal::Matcher, Matcher) { + if (const Decl *Declaration = Node.getAsDecl()) + return Matcher.matches(*Declaration, Finder, Builder); + return false; +} /// \brief Matches C++ constructor declarations. /// @@ -160,16 +245,41 @@ /// int DoSomething(); /// }; const internal::VariadicDynCastAllOfMatcher< - clang::Decl, - clang::CXXConstructorDecl> constructor; + Decl, + CXXConstructorDecl> constructor; + +/// \brief Matches explicit C++ destructor declarations. +/// +/// Example matches Foo::~Foo() +/// class Foo { +/// public: +/// virtual ~Foo(); +/// }; +const internal::VariadicDynCastAllOfMatcher destructor; + +/// \brief Matches enum declarations. +/// +/// Example matches X +/// enum X { +/// A, B, C +/// }; +const internal::VariadicDynCastAllOfMatcher enumDecl; + +/// \brief Matches enum constants. +/// +/// Example matches A, B, C +/// enum X { +/// A, B, C +/// }; +const internal::VariadicDynCastAllOfMatcher< + Decl, + EnumConstantDecl> enumConstant; /// \brief Matches method declarations. /// /// Example matches y /// class X { void y() }; -const internal::VariadicDynCastAllOfMatcher< - clang::Decl, - clang::CXXMethodDecl> method; +const internal::VariadicDynCastAllOfMatcher method; /// \brief Matches variable declarations. /// @@ -178,9 +288,7 @@ /// /// Example matches a /// int a; -const internal::VariadicDynCastAllOfMatcher< - clang::Decl, - clang::VarDecl> variable; +const internal::VariadicDynCastAllOfMatcher variable; /// \brief Matches field declarations. /// @@ -188,17 +296,13 @@ /// class X { int m; }; /// field() /// matches 'm'. -const internal::VariadicDynCastAllOfMatcher< - clang::Decl, - clang::FieldDecl> field; +const internal::VariadicDynCastAllOfMatcher field; /// \brief Matches function declarations. /// /// Example matches f /// void f(); -const internal::VariadicDynCastAllOfMatcher< - clang::Decl, - clang::FunctionDecl> function; +const internal::VariadicDynCastAllOfMatcher function; /// \brief Matches statements. @@ -207,7 +311,7 @@ /// { ++a; } /// statement() /// matches both the compound statement '{ ++a; }' and '++a'. -const internal::VariadicDynCastAllOfMatcher statement; +const internal::VariadicDynCastAllOfMatcher statement; /// \brief Matches declaration statements. /// @@ -216,8 +320,8 @@ /// declarationStatement() /// matches 'int a'. const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, - clang::DeclStmt> declarationStatement; + Stmt, + DeclStmt> declarationStatement; /// \brief Matches member expressions. /// @@ -229,15 +333,34 @@ /// memberExpression() /// matches this->x, x, y.x, a, this->b const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, - clang::MemberExpr> memberExpression; + Stmt, + MemberExpr> memberExpression; /// \brief Matches call expressions. /// /// Example matches x.y() /// X x; /// x.y(); -const internal::VariadicDynCastAllOfMatcher call; +const internal::VariadicDynCastAllOfMatcher call; + +/// \brief Matches init list expressions. +/// +/// Given +/// int a[] = { 1, 2 }; +/// struct B { int x, y; }; +/// B b = { 5, 6 }; +/// initList() +/// matches "{ 1, 2 }" and "{ 5, 6 }" +const internal::VariadicDynCastAllOfMatcher initListExpr; + +/// \brief Matches using declarations. +/// +/// Given +/// namespace X { int x; } +/// using X::x; +/// usingDecl() +/// matches \code using X::x \endcode +const internal::VariadicDynCastAllOfMatcher usingDecl; /// \brief Matches constructor call expressions (including implicit ones). /// @@ -248,18 +371,18 @@ /// int n; /// f(string(ptr, n), ptr); const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, - clang::CXXConstructExpr> constructorCall; + Stmt, + CXXConstructExpr> constructorCall; /// \brief Matches nodes where temporaries are created. /// /// Example matches FunctionTakesString(GetStringByValue()) -/// (matcher = bindTemporaryExpr()) +/// (matcher = bindTemporaryExpression()) /// FunctionTakesString(GetStringByValue()); /// FunctionTakesStringByPointer(GetStringPointer()); const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, - clang::CXXBindTemporaryExpr> bindTemporaryExpression; + Stmt, + CXXBindTemporaryExpr> bindTemporaryExpression; /// \brief Matches new expressions. /// @@ -268,8 +391,28 @@ /// newExpression() /// matches 'new X'. const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, - clang::CXXNewExpr> newExpression; + Stmt, + CXXNewExpr> newExpression; + +/// \brief Matches delete expressions. +/// +/// Given +/// delete X; +/// deleteExpression() +/// matches 'delete X'. +const internal::VariadicDynCastAllOfMatcher< + Stmt, + CXXDeleteExpr> deleteExpression; + +/// \brief Matches array subscript expressions. +/// +/// Given +/// int i = a[1]; +/// arraySubscriptExpr() +/// matches "a[1]" +const internal::VariadicDynCastAllOfMatcher< + Stmt, + ArraySubscriptExpr> arraySubscriptExpr; /// \brief Matches the value of a default argument at the call site. /// @@ -279,8 +422,8 @@ /// void f(int x, int y = 0); /// f(42); const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, - clang::CXXDefaultArgExpr> defaultArgument; + Stmt, + CXXDefaultArgExpr> defaultArgument; /// \brief Matches overloaded operator calls. /// @@ -295,16 +438,16 @@ /// ostream &o; int b = 1, c = 1; /// o << b << c; const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, - clang::CXXOperatorCallExpr> overloadedOperatorCall; + Stmt, + CXXOperatorCallExpr> overloadedOperatorCall; /// \brief Matches expressions. /// /// Example matches x() /// void f() { x(); } const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, - clang::Expr> expression; + Stmt, + Expr> expression; /// \brief Matches expressions that refer to declarations. /// @@ -312,21 +455,21 @@ /// bool x; /// if (x) {} const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, - clang::DeclRefExpr> declarationReference; + Stmt, + DeclRefExpr> declarationReference; /// \brief Matches if statements. /// /// Example matches 'if (x) {}' /// if (x) {} -const internal::VariadicDynCastAllOfMatcher ifStmt; +const internal::VariadicDynCastAllOfMatcher ifStmt; /// \brief Matches for statements. /// /// Example matches 'for (;;) {}' /// for (;;) {} const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, clang::ForStmt> forStmt; + Stmt, ForStmt> forStmt; /// \brief Matches while statements. /// @@ -335,8 +478,8 @@ /// whileStmt() /// matches 'while (true) {}'. const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, - clang::WhileStmt> whileStmt; + Stmt, + WhileStmt> whileStmt; /// \brief Matches do statements. /// @@ -344,7 +487,7 @@ /// do {} while (true); /// doStmt() /// matches 'do {} while(true)' -const internal::VariadicDynCastAllOfMatcher doStmt; +const internal::VariadicDynCastAllOfMatcher doStmt; /// \brief Matches case and default statements inside switch statements. /// @@ -353,32 +496,32 @@ /// switchCase() /// matches 'case 42: break;' and 'default: break;'. const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, - clang::SwitchCase> switchCase; + Stmt, + SwitchCase> switchCase; /// \brief Matches compound statements. /// /// Example matches '{}' and '{{}}'in 'for (;;) {{}}' /// for (;;) {{}} const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, - clang::CompoundStmt> compoundStatement; + Stmt, + CompoundStmt> compoundStatement; /// \brief Matches bool literals. /// /// Example matches true /// true const internal::VariadicDynCastAllOfMatcher< - clang::Expr, - clang::CXXBoolLiteralExpr> boolLiteral; + Expr, + CXXBoolLiteralExpr> boolLiteral; /// \brief Matches string literals (also matches wide string literals). /// /// Example matches "abcd", L"abcd" /// char *s = "abcd"; wchar_t *ws = L"abcd" const internal::VariadicDynCastAllOfMatcher< - clang::Expr, - clang::StringLiteral> stringLiteral; + Expr, + StringLiteral> stringLiteral; /// \brief Matches character literals (also matches wchar_t). /// @@ -388,8 +531,8 @@ /// Example matches 'a', L'a' /// char ch = 'a'; wchar_t chw = L'a'; const internal::VariadicDynCastAllOfMatcher< - clang::Expr, - clang::CharacterLiteral> characterLiteral; + Expr, + CharacterLiteral> characterLiteral; /// \brief Matches integer literals of all sizes / encodings. /// @@ -397,32 +540,32 @@ /// /// Example matches 1, 1L, 0x1, 1U const internal::VariadicDynCastAllOfMatcher< - clang::Expr, - clang::IntegerLiteral> integerLiteral; + Expr, + IntegerLiteral> integerLiteral; /// \brief Matches binary operator expressions. /// /// Example matches a || b /// !(a || b) const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, - clang::BinaryOperator> binaryOperator; + Stmt, + BinaryOperator> binaryOperator; /// \brief Matches unary operator expressions. /// /// Example matches !a /// !a || b const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, - clang::UnaryOperator> unaryOperator; + Stmt, + UnaryOperator> unaryOperator; /// \brief Matches conditional operator expressions. /// /// Example matches a ? b : c /// (a ? b : c) + 42 const internal::VariadicDynCastAllOfMatcher< - clang::Stmt, - clang::ConditionalOperator> conditionalOperator; + Stmt, + ConditionalOperator> conditionalOperator; /// \brief Matches a reinterpret_cast expression. /// @@ -433,8 +576,8 @@ /// Example matches reinterpret_cast(&p) in /// void* p = reinterpret_cast(&p); const internal::VariadicDynCastAllOfMatcher< - clang::Expr, - clang::CXXReinterpretCastExpr> reinterpretCast; + Expr, + CXXReinterpretCastExpr> reinterpretCast; /// \brief Matches a C++ static_cast expression. /// @@ -448,8 +591,8 @@ /// in /// long eight(static_cast(8)); const internal::VariadicDynCastAllOfMatcher< - clang::Expr, - clang::CXXStaticCastExpr> staticCast; + Expr, + CXXStaticCastExpr> staticCast; /// \brief Matches a dynamic_cast expression. /// @@ -462,8 +605,8 @@ /// B b; /// D* p = dynamic_cast(&b); const internal::VariadicDynCastAllOfMatcher< - clang::Expr, - clang::CXXDynamicCastExpr> dynamicCast; + Expr, + CXXDynamicCastExpr> dynamicCast; /// \brief Matches a const_cast expression. /// @@ -472,8 +615,8 @@ /// const int& r(n); /// int* p = const_cast(&r); const internal::VariadicDynCastAllOfMatcher< - clang::Expr, - clang::CXXConstCastExpr> constCast; + Expr, + CXXConstCastExpr> constCast; /// \brief Matches explicit cast expressions. /// @@ -493,16 +636,16 @@ /// but does not match the implicit conversion in /// long ell = 42; const internal::VariadicDynCastAllOfMatcher< - clang::Expr, - clang::ExplicitCastExpr> explicitCast; + Expr, + ExplicitCastExpr> explicitCast; /// \brief Matches the implicit cast nodes of Clang's AST. /// /// This matches many different places, including function call return value /// eliding, as well as any type conversions. const internal::VariadicDynCastAllOfMatcher< - clang::Expr, - clang::ImplicitCastExpr> implicitCast; + Expr, + ImplicitCastExpr> implicitCast; /// \brief Matches functional cast expressions /// @@ -511,8 +654,8 @@ /// Foo g = (Foo) bar; /// Foo h = Foo(bar); const internal::VariadicDynCastAllOfMatcher< - clang::Expr, - clang::CXXFunctionalCastExpr> functionalCast; + Expr, + CXXFunctionalCastExpr> functionalCast; /// \brief Various overloads for the anyOf matcher. /// @{ @@ -563,6 +706,56 @@ } /// @} +/// \brief Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL) +/// +/// Given +/// Foo x = bar; +/// int y = sizeof(x) + alignof(x); +/// unaryExprOrTypeTraitExpr() +/// matches \c sizeof(x) and \c alignof(x) +const internal::VariadicDynCastAllOfMatcher< + Stmt, + UnaryExprOrTypeTraitExpr> unaryExprOrTypeTraitExpr; + +/// \brief Matches unary expressions that have a specific type of argument. +/// +/// Given +/// int a, c; float b; int s = sizeof(a) + sizeof(b) + alignof(c); +/// unaryExprOrTypeTraitExpr(hasArgumentOfType(asString("int")) +/// matches \c sizeof(a) and \c alignof(c) +AST_MATCHER_P(UnaryExprOrTypeTraitExpr, hasArgumentOfType, + internal::Matcher, Matcher) { + const QualType ArgumentType = Node.getTypeOfArgument(); + return Matcher.matches(ArgumentType, Finder, Builder); +} + +/// \brief Matches unary expressions of a certain kind. +/// +/// Given +/// int x; +/// int s = sizeof(x) + alignof(x) +/// unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf)) +/// matches \c sizeof(x) +AST_MATCHER_P(UnaryExprOrTypeTraitExpr, ofKind, UnaryExprOrTypeTrait, Kind) { + return Node.getKind() == Kind; +} + +/// \brief Same as unaryExprOrTypeTraitExpr, but only matching +/// alignof. +inline internal::Matcher alignOfExpr( + const internal::Matcher &Matcher) { + return internal::Matcher(unaryExprOrTypeTraitExpr(allOf( + ofKind(UETT_AlignOf), Matcher))); +} + +/// \brief Same as unaryExprOrTypeTraitExpr, but only matching +/// sizeof. +inline internal::Matcher sizeOfExpr( + const internal::Matcher &Matcher) { + return internal::Matcher(unaryExprOrTypeTraitExpr(allOf( + ofKind(UETT_SizeOf), Matcher))); +} + /// \brief Matches NamedDecl nodes that have the specified name. /// /// Supports specifying enclosing namespaces or classes by prefixing the name @@ -574,7 +767,7 @@ /// /// Example matches X (Name is one of "::a::b::X", "a::b::X", "b::X", "X") /// namespace a { namespace b { class X; } } -AST_MATCHER_P(clang::NamedDecl, hasName, std::string, Name) { +AST_MATCHER_P(NamedDecl, hasName, std::string, Name) { assert(!Name.empty()); const std::string FullNameString = "::" + Node.getQualifiedNameAsString(); const llvm::StringRef FullName = FullNameString; @@ -586,6 +779,25 @@ } } +/// \brief Matches NamedDecl nodes whose full names match partial match the +/// given RegExp. +/// +/// Supports specifying enclosing namespaces or classes by +/// prefixing the name with '::'. Does not match typedefs +/// of an underlying type with the given name. +/// +/// Example matches X (regexp == "::X") +/// class X; +/// +/// Example matches X (regexp is one of "::X", "^foo::.*X", among others) +/// namespace foo { namespace bar { class X; } } +AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) { + assert(!RegExp.empty()); + std::string FullNameString = "::" + Node.getQualifiedNameAsString(); + llvm::Regex RE(RegExp); + return RE.match(FullNameString); +} + /// \brief Matches overloaded operator names. /// /// Matches overloaded operator names specified in strings without the @@ -596,9 +808,9 @@ /// a << b; /// c && d; // assuming both operator<< /// // and operator&& are overloaded somewhere. -AST_MATCHER_P(clang::CXXOperatorCallExpr, +AST_MATCHER_P(CXXOperatorCallExpr, hasOverloadedOperatorName, std::string, Name) { - return clang::getOperatorSpelling(Node.getOperator()) == Name; + return getOperatorSpelling(Node.getOperator()) == Name; } /// \brief Matches C++ classes that are directly or indirectly derived from @@ -621,7 +833,7 @@ /// class Foo; /// typedef Foo X; /// class Bar : public Foo {}; // derived from a type that X is a typedef of -AST_MATCHER_P(clang::CXXRecordDecl, isDerivedFrom, std::string, Base) { +AST_MATCHER_P(CXXRecordDecl, isDerivedFrom, std::string, Base) { assert(!Base.empty()); return Finder->classIsDerivedFrom(&Node, Base); } @@ -722,11 +934,11 @@ /// \brief Matches a type if the declaration of the type matches the given /// matcher. inline internal::PolymorphicMatcherWithParam1< internal::HasDeclarationMatcher, - internal::Matcher > - hasDeclaration(const internal::Matcher &InnerMatcher) { + internal::Matcher > + hasDeclaration(const internal::Matcher &InnerMatcher) { return internal::PolymorphicMatcherWithParam1< internal::HasDeclarationMatcher, - internal::Matcher >(InnerMatcher); + internal::Matcher >(InnerMatcher); } /// \brief Matches on the implicit object argument of a member call expression. @@ -736,9 +948,9 @@ /// void z() { Y y; y.x(); }", /// /// FIXME: Overload to allow directly matching types? -AST_MATCHER_P(clang::CXXMemberCallExpr, on, internal::Matcher, +AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher, InnerMatcher) { - const clang::Expr *ExprNode = const_cast(Node) + const Expr *ExprNode = const_cast(Node) .getImplicitObjectArgument() ->IgnoreParenImpCasts(); return (ExprNode != NULL && @@ -755,13 +967,13 @@ /// with callee(...) /// matching this->x, x, y.x, f respectively /// -/// Note: Callee cannot take the more general internal::Matcher +/// Note: Callee cannot take the more general internal::Matcher /// because this introduces ambiguous overloads with calls to Callee taking a -/// internal::Matcher, as the matcher hierarchy is purely +/// internal::Matcher, as the matcher hierarchy is purely /// implemented in terms of implicit casts. -AST_MATCHER_P(clang::CallExpr, callee, internal::Matcher, +AST_MATCHER_P(CallExpr, callee, internal::Matcher, InnerMatcher) { - const clang::Expr *ExprNode = Node.getCallee(); + const Expr *ExprNode = Node.getCallee(); return (ExprNode != NULL && InnerMatcher.matches(*ExprNode, Finder, Builder)); } @@ -772,9 +984,9 @@ /// Example matches y.x() (matcher = call(callee(method(hasName("x"))))) /// class Y { public: void x(); }; /// void z() { Y y; y.x(); -inline internal::Matcher callee( - const internal::Matcher &InnerMatcher) { - return internal::Matcher(hasDeclaration(InnerMatcher)); +inline internal::Matcher callee( + const internal::Matcher &InnerMatcher) { + return internal::Matcher(hasDeclaration(InnerMatcher)); } /// \brief Matches if the expression's or declaration's type matches a type @@ -786,10 +998,10 @@ /// hasDeclaration(record(hasName("X")))))) /// class X {}; /// void y(X &x) { x; X z; } -AST_POLYMORPHIC_MATCHER_P(hasType, internal::Matcher, +AST_POLYMORPHIC_MATCHER_P(hasType, internal::Matcher, InnerMatcher) { - TOOLING_COMPILE_ASSERT((llvm::is_base_of::value || - llvm::is_base_of::value), + TOOLING_COMPILE_ASSERT((llvm::is_base_of::value || + llvm::is_base_of::value), instantiated_with_wrong_types); return InnerMatcher.matches(Node.getType(), Finder, Builder); } @@ -809,12 +1021,23 @@ /// void y(X &x) { x; X z; } inline internal::PolymorphicMatcherWithParam1< internal::matcher_hasTypeMatcher, - internal::Matcher > -hasType(const internal::Matcher &InnerMatcher) { - return hasType(internal::Matcher( + internal::Matcher > +hasType(const internal::Matcher &InnerMatcher) { + return hasType(internal::Matcher( hasDeclaration(InnerMatcher))); } +/// \brief Matches if the matched type is represented by the given string. +/// +/// Given +/// class Y { public: void x(); }; +/// void z() { Y* y; y->x(); } +/// call(on(hasType(asString("class Y *")))) +/// matches y->x() +AST_MATCHER_P(QualType, asString, std::string, Name) { + return Name == Node.getAsString(); +} + /// \brief Matches if the matched type is a pointer type and the pointee type /// matches the specified matcher. /// @@ -823,16 +1046,16 @@ /// class Y { public: void x(); }; /// void z() { Y *y; y->x(); } AST_MATCHER_P( - clang::QualType, pointsTo, internal::Matcher, + QualType, pointsTo, internal::Matcher, InnerMatcher) { - return (Node->isPointerType() && + return (!Node.isNull() && Node->isPointerType() && InnerMatcher.matches(Node->getPointeeType(), Finder, Builder)); } /// \brief Overloaded to match the pointee type's declaration. -inline internal::Matcher pointsTo( - const internal::Matcher &InnerMatcher) { - return pointsTo(internal::Matcher( +inline internal::Matcher pointsTo( + const internal::Matcher &InnerMatcher) { + return pointsTo(internal::Matcher( hasDeclaration(InnerMatcher))); } @@ -846,38 +1069,38 @@ /// X &x = b; /// const X &y = b; /// }; -AST_MATCHER_P(clang::QualType, references, internal::Matcher, +AST_MATCHER_P(QualType, references, internal::Matcher, InnerMatcher) { - return (Node->isReferenceType() && + return (!Node.isNull() && Node->isReferenceType() && InnerMatcher.matches(Node->getPointeeType(), Finder, Builder)); } /// \brief Overloaded to match the referenced type's declaration. -inline internal::Matcher references( - const internal::Matcher &InnerMatcher) { - return references(internal::Matcher( +inline internal::Matcher references( + const internal::Matcher &InnerMatcher) { + return references(internal::Matcher( hasDeclaration(InnerMatcher))); } -AST_MATCHER_P(clang::CXXMemberCallExpr, onImplicitObjectArgument, - internal::Matcher, InnerMatcher) { - const clang::Expr *ExprNode = - const_cast(Node).getImplicitObjectArgument(); +AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument, + internal::Matcher, InnerMatcher) { + const Expr *ExprNode = + const_cast(Node).getImplicitObjectArgument(); return (ExprNode != NULL && InnerMatcher.matches(*ExprNode, Finder, Builder)); } /// \brief Matches if the expression's type either matches the specified /// matcher, or is a pointer to a type that matches the InnerMatcher. -inline internal::Matcher thisPointerType( - const internal::Matcher &InnerMatcher) { +inline internal::Matcher thisPointerType( + const internal::Matcher &InnerMatcher) { return onImplicitObjectArgument( anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher)))); } /// \brief Overloaded to match the type's declaration. -inline internal::Matcher thisPointerType( - const internal::Matcher &InnerMatcher) { +inline internal::Matcher thisPointerType( + const internal::Matcher &InnerMatcher) { return onImplicitObjectArgument( anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher)))); } @@ -889,13 +1112,36 @@ /// (matcher = declarationReference(to(variable(hasName("x"))))) /// bool x; /// if (x) {} -AST_MATCHER_P(clang::DeclRefExpr, to, internal::Matcher, +AST_MATCHER_P(DeclRefExpr, to, internal::Matcher, InnerMatcher) { - const clang::Decl *DeclNode = Node.getDecl(); + const Decl *DeclNode = Node.getDecl(); return (DeclNode != NULL && InnerMatcher.matches(*DeclNode, Finder, Builder)); } +/// \brief Matches a \c DeclRefExpr that refers to a declaration through a +/// specific using shadow declaration. +/// +/// FIXME: This currently only works for functions. Fix. +/// +/// Given +/// namespace a { void f() {} } +/// using a::f; +/// void g() { +/// f(); // Matches this .. +/// a::f(); // .. but not this. +/// } +/// declarationReference(throughUsingDeclaration(anything())) +/// matches \c f() +AST_MATCHER_P(DeclRefExpr, throughUsingDecl, + internal::Matcher, Matcher) { + const NamedDecl *FoundDecl = Node.getFoundDecl(); + if (const UsingShadowDecl *UsingDecl = + llvm::dyn_cast(FoundDecl)) + return Matcher.matches(*UsingDecl, Finder, Builder); + return false; +} + /// \brief Matches a variable declaration that has an initializer expression /// that matches the given matcher. /// @@ -903,9 +1149,9 @@ /// bool y() { return true; } /// bool x = y(); AST_MATCHER_P( - clang::VarDecl, hasInitializer, internal::Matcher, + VarDecl, hasInitializer, internal::Matcher, InnerMatcher) { - const clang::Expr *Initializer = Node.getAnyInitializer(); + const Expr *Initializer = Node.getAnyInitializer(); return (Initializer != NULL && InnerMatcher.matches(*Initializer, Finder, Builder)); } @@ -917,8 +1163,8 @@ /// void f(int x, int y); /// f(0, 0); AST_POLYMORPHIC_MATCHER_P(argumentCountIs, unsigned, N) { - TOOLING_COMPILE_ASSERT((llvm::is_base_of::value || - llvm::is_base_of::value || + llvm::is_base_of::value), instantiated_with_wrong_types); return Node.getNumArgs() == N; @@ -931,9 +1177,9 @@ /// (matcher = call(hasArgument(0, declarationReference()))) /// void x(int) { int y; x(y); } AST_POLYMORPHIC_MATCHER_P2( - hasArgument, unsigned, N, internal::Matcher, InnerMatcher) { - TOOLING_COMPILE_ASSERT((llvm::is_base_of::value || - llvm::is_base_of, InnerMatcher) { + TOOLING_COMPILE_ASSERT((llvm::is_base_of::value || + llvm::is_base_of::value), instantiated_with_wrong_types); return (N < Node.getNumArgs() && @@ -948,11 +1194,11 @@ /// Foo() : foo_(1) { } /// int foo_; /// }; -/// record(Has(Constructor(hasAnyConstructorInitializer(anything())))) -/// Class matches Foo, hasAnyConstructorInitializer matches foo_(1) -AST_MATCHER_P(clang::CXXConstructorDecl, hasAnyConstructorInitializer, - internal::Matcher, InnerMatcher) { - for (clang::CXXConstructorDecl::init_const_iterator I = Node.init_begin(); +/// record(has(constructor(hasAnyConstructorInitializer(anything())))) +/// record matches Foo, hasAnyConstructorInitializer matches foo_(1) +AST_MATCHER_P(CXXConstructorDecl, hasAnyConstructorInitializer, + internal::Matcher, InnerMatcher) { + for (CXXConstructorDecl::init_const_iterator I = Node.init_begin(); I != Node.init_end(); ++I) { if (InnerMatcher.matches(**I, Finder, Builder)) { return true; @@ -972,9 +1218,9 @@ /// forField(hasName("foo_")))))) /// matches Foo /// with forField matching foo_ -AST_MATCHER_P(clang::CXXCtorInitializer, forField, - internal::Matcher, InnerMatcher) { - const clang::FieldDecl *NodeAsDecl = Node.getMember(); +AST_MATCHER_P(CXXCtorInitializer, forField, + internal::Matcher, InnerMatcher) { + const FieldDecl *NodeAsDecl = Node.getMember(); return (NodeAsDecl != NULL && InnerMatcher.matches(*NodeAsDecl, Finder, Builder)); } @@ -990,9 +1236,9 @@ /// withInitializer(integerLiteral(equals(1))))))) /// matches Foo /// with withInitializer matching (1) -AST_MATCHER_P(clang::CXXCtorInitializer, withInitializer, - internal::Matcher, InnerMatcher) { - const clang::Expr* NodeAsExpr = Node.getInit(); +AST_MATCHER_P(CXXCtorInitializer, withInitializer, + internal::Matcher, InnerMatcher) { + const Expr* NodeAsExpr = Node.getInit(); return (NodeAsExpr != NULL && InnerMatcher.matches(*NodeAsExpr, Finder, Builder)); } @@ -1008,13 +1254,13 @@ /// }; /// constructor(hasAnyConstructorInitializer(isWritten())) /// will match Foo(int), but not Foo() -AST_MATCHER(clang::CXXCtorInitializer, isWritten) { +AST_MATCHER(CXXCtorInitializer, isWritten) { return Node.isWritten(); } /// \brief Matches a constructor declaration that has been implicitly added /// by the compiler (eg. implicit default/copy constructors). -AST_MATCHER(clang::CXXConstructorDecl, isImplicit) { +AST_MATCHER(CXXConstructorDecl, isImplicit) { return Node.isImplicit(); } @@ -1027,10 +1273,10 @@ /// matches x(1, y, 42) /// with hasAnyArgument(...) /// matching y -AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, internal::Matcher, +AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, internal::Matcher, InnerMatcher) { - TOOLING_COMPILE_ASSERT((llvm::is_base_of::value || - llvm::is_base_of::value || + llvm::is_base_of::value), instantiated_with_wrong_types); for (unsigned I = 0; I < Node.getNumArgs(); ++I) { @@ -1050,8 +1296,8 @@ /// matches f(int x) {} /// with hasParameter(...) /// matching int x -AST_MATCHER_P2(clang::FunctionDecl, hasParameter, - unsigned, N, internal::Matcher, +AST_MATCHER_P2(FunctionDecl, hasParameter, + unsigned, N, internal::Matcher, InnerMatcher) { return (N < Node.getNumParams() && InnerMatcher.matches( @@ -1068,8 +1314,8 @@ /// matches f(int x, int y, int z) {} /// with hasAnyParameter(...) /// matching int y -AST_MATCHER_P(clang::FunctionDecl, hasAnyParameter, - internal::Matcher, InnerMatcher) { +AST_MATCHER_P(FunctionDecl, hasAnyParameter, + internal::Matcher, InnerMatcher) { for (unsigned I = 0; I < Node.getNumParams(); ++I) { if (InnerMatcher.matches(*Node.getParamDecl(I), Finder, Builder)) { return true; @@ -1078,18 +1324,28 @@ return false; } +/// \brief Matches the return type of a function declaration. +/// +/// Given: +/// class X { int f() { return 1; } }; +/// method(returns(asString("int"))) +/// matches int f() { return 1; } +AST_MATCHER_P(FunctionDecl, returns, internal::Matcher, Matcher) { + return Matcher.matches(Node.getResultType(), Finder, Builder); +} + /// \brief Matches the condition expression of an if statement or conditional /// operator. /// /// Example matches true (matcher = hasCondition(boolLiteral(equals(true)))) /// if (true) {} -AST_POLYMORPHIC_MATCHER_P(hasCondition, internal::Matcher, +AST_POLYMORPHIC_MATCHER_P(hasCondition, internal::Matcher, InnerMatcher) { TOOLING_COMPILE_ASSERT( - (llvm::is_base_of::value) || - (llvm::is_base_of::value), + (llvm::is_base_of::value) || + (llvm::is_base_of::value), has_condition_requires_if_statement_or_conditional_operator); - const clang::Expr *const Condition = Node.getCond(); + const Expr *const Condition = Node.getCond(); return (Condition != NULL && InnerMatcher.matches(*Condition, Finder, Builder)); } @@ -1100,14 +1356,43 @@ /// if (A* a = GetAPointer()) {} /// hasConditionVariableStatment(...) /// matches 'A* a = GetAPointer()'. -AST_MATCHER_P(clang::IfStmt, hasConditionVariableStatement, - internal::Matcher, InnerMatcher) { - const clang::DeclStmt* const DeclarationStatement = +AST_MATCHER_P(IfStmt, hasConditionVariableStatement, + internal::Matcher, InnerMatcher) { + const DeclStmt* const DeclarationStatement = Node.getConditionVariableDeclStmt(); return DeclarationStatement != NULL && InnerMatcher.matches(*DeclarationStatement, Finder, Builder); } +/// \brief Matches the index expression of an array subscript expression. +/// +/// Given +/// int i[5]; +/// void f() { i[1] = 42; } +/// arraySubscriptExpression(hasIndex(integerLiteral())) +/// matches \c i[1] with the \c integerLiteral() matching \c 1 +AST_MATCHER_P(ArraySubscriptExpr, hasIndex, + internal::Matcher, matcher) { + if (const Expr* Expression = Node.getIdx()) + return matcher.matches(*Expression, Finder, Builder); + return false; +} + +/// \brief Matches the base expression of an array subscript expression. +/// +/// Given +/// int i[5]; +/// void f() { i[1] = 42; } +/// arraySubscriptExpression(hasBase(implicitCast( +/// hasSourceExpression(declarationReference())))) +/// matches \c i[1] with the \c declarationReference() matching \c i +AST_MATCHER_P(ArraySubscriptExpr, hasBase, + internal::Matcher, matcher) { + if (const Expr* Expression = Node.getBase()) + return matcher.matches(*Expression, Finder, Builder); + return false; +} + /// \brief Matches a 'for' statement that has a given body. /// /// Given @@ -1116,9 +1401,9 @@ /// matches 'for (;;) {}' /// with compoundStatement() /// matching '{}' -AST_MATCHER_P(clang::ForStmt, hasBody, internal::Matcher, +AST_MATCHER_P(ForStmt, hasBody, internal::Matcher, InnerMatcher) { - const clang::Stmt *const Statement = Node.getBody(); + const Stmt *const Statement = Node.getBody(); return (Statement != NULL && InnerMatcher.matches(*Statement, Finder, Builder)); } @@ -1132,9 +1417,9 @@ /// matches '{ {}; 1+2; }' /// with compoundStatement() /// matching '{}' -AST_MATCHER_P(clang::CompoundStmt, hasAnySubstatement, - internal::Matcher, InnerMatcher) { - for (clang::CompoundStmt::const_body_iterator It = Node.body_begin(); +AST_MATCHER_P(CompoundStmt, hasAnySubstatement, + internal::Matcher, InnerMatcher) { + for (CompoundStmt::const_body_iterator It = Node.body_begin(); It != Node.body_end(); ++It) { if (InnerMatcher.matches(**It, Finder, Builder)) return true; @@ -1150,7 +1435,7 @@ /// compoundStatement(statementCountIs(0))) /// matches '{}' /// but does not match the outer compound statement. -AST_MATCHER_P(clang::CompoundStmt, statementCountIs, unsigned, N) { +AST_MATCHER_P(CompoundStmt, statementCountIs, unsigned, N) { return Node.size() == N; } @@ -1173,8 +1458,8 @@ /// !(a || b) AST_POLYMORPHIC_MATCHER_P(hasOperatorName, std::string, Name) { TOOLING_COMPILE_ASSERT( - (llvm::is_base_of::value) || - (llvm::is_base_of::value), + (llvm::is_base_of::value) || + (llvm::is_base_of::value), has_condition_requires_if_statement_or_conditional_operator); return Name == Node.getOpcodeStr(Node.getOpcode()); } @@ -1183,9 +1468,9 @@ /// /// Example matches a (matcher = binaryOperator(hasLHS())) /// a || b -AST_MATCHER_P(clang::BinaryOperator, hasLHS, - internal::Matcher, InnerMatcher) { - clang::Expr *LeftHandSide = Node.getLHS(); +AST_MATCHER_P(BinaryOperator, hasLHS, + internal::Matcher, InnerMatcher) { + Expr *LeftHandSide = Node.getLHS(); return (LeftHandSide != NULL && InnerMatcher.matches(*LeftHandSide, Finder, Builder)); } @@ -1194,17 +1479,17 @@ /// /// Example matches b (matcher = binaryOperator(hasRHS())) /// a || b -AST_MATCHER_P(clang::BinaryOperator, hasRHS, - internal::Matcher, InnerMatcher) { - clang::Expr *RightHandSide = Node.getRHS(); +AST_MATCHER_P(BinaryOperator, hasRHS, + internal::Matcher, InnerMatcher) { + Expr *RightHandSide = Node.getRHS(); return (RightHandSide != NULL && InnerMatcher.matches(*RightHandSide, Finder, Builder)); } /// \brief Matches if either the left hand side or the right hand side of a /// binary operator matches. -inline internal::Matcher hasEitherOperand( - const internal::Matcher &InnerMatcher) { +inline internal::Matcher hasEitherOperand( + const internal::Matcher &InnerMatcher) { return anyOf(hasLHS(InnerMatcher), hasRHS(InnerMatcher)); } @@ -1212,23 +1497,24 @@ /// /// Example matches true (matcher = hasOperand(boolLiteral(equals(true)))) /// !true -AST_MATCHER_P(clang::UnaryOperator, hasUnaryOperand, - internal::Matcher, InnerMatcher) { - const clang::Expr * const Operand = Node.getSubExpr(); +AST_MATCHER_P(UnaryOperator, hasUnaryOperand, + internal::Matcher, InnerMatcher) { + const Expr * const Operand = Node.getSubExpr(); return (Operand != NULL && InnerMatcher.matches(*Operand, Finder, Builder)); } -/// Matches if the implicit cast's source expression matches the given matcher. +/// \brief Matches if the implicit cast's source expression matches the given +/// matcher. /// /// Example: matches "a string" (matcher = /// hasSourceExpression(constructorCall())) /// /// class URL { URL(string); }; /// URL url = "a string"; -AST_MATCHER_P(clang::ImplicitCastExpr, hasSourceExpression, - internal::Matcher, InnerMatcher) { - const clang::Expr* const SubExpression = Node.getSubExpr(); +AST_MATCHER_P(ImplicitCastExpr, hasSourceExpression, + internal::Matcher, InnerMatcher) { + const Expr* const SubExpression = Node.getSubExpr(); return (SubExpression != NULL && InnerMatcher.matches(*SubExpression, Finder, Builder)); } @@ -1237,9 +1523,9 @@ /// /// (Note: Clang's AST refers to other conversions as "casts" too, and calls /// actual casts "explicit" casts.) -AST_MATCHER_P(clang::ExplicitCastExpr, hasDestinationType, - internal::Matcher, InnerMatcher) { - const clang::QualType NodeType = Node.getTypeAsWritten(); +AST_MATCHER_P(ExplicitCastExpr, hasDestinationType, + internal::Matcher, InnerMatcher) { + const QualType NodeType = Node.getTypeAsWritten(); return InnerMatcher.matches(NodeType, Finder, Builder); } @@ -1247,8 +1533,8 @@ /// matcher. /// /// FIXME: Unit test this matcher -AST_MATCHER_P(clang::ImplicitCastExpr, hasImplicitDestinationType, - internal::Matcher, InnerMatcher) { +AST_MATCHER_P(ImplicitCastExpr, hasImplicitDestinationType, + internal::Matcher, InnerMatcher) { return InnerMatcher.matches(Node.getType(), Finder, Builder); } @@ -1256,9 +1542,9 @@ /// /// Example matches a /// condition ? a : b -AST_MATCHER_P(clang::ConditionalOperator, hasTrueExpression, - internal::Matcher, InnerMatcher) { - clang::Expr *Expression = Node.getTrueExpr(); +AST_MATCHER_P(ConditionalOperator, hasTrueExpression, + internal::Matcher, InnerMatcher) { + Expr *Expression = Node.getTrueExpr(); return (Expression != NULL && InnerMatcher.matches(*Expression, Finder, Builder)); } @@ -1267,9 +1553,9 @@ /// /// Example matches b /// condition ? a : b -AST_MATCHER_P(clang::ConditionalOperator, hasFalseExpression, - internal::Matcher, InnerMatcher) { - clang::Expr *Expression = Node.getFalseExpr(); +AST_MATCHER_P(ConditionalOperator, hasFalseExpression, + internal::Matcher, InnerMatcher) { + Expr *Expression = Node.getFalseExpr(); return (Expression != NULL && InnerMatcher.matches(*Expression, Finder, Builder)); } @@ -1304,9 +1590,9 @@ /// A(); /// }; /// A a = A(); -AST_MATCHER_P(clang::CXXMethodDecl, ofClass, - internal::Matcher, InnerMatcher) { - const clang::CXXRecordDecl *Parent = Node.getParent(); +AST_MATCHER_P(CXXMethodDecl, ofClass, + internal::Matcher, InnerMatcher) { + const CXXRecordDecl *Parent = Node.getParent(); return (Parent != NULL && InnerMatcher.matches(*Parent, Finder, Builder)); } @@ -1324,11 +1610,11 @@ /// }; /// memberExpression(isArrow()) /// matches this->x, x, y.x, a, this->b -inline internal::Matcher isArrow() { +inline internal::Matcher isArrow() { return makeMatcher(new internal::IsArrowMatcher()); } -/// \brief Matches clang::QualType nodes that are const-qualified, i.e., that +/// \brief Matches QualType nodes that are const-qualified, i.e., that /// include "top-level" const. /// /// Given @@ -1341,7 +1627,7 @@ /// matches "void b(int const)", "void c(const int)" and /// "void e(int const) {}". It does not match d as there /// is no top-level const on the parameter type "const int *". -inline internal::Matcher isConstQualified() { +inline internal::Matcher isConstQualified() { return makeMatcher(new internal::IsConstQualifiedMatcher()); } @@ -1355,8 +1641,8 @@ /// memberExpression(member(hasName("first"))) /// matches second.first /// but not first.second (because the member name there is "second"). -AST_MATCHER_P(clang::MemberExpr, member, - internal::Matcher, InnerMatcher) { +AST_MATCHER_P(MemberExpr, member, + internal::Matcher, InnerMatcher) { return InnerMatcher.matches(*Node.getMemberDecl(), Finder, Builder); } @@ -1370,11 +1656,43 @@ /// matches "x.m" and "m" /// with hasObjectExpression(...) /// matching "x" and the implicit object expression of "m" which has type X*. -AST_MATCHER_P(clang::MemberExpr, hasObjectExpression, - internal::Matcher, InnerMatcher) { +AST_MATCHER_P(MemberExpr, hasObjectExpression, + internal::Matcher, InnerMatcher) { return InnerMatcher.matches(*Node.getBase(), Finder, Builder); } +/// \brief Matches any using shadow declaration. +/// +/// Given +/// namespace X { void b(); } +/// using X::b; +/// usingDecl(hasAnyUsingShadowDecl(hasName("b")))) +/// matches \code using X::b \endcode +AST_MATCHER_P(UsingDecl, hasAnyUsingShadowDecl, + internal::Matcher, Matcher) { + for (UsingDecl::shadow_iterator II = Node.shadow_begin(); + II != Node.shadow_end(); ++II) { + if (Matcher.matches(**II, Finder, Builder)) + return true; + } + return false; +} + +/// \brief Matches a using shadow declaration where the target declaration is +/// matched by the given matcher. +/// +/// Given +/// namespace X { int a; void b(); } +/// using X::a; +/// using X::b; +/// usingDecl(hasAnyUsingShadowDecl(hasTargetDecl(function()))) +/// matches \code using X::b \endcode +/// but not \code using X::a \endcode +AST_MATCHER_P(UsingShadowDecl, hasTargetDecl, + internal::Matcher, Matcher) { + return Matcher.matches(*Node.getTargetDecl(), Finder, Builder); +} + /// \brief Matches template instantiations of function, class, or static /// member variable template instantiations. /// Index: include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- include/clang/ASTMatchers/ASTMatchersInternal.h +++ include/clang/ASTMatchers/ASTMatchersInternal.h @@ -84,8 +84,8 @@ BoundNodesTree(); /// \brief Create a BoundNodesTree from pre-filled maps of bindings. - BoundNodesTree(const std::map& DeclBindings, - const std::map& StmtBindings, + BoundNodesTree(const std::map& DeclBindings, + const std::map& StmtBindings, const std::vector RecursiveBindings); /// \brief Adds all bound nodes to bound_nodes_builder. @@ -99,8 +99,8 @@ private: void visitMatchesRecursively( Visitor* ResultVistior, - std::map DeclBindings, - std::map StmtBindings); + std::map DeclBindings, + std::map StmtBindings); template void copyBindingsTo(const T& bindings, BoundNodesTreeBuilder* Builder) const; @@ -108,8 +108,8 @@ // FIXME: Find out whether we want to use different data structures here - // first benchmarks indicate that it doesn't matter though. - std::map DeclBindings; - std::map StmtBindings; + std::map DeclBindings; + std::map StmtBindings; std::vector RecursiveBindings; }; @@ -126,10 +126,8 @@ /// /// FIXME: Add overloads for all AST base types. /// @{ - void setBinding(const std::pair& binding); - void setBinding(const std::pair& binding); + void setBinding(const std::string &Id, const Decl *Node); + void setBinding(const std::string &Id, const Stmt *Node); /// @} /// \brief Adds a branch in the tree. @@ -142,8 +140,8 @@ BoundNodesTreeBuilder(const BoundNodesTreeBuilder&); // DO NOT IMPLEMENT void operator=(const BoundNodesTreeBuilder&); // DO NOT IMPLEMENT - std::map DeclBindings; - std::map StmtBindings; + std::map DeclBindings; + std::map StmtBindings; std::vector RecursiveBindings; }; @@ -262,10 +260,10 @@ template class HasDeclarationMatcher : public MatcherInterface { TOOLING_COMPILE_ASSERT((llvm::is_same< DeclMatcherT, - Matcher >::value), + Matcher >::value), instantiated_with_wrong_types); public: - explicit HasDeclarationMatcher(const Matcher &InnerMatcher) + explicit HasDeclarationMatcher(const Matcher &InnerMatcher) : InnerMatcher(InnerMatcher) {} virtual bool matches(const T &Node, @@ -277,34 +275,36 @@ private: /// \brief Extracts the CXXRecordDecl of a QualType and returns whether the /// inner matcher matches on it. - bool matchesSpecialized(const clang::QualType &Node, ASTMatchFinder *Finder, + bool matchesSpecialized(const QualType &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { /// FIXME: Add other ways to convert... - clang::CXXRecordDecl *NodeAsRecordDecl = Node->getAsCXXRecordDecl(); + if (Node.isNull()) + return false; + CXXRecordDecl *NodeAsRecordDecl = Node->getAsCXXRecordDecl(); return NodeAsRecordDecl != NULL && InnerMatcher.matches(*NodeAsRecordDecl, Finder, Builder); } /// \brief Extracts the Decl of the callee of a CallExpr and returns whether /// the inner matcher matches on it. - bool matchesSpecialized(const clang::CallExpr &Node, ASTMatchFinder *Finder, + bool matchesSpecialized(const CallExpr &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { - const clang::Decl *NodeAsDecl = Node.getCalleeDecl(); + const Decl *NodeAsDecl = Node.getCalleeDecl(); return NodeAsDecl != NULL && InnerMatcher.matches(*NodeAsDecl, Finder, Builder); } /// \brief Extracts the Decl of the constructor call and returns whether the /// inner matcher matches on it. - bool matchesSpecialized(const clang::CXXConstructExpr &Node, + bool matchesSpecialized(const CXXConstructExpr &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { - const clang::Decl *NodeAsDecl = Node.getConstructor(); + const Decl *NodeAsDecl = Node.getConstructor(); return NodeAsDecl != NULL && InnerMatcher.matches(*NodeAsDecl, Finder, Builder); } - const Matcher InnerMatcher; + const Matcher InnerMatcher; }; /// \brief IsBaseType::value is true if T is a "base" type in the AST @@ -312,10 +312,10 @@ template struct IsBaseType { static const bool value = - (llvm::is_same::value || - llvm::is_same::value || - llvm::is_same::value || - llvm::is_same::value); + (llvm::is_same::value || + llvm::is_same::value || + llvm::is_same::value || + llvm::is_same::value); }; template const bool IsBaseType::value; @@ -326,19 +326,19 @@ public: virtual ~UntypedBaseMatcher() {} - virtual bool matches(const clang::Decl &DeclNode, ASTMatchFinder *Finder, + virtual bool matches(const Decl &DeclNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { return false; } - virtual bool matches(const clang::QualType &TypeNode, ASTMatchFinder *Finder, + virtual bool matches(const QualType &TypeNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { return false; } - virtual bool matches(const clang::Stmt &StmtNode, ASTMatchFinder *Finder, + virtual bool matches(const Stmt &StmtNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { return false; } - virtual bool matches(const clang::CXXCtorInitializer &CtorInitNode, + virtual bool matches(const CXXCtorInitializer &CtorInitNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { return false; @@ -414,26 +414,26 @@ /// from a base type with the given name. /// /// A class is considered to be also derived from itself. - virtual bool classIsDerivedFrom(const clang::CXXRecordDecl *Declaration, + virtual bool classIsDerivedFrom(const CXXRecordDecl *Declaration, StringRef BaseName) const = 0; // FIXME: Implement for other base nodes. - virtual bool matchesChildOf(const clang::Decl &DeclNode, + virtual bool matchesChildOf(const Decl &DeclNode, const UntypedBaseMatcher &BaseMatcher, BoundNodesTreeBuilder *Builder, TraversalKind Traverse, BindKind Bind) = 0; - virtual bool matchesChildOf(const clang::Stmt &StmtNode, + virtual bool matchesChildOf(const Stmt &StmtNode, const UntypedBaseMatcher &BaseMatcher, BoundNodesTreeBuilder *Builder, TraversalKind Traverse, BindKind Bind) = 0; - virtual bool matchesDescendantOf(const clang::Decl &DeclNode, + virtual bool matchesDescendantOf(const Decl &DeclNode, const UntypedBaseMatcher &BaseMatcher, BoundNodesTreeBuilder *Builder, BindKind Bind) = 0; - virtual bool matchesDescendantOf(const clang::Stmt &StmtNode, + virtual bool matchesDescendantOf(const Stmt &StmtNode, const UntypedBaseMatcher &BaseMatcher, BoundNodesTreeBuilder *Builder, BindKind Bind) = 0; @@ -566,17 +566,17 @@ const Matcher InnerMatcher; }; -/// \brief Enables the user to pass a Matcher to +/// \brief Enables the user to pass a Matcher to /// Call(). /// /// FIXME: Alternatives are using more specific methods than Call, like /// MemberCall, or not using VariadicFunction for Call and overloading it. template <> template <> -inline Matcher:: -operator Matcher() const { +inline Matcher:: +operator Matcher() const { return makeMatcher( - new DynCastMatcher(*this)); + new DynCastMatcher(*this)); } /// \brief Matcher that wraps an inner Matcher and binds the matched node @@ -594,7 +594,7 @@ BoundNodesTreeBuilder *Builder) const { bool Result = InnerMatcher.matches(Node, Finder, Builder); if (Result) { - Builder->setBinding(std::pair(ID, &Node)); + Builder->setBinding(ID, &Node); } return Result; } @@ -795,11 +795,11 @@ /// the value the ValueEqualsMatcher was constructed with. template class ValueEqualsMatcher : public SingleNodeMatcherInterface { - TOOLING_COMPILE_ASSERT((llvm::is_base_of::value || - llvm::is_base_of::value || + llvm::is_base_of::value || - llvm::is_base_of::value || - llvm::is_base_of::value), + llvm::is_base_of::value || + llvm::is_base_of::value), the_node_must_have_a_getValue_method); public: explicit ValueEqualsMatcher(const ValueT &ExpectedValue) @@ -816,9 +816,9 @@ template class IsDefinitionMatcher : public SingleNodeMatcherInterface { TOOLING_COMPILE_ASSERT( - (llvm::is_base_of::value) || - (llvm::is_base_of::value) || - (llvm::is_base_of::value), + (llvm::is_base_of::value) || + (llvm::is_base_of::value) || + (llvm::is_base_of::value), is_definition_requires_isThisDeclarationADefinition_method); public: virtual bool matchesNode(const T &Node) const { @@ -830,32 +830,32 @@ /// CXXRecordDecl nodes. template class IsTemplateInstantiationMatcher : public MatcherInterface { - TOOLING_COMPILE_ASSERT((llvm::is_base_of::value) || - (llvm::is_base_of::value) || - (llvm::is_base_of::value), + TOOLING_COMPILE_ASSERT((llvm::is_base_of::value) || + (llvm::is_base_of::value) || + (llvm::is_base_of::value), requires_getTemplateSpecializationKind_method); public: virtual bool matches(const T& Node, ASTMatchFinder* Finder, BoundNodesTreeBuilder* Builder) const { return (Node.getTemplateSpecializationKind() == - clang::TSK_ImplicitInstantiation || + TSK_ImplicitInstantiation || Node.getTemplateSpecializationKind() == - clang::TSK_ExplicitInstantiationDefinition); + TSK_ExplicitInstantiationDefinition); } }; -class IsArrowMatcher : public SingleNodeMatcherInterface { +class IsArrowMatcher : public SingleNodeMatcherInterface { public: - virtual bool matchesNode(const clang::MemberExpr &Node) const { + virtual bool matchesNode(const MemberExpr &Node) const { return Node.isArrow(); } }; class IsConstQualifiedMatcher - : public SingleNodeMatcherInterface { + : public SingleNodeMatcherInterface { public: - virtual bool matchesNode(const clang::QualType& Node) const { + virtual bool matchesNode(const QualType& Node) const { return Node.isConstQualified(); } }; @@ -867,11 +867,11 @@ /// /// For example: /// const VariadicDynCastAllOfMatcher< -/// clang::Decl, clang::CXXRecordDecl> record; -/// Creates a functor record(...) that creates a Matcher given -/// a variable number of arguments of type Matcher. -/// The returned matcher matches if the given clang::Decl can by dynamically -/// casted to clang::CXXRecordDecl and all given matchers match. +/// Decl, CXXRecordDecl> record; +/// Creates a functor record(...) that creates a Matcher given +/// a variable number of arguments of type Matcher. +/// The returned matcher matches if the given Decl can by dynamically +/// casted to CXXRecordDecl and all given matchers match. template class VariadicDynCastAllOfMatcher : public llvm::VariadicFunction< Index: lib/ASTMatchers/ASTMatchFinder.cpp =================================================================== --- lib/ASTMatchers/ASTMatchFinder.cpp +++ lib/ASTMatchers/ASTMatchFinder.cpp @@ -51,9 +51,9 @@ // A RecursiveASTVisitor that traverses all children or all descendants of // a node. class MatchChildASTVisitor - : public clang::RecursiveASTVisitor { + : public RecursiveASTVisitor { public: - typedef clang::RecursiveASTVisitor VisitorBase; + typedef RecursiveASTVisitor VisitorBase; // Creates an AST visitor that matches 'matcher' on all children or // descendants of a traversed node. max_depth is the maximum depth @@ -95,21 +95,21 @@ // The following are overriding methods from the base visitor class. // They are public only to allow CRTP to work. They are *not *part // of the public API of this class. - bool TraverseDecl(clang::Decl *DeclNode) { + bool TraverseDecl(Decl *DeclNode) { return (DeclNode == NULL) || traverse(*DeclNode); } - bool TraverseStmt(clang::Stmt *StmtNode) { - const clang::Stmt *StmtToTraverse = StmtNode; + bool TraverseStmt(Stmt *StmtNode) { + const Stmt *StmtToTraverse = StmtNode; if (Traversal == ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses) { - const clang::Expr *ExprNode = dyn_cast_or_null(StmtNode); + const Expr *ExprNode = dyn_cast_or_null(StmtNode); if (ExprNode != NULL) { StmtToTraverse = ExprNode->IgnoreParenImpCasts(); } } return (StmtToTraverse == NULL) || traverse(*StmtToTraverse); } - bool TraverseType(clang::QualType TypeNode) { + bool TraverseType(QualType TypeNode) { return traverse(TypeNode); } @@ -134,13 +134,13 @@ // Forwards the call to the corresponding Traverse*() method in the // base visitor class. - bool baseTraverse(const clang::Decl &DeclNode) { - return VisitorBase::TraverseDecl(const_cast(&DeclNode)); + bool baseTraverse(const Decl &DeclNode) { + return VisitorBase::TraverseDecl(const_cast(&DeclNode)); } - bool baseTraverse(const clang::Stmt &StmtNode) { - return VisitorBase::TraverseStmt(const_cast(&StmtNode)); + bool baseTraverse(const Stmt &StmtNode) { + return VisitorBase::TraverseStmt(const_cast(&StmtNode)); } - bool baseTraverse(clang::QualType TypeNode) { + bool baseTraverse(QualType TypeNode) { return VisitorBase::TraverseType(TypeNode); } @@ -197,7 +197,7 @@ // Controls the outermost traversal of the AST and allows to match multiple // matchers. -class MatchASTVisitor : public clang::RecursiveASTVisitor, +class MatchASTVisitor : public RecursiveASTVisitor, public ASTMatchFinder { public: MatchASTVisitor(std::vector< std::pairgetUnderlyingType().getTypePtr(); - const clang::Type *CanonicalType = // root of the typedef tree + const Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr(); + const Type *CanonicalType = // root of the typedef tree ActiveASTContext->getCanonicalType(TypeNode); TypeToUnqualifiedAliases[CanonicalType].insert( DeclNode->getName().str()); return true; } - bool TraverseDecl(clang::Decl *DeclNode); - bool TraverseStmt(clang::Stmt *StmtNode); - bool TraverseType(clang::QualType TypeNode); - bool TraverseTypeLoc(clang::TypeLoc TypeNode); + bool TraverseDecl(Decl *DeclNode); + bool TraverseStmt(Stmt *StmtNode); + bool TraverseType(QualType TypeNode); + bool TraverseTypeLoc(TypeLoc TypeNode); // Matches children or descendants of 'Node' with 'BaseMatcher'. template @@ -260,8 +260,8 @@ const UntypedBaseMatcher &BaseMatcher, BoundNodesTreeBuilder *Builder, int MaxDepth, TraversalKind Traversal, BindKind Bind) { - TOOLING_COMPILE_ASSERT((llvm::is_same::value) || - (llvm::is_same::value), + TOOLING_COMPILE_ASSERT((llvm::is_same::value) || + (llvm::is_same::value), type_does_not_support_memoization); const UntypedMatchInput input(BaseMatcher.getID(), &Node); std::pair InsertResult @@ -288,11 +288,11 @@ return Visitor.findMatch(Node); } - virtual bool classIsDerivedFrom(const clang::CXXRecordDecl *Declaration, + virtual bool classIsDerivedFrom(const CXXRecordDecl *Declaration, StringRef BaseName) const; // Implements ASTMatchFinder::MatchesChildOf. - virtual bool matchesChildOf(const clang::Decl &DeclNode, + virtual bool matchesChildOf(const Decl &DeclNode, const UntypedBaseMatcher &BaseMatcher, BoundNodesTreeBuilder *Builder, TraversalKind Traversal, @@ -300,7 +300,7 @@ return matchesRecursively(DeclNode, BaseMatcher, Builder, 1, Traversal, Bind); } - virtual bool matchesChildOf(const clang::Stmt &StmtNode, + virtual bool matchesChildOf(const Stmt &StmtNode, const UntypedBaseMatcher &BaseMatcher, BoundNodesTreeBuilder *Builder, TraversalKind Traversal, @@ -310,14 +310,14 @@ } // Implements ASTMatchFinder::MatchesDescendantOf. - virtual bool matchesDescendantOf(const clang::Decl &DeclNode, + virtual bool matchesDescendantOf(const Decl &DeclNode, const UntypedBaseMatcher &BaseMatcher, BoundNodesTreeBuilder *Builder, BindKind Bind) { return memoizedMatchesRecursively(DeclNode, BaseMatcher, Builder, INT_MAX, TK_AsIs, Bind); } - virtual bool matchesDescendantOf(const clang::Stmt &StmtNode, + virtual bool matchesDescendantOf(const Stmt &StmtNode, const UntypedBaseMatcher &BaseMatcher, BoundNodesTreeBuilder *Builder, BindKind Bind) { @@ -333,7 +333,7 @@ // the aggregated bound nodes for each match. class MatchVisitor : public BoundNodesTree::Visitor { public: - MatchVisitor(clang::ASTContext* Context, + MatchVisitor(ASTContext* Context, MatchFinder::MatchCallback* Callback) : Context(Context), Callback(Callback) {} @@ -343,16 +343,16 @@ } private: - clang::ASTContext* Context; + ASTContext* Context; MatchFinder::MatchCallback* Callback; }; // Returns true if 'TypeNode' is also known by the name 'Name'. In other // words, there is a type (including typedef) with the name 'Name' // that is equal to 'TypeNode'. - bool typeHasAlias(const clang::Type *TypeNode, + bool typeHasAlias(const Type *TypeNode, StringRef Name) const { - const clang::Type *const CanonicalType = + const Type *const CanonicalType = ActiveASTContext->getCanonicalType(TypeNode); const std::set *UnqualifiedAlias = find(TypeToUnqualifiedAliases, CanonicalType); @@ -378,10 +378,10 @@ std::vector< std::pair > *const Triggers; - clang::ASTContext *ActiveASTContext; + ASTContext *ActiveASTContext; // Maps a canonical type to the names of its typedefs. - llvm::DenseMap > + llvm::DenseMap > TypeToUnqualifiedAliases; // Maps (matcher, node) -> the match result for memoization. @@ -393,7 +393,7 @@ // from a base type with the given name. A class is considered to be // also derived from itself. bool -MatchASTVisitor::classIsDerivedFrom(const clang::CXXRecordDecl *Declaration, +MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration, StringRef BaseName) const { if (Declaration->getName() == BaseName) { return true; @@ -401,24 +401,24 @@ if (!Declaration->hasDefinition()) { return false; } - typedef clang::CXXRecordDecl::base_class_const_iterator BaseIterator; + typedef CXXRecordDecl::base_class_const_iterator BaseIterator; for (BaseIterator It = Declaration->bases_begin(), End = Declaration->bases_end(); It != End; ++It) { - const clang::Type *TypeNode = It->getType().getTypePtr(); + const Type *TypeNode = It->getType().getTypePtr(); if (typeHasAlias(TypeNode, BaseName)) return true; - // clang::Type::getAs<...>() drills through typedefs. - if (TypeNode->getAs() != NULL || - TypeNode->getAs() != NULL) { + // Type::getAs<...>() drills through typedefs. + if (TypeNode->getAs() != NULL || + TypeNode->getAs() != NULL) { // Dependent names and template TypeNode parameters will be matched when // the template is instantiated. continue; } - clang::CXXRecordDecl *ClassDecl = NULL; - clang::TemplateSpecializationType const *TemplateType = - TypeNode->getAs(); + CXXRecordDecl *ClassDecl = NULL; + TemplateSpecializationType const *TemplateType = + TypeNode->getAs(); if (TemplateType != NULL) { if (TemplateType->getTemplateName().isDependent()) { // Dependent template specializations will be matched when the @@ -434,12 +434,12 @@ // declaration which is neither an explicit nor partial specialization of // another template declaration, getAsCXXRecordDecl() returns NULL and // we get the CXXRecordDecl of the templated declaration. - clang::CXXRecordDecl *SpecializationDecl = + CXXRecordDecl *SpecializationDecl = TemplateType->getAsCXXRecordDecl(); if (SpecializationDecl != NULL) { ClassDecl = SpecializationDecl; } else { - ClassDecl = llvm::dyn_cast( + ClassDecl = llvm::dyn_cast( TemplateType->getTemplateName() .getAsTemplateDecl()->getTemplatedDecl()); } @@ -455,33 +455,33 @@ return false; } -bool MatchASTVisitor::TraverseDecl(clang::Decl *DeclNode) { +bool MatchASTVisitor::TraverseDecl(Decl *DeclNode) { if (DeclNode == NULL) { return true; } match(*DeclNode); - return clang::RecursiveASTVisitor::TraverseDecl(DeclNode); + return RecursiveASTVisitor::TraverseDecl(DeclNode); } -bool MatchASTVisitor::TraverseStmt(clang::Stmt *StmtNode) { +bool MatchASTVisitor::TraverseStmt(Stmt *StmtNode) { if (StmtNode == NULL) { return true; } match(*StmtNode); - return clang::RecursiveASTVisitor::TraverseStmt(StmtNode); + return RecursiveASTVisitor::TraverseStmt(StmtNode); } -bool MatchASTVisitor::TraverseType(clang::QualType TypeNode) { +bool MatchASTVisitor::TraverseType(QualType TypeNode) { match(TypeNode); - return clang::RecursiveASTVisitor::TraverseType(TypeNode); + return RecursiveASTVisitor::TraverseType(TypeNode); } -bool MatchASTVisitor::TraverseTypeLoc(clang::TypeLoc TypeLoc) { - return clang::RecursiveASTVisitor:: +bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLoc) { + return RecursiveASTVisitor:: TraverseType(TypeLoc.getType()); } -class MatchASTConsumer : public clang::ASTConsumer { +class MatchASTConsumer : public ASTConsumer { public: MatchASTConsumer(std::vector< std::pair > *Triggers, @@ -490,7 +490,7 @@ ParsingDone(ParsingDone) {} private: - virtual void HandleTranslationUnit(clang::ASTContext &Context) { + virtual void HandleTranslationUnit(ASTContext &Context) { if (ParsingDone != NULL) { ParsingDone->run(); } @@ -507,7 +507,7 @@ } // end namespace internal MatchFinder::MatchResult::MatchResult(const BoundNodes &Nodes, - clang::ASTContext *Context) + ASTContext *Context) : Nodes(Nodes), Context(Context), SourceManager(&Context->getSourceManager()) {} @@ -528,22 +528,22 @@ void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch, MatchCallback *Action) { Triggers.push_back(std::make_pair( - new internal::TypedBaseMatcher(NodeMatch), Action)); + new internal::TypedBaseMatcher(NodeMatch), Action)); } void MatchFinder::addMatcher(const TypeMatcher &NodeMatch, MatchCallback *Action) { Triggers.push_back(std::make_pair( - new internal::TypedBaseMatcher(NodeMatch), Action)); + new internal::TypedBaseMatcher(NodeMatch), Action)); } void MatchFinder::addMatcher(const StatementMatcher &NodeMatch, MatchCallback *Action) { Triggers.push_back(std::make_pair( - new internal::TypedBaseMatcher(NodeMatch), Action)); + new internal::TypedBaseMatcher(NodeMatch), Action)); } -clang::ASTConsumer *MatchFinder::newASTConsumer() { +ASTConsumer *MatchFinder::newASTConsumer() { return new internal::MatchASTConsumer(&Triggers, ParsingDone); } Index: lib/ASTMatchers/ASTMatchersInternal.cpp =================================================================== --- lib/ASTMatchers/ASTMatchersInternal.cpp +++ lib/ASTMatchers/ASTMatchersInternal.cpp @@ -21,8 +21,8 @@ BoundNodesTree::BoundNodesTree() {} BoundNodesTree::BoundNodesTree( - const std::map& DeclBindings, - const std::map& StmtBindings, + const std::map& DeclBindings, + const std::map& StmtBindings, const std::vector RecursiveBindings) : DeclBindings(DeclBindings), StmtBindings(StmtBindings), RecursiveBindings(RecursiveBindings) {} @@ -44,22 +44,22 @@ for (typename T::const_iterator I = Bindings.begin(), E = Bindings.end(); I != E; ++I) { - Builder->setBinding(*I); + Builder->setBinding(I->first, I->second); } } void BoundNodesTree::visitMatches(Visitor* ResultVisitor) { - std::map AggregatedDeclBindings; - std::map AggregatedStmtBindings; + std::map AggregatedDeclBindings; + std::map AggregatedStmtBindings; visitMatchesRecursively(ResultVisitor, AggregatedDeclBindings, AggregatedStmtBindings); } void BoundNodesTree:: visitMatchesRecursively(Visitor* ResultVisitor, - std::map + std::map AggregatedDeclBindings, - std::map + std::map AggregatedStmtBindings) { copy(DeclBindings.begin(), DeclBindings.end(), inserter(AggregatedDeclBindings, AggregatedDeclBindings.begin())); @@ -79,14 +79,14 @@ BoundNodesTreeBuilder::BoundNodesTreeBuilder() {} -void BoundNodesTreeBuilder:: -setBinding(const std::pair& Binding) { - DeclBindings.insert(Binding); +void BoundNodesTreeBuilder::setBinding(const std::string &Id, + const Decl *Node) { + DeclBindings[Id] = Node; } -void BoundNodesTreeBuilder:: -setBinding(const std::pair& Binding) { - StmtBindings.insert(Binding); +void BoundNodesTreeBuilder::setBinding(const std::string &Id, + const Stmt *Node) { + StmtBindings[Id] = Node; } void BoundNodesTreeBuilder::addMatch(const BoundNodesTree& Bindings) { Index: unittests/ASTMatchers/ASTMatchersTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersTest.cpp +++ unittests/ASTMatchers/ASTMatchersTest.cpp @@ -24,6 +24,13 @@ }, ""); } +TEST(HasNameDeathTest, DiesOnEmptyPattern) { + ASSERT_DEBUG_DEATH({ + DeclarationMatcher HasEmptyName = record(matchesName("")); + EXPECT_TRUE(notMatches("class X {};", HasEmptyName)); + }, ""); +} + TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) { ASSERT_DEBUG_DEATH({ DeclarationMatcher IsDerivedFromEmpty = record(isDerivedFrom("")); @@ -40,10 +47,34 @@ EXPECT_TRUE(matches("void foo() try { } catch(int X) { }", NamedX)); EXPECT_TRUE(matches("void foo() { int X; }", NamedX)); EXPECT_TRUE(matches("namespace X { }", NamedX)); + EXPECT_TRUE(matches("enum X { A, B, C };", NamedX)); EXPECT_TRUE(notMatches("#define X 1", NamedX)); } +TEST(NameableDeclaration, REMatchesVariousDecls) { + DeclarationMatcher NamedX = nameableDeclaration(matchesName("::X")); + EXPECT_TRUE(matches("typedef int Xa;", NamedX)); + EXPECT_TRUE(matches("int Xb;", NamedX)); + EXPECT_TRUE(matches("class foo { virtual void Xc(); };", NamedX)); + EXPECT_TRUE(matches("void foo() try { } catch(int Xdef) { }", NamedX)); + EXPECT_TRUE(matches("void foo() { int Xgh; }", NamedX)); + EXPECT_TRUE(matches("namespace Xij { }", NamedX)); + EXPECT_TRUE(matches("enum X { A, B, C };", NamedX)); + + EXPECT_TRUE(notMatches("#define Xkl 1", NamedX)); + + DeclarationMatcher StartsWithNo = nameableDeclaration(matchesName("::no")); + EXPECT_TRUE(matches("int no_foo;", StartsWithNo)); + EXPECT_TRUE(matches("class foo { virtual void nobody(); };", StartsWithNo)); + + DeclarationMatcher Abc = nameableDeclaration(matchesName("a.*b.*c")); + EXPECT_TRUE(matches("int abc;", Abc)); + EXPECT_TRUE(matches("int aFOObBARc;", Abc)); + EXPECT_TRUE(notMatches("int cab;", Abc)); + EXPECT_TRUE(matches("int cabc;", Abc)); +} + TEST(DeclarationMatcher, MatchClass) { DeclarationMatcher ClassMatcher(record()); #if !defined(_MSC_VER) @@ -456,6 +487,21 @@ "};", ZDescendantClassXDescendantClassY)); } +TEST(Enum, DoesNotMatchClasses) { + EXPECT_TRUE(notMatches("class X {};", enumDecl(hasName("X")))); +} + +TEST(Enum, MatchesEnums) { + EXPECT_TRUE(matches("enum X {};", enumDecl(hasName("X")))); +} + +TEST(EnumConstant, Matches) { + DeclarationMatcher Matcher = enumConstant(hasName("A")); + EXPECT_TRUE(matches("enum X{ A };", Matcher)); + EXPECT_TRUE(notMatches("enum X{ B };", Matcher)); + EXPECT_TRUE(notMatches("enum X {};", Matcher)); +} + TEST(StatementMatcher, Has) { StatementMatcher HasVariableI = expression( @@ -552,23 +598,40 @@ DeclarationMatcher ClassX = has(id("x", record(hasName("X")))); EXPECT_TRUE(matchAndVerifyResultTrue("class X {};", - ClassX, new VerifyIdIsBoundToDecl("x"))); + ClassX, new VerifyIdIsBoundToDecl("x"))); EXPECT_TRUE(matchAndVerifyResultFalse("class X {};", - ClassX, new VerifyIdIsBoundToDecl("other-id"))); + ClassX, new VerifyIdIsBoundToDecl("other-id"))); TypeMatcher TypeAHasClassB = hasDeclaration( record(hasName("A"), has(id("b", record(hasName("B")))))); EXPECT_TRUE(matchAndVerifyResultTrue("class A { public: A *a; class B {}; };", TypeAHasClassB, - new VerifyIdIsBoundToDecl("b"))); + new VerifyIdIsBoundToDecl("b"))); StatementMatcher MethodX = id("x", call(callee(method(hasName("x"))))); EXPECT_TRUE(matchAndVerifyResultTrue("class A { void x() { x(); } };", MethodX, - new VerifyIdIsBoundToStmt("x"))); + new VerifyIdIsBoundToStmt("x"))); +} + +TEST(Matcher, BindTheSameNameInAlternatives) { + StatementMatcher matcher = anyOf( + binaryOperator(hasOperatorName("+"), + hasLHS(id("x", expression())), + hasRHS(integerLiteral(equals(0)))), + binaryOperator(hasOperatorName("+"), + hasLHS(integerLiteral(equals(0))), + hasRHS(id("x", expression())))); + + EXPECT_TRUE(matchAndVerifyResultTrue( + // The first branch of the matcher binds x to 0 but then fails. + // The second branch binds x to f() and succeeds. + "int f() { return 0 + f(); }", + matcher, + new VerifyIdIsBoundToStmt("x"))); } TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) { @@ -613,7 +676,7 @@ TEST(Matcher, Call) { // FIXME: Do we want to overload Call() to directly take - // Matcher, too? + // Matcher, too? StatementMatcher MethodX = call(hasDeclaration(method(hasName("x")))); EXPECT_TRUE(matches("class Y { void x() { x(); } };", MethodX)); @@ -657,6 +720,18 @@ MethodOnYPointer)); } +TEST(HasType, MatchesAsString) { + EXPECT_TRUE( + matches("class Y { public: void x(); }; void z() {Y* y; y->x(); }", + call(on(hasType(asString("class Y *")))))); + EXPECT_TRUE(matches("class X { void x(int x) {} };", + method(hasParameter(0, hasType(asString("int")))))); + EXPECT_TRUE(matches("namespace ns { struct A {}; } struct B { ns::A a; };", + field(hasType(asString("ns::A"))))); + EXPECT_TRUE(matches("namespace { struct A {}; } struct B { A a; };", + field(hasType(asString("struct ::A"))))); +} + TEST(Matcher, OverloadedOperatorCall) { StatementMatcher OpCall = overloadedOperatorCall(); // Unary operator @@ -772,6 +847,30 @@ CallOnVariableY)); } +TEST(UnaryExprOrTypeTraitExpr, MatchesSizeOfAndAlignOf) { + EXPECT_TRUE(matches("void x() { int a = sizeof(a); }", + unaryExprOrTypeTraitExpr())); + EXPECT_TRUE(notMatches("void x() { int a = sizeof(a); }", + alignOfExpr(anything()))); + // FIXME: Uncomment once alignof is enabled. + // EXPECT_TRUE(matches("void x() { int a = alignof(a); }", + // unaryExprOrTypeTraitExpr())); + // EXPECT_TRUE(notMatches("void x() { int a = alignof(a); }", + // sizeOfExpr())); +} + +TEST(UnaryExpressionOrTypeTraitExpression, MatchesCorrectType) { + EXPECT_TRUE(matches("void x() { int a = sizeof(a); }", sizeOfExpr( + hasArgumentOfType(asString("int"))))); + EXPECT_TRUE(notMatches("void x() { int a = sizeof(a); }", sizeOfExpr( + hasArgumentOfType(asString("float"))))); + EXPECT_TRUE(matches( + "struct A {}; void x() { A a; int b = sizeof(a); }", + sizeOfExpr(hasArgumentOfType(hasDeclaration(record(hasName("A"))))))); + EXPECT_TRUE(notMatches("void x() { int a = sizeof(a); }", sizeOfExpr( + hasArgumentOfType(hasDeclaration(record(hasName("string"))))))); +} + TEST(MemberExpression, DoesNotMatchClasses) { EXPECT_TRUE(notMatches("class Y { void x() {} };", memberExpression())); } @@ -939,6 +1038,15 @@ method(hasAnyParameter(hasType(record(hasName("X"))))))); } +TEST(Returns, MatchesReturnTypes) { + EXPECT_TRUE(matches("class Y { int f() { return 1; } };", + function(returns(asString("int"))))); + EXPECT_TRUE(notMatches("class Y { int f() { return 1; } };", + function(returns(asString("float"))))); + EXPECT_TRUE(matches("class Y { Y getMe() { return *this; } };", + function(returns(hasDeclaration(record(hasName("Y"))))))); +} + TEST(HasAnyParameter, DoesntMatchIfInnerMatcherDoesntMatch) { EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };", method(hasAnyParameter(hasType(record(hasName("X"))))))); @@ -1062,6 +1170,15 @@ constructor(unless(isImplicit())))); } +TEST(DestructorDeclaration, MatchesVirtualDestructor) { + EXPECT_TRUE(matches("class Foo { virtual ~Foo(); };", + destructor(ofClass(hasName("Foo"))))); +} + +TEST(DestructorDeclaration, DoesNotMatchImplicitDestructor) { + EXPECT_TRUE(notMatches("class Foo {};", destructor(ofClass(hasName("Foo"))))); +} + TEST(HasAnyConstructorInitializer, SimpleCase) { EXPECT_TRUE(notMatches( "class Foo { Foo() { } };", @@ -1162,6 +1279,11 @@ New)); } +TEST(Matcher, DeleteExpression) { + EXPECT_TRUE(matches("struct A {}; void f(A* a) { delete a; }", + deleteExpression())); +} + TEST(Matcher, DefaultArgument) { StatementMatcher Arg = defaultArgument(); @@ -1412,6 +1534,32 @@ notMatches("void x() { true ? false : true; }", ConditionalFalse)); } +TEST(ArraySubscriptMatchers, ArraySubscripts) { + EXPECT_TRUE(matches("int i[2]; void f() { i[1] = 1; }", + arraySubscriptExpr())); + EXPECT_TRUE(notMatches("int i; void f() { i = 1; }", + arraySubscriptExpr())); +} + +TEST(ArraySubscriptMatchers, ArrayIndex) { + EXPECT_TRUE(matches( + "int i[2]; void f() { i[1] = 1; }", + arraySubscriptExpr(hasIndex(integerLiteral(equals(1)))))); + EXPECT_TRUE(matches( + "int i[2]; void f() { 1[i] = 1; }", + arraySubscriptExpr(hasIndex(integerLiteral(equals(1)))))); + EXPECT_TRUE(notMatches( + "int i[2]; void f() { i[1] = 1; }", + arraySubscriptExpr(hasIndex(integerLiteral(equals(0)))))); +} + +TEST(ArraySubscriptMatchers, MatchesArrayBase) { + EXPECT_TRUE(matches( + "int i[2]; void f() { i[1] = 2; }", + arraySubscriptExpr(hasBase(implicitCast( + hasSourceExpression(declarationReference())))))); +} + TEST(Matcher, HasNameSupportsNamespaces) { EXPECT_TRUE(matches("namespace a { namespace b { class C; } }", record(hasName("a::b::C")))); @@ -1519,8 +1667,33 @@ hasDescendant(call(callee(method(hasName("x")))))))); } +TEST(Matcher, HandlesNullQualTypes) { + // FIXME: Add a Type matcher so we can replace uses of this + // variable with Type(True()) + const TypeMatcher AnyType = anything(); + + // We don't really care whether this matcher succeeds; we're testing that + // it completes without crashing. + EXPECT_TRUE(matches( + "struct A { };" + "template " + "void f(T t) {" + " T local_t(t /* this becomes a null QualType in the AST */);" + "}" + "void g() {" + " f(0);" + "}", + expression(hasType(TypeMatcher( + anyOf( + TypeMatcher(hasDeclaration(anything())), + pointsTo(AnyType), + references(AnyType) + // Other QualType matchers should go here. + )))))); +} + // For testing AST_MATCHER_P(). -AST_MATCHER_P(clang::Decl, just, internal::Matcher, AMatcher) { +AST_MATCHER_P(Decl, just, internal::Matcher, AMatcher) { // Make sure all special variables are used: node, match_finder, // bound_nodes_builder, and the parameter named 'AMatcher'. return AMatcher.matches(Node, Finder, Builder); @@ -1530,21 +1703,21 @@ DeclarationMatcher HasClassB = just(has(id("b", record(hasName("B"))))); EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };", - HasClassB, new VerifyIdIsBoundToDecl("b"))); + HasClassB, new VerifyIdIsBoundToDecl("b"))); EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };", - HasClassB, new VerifyIdIsBoundToDecl("a"))); + HasClassB, new VerifyIdIsBoundToDecl("a"))); EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };", - HasClassB, new VerifyIdIsBoundToDecl("b"))); + HasClassB, new VerifyIdIsBoundToDecl("b"))); } AST_POLYMORPHIC_MATCHER_P( - polymorphicHas, internal::Matcher, AMatcher) { - TOOLING_COMPILE_ASSERT((llvm::is_same::value) || - (llvm::is_same::value), + polymorphicHas, internal::Matcher, AMatcher) { + TOOLING_COMPILE_ASSERT((llvm::is_same::value) || + (llvm::is_same::value), assert_node_type_is_accessible); - internal::TypedBaseMatcher ChildMatcher(AMatcher); + internal::TypedBaseMatcher ChildMatcher(AMatcher); return Finder->matchesChildOf( Node, ChildMatcher, Builder, ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses, @@ -1555,13 +1728,13 @@ DeclarationMatcher HasClassB = polymorphicHas(id("b", record(hasName("B")))); EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };", - HasClassB, new VerifyIdIsBoundToDecl("b"))); + HasClassB, new VerifyIdIsBoundToDecl("b"))); EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };", - HasClassB, new VerifyIdIsBoundToDecl("a"))); + HasClassB, new VerifyIdIsBoundToDecl("a"))); EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };", - HasClassB, new VerifyIdIsBoundToDecl("b"))); + HasClassB, new VerifyIdIsBoundToDecl("b"))); StatementMatcher StatementHasClassB = polymorphicHas(record(hasName("B"))); @@ -1831,6 +2004,41 @@ EXPECT_TRUE(matches("void x() { int a; }", declarationStatement())); } +TEST(InitListExpression, MatchesInitListExpression) { + EXPECT_TRUE(matches("int a[] = { 1, 2 };", + initListExpr(hasType(asString("int [2]"))))); + EXPECT_TRUE(matches("struct B { int x, y; }; B b = { 5, 6 };", + initListExpr(hasType(record(hasName("B")))))); +} + +TEST(UsingDeclaration, MatchesUsingDeclarations) { + EXPECT_TRUE(matches("namespace X { int x; } using X::x;", + usingDecl())); +} + +TEST(UsingDeclaration, MatchesShadowUsingDelcarations) { + EXPECT_TRUE(matches("namespace f { int a; } using f::a;", + usingDecl(hasAnyUsingShadowDecl(hasName("a"))))); +} + +TEST(UsingDeclaration, MatchesSpecificTarget) { + EXPECT_TRUE(matches("namespace f { int a; void b(); } using f::b;", + usingDecl(hasAnyUsingShadowDecl( + hasTargetDecl(function()))))); + EXPECT_TRUE(notMatches("namespace f { int a; void b(); } using f::a;", + usingDecl(hasAnyUsingShadowDecl( + hasTargetDecl(function()))))); +} + +TEST(UsingDeclaration, ThroughUsingDeclaration) { + EXPECT_TRUE(matches( + "namespace a { void f(); } using a::f; void g() { f(); }", + declarationReference(throughUsingDecl(anything())))); + EXPECT_TRUE(notMatches( + "namespace a { void f(); } using a::f; void g() { a::f(); }", + declarationReference(throughUsingDecl(anything())))); +} + TEST(While, MatchesWhileLoops) { EXPECT_TRUE(notMatches("void x() {}", whileStmt())); EXPECT_TRUE(matches("void x() { while(true); }", whileStmt())); @@ -1871,26 +2079,26 @@ TEST(ForEach, BindsOneNode) { EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; };", record(hasName("C"), forEach(id("x", field(hasName("x"))))), - new VerifyIdIsBoundToDecl("x", 1))); + new VerifyIdIsBoundToDecl("x", 1))); } TEST(ForEach, BindsMultipleNodes) { EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; int y; int z; };", record(hasName("C"), forEach(id("f", field()))), - new VerifyIdIsBoundToDecl("f", 3))); + new VerifyIdIsBoundToDecl("f", 3))); } TEST(ForEach, BindsRecursiveCombinations) { EXPECT_TRUE(matchAndVerifyResultTrue( "class C { class D { int x; int y; }; class E { int y; int z; }; };", record(hasName("C"), forEach(record(forEach(id("f", field()))))), - new VerifyIdIsBoundToDecl("f", 4))); + new VerifyIdIsBoundToDecl("f", 4))); } TEST(ForEachDescendant, BindsOneNode) { EXPECT_TRUE(matchAndVerifyResultTrue("class C { class D { int x; }; };", record(hasName("C"), forEachDescendant(id("x", field(hasName("x"))))), - new VerifyIdIsBoundToDecl("x", 1))); + new VerifyIdIsBoundToDecl("x", 1))); } TEST(ForEachDescendant, BindsMultipleNodes) { @@ -1898,7 +2106,7 @@ "class C { class D { int x; int y; }; " " class E { class F { int y; int z; }; }; };", record(hasName("C"), forEachDescendant(id("f", field()))), - new VerifyIdIsBoundToDecl("f", 4))); + new VerifyIdIsBoundToDecl("f", 4))); } TEST(ForEachDescendant, BindsRecursiveCombinations) { @@ -1907,7 +2115,7 @@ " class E { class F { class G { int y; int z; }; }; }; }; };", record(hasName("C"), forEachDescendant(record( forEachDescendant(id("f", field()))))), - new VerifyIdIsBoundToDecl("f", 8))); + new VerifyIdIsBoundToDecl("f", 8))); }