summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManuel Klimek <klimek@google.com>2012-07-06 05:48:52 +0000
committerManuel Klimek <klimek@google.com>2012-07-06 05:48:52 +0000
commit4da216637fa1ad4bdfd31bc265edb57ca35c2c12 (patch)
tree08b93fbc99de82a43b0bb4dba96dbfbf96abac45
parentea7eb071166c69e11bfda4f1d89d5c2b6bbcdca3 (diff)
downloadclang-4da216637fa1ad4bdfd31bc265edb57ca35c2c12.tar.gz
clang-4da216637fa1ad4bdfd31bc265edb57ca35c2c12.tar.bz2
clang-4da216637fa1ad4bdfd31bc265edb57ca35c2c12.tar.xz
Adds the AST Matcher library, which provides a in-C++ DSL to express
matches on interesting parts of the AST, and callback mechanisms to act on them. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159805 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/ASTMatchers/ASTMatchFinder.h141
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h1403
-rw-r--r--include/clang/ASTMatchers/ASTMatchersInternal.h888
-rw-r--r--include/clang/ASTMatchers/ASTMatchersMacros.h224
-rw-r--r--lib/ASTMatchers/ASTMatchFinder.cpp556
-rw-r--r--lib/ASTMatchers/ASTMatchersInternal.cpp102
-rw-r--r--lib/ASTMatchers/CMakeLists.txt7
-rw-r--r--lib/ASTMatchers/Makefile15
-rw-r--r--lib/CMakeLists.txt1
-rwxr-xr-xlib/Makefile2
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.cpp1979
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h128
-rw-r--r--unittests/ASTMatchers/CMakeLists.txt5
-rw-r--r--unittests/ASTMatchers/Makefile19
-rw-r--r--unittests/CMakeLists.txt1
-rw-r--r--unittests/Makefile2
16 files changed, 5471 insertions, 2 deletions
diff --git a/include/clang/ASTMatchers/ASTMatchFinder.h b/include/clang/ASTMatchers/ASTMatchFinder.h
new file mode 100644
index 0000000000..dd237eece3
--- /dev/null
+++ b/include/clang/ASTMatchers/ASTMatchFinder.h
@@ -0,0 +1,141 @@
+//===--- ASTMatchFinder.h - Structural query framework ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Provides a way to construct an ASTConsumer that runs given matchers
+// over the AST and invokes a given callback on every match.
+//
+// The general idea is to construct a matcher expression that describes a
+// subtree match on the AST. Next, a callback that is executed every time the
+// expression matches is registered, and the matcher is run over the AST of
+// some code. Matched subexpressions can be bound to string IDs and easily
+// be accessed from the registered callback. The callback can than use the
+// AST nodes that the subexpressions matched on to output information about
+// the match or construct changes that can be applied to the code.
+//
+// Example:
+// class HandleMatch : public MatchFinder::MatchCallback {
+// public:
+// virtual void Run(const MatchFinder::MatchResult &Result) {
+// const CXXRecordDecl *Class =
+// Result.Nodes.GetDeclAs<CXXRecordDecl>("id");
+// ...
+// }
+// };
+//
+// int main(int argc, char **argv) {
+// ClangTool Tool(argc, argv);
+// MatchFinder finder;
+// finder.AddMatcher(Id("id", record(hasName("::a_namespace::AClass"))),
+// new HandleMatch);
+// return Tool.Run(newFrontendActionFactory(&finder));
+// }
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H
+#define LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H
+
+#include "clang/ASTMatchers/ASTMatchers.h"
+
+namespace clang {
+
+namespace ast_matchers {
+
+/// \brief A class to allow finding matches over the Clang AST.
+///
+/// After creation, you can add multiple matchers to the MatchFinder via
+/// calls to addMatcher(...).
+///
+/// Once all matchers are added, newASTConsumer() returns an ASTConsumer
+/// that will trigger the callbacks specified via addMatcher(...) when a match
+/// is found.
+///
+/// See ASTMatchers.h for more information about how to create matchers.
+///
+/// Not intended to be subclassed.
+class MatchFinder {
+public:
+ /// \brief Contains all information for a given match.
+ ///
+ /// Every time a match is found, the MatchFinder will invoke the registered
+ /// MatchCallback with a MatchResult containing information about the match.
+ struct MatchResult {
+ MatchResult(const BoundNodes &Nodes, clang::ASTContext *Context);
+
+ /// \brief Contains the nodes bound on the current match.
+ ///
+ /// This allows user code to easily extract matched AST nodes.
+ const BoundNodes Nodes;
+
+ /// \brief Utilities for interpreting the matched AST structures.
+ /// @{
+ clang::ASTContext * const Context;
+ clang::SourceManager * const SourceManager;
+ /// @}
+ };
+
+ /// \brief Called when the Match registered for it was successfully found
+ /// in the AST.
+ class MatchCallback {
+ public:
+ virtual ~MatchCallback();
+ virtual void run(const MatchResult &Result) = 0;
+ };
+
+ /// \brief Called when parsing is finished. Intended for testing only.
+ class ParsingDoneTestCallback {
+ public:
+ virtual ~ParsingDoneTestCallback();
+ virtual void run() = 0;
+ };
+
+ MatchFinder();
+ ~MatchFinder();
+
+ /// \brief Adds a matcher to execute when running over the AST.
+ ///
+ /// Calls 'Action' with the BoundNodes on every match.
+ /// Adding more than one 'NodeMatch' allows finding different matches in a
+ /// single pass over the AST.
+ ///
+ /// Does not take ownership of 'Action'.
+ /// @{
+ void addMatcher(const DeclarationMatcher &NodeMatch,
+ MatchCallback *Action);
+ void addMatcher(const TypeMatcher &NodeMatch,
+ MatchCallback *Action);
+ void addMatcher(const StatementMatcher &NodeMatch,
+ MatchCallback *Action);
+ /// @}
+
+ /// \brief Creates a clang ASTConsumer that finds all matches.
+ clang::ASTConsumer *newASTConsumer();
+
+ /// \brief Registers a callback to notify the end of parsing.
+ ///
+ /// The provided closure is called after parsing is done, before the AST is
+ /// traversed. Useful for benchmarking.
+ /// Each call to FindAll(...) will call the closure once.
+ void registerTestCallbackAfterParsing(ParsingDoneTestCallback *ParsingDone);
+
+private:
+ /// \brief The MatchCallback*'s will be called every time the
+ /// UntypedBaseMatcher matches on the AST.
+ std::vector< std::pair<
+ const internal::UntypedBaseMatcher*,
+ MatchCallback*> > Triggers;
+
+ /// \brief Called when parsing is done.
+ ParsingDoneTestCallback *ParsingDone;
+};
+
+} // end namespace ast_matchers
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCH_FINDER_H
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
new file mode 100644
index 0000000000..69e9c4b53d
--- /dev/null
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -0,0 +1,1403 @@
+//===--- ASTMatchers.h - Structural query framework -------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements matchers to be used together with the MatchFinder to
+// match AST nodes.
+//
+// Matchers are created by generator functions, which can be combined in
+// a functional in-language DSL to express queries over the C++ AST.
+//
+// For example, to match a class with a certain name, one would call:
+// record(hasName("MyClass"))
+// which returns a matcher that can be used to find all AST nodes that declare
+// a class named 'MyClass'.
+//
+// For more complicated match expressions we're often interested in accessing
+// multiple parts of the matched AST nodes once a match is found. In that case,
+// use the id(...) matcher around the match expressions that match the nodes
+// you want to access.
+//
+// For example, when we're interested in child classes of a certain class, we
+// would write:
+// record(hasName("MyClass"), hasChild(id("child", record())))
+// When the match is found via the MatchFinder, a user provided callback will
+// be called with a BoundNodes instance that contains a mapping from the
+// strings that we provided for the id(...) calls to the nodes that were
+// matched.
+// In the given example, each time our matcher finds a match we get a callback
+// where "child" is bound to the CXXRecordDecl node of the matching child
+// class declaration.
+//
+// See ASTMatchersInternal.h for a more in-depth explanation of the
+// implementation details of the matcher framework.
+//
+// See ASTMatchFinder.h for how to use the generated matchers to run over
+// an AST.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H
+#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H
+
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "clang/ASTMatchers/ASTMatchersMacros.h"
+#include "llvm/ADT/Twine.h"
+
+namespace clang {
+namespace ast_matchers {
+
+/// \brief Maps string IDs to AST nodes matched by parts of a matcher.
+///
+/// The bound nodes are generated by adding id(...) matchers into the
+/// match expression around the matchers for the nodes we want to access later.
+///
+/// The instances of BoundNodes are created by MatchFinder when the user's
+/// callbacks are executed every time a match is found.
+class BoundNodes {
+public:
+ /// \brief Returns the AST node bound to 'ID'.
+ /// Returns NULL if there was no node bound to 'ID' or if there is a node but
+ /// it cannot be converted to the specified type.
+ /// FIXME: We'll need one of those for every base type.
+ /// @{
+ template <typename T>
+ const T *getDeclAs(StringRef ID) const {
+ return getNodeAs<T>(DeclBindings, ID);
+ }
+ template <typename T>
+ const T *getStmtAs(StringRef ID) const {
+ return getNodeAs<T>(StmtBindings, ID);
+ }
+ /// @}
+
+private:
+ /// \brief Create BoundNodes from a pre-filled map of bindings.
+ BoundNodes(const std::map<std::string, const clang::Decl*> &DeclBindings,
+ const std::map<std::string, const clang::Stmt*> &StmtBindings)
+ : DeclBindings(DeclBindings), StmtBindings(StmtBindings) {}
+
+ template <typename T, typename MapT>
+ const T *getNodeAs(const MapT &Bindings, StringRef ID) const {
+ typename MapT::const_iterator It = Bindings.find(ID);
+ if (It == Bindings.end()) {
+ return NULL;
+ }
+ return llvm::dyn_cast<T>(It->second);
+ }
+
+ std::map<std::string, const clang::Decl*> DeclBindings;
+ std::map<std::string, const clang::Stmt*> StmtBindings;
+
+ friend class internal::BoundNodesTree;
+};
+
+/// \brief If the provided matcher matches a node, binds the node to 'ID'.
+///
+/// FIXME: Add example for accessing it.
+template <typename T>
+internal::Matcher<T> id(const std::string &ID,
+ const internal::Matcher<T> &InnerMatcher) {
+ return internal::Matcher<T>(new internal::IdMatcher<T>(ID, InnerMatcher));
+}
+
+/// \brief Types of matchers for the top-level classes in the AST class
+/// hierarchy.
+/// @{
+typedef internal::Matcher<clang::Decl> DeclarationMatcher;
+typedef internal::Matcher<clang::QualType> TypeMatcher;
+typedef internal::Matcher<clang::Stmt> StatementMatcher;
+/// @}
+
+/// \brief Matches any node.
+///
+/// Useful when another matcher requires a child matcher, but there's no
+/// additional constraint. This will often be used with an explicit conversion
+/// to a internal::Matcher<> type such as TypeMatcher.
+///
+/// Example: DeclarationMatcher(anything()) matches all declarations, e.g.,
+/// "int* p" and "void f()" in
+/// int* p;
+/// void f();
+inline internal::PolymorphicMatcherWithParam0<internal::TrueMatcher> anything() {
+ return internal::PolymorphicMatcherWithParam0<internal::TrueMatcher>();
+}
+
+/// \brief Matches a declaration of anything that could have a name.
+///
+/// Example matches X, S, the anonymous union type, i, and U;
+/// typedef int X;
+/// struct S {
+/// union {
+/// int i;
+/// } U;
+/// };
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Decl,
+ clang::NamedDecl> nameableDeclaration;
+
+/// \brief Matches C++ class declarations.
+///
+/// Example matches X, Z
+/// class X;
+/// template<class T> class Z {};
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Decl,
+ clang::CXXRecordDecl> record;
+
+/// \brief Matches C++ constructor declarations.
+///
+/// Example matches Foo::Foo() and Foo::Foo(int)
+/// class Foo {
+/// public:
+/// Foo();
+/// Foo(int);
+/// int DoSomething();
+/// };
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Decl,
+ clang::CXXConstructorDecl> constructor;
+
+/// \brief Matches method declarations.
+///
+/// Example matches y
+/// class X { void y() };
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Decl,
+ clang::CXXMethodDecl> method;
+
+/// \brief Matches variable declarations.
+///
+/// Note: this does not match declarations of member variables, which are
+/// "field" declarations in Clang parlance.
+///
+/// Example matches a
+/// int a;
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Decl,
+ clang::VarDecl> variable;
+
+/// \brief Matches field declarations.
+///
+/// Given
+/// class X { int m; };
+/// field()
+/// matches 'm'.
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Decl,
+ clang::FieldDecl> field;
+
+/// \brief Matches function declarations.
+///
+/// Example matches f
+/// void f();
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Decl,
+ clang::FunctionDecl> function;
+
+
+/// \brief Matches statements.
+///
+/// Given
+/// { ++a; }
+/// statement()
+/// matches both the compound statement '{ ++a; }' and '++a'.
+const internal::VariadicDynCastAllOfMatcher<clang::Stmt, clang::Stmt> statement;
+
+/// \brief Matches declaration statements.
+///
+/// Given
+/// int a;
+/// declarationStatement()
+/// matches 'int a'.
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt,
+ clang::DeclStmt> declarationStatement;
+
+/// \brief Matches member expressions.
+///
+/// Given
+/// class Y {
+/// void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; }
+/// int a; static int b;
+/// };
+/// memberExpression()
+/// matches this->x, x, y.x, a, this->b
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt,
+ clang::MemberExpr> memberExpression;
+
+/// \brief Matches call expressions.
+///
+/// Example matches x.y()
+/// X x;
+/// x.y();
+const internal::VariadicDynCastAllOfMatcher<clang::Stmt, clang::CallExpr> call;
+
+/// \brief Matches constructor call expressions (including implicit ones).
+///
+/// Example matches string(ptr, n) and ptr within arguments of f
+/// (matcher = constructorCall())
+/// void f(const string &a, const string &b);
+/// char *ptr;
+/// int n;
+/// f(string(ptr, n), ptr);
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt,
+ clang::CXXConstructExpr> constructorCall;
+
+/// \brief Matches nodes where temporaries are created.
+///
+/// Example matches FunctionTakesString(GetStringByValue())
+/// (matcher = bindTemporaryExpr())
+/// FunctionTakesString(GetStringByValue());
+/// FunctionTakesStringByPointer(GetStringPointer());
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt,
+ clang::CXXBindTemporaryExpr> bindTemporaryExpression;
+
+/// \brief Matches new expressions.
+///
+/// Given
+/// new X;
+/// newExpression()
+/// matches 'new X'.
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt,
+ clang::CXXNewExpr> newExpression;
+
+/// \brief Matches the value of a default argument at the call site.
+///
+/// Example matches the CXXDefaultArgExpr placeholder inserted for the
+/// default value of the second parameter in the call expression f(42)
+/// (matcher = defaultArgument())
+/// void f(int x, int y = 0);
+/// f(42);
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt,
+ clang::CXXDefaultArgExpr> defaultArgument;
+
+/// \brief Matches overloaded operator calls.
+///
+/// Note that if an operator isn't overloaded, it won't match. Instead, use
+/// binaryOperator matcher.
+/// Currently it does not match operators such as new delete.
+/// FIXME: figure out why these do not match?
+///
+/// Example matches both operator<<((o << b), c) and operator<<(o, b)
+/// (matcher = overloadedOperatorCall())
+/// ostream &operator<< (ostream &out, int i) { };
+/// ostream &o; int b = 1, c = 1;
+/// o << b << c;
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt,
+ clang::CXXOperatorCallExpr> overloadedOperatorCall;
+
+/// \brief Matches expressions.
+///
+/// Example matches x()
+/// void f() { x(); }
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt,
+ clang::Expr> expression;
+
+/// \brief Matches expressions that refer to declarations.
+///
+/// Example matches x in if (x)
+/// bool x;
+/// if (x) {}
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt,
+ clang::DeclRefExpr> declarationReference;
+
+/// \brief Matches if statements.
+///
+/// Example matches 'if (x) {}'
+/// if (x) {}
+const internal::VariadicDynCastAllOfMatcher<clang::Stmt, clang::IfStmt> ifStmt;
+
+/// \brief Matches for statements.
+///
+/// Example matches 'for (;;) {}'
+/// for (;;) {}
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt, clang::ForStmt> forStmt;
+
+/// \brief Matches while statements.
+///
+/// Given
+/// while (true) {}
+/// whileStmt()
+/// matches 'while (true) {}'.
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt,
+ clang::WhileStmt> whileStmt;
+
+/// \brief Matches do statements.
+///
+/// Given
+/// do {} while (true);
+/// doStmt()
+/// matches 'do {} while(true)'
+const internal::VariadicDynCastAllOfMatcher<clang::Stmt, clang::DoStmt> doStmt;
+
+/// \brief Matches case and default statements inside switch statements.
+///
+/// Given
+/// switch(a) { case 42: break; default: break; }
+/// switchCase()
+/// matches 'case 42: break;' and 'default: break;'.
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt,
+ clang::SwitchCase> switchCase;
+
+/// \brief Matches compound statements.
+///
+/// Example matches '{}' and '{{}}'in 'for (;;) {{}}'
+/// for (;;) {{}}
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt,
+ clang::CompoundStmt> compoundStatement;
+
+/// \brief Matches bool literals.
+///
+/// Example matches true
+/// true
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Expr,
+ clang::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;
+
+/// \brief Matches character literals (also matches wchar_t).
+///
+/// Not matching Hex-encoded chars (e.g. 0x1234, which is a IntegerLiteral),
+/// though.
+///
+/// Example matches 'a', L'a'
+/// char ch = 'a'; wchar_t chw = L'a';
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Expr,
+ clang::CharacterLiteral> characterLiteral;
+
+/// \brief Matches integer literals of all sizes / encodings.
+///
+/// Not matching character-encoded integers such as L'a'.
+///
+/// Example matches 1, 1L, 0x1, 1U
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Expr,
+ clang::IntegerLiteral> integerLiteral;
+
+/// \brief Matches binary operator expressions.
+///
+/// Example matches a || b
+/// !(a || b)
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt,
+ clang::BinaryOperator> binaryOperator;
+
+/// \brief Matches unary operator expressions.
+///
+/// Example matches !a
+/// !a || b
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt,
+ clang::UnaryOperator> unaryOperator;
+
+/// \brief Matches conditional operator expressions.
+///
+/// Example matches a ? b : c
+/// (a ? b : c) + 42
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Stmt,
+ clang::ConditionalOperator> conditionalOperator;
+
+/// \brief Matches a reinterpret_cast expression.
+///
+/// Either the source expression or the destination type can be matched
+/// using has(), but hasDestinationType() is more specific and can be
+/// more readable.
+///
+/// Example matches reinterpret_cast<char*>(&p) in
+/// void* p = reinterpret_cast<char*>(&p);
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Expr,
+ clang::CXXReinterpretCastExpr> reinterpretCast;
+
+/// \brief Matches a C++ static_cast expression.
+///
+/// \see hasDestinationType
+/// \see reinterpretCast
+///
+/// Example:
+/// staticCast()
+/// matches
+/// static_cast<long>(8)
+/// in
+/// long eight(static_cast<long>(8));
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Expr,
+ clang::CXXStaticCastExpr> staticCast;
+
+/// \brief Matches a dynamic_cast expression.
+///
+/// Example:
+/// dynamicCast()
+/// matches
+/// dynamic_cast<D*>(&b);
+/// in
+/// struct B { virtual ~B() {} }; struct D : B {};
+/// B b;
+/// D* p = dynamic_cast<D*>(&b);
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Expr,
+ clang::CXXDynamicCastExpr> dynamicCast;
+
+/// \brief Matches a const_cast expression.
+///
+/// Example: Matches const_cast<int*>(&r) in
+/// int n = 42;
+/// const int& r(n);
+/// int* p = const_cast<int*>(&r);
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Expr,
+ clang::CXXConstCastExpr> constCast;
+
+/// \brief Matches explicit cast expressions.
+///
+/// Matches any cast expression written in user code, whether it be a
+/// C-style cast, a functional-style cast, or a keyword cast.
+///
+/// Does not match implicit conversions.
+///
+/// Note: the name "explicitCast" is chosen to match Clang's terminology, as
+/// Clang uses the term "cast" to apply to implicit conversions as well as to
+/// actual cast expressions.
+///
+/// \see hasDestinationType.
+///
+/// Example: matches all five of the casts in
+/// int((int)(reinterpret_cast<int>(static_cast<int>(const_cast<int>(42)))))
+/// but does not match the implicit conversion in
+/// long ell = 42;
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Expr,
+ clang::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;
+
+/// \brief Matches functional cast expressions
+///
+/// Example: Matches Foo(bar);
+/// Foo f = bar;
+/// Foo g = (Foo) bar;
+/// Foo h = Foo(bar);
+const internal::VariadicDynCastAllOfMatcher<
+ clang::Expr,
+ clang::CXXFunctionalCastExpr> functionalCast;
+
+/// \brief Various overloads for the anyOf matcher.
+/// @{
+template<typename C1, typename C2>
+internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C1, C2>
+anyOf(const C1 &P1, const C2 &P2) {
+ return internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher,
+ C1, C2 >(P1, P2);
+}
+template<typename C1, typename C2, typename C3>
+internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C1,
+ internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C2, C3> >
+anyOf(const C1 &P1, const C2 &P2, const C3 &P3) {
+ return anyOf(P1, anyOf(P2, P3));
+}
+template<typename C1, typename C2, typename C3, typename C4>
+internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C1,
+ internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C2,
+ internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher,
+ C3, C4> > >
+anyOf(const C1 &P1, const C2 &P2, const C3 &P3, const C4 &P4) {
+ return AnyOf(P1, AnyOf(P2, AnyOf(P3, P4)));
+}
+template<typename C1, typename C2, typename C3, typename C4, typename C5>
+internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C1,
+ internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C2,
+ internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, C3,
+ internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher,
+ C4, C5> > > >
+anyOf(const C1& P1, const C2& P2, const C3& P3, const C4& P4, const C5& P5) {
+ return anyOf(P1, anyOf(P2, anyOf(P3, anyOf(P4, P5))));
+}
+/// @}
+
+/// \brief Various overloads for the allOf matcher.
+/// @{
+template<typename C1, typename C2>
+internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, C1, C2>
+allOf(const C1 &P1, const C2 &P2) {
+ return internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher,
+ C1, C2>(P1, P2);
+}
+template<typename C1, typename C2, typename C3>
+internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, C1,
+ internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, C2, C3> >
+allOf(const C1& P1, const C2& P2, const C3& P3) {
+ return AllOf(P1, AllOf(P2, P3));
+}
+/// @}
+
+/// \brief Matches NamedDecl nodes that have the specified name.
+///
+/// Supports specifying enclosing namespaces or classes by prefixing the name
+/// with '<enclosing>::'.
+/// Does not match typedefs of an underlying type with the given name.
+///
+/// Example matches X (Name == "X")
+/// class X;
+///
+/// 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) {
+ assert(!Name.empty());
+ const std::string FullNameString = "::" + Node.getQualifiedNameAsString();
+ const llvm::StringRef FullName = FullNameString;
+ const llvm::StringRef Pattern = Name;
+ if (Pattern.startswith("::")) {
+ return FullName == Pattern;
+ } else {
+ return FullName.endswith(("::" + Pattern).str());
+ }
+}
+
+/// \brief Matches overloaded operator names.
+///
+/// Matches overloaded operator names specified in strings without the
+/// "operator" prefix, such as "<<", for OverloadedOperatorCall's.
+///
+/// Example matches a << b
+/// (matcher == overloadedOperatorCall(hasOverloadedOperatorName("<<")))
+/// a << b;
+/// c && d; // assuming both operator<<
+/// // and operator&& are overloaded somewhere.
+AST_MATCHER_P(clang::CXXOperatorCallExpr,
+ hasOverloadedOperatorName, std::string, Name) {
+ return clang::getOperatorSpelling(Node.getOperator()) == Name;
+}
+
+/// \brief Matches C++ classes that are directly or indirectly derived from
+/// the given base class.
+///
+/// Note that a class is considered to be also derived from itself.
+/// The parameter specified the name of the base type (either a class or a
+/// typedef), and does not allow structural matches for namespaces or template
+/// type parameters.
+///
+/// Example matches X, Y, Z, C (Base == "X")
+/// class X; // A class is considered to be derived from itself
+/// class Y : public X {}; // directly derived
+/// class Z : public Y {}; // indirectly derived
+/// typedef X A;
+/// typedef A B;
+/// class C : public B {}; // derived from a typedef of X
+///
+/// In the following example, Bar matches isDerivedFrom("X"):
+/// 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) {
+ assert(!Base.empty());
+ return Finder->classIsDerivedFrom(&Node, Base);
+}
+
+/// \brief Matches AST nodes that have child AST nodes that match the
+/// provided matcher.
+///
+/// Example matches X, Y (matcher = record(has(record(hasName("X")))
+/// class X {}; // Matches X, because X::X is a class of name X inside X.
+/// class Y { class X {}; };
+/// class Z { class Y { class X {}; }; }; // Does not match Z.
+///
+/// ChildT must be an AST base type.
+template <typename ChildT>
+internal::ArgumentAdaptingMatcher<internal::HasMatcher, ChildT> has(
+ const internal::Matcher<ChildT> &ChildMatcher) {
+ return internal::ArgumentAdaptingMatcher<internal::HasMatcher,
+ ChildT>(ChildMatcher);
+}
+
+/// \brief Matches AST nodes that have descendant AST nodes that match the
+/// provided matcher.
+///
+/// Example matches X, Y, Z
+/// (matcher = record(hasDescendant(record(hasName("X")))))
+/// class X {}; // Matches X, because X::X is a class of name X inside X.
+/// class Y { class X {}; };
+/// class Z { class Y { class X {}; }; };
+///
+/// DescendantT must be an AST base type.
+template <typename DescendantT>
+internal::ArgumentAdaptingMatcher<internal::HasDescendantMatcher, DescendantT>
+hasDescendant(const internal::Matcher<DescendantT> &DescendantMatcher) {
+ return internal::ArgumentAdaptingMatcher<
+ internal::HasDescendantMatcher,
+ DescendantT>(DescendantMatcher);
+}
+
+
+/// \brief Matches AST nodes that have child AST nodes that match the
+/// provided matcher.
+///
+/// Example matches X, Y (matcher = record(forEach(record(hasName("X")))
+/// class X {}; // Matches X, because X::X is a class of name X inside X.
+/// class Y { class X {}; };
+/// class Z { class Y { class X {}; }; }; // Does not match Z.
+///
+/// ChildT must be an AST base type.
+///
+/// As opposed to 'has', 'forEach' will cause a match for each result that
+/// matches instead of only on the first one.
+template <typename ChildT>
+internal::ArgumentAdaptingMatcher<internal::ForEachMatcher, ChildT> forEach(
+ const internal::Matcher<ChildT>& ChildMatcher) {
+ return internal::ArgumentAdaptingMatcher<
+ internal::ForEachMatcher,
+ ChildT>(ChildMatcher);
+}
+
+/// \brief Matches AST nodes that have descendant AST nodes that match the
+/// provided matcher.
+///
+/// Example matches X, A, B, C
+/// (matcher = record(forEachDescendant(record(hasName("X")))))
+/// class X {}; // Matches X, because X::X is a class of name X inside X.
+/// class A { class X {}; };
+/// class B { class C { class X {}; }; };
+///
+/// DescendantT must be an AST base type.
+///
+/// As opposed to 'hasDescendant', 'forEachDescendant' will cause a match for
+/// each result that matches instead of only on the first one.
+///
+/// Note: Recursively combined ForEachDescendant can cause many matches:
+/// record(forEachDescendant(record(forEachDescendant(record()))))
+/// will match 10 times (plus injected class name matches) on:
+/// class A { class B { class C { class D { class E {}; }; }; }; };
+template <typename DescendantT>
+internal::ArgumentAdaptingMatcher<internal::ForEachDescendantMatcher, DescendantT>
+forEachDescendant(
+ const internal::Matcher<DescendantT>& DescendantMatcher) {
+ return internal::ArgumentAdaptingMatcher<
+ internal::ForEachDescendantMatcher,
+ DescendantT>(DescendantMatcher);
+}
+
+/// \brief Matches if the provided matcher does not match.
+///
+/// Example matches Y (matcher = record(unless(hasName("X"))))
+/// class X {};
+/// class Y {};
+template <typename M>
+internal::PolymorphicMatcherWithParam1<internal::NotMatcher, M> unless(const M &InnerMatcher) {
+ return internal::PolymorphicMatcherWithParam1<
+ internal::NotMatcher, M>(InnerMatcher);
+}
+
+/// \brief Matches a type if the declaration of the type matches the given
+/// matcher.
+inline internal::PolymorphicMatcherWithParam1< internal::HasDeclarationMatcher,
+ internal::Matcher<clang::Decl> >
+ hasDeclaration(const internal::Matcher<clang::Decl> &InnerMatcher) {
+ return internal::PolymorphicMatcherWithParam1<
+ internal::HasDeclarationMatcher,
+ internal::Matcher<clang::Decl> >(InnerMatcher);
+}
+
+/// \brief Matches on the implicit object argument of a member call expression.
+///
+/// Example matches y.x() (matcher = call(on(hasType(record(hasName("Y"))))))
+/// class Y { public: void x(); };
+/// void z() { Y y; y.x(); }",
+///
+/// FIXME: Overload to allow directly matching types?
+AST_MATCHER_P(clang::CXXMemberCallExpr, on, internal::Matcher<clang::Expr>,
+ InnerMatcher) {
+ const clang::Expr *ExprNode = const_cast<clang::CXXMemberCallExpr&>(Node)
+ .getImplicitObjectArgument()
+ ->IgnoreParenImpCasts();
+ return (ExprNode != NULL &&
+ InnerMatcher.matches(*ExprNode, Finder, Builder));
+}
+
+/// \brief Matches if the call expression's callee expression matches.
+///
+/// Given
+/// class Y { void x() { this->x(); x(); Y y; y.x(); } };
+/// void f() { f(); }
+/// call(callee(expression()))
+/// matches this->x(), x(), y.x(), f()
+/// with callee(...)
+/// matching this->x, x, y.x, f respectively
+///
+/// Note: Callee cannot take the more general internal::Matcher<clang::Expr>
+/// because this introduces ambiguous overloads with calls to Callee taking a
+/// internal::Matcher<clang::Decl>, as the matcher hierarchy is purely
+/// implemented in terms of implicit casts.
+AST_MATCHER_P(clang::CallExpr, callee, internal::Matcher<clang::Stmt>,
+ InnerMatcher) {
+ const clang::Expr *ExprNode = Node.getCallee();
+ return (ExprNode != NULL &&
+ InnerMatcher.matches(*ExprNode, Finder, Builder));
+}
+
+/// \brief Matches if the call expression's callee's declaration matches the
+/// given matcher.
+///
+/// Example matches y.x() (matcher = call(callee(method(hasName("x")))))
+/// class Y { public: void x(); };
+/// void z() { Y y; y.x();
+inline internal::Matcher<clang::CallExpr> callee(
+ const internal::Matcher<clang::Decl> &InnerMatcher) {
+ return internal::Matcher<clang::CallExpr>(hasDeclaration(InnerMatcher));
+}
+
+/// \brief Matches if the expression's or declaration's type matches a type
+/// matcher.
+///
+/// Example matches x (matcher = expression(hasType(
+/// hasDeclaration(record(hasName("X"))))))
+/// and z (matcher = variable(hasType(
+/// hasDeclaration(record(hasName("X"))))))
+/// class X {};
+/// void y(X &x) { x; X z; }
+AST_POLYMORPHIC_MATCHER_P(hasType, internal::Matcher<clang::QualType>,
+ InnerMatcher) {
+ TOOLING_COMPILE_ASSERT((llvm::is_base_of<clang::Expr, NodeType>::value ||
+ llvm::is_base_of<clang::ValueDecl, NodeType>::value),
+ instantiated_with_wrong_types);
+ return InnerMatcher.matches(Node.getType(), Finder, Builder);
+}
+
+/// \brief Overloaded to match the declaration of the expression's or value
+/// declaration's type.
+///
+/// In case of a value declaration (for example a variable declaration),
+/// this resolves one layer of indirection. For example, in the value
+/// declaration "X x;", record(hasName("X")) matches the declaration of X,
+/// while variable(hasType(record(hasName("X")))) matches the declaration
+/// of x."
+///
+/// Example matches x (matcher = expression(hasType(record(hasName("X")))))
+/// and z (matcher = variable(hasType(record(hasName("X")))))
+/// class X {};
+/// void y(X &x) { x; X z; }
+inline internal::PolymorphicMatcherWithParam1<
+ internal::matcher_hasTypeMatcher,
+ internal::Matcher<clang::QualType> >
+hasType(const internal::Matcher<clang::Decl> &InnerMatcher) {
+ return hasType(internal::Matcher<clang::QualType>(
+ hasDeclaration(InnerMatcher)));
+}
+
+/// \brief Matches if the matched type is a pointer type and the pointee type
+/// matches the specified matcher.
+///
+/// Example matches y->x()
+/// (matcher = call(on(hasType(pointsTo(record(hasName("Y")))))))
+/// class Y { public: void x(); };
+/// void z() { Y *y; y->x(); }
+AST_MATCHER_P(
+ clang::QualType, pointsTo, internal::Matcher<clang::QualType>,
+ InnerMatcher) {
+ return (Node->isPointerType() &&
+ InnerMatcher.matches(Node->getPointeeType(), Finder, Builder));
+}
+
+/// \brief Overloaded to match the pointee type's declaration.
+inline internal::Matcher<clang::QualType> pointsTo(
+ const internal::Matcher<clang::Decl> &InnerMatcher) {
+ return pointsTo(internal::Matcher<clang::QualType>(
+ hasDeclaration(InnerMatcher)));
+}
+
+/// \brief Matches if the matched type is a reference type and the referenced
+/// type matches the specified matcher.
+///
+/// Example matches X &x and const X &y
+/// (matcher = variable(hasType(references(record(hasName("X"))))))
+/// class X {
+/// void a(X b) {
+/// X &x = b;
+/// const X &y = b;
+/// };
+AST_MATCHER_P(clang::QualType, references, internal::Matcher<clang::QualType>,
+ InnerMatcher) {
+ return (Node->isReferenceType() &&
+ InnerMatcher.matches(Node->getPointeeType(), Finder, Builder));
+}
+
+/// \brief Overloaded to match the referenced type's declaration.
+inline internal::Matcher<clang::QualType> references(
+ const internal::Matcher<clang::Decl> &InnerMatcher) {
+ return references(internal::Matcher<clang::QualType>(
+ hasDeclaration(InnerMatcher)));
+}
+
+AST_MATCHER_P(clang::CXXMemberCallExpr, onImplicitObjectArgument,
+ internal::Matcher<clang::Expr>, InnerMatcher) {
+ const clang::Expr *ExprNode =
+ const_cast<clang::CXXMemberCallExpr&>(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<clang::CallExpr> thisPointerType(
+ const internal::Matcher<clang::QualType> &InnerMatcher) {
+ return onImplicitObjectArgument(
+ anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))));
+}
+
+/// \brief Overloaded to match the type's declaration.
+inline internal::Matcher<clang::CallExpr> thisPointerType(
+ const internal::Matcher<clang::Decl> &InnerMatcher) {
+ return onImplicitObjectArgument(
+ anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))));
+}
+
+/// \brief Matches a DeclRefExpr that refers to a declaration that matches the
+/// specified matcher.
+///
+/// Example matches x in if(x)
+/// (matcher = declarationReference(to(variable(hasName("x")))))
+/// bool x;
+/// if (x) {}
+AST_MATCHER_P(clang::DeclRefExpr, to, internal::Matcher<clang::Decl>,
+ InnerMatcher) {
+ const clang::Decl *DeclNode = Node.getDecl();
+ return (DeclNode != NULL &&
+ InnerMatcher.matches(*DeclNode, Finder, Builder));
+}
+
+/// \brief Matches a variable declaration that has an initializer expression
+/// that matches the given matcher.
+///
+/// Example matches x (matcher = variable(hasInitializer(call())))
+/// bool y() { return true; }
+/// bool x = y();
+AST_MATCHER_P(
+ clang::VarDecl, hasInitializer, internal::Matcher<clang::Expr>,
+ InnerMatcher) {
+ const clang::Expr *Initializer = Node.getAnyInitializer();
+ return (Initializer != NULL &&
+ InnerMatcher.matches(*Initializer, Finder, Builder));
+}
+
+/// \brief Checks that a call expression or a constructor call expression has
+/// a specific number of arguments (including absent default arguments).
+///
+/// Example matches f(0, 0) (matcher = call(argumentCountIs(2)))
+/// void f(int x, int y);
+/// f(0, 0);
+AST_POLYMORPHIC_MATCHER_P(argumentCountIs, unsigned, N) {
+ TOOLING_COMPILE_ASSERT((llvm::is_base_of<clang::CallExpr, NodeType>::value ||
+ llvm::is_base_of<clang::CXXConstructExpr,
+ NodeType>::value),
+ instantiated_with_wrong_types);
+ return Node.getNumArgs() == N;
+}
+
+/// \brief Matches the n'th argument of a call expression or a constructor
+/// call expression.
+///
+/// Example matches y in x(y)
+/// (matcher = call(hasArgument(0, declarationReference())))
+/// void x(int) { int y; x(y); }
+AST_POLYMORPHIC_MATCHER_P2(
+ hasArgument, unsigned, N, internal::Matcher<clang::Expr>, InnerMatcher) {
+ TOOLING_COMPILE_ASSERT((llvm::is_base_of<clang::CallExpr, NodeType>::value ||
+ llvm::is_base_of<clang::CXXConstructExpr,
+ NodeType>::value),
+ instantiated_with_wrong_types);
+ return (N < Node.getNumArgs() &&
+ InnerMatcher.matches(
+ *Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder));
+}
+
+/// \brief Matches a constructor initializer.
+///
+/// Given
+/// struct Foo {
+/// 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<clang::CXXCtorInitializer>, InnerMatcher) {
+ for (clang::CXXConstructorDecl::init_const_iterator I = Node.init_begin();
+ I != Node.init_end(); ++I) {
+ if (InnerMatcher.matches(**I, Finder, Builder)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/// \brief Matches the field declaration of a constructor initializer.
+///
+/// Given
+/// struct Foo {
+/// Foo() : foo_(1) { }
+/// int foo_;
+/// };
+/// record(has(constructor(hasAnyConstructorInitializer(
+/// forField(hasName("foo_"))))))
+/// matches Foo
+/// with forField matching foo_
+AST_MATCHER_P(clang::CXXCtorInitializer, forField,
+ internal::Matcher<clang::FieldDecl>, InnerMatcher) {
+ const clang::FieldDecl *NodeAsDecl = Node.getMember();
+ return (NodeAsDecl != NULL &&
+ InnerMatcher.matches(*NodeAsDecl, Finder, Builder));
+}
+
+/// \brief Matches the initializer expression of a constructor initializer.
+///
+/// Given
+/// struct Foo {
+/// Foo() : foo_(1) { }
+/// int foo_;
+/// };
+/// record(has(constructor(hasAnyConstructorInitializer(
+/// withInitializer(integerLiteral(equals(1)))))))
+/// matches Foo
+/// with withInitializer matching (1)
+AST_MATCHER_P(clang::CXXCtorInitializer, withInitializer,
+ internal::Matcher<clang::Expr>, InnerMatcher) {
+ const clang::Expr* NodeAsExpr = Node.getInit();
+ return (NodeAsExpr != NULL &&
+ InnerMatcher.matches(*NodeAsExpr, Finder, Builder));
+}
+
+/// \brief Matches a contructor initializer if it is explicitly written in
+/// code (as opposed to implicitly added by the compiler).
+///
+/// Given
+/// struct Foo {
+/// Foo() { }
+/// Foo(int) : foo_("A") { }
+/// string foo_;
+/// };
+/// constructor(hasAnyConstructorInitializer(isWritten()))
+/// will match Foo(int), but not Foo()
+AST_MATCHER(clang::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) {
+ return Node.isImplicit();
+}
+
+/// \brief Matches any argument of a call expression or a constructor call
+/// expression.
+///
+/// Given
+/// void x(int, int, int) { int y; x(1, y, 42); }
+/// call(hasAnyArgument(declarationReference()))
+/// matches x(1, y, 42)
+/// with hasAnyArgument(...)
+/// matching y
+AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, internal::Matcher<clang::Expr>,
+ InnerMatcher) {
+ TOOLING_COMPILE_ASSERT((llvm::is_base_of<clang::CallExpr, NodeType>::value ||
+ llvm::is_base_of<clang::CXXConstructExpr,
+ NodeType>::value),
+ instantiated_with_wrong_types);
+ for (unsigned I = 0; I < Node.getNumArgs(); ++I) {
+ if (InnerMatcher.matches(*Node.getArg(I)->IgnoreParenImpCasts(),
+ Finder, Builder)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/// \brief Matches the n'th parameter of a function declaration.
+///
+/// Given
+/// class X { void f(int x) {} };
+/// method(hasParameter(0, hasType(variable())))
+/// matches f(int x) {}
+/// with hasParameter(...)
+/// matching int x
+AST_MATCHER_P2(clang::FunctionDecl, hasParameter,
+ unsigned, N, internal::Matcher<clang::ParmVarDecl>,
+ InnerMatcher) {
+ return (N < Node.getNumParams() &&
+ InnerMatcher.matches(
+ *Node.getParamDecl(N), Finder, Builder));
+}
+
+/// \brief Matches any parameter of a function declaration.
+///
+/// Does not match the 'this' parameter of a method.
+///
+/// Given
+/// class X { void f(int x, int y, int z) {} };
+/// method(hasAnyParameter(hasName("y")))
+/// matches f(int x, int y, int z) {}
+/// with hasAnyParameter(...)
+/// matching int y
+AST_MATCHER_P(clang::FunctionDecl, hasAnyParameter,
+ internal::Matcher<clang::ParmVarDecl>, InnerMatcher) {
+ for (unsigned I = 0; I < Node.getNumParams(); ++I) {
+ if (InnerMatcher.matches(*Node.getParamDecl(I), Finder, Builder)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/// \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<clang::Expr>,
+ InnerMatcher) {
+ TOOLING_COMPILE_ASSERT(
+ (llvm::is_base_of<clang::IfStmt, NodeType>::value) ||
+ (llvm::is_base_of<clang::ConditionalOperator, NodeType>::value),
+ has_condition_requires_if_statement_or_conditional_operator);
+ const clang::Expr *const Condition = Node.getCond();
+ return (Condition != NULL &&
+ InnerMatcher.matches(*Condition, Finder, Builder));
+}
+
+/// \brief Matches the condition variable statement in an if statement.
+///
+/// Given
+/// if (A* a = GetAPointer()) {}
+/// hasConditionVariableStatment(...)
+/// matches 'A* a = GetAPointer()'.
+AST_MATCHER_P(clang::IfStmt, hasConditionVariableStatement,
+ internal::Matcher<clang::DeclStmt>, InnerMatcher) {
+ const clang::DeclStmt* const DeclarationStatement =
+ Node.getConditionVariableDeclStmt();
+ return DeclarationStatement != NULL &&
+ InnerMatcher.matches(*DeclarationStatement, Finder, Builder);
+}
+
+/// \brief Matches a 'for' statement that has a given body.
+///
+/// Given
+/// for (;;) {}
+/// hasBody(compoundStatement())
+/// matches 'for (;;) {}'
+/// with compoundStatement()
+/// matching '{}'
+AST_MATCHER_P(clang::ForStmt, hasBody, internal::Matcher<clang::Stmt>,
+ InnerMatcher) {
+ const clang::Stmt *const Statement = Node.getBody();
+ return (Statement != NULL &&
+ InnerMatcher.matches(*Statement, Finder, Builder));
+}
+
+/// \brief Matches compound statements where at least one substatement matches
+/// a given matcher.
+///
+/// Given
+/// { {}; 1+2; }
+/// hasAnySubstatement(compoundStatement())
+/// matches '{ {}; 1+2; }'
+/// with compoundStatement()
+/// matching '{}'
+AST_MATCHER_P(clang::CompoundStmt, hasAnySubstatement,
+ internal::Matcher<clang::Stmt>, InnerMatcher) {
+ for (clang::CompoundStmt::const_body_iterator It = Node.body_begin();
+ It != Node.body_end();
+ ++It) {
+ if (InnerMatcher.matches(**It, Finder, Builder)) return true;
+ }
+ return false;
+}
+
+/// \brief Checks that a compound statement contains a specific number of
+/// child statements.
+///
+/// Example: Given
+/// { for (;;) {} }
+/// compoundStatement(statementCountIs(0)))
+/// matches '{}'
+/// but does not match the outer compound statement.
+AST_MATCHER_P(clang::CompoundStmt, statementCountIs, unsigned, N) {
+ return Node.size() == N;
+}
+
+/// \brief Matches literals that are equal to the given value.
+///
+/// Example matches true (matcher = boolLiteral(equals(true)))
+/// true
+template <typename ValueT>
+internal::PolymorphicMatcherWithParam1<internal::ValueEqualsMatcher, ValueT>
+equals(const ValueT &Value) {
+ return internal::PolymorphicMatcherWithParam1<
+ internal::ValueEqualsMatcher,
+ ValueT>(Value);
+}
+
+/// \brief Matches the operator Name of operator expressions (binary or
+/// unary).
+///
+/// Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
+/// !(a || b)
+AST_POLYMORPHIC_MATCHER_P(hasOperatorName, std::string, Name) {
+ TOOLING_COMPILE_ASSERT(
+ (llvm::is_base_of<clang::BinaryOperator, NodeType>::value) ||
+ (llvm::is_base_of<clang::UnaryOperator, NodeType>::value),
+ has_condition_requires_if_statement_or_conditional_operator);
+ return Name == Node.getOpcodeStr(Node.getOpcode());
+}
+
+/// \brief Matches the left hand side of binary operator expressions.
+///
+/// Example matches a (matcher = binaryOperator(hasLHS()))
+/// a || b
+AST_MATCHER_P(clang::BinaryOperator, hasLHS,
+ internal::Matcher<clang::Expr>, InnerMatcher) {
+ clang::Expr *LeftHandSide = Node.getLHS();
+ return (LeftHandSide != NULL &&
+ InnerMatcher.matches(*LeftHandSide, Finder, Builder));
+}
+
+/// \brief Matches the right hand side of binary operator expressions.
+///
+/// Example matches b (matcher = binaryOperator(hasRHS()))
+/// a || b
+AST_MATCHER_P(clang::BinaryOperator, hasRHS,
+ internal::Matcher<clang::Expr>, InnerMatcher) {
+ clang::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<clang::BinaryOperator> hasEitherOperand(
+ const internal::Matcher<clang::Expr> &InnerMatcher) {
+ return anyOf(hasLHS(InnerMatcher), hasRHS(InnerMatcher));
+}
+
+/// \brief Matches if the operand of a unary operator matches.
+///
+/// Example matches true (matcher = hasOperand(boolLiteral(equals(true))))
+/// !true
+AST_MATCHER_P(clang::UnaryOperator, hasUnaryOperand,
+ internal::Matcher<clang::Expr>, InnerMatcher) {
+ const clang::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.
+///
+/// Example: matches "a string" (matcher =
+/// hasSourceExpression(constructorCall()))
+///
+/// class URL { URL(string); };
+/// URL url = "a string";
+AST_MATCHER_P(clang::ImplicitCastExpr, hasSourceExpression,
+ internal::Matcher<clang::Expr>, InnerMatcher) {
+ const clang::Expr* const SubExpression = Node.getSubExpr();
+ return (SubExpression != NULL &&
+ InnerMatcher.matches(*SubExpression, Finder, Builder));
+}
+
+/// \brief Matches casts whose destination type matches a given matcher.
+///
+/// (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<clang::QualType>, InnerMatcher) {
+ const clang::QualType NodeType = Node.getTypeAsWritten();
+ return InnerMatcher.matches(NodeType, Finder, Builder);
+}
+
+/// \brief Matches implicit casts whose destination type matches a given
+/// matcher.
+///
+/// FIXME: Unit test this matcher
+AST_MATCHER_P(clang::ImplicitCastExpr, hasImplicitDestinationType,
+ internal::Matcher<clang::QualType>, InnerMatcher) {
+ return InnerMatcher.matches(Node.getType(), Finder, Builder);
+}
+
+/// \brief Matches the true branch expression of a conditional operator.
+///
+/// Example matches a
+/// condition ? a : b
+AST_MATCHER_P(clang::ConditionalOperator, hasTrueExpression,
+ internal::Matcher<clang::Expr>, InnerMatcher) {
+ clang::Expr *Expression = Node.getTrueExpr();
+ return (Expression != NULL &&
+ InnerMatcher.matches(*Expression, Finder, Builder));
+}
+
+/// \brief Matches the false branch expression of a conditional operator.
+///
+/// Example matches b
+/// condition ? a : b
+AST_MATCHER_P(clang::ConditionalOperator, hasFalseExpression,
+ internal::Matcher<clang::Expr>, InnerMatcher) {
+ clang::Expr *Expression = Node.getFalseExpr();
+ return (Expression != NULL &&
+ InnerMatcher.matches(*Expression, Finder, Builder));
+}
+
+/// \brief Matches if a declaration has a body attached.
+///
+/// Example matches A, va, fa
+/// class A {};
+/// class B; // Doesn't match, as it has no body.
+/// int va;
+/// extern int vb; // Doesn't match, as it doesn't define the variable.
+/// void fa() {}
+/// void fb(); // Doesn't match, as it has no body.
+inline internal::PolymorphicMatcherWithParam0<internal::IsDefinitionMatcher>
+isDefinition() {
+ return internal::PolymorphicMatcherWithParam0<
+ internal::IsDefinitionMatcher>();
+}
+
+/// \brief Matches the class declaration that the given method declaration
+/// belongs to.
+///
+/// FIXME: Generalize this for other kinds of declarations.
+/// FIXME: What other kind of declarations would we need to generalize
+/// this to?
+///
+/// Example matches A() in the last line
+/// (matcher = constructorCall(hasDeclaration(method(
+/// ofClass(hasName("A"))))))
+/// class A {
+/// public:
+/// A();
+/// };
+/// A a = A();
+AST_MATCHER_P(clang::CXXMethodDecl, ofClass,
+ internal::Matcher<clang::CXXRecordDecl>, InnerMatcher) {
+ const clang::CXXRecordDecl *Parent = Node.getParent();
+ return (Parent != NULL &&
+ InnerMatcher.matches(*Parent, Finder, Builder));
+}
+
+/// \brief Matches member expressions that are called with '->' as opposed
+/// to '.'.
+///
+/// Member calls on the implicit this pointer match as called with '->'.
+///
+/// Given
+/// class Y {
+/// void x() { this->x(); x(); Y y; y.x(); a; this->b; Y::b; }
+/// int a;
+/// static int b;
+/// };
+/// memberExpression(isArrow())
+/// matches this->x, x, y.x, a, this->b
+inline internal::Matcher<clang::MemberExpr> isArrow() {
+ return makeMatcher(new internal::IsArrowMatcher());
+}
+
+/// \brief Matches clang::QualType nodes that are const-qualified, i.e., that
+/// include "top-level" const.
+///
+/// Given
+/// void a(int);
+/// void b(int const);
+/// void c(const int);
+/// void d(const int*);
+/// void e(int const) {};
+/// function(hasAnyParameter(hasType(isConstQualified())))
+/// 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<clang::QualType> isConstQualified() {
+ return makeMatcher(new internal::IsConstQualifiedMatcher());
+}
+
+/// \brief Matches a member expression where the member is matched by a
+/// given matcher.
+///
+/// Given
+/// struct { int first, second; } first, second;
+/// int i(second.first);
+/// int j(first.second);
+/// 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<clang::ValueDecl>, InnerMatcher) {
+ return InnerMatcher.matches(*Node.getMemberDecl(), Finder, Builder);
+}
+
+/// \brief Matches a member expression where the object expression is
+/// matched by a given matcher.
+///
+/// Given
+/// struct X { int m; };
+/// void f(X x) { x.m; m; }
+/// memberExpression(hasObjectExpression(hasType(record(hasName("X")))))))
+/// 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<clang::Expr>, InnerMatcher) {
+ return InnerMatcher.matches(*Node.getBase(), Finder, Builder);
+}
+
+/// \brief Matches template instantiations of function, class, or static
+/// member variable template instantiations.
+///
+/// Given
+/// template <typename T> class X {}; class A {}; X<A> x;
+/// or
+/// template <typename T> class X {}; class A {}; template class X<A>;
+/// record(hasName("::X"), isTemplateInstantiation())
+/// matches the template instantiation of X<A>.
+///
+/// But given
+/// template <typename T> class X {}; class A {};
+/// template <> class X<A> {}; X<A> x;
+/// record(hasName("::X"), isTemplateInstantiation())
+/// does not match, as X<A> is an explicit template specialization.
+inline internal::PolymorphicMatcherWithParam0<
+ internal::IsTemplateInstantiationMatcher>
+isTemplateInstantiation() {
+ return internal::PolymorphicMatcherWithParam0<
+ internal::IsTemplateInstantiationMatcher>();
+}
+
+} // end namespace ast_matchers
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
new file mode 100644
index 0000000000..d9a557e78c
--- /dev/null
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -0,0 +1,888 @@
+//===--- ASTMatchersInternal.h - Structural query framework -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements the base layer of the matcher framework.
+//
+// Matchers are methods that return a Matcher<T> which provides a method
+// Matches(...) which is a predicate on an AST node. The Matches method's
+// parameters define the context of the match, which allows matchers to recurse
+// or store the current node as bound to a specific string, so that it can be
+// retrieved later.
+//
+// In general, matchers have two parts:
+// 1. A function Matcher<T> MatcherName(<arguments>) which returns a Matcher<T>
+// based on the arguments and optionally on template type deduction based
+// on the arguments. Matcher<T>s form an implicit reverse hierarchy
+// to clang's AST class hierarchy, meaning that you can use a Matcher<Base>
+// everywhere a Matcher<Derived> is required.
+// 2. An implementation of a class derived from MatcherInterface<T>.
+//
+// The matcher functions are defined in ASTMatchers.h. To make it possible
+// to implement both the matcher function and the implementation of the matcher
+// interface in one place, ASTMatcherMacros.h defines macros that allow
+// implementing a matcher in a single place.
+//
+// This file contains the base classes needed to construct the actual matchers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
+#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/Stmt.h"
+#include "llvm/ADT/VariadicFunction.h"
+#include <map>
+#include <string>
+#include <vector>
+
+/// FIXME: Move into the llvm support library.
+template <bool> struct CompileAssert {};
+#define TOOLING_COMPILE_ASSERT(Expr, Msg) \
+ typedef CompileAssert<(bool(Expr))> Msg[bool(Expr) ? 1 : -1]
+
+namespace clang {
+namespace ast_matchers {
+
+class BoundNodes;
+
+namespace internal {
+
+class BoundNodesTreeBuilder;
+
+/// \brief A tree of bound nodes in match results.
+///
+/// If a match can contain multiple matches on the same node with different
+/// matching subexpressions, BoundNodesTree contains a branch for each of
+/// those matching subexpressions.
+///
+/// BoundNodesTree's are created during the matching process; when a match
+/// is found, we iterate over the tree and create a BoundNodes object containing
+/// the union of all bound nodes on the path from the root to a each leaf.
+class BoundNodesTree {
+public:
+ /// \brief A visitor interface to visit all BoundNodes results for a
+ /// BoundNodesTree.
+ class Visitor {
+ public:
+ virtual ~Visitor() {}
+
+ /// \brief Called multiple times during a single call to VisitMatches(...).
+ ///
+ /// 'BoundNodesView' contains the bound nodes for a single match.
+ virtual void visitMatch(const BoundNodes& BoundNodesView) = 0;
+ };
+
+ BoundNodesTree();
+
+ /// \brief Create a BoundNodesTree from pre-filled maps of bindings.
+ BoundNodesTree(const std::map<std::string, const clang::Decl*>& DeclBindings,
+ const std::map<std::string, const clang::Stmt*>& StmtBindings,
+ const std::vector<BoundNodesTree> RecursiveBindings);
+
+ /// \brief Adds all bound nodes to bound_nodes_builder.
+ void copyTo(BoundNodesTreeBuilder* Builder) const;
+
+ /// \brief Visits all matches that this BoundNodesTree represents.
+ ///
+ /// The ownership of 'ResultVisitor' remains at the caller.
+ void visitMatches(Visitor* ResultVisitor);
+
+private:
+ void visitMatchesRecursively(
+ Visitor* ResultVistior,
+ std::map<std::string, const clang::Decl*> DeclBindings,
+ std::map<std::string, const clang::Stmt*> StmtBindings);
+
+ template <typename T>
+ void copyBindingsTo(const T& bindings, BoundNodesTreeBuilder* Builder) const;
+
+ // FIXME: Find out whether we want to use different data structures here -
+ // first benchmarks indicate that it doesn't matter though.
+
+ std::map<std::string, const clang::Decl*> DeclBindings;
+ std::map<std::string, const clang::Stmt*> StmtBindings;
+
+ std::vector<BoundNodesTree> RecursiveBindings;
+};
+
+/// \brief Creates BoundNodesTree objects.
+///
+/// The tree builder is used during the matching process to insert the bound
+/// nodes from the Id matcher.
+class BoundNodesTreeBuilder {
+public:
+ BoundNodesTreeBuilder();
+
+ /// \brief Add a binding from an id to a node.
+ ///
+ /// FIXME: Add overloads for all AST base types.
+ /// @{
+ void setBinding(const std::pair<const std::string,
+ const clang::Decl*>& binding);
+ void setBinding(const std::pair<const std::string,
+ const clang::Stmt*>& binding);
+ /// @}
+
+ /// \brief Adds a branch in the tree.
+ void addMatch(const BoundNodesTree& Bindings);
+
+ /// \brief Returns a BoundNodes object containing all current bindings.
+ BoundNodesTree build() const;
+
+private:
+ BoundNodesTreeBuilder(const BoundNodesTreeBuilder&); // DO NOT IMPLEMENT
+ void operator=(const BoundNodesTreeBuilder&); // DO NOT IMPLEMENT
+
+ std::map<std::string, const clang::Decl*> DeclBindings;
+ std::map<std::string, const clang::Stmt*> StmtBindings;
+
+ std::vector<BoundNodesTree> RecursiveBindings;
+};
+
+class ASTMatchFinder;
+
+/// \brief Generic interface for matchers on an AST node of type T.
+///
+/// Implement this if your matcher may need to inspect the children or
+/// descendants of the node or bind matched nodes to names. If you are
+/// writing a simple matcher that only inspects properties of the
+/// current node and doesn't care about its children or descendants,
+/// implement SingleNodeMatcherInterface instead.
+template <typename T>
+class MatcherInterface : public llvm::RefCountedBaseVPTR {
+public:
+ virtual ~MatcherInterface() {}
+
+ /// \brief Returns true if 'Node' can be matched.
+ ///
+ /// May bind 'Node' to an ID via 'Builder', or recurse into
+ /// the AST via 'Finder'.
+ virtual bool matches(const T &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const = 0;
+};
+
+/// \brief Interface for matchers that only evaluate properties on a single node.
+template <typename T>
+class SingleNodeMatcherInterface : public MatcherInterface<T> {
+public:
+ /// \brief Returns true if the matcher matches the provided node.
+ ///
+ /// A subclass must implement this instead of Matches().
+ virtual bool matchesNode(const T &Node) const = 0;
+
+private:
+ /// Implements MatcherInterface::Matches.
+ virtual bool matches(const T &Node,
+ ASTMatchFinder * /* Finder */,
+ BoundNodesTreeBuilder * /* Builder */) const {
+ return matchesNode(Node);
+ }
+};
+
+/// \brief Wrapper of a MatcherInterface<T> *that allows copying.
+///
+/// A Matcher<Base> can be used anywhere a Matcher<Derived> is
+/// required. This establishes an is-a relationship which is reverse
+/// to the AST hierarchy. In other words, Matcher<T> is contravariant
+/// with respect to T. The relationship is built via a type conversion
+/// operator rather than a type hierarchy to be able to templatize the
+/// type hierarchy instead of spelling it out.
+template <typename T>
+class Matcher {
+public:
+ /// \brief Takes ownership of the provided implementation pointer.
+ explicit Matcher(MatcherInterface<T> *Implementation)
+ : Implementation(Implementation) {}
+
+ /// \brief Forwards the call to the underlying MatcherInterface<T> pointer.
+ bool matches(const T &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return Implementation->matches(Node, Finder, Builder);
+ }
+
+ /// \brief Implicitly converts this object to a Matcher<Derived>.
+ ///
+ /// Requires Derived to be derived from T.
+ template <typename Derived>
+ operator Matcher<Derived>() const {
+ return Matcher<Derived>(new ImplicitCastMatcher<Derived>(*this));
+ }
+
+ /// \brief Returns an ID that uniquely identifies the matcher.
+ uint64_t getID() const {
+ /// FIXME: Document the requirements this imposes on matcher
+ /// implementations (no new() implementation_ during a Matches()).
+ return reinterpret_cast<uint64_t>(Implementation.getPtr());
+ }
+
+private:
+ /// \brief Allows conversion from Matcher<T> to Matcher<Derived> if Derived
+ /// is derived from T.
+ template <typename Derived>
+ class ImplicitCastMatcher : public MatcherInterface<Derived> {
+ public:
+ explicit ImplicitCastMatcher(const Matcher<T> &From)
+ : From(From) {}
+
+ virtual bool matches(const Derived &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return From.matches(Node, Finder, Builder);
+ }
+
+ private:
+ const Matcher<T> From;
+ };
+
+ llvm::IntrusiveRefCntPtr< MatcherInterface<T> > Implementation;
+}; // class Matcher
+
+/// \brief A convenient helper for creating a Matcher<T> without specifying
+/// the template type argument.
+template <typename T>
+inline Matcher<T> makeMatcher(MatcherInterface<T> *Implementation) {
+ return Matcher<T>(Implementation);
+}
+
+/// \brief Matches declarations for QualType and CallExpr.
+///
+/// Type argument DeclMatcherT is required by PolymorphicMatcherWithParam1 but
+/// not actually used.
+template <typename T, typename DeclMatcherT>
+class HasDeclarationMatcher : public MatcherInterface<T> {
+ TOOLING_COMPILE_ASSERT((llvm::is_same< DeclMatcherT,
+ Matcher<clang::Decl> >::value),
+ instantiated_with_wrong_types);
+public:
+ explicit HasDeclarationMatcher(const Matcher<clang::Decl> &InnerMatcher)
+ : InnerMatcher(InnerMatcher) {}
+
+ virtual bool matches(const T &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return matchesSpecialized(Node, Finder, Builder);
+ }
+
+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,
+ BoundNodesTreeBuilder *Builder) const {
+ /// FIXME: Add other ways to convert...
+ clang::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,
+ BoundNodesTreeBuilder *Builder) const {
+ const clang::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,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ const clang::Decl *NodeAsDecl = Node.getConstructor();
+ return NodeAsDecl != NULL &&
+ InnerMatcher.matches(*NodeAsDecl, Finder, Builder);
+ }
+
+ const Matcher<clang::Decl> InnerMatcher;
+};
+
+/// \brief IsBaseType<T>::value is true if T is a "base" type in the AST
+/// node class hierarchies (i.e. if T is Decl, Stmt, or QualType).
+template <typename T>
+struct IsBaseType {
+ static const bool value =
+ (llvm::is_same<T, clang::Decl>::value ||
+ llvm::is_same<T, clang::Stmt>::value ||
+ llvm::is_same<T, clang::QualType>::value ||
+ llvm::is_same<T, clang::CXXCtorInitializer>::value);
+};
+template <typename T>
+const bool IsBaseType<T>::value;
+
+/// \brief Interface that can match any AST base node type and contains default
+/// implementations returning false.
+class UntypedBaseMatcher : public llvm::RefCountedBaseVPTR {
+public:
+ virtual ~UntypedBaseMatcher() {}
+
+ virtual bool matches(const clang::Decl &DeclNode, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return false;
+ }
+ virtual bool matches(const clang::QualType &TypeNode, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return false;
+ }
+ virtual bool matches(const clang::Stmt &StmtNode, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return false;
+ }
+ virtual bool matches(const clang::CXXCtorInitializer &CtorInitNode,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return false;
+ }
+
+ /// \brief Returns a unique ID for the matcher.
+ virtual uint64_t getID() const = 0;
+};
+
+/// \brief An UntypedBaseMatcher that overwrites the Matches(...) method for
+/// node type T. T must be an AST base type.
+template <typename T>
+class TypedBaseMatcher : public UntypedBaseMatcher {
+ TOOLING_COMPILE_ASSERT(IsBaseType<T>::value,
+ typed_base_matcher_can_only_be_used_with_base_type);
+public:
+ explicit TypedBaseMatcher(const Matcher<T> &InnerMatcher)
+ : InnerMatcher(InnerMatcher) {}
+
+ using UntypedBaseMatcher::matches;
+ /// \brief Implements UntypedBaseMatcher::Matches.
+ ///
+ /// Since T is guaranteed to be a "base" AST node type, this method is
+ /// guaranteed to override one of the matches() methods from
+ /// UntypedBaseMatcher.
+ virtual bool matches(const T &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return InnerMatcher.matches(Node, Finder, Builder);
+ }
+
+ /// \brief Implements UntypedBaseMatcher::getID.
+ virtual uint64_t getID() const {
+ return InnerMatcher.getID();
+ }
+
+private:
+ Matcher<T> InnerMatcher;
+};
+
+/// \brief Interface that allows matchers to traverse the AST.
+/// FIXME: Find a better name.
+///
+/// This provides two entry methods for each base node type in the AST:
+/// - matchesChildOf:
+/// Matches a matcher on every child node of the given node. Returns true
+/// if at least one child node could be matched.
+/// - matchesDescendantOf:
+/// Matches a matcher on all descendant nodes of the given node. Returns true
+/// if at least one descendant matched.
+class ASTMatchFinder {
+public:
+ /// \brief Defines how we descend a level in the AST when we pass
+ /// through expressions.
+ enum TraversalKind {
+ /// Will traverse any child nodes.
+ TK_AsIs,
+ /// Will not traverse implicit casts and parentheses.
+ TK_IgnoreImplicitCastsAndParentheses
+ };
+
+ /// \brief Defines how bindings are processed on recursive matches.
+ enum BindKind {
+ /// Stop at the first match and only bind the first match.
+ BK_First,
+ /// Create results for all combinations of bindings that match.
+ BK_All
+ };
+
+ virtual ~ASTMatchFinder() {}
+
+ /// \brief Returns true if the given class is directly or indirectly derived
+ /// 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,
+ StringRef BaseName) const = 0;
+
+ // FIXME: Implement for other base nodes.
+ virtual bool matchesChildOf(const clang::Decl &DeclNode,
+ const UntypedBaseMatcher &BaseMatcher,
+ BoundNodesTreeBuilder *Builder,
+ TraversalKind Traverse,
+ BindKind Bind) = 0;
+ virtual bool matchesChildOf(const clang::Stmt &StmtNode,
+ const UntypedBaseMatcher &BaseMatcher,
+ BoundNodesTreeBuilder *Builder,
+ TraversalKind Traverse,
+ BindKind Bind) = 0;
+
+ virtual bool matchesDescendantOf(const clang::Decl &DeclNode,
+ const UntypedBaseMatcher &BaseMatcher,
+ BoundNodesTreeBuilder *Builder,
+ BindKind Bind) = 0;
+ virtual bool matchesDescendantOf(const clang::Stmt &StmtNode,
+ const UntypedBaseMatcher &BaseMatcher,
+ BoundNodesTreeBuilder *Builder,
+ BindKind Bind) = 0;
+};
+
+/// \brief Converts a Matcher<T> to a matcher of desired type To by "adapting"
+/// a To into a T.
+///
+/// The ArgumentAdapterT argument specifies how the adaptation is done.
+///
+/// For example:
+/// ArgumentAdaptingMatcher<DynCastMatcher, T>(InnerMatcher);
+/// returns a matcher that can be used where a Matcher<To> is required, if
+/// To and T are in the same type hierarchy, and thus dyn_cast can be
+/// called to convert a To to a T.
+///
+/// FIXME: Make sure all our applications of this class actually require
+/// knowledge about the inner type. DynCastMatcher obviously does, but the
+/// Has *matchers require the inner type solely for COMPILE_ASSERT purposes.
+template <template <typename ToArg, typename FromArg> class ArgumentAdapterT,
+ typename T>
+class ArgumentAdaptingMatcher {
+public:
+ explicit ArgumentAdaptingMatcher(const Matcher<T> &InnerMatcher)
+ : InnerMatcher(InnerMatcher) {}
+
+ template <typename To>
+ operator Matcher<To>() const {
+ return Matcher<To>(new ArgumentAdapterT<To, T>(InnerMatcher));
+ }
+
+private:
+ const Matcher<T> InnerMatcher;
+};
+
+/// \brief A PolymorphicMatcherWithParamN<MatcherT, P1, ..., PN> object can be
+/// created from N parameters p1, ..., pN (of type P1, ..., PN) and
+/// used as a Matcher<T> where a MatcherT<T, P1, ..., PN>(p1, ..., pN)
+/// can be constructed.
+///
+/// For example:
+/// - PolymorphicMatcherWithParam0<IsDefinitionMatcher>()
+/// creates an object that can be used as a Matcher<T> for any type T
+/// where an IsDefinitionMatcher<T>() can be constructed.
+/// - PolymorphicMatcherWithParam1<ValueEqualsMatcher, int>(42)
+/// creates an object that can be used as a Matcher<T> for any type T
+/// where a ValueEqualsMatcher<T, int>(42) can be constructed.
+template <template <typename T> class MatcherT>
+class PolymorphicMatcherWithParam0 {
+public:
+ template <typename T>
+ operator Matcher<T>() const {
+ return Matcher<T>(new MatcherT<T>());
+ }
+};
+
+template <template <typename T, typename P1> class MatcherT,
+ typename P1>
+class PolymorphicMatcherWithParam1 {
+public:
+ explicit PolymorphicMatcherWithParam1(const P1 &Param1)
+ : Param1(Param1) {}
+
+ template <typename T>
+ operator Matcher<T>() const {
+ return Matcher<T>(new MatcherT<T, P1>(Param1));
+ }
+
+private:
+ const P1 Param1;
+};
+
+template <template <typename T, typename P1, typename P2> class MatcherT,
+ typename P1, typename P2>
+class PolymorphicMatcherWithParam2 {
+public:
+ PolymorphicMatcherWithParam2(const P1 &Param1, const P2 &Param2)
+ : Param1(Param1), Param2(Param2) {}
+
+ template <typename T>
+ operator Matcher<T>() const {
+ return Matcher<T>(new MatcherT<T, P1, P2>(Param1, Param2));
+ }
+
+private:
+ const P1 Param1;
+ const P2 Param2;
+};
+
+/// \brief Matches any instance of the given NodeType.
+///
+/// This is useful when a matcher syntactically requires a child matcher,
+/// but the context doesn't care. See for example: anything().
+///
+/// FIXME: Alternatively we could also create a IsAMatcher or something
+/// that checks that a dyn_cast is possible. This is purely needed for the
+/// difference between calling for example:
+/// record()
+/// and
+/// record(SomeMatcher)
+/// In the second case we need the correct type we were dyn_cast'ed to in order
+/// to get the right type for the inner matcher. In the first case we don't need
+/// that, but we use the type conversion anyway and insert a TrueMatcher.
+template <typename T>
+class TrueMatcher : public SingleNodeMatcherInterface<T> {
+public:
+ virtual bool matchesNode(const T &Node) const {
+ return true;
+ }
+};
+
+/// \brief Provides a MatcherInterface<T> for a Matcher<To> that matches if T is
+/// dyn_cast'able into To and the given Matcher<To> matches on the dyn_cast'ed
+/// node.
+template <typename T, typename To>
+class DynCastMatcher : public MatcherInterface<T> {
+public:
+ explicit DynCastMatcher(const Matcher<To> &InnerMatcher)
+ : InnerMatcher(InnerMatcher) {}
+
+ virtual bool matches(const T &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ const To *InnerMatchValue = llvm::dyn_cast<To>(&Node);
+ return InnerMatchValue != NULL &&
+ InnerMatcher.matches(*InnerMatchValue, Finder, Builder);
+ }
+
+private:
+ const Matcher<To> InnerMatcher;
+};
+
+/// \brief Enables the user to pass a Matcher<clang::CXXMemberCallExpr> 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<clang::CXXMemberCallExpr>::
+operator Matcher<clang::CallExpr>() const {
+ return makeMatcher(
+ new DynCastMatcher<clang::CallExpr, clang::CXXMemberCallExpr>(*this));
+}
+
+/// \brief Matcher<T> that wraps an inner Matcher<T> and binds the matched node
+/// to an ID if the inner matcher matches on the node.
+template <typename T>
+class IdMatcher : public MatcherInterface<T> {
+public:
+ /// \brief Creates an IdMatcher that binds to 'ID' if 'InnerMatcher' matches
+ /// the node.
+ IdMatcher(StringRef ID, const Matcher<T> &InnerMatcher)
+ : ID(ID), InnerMatcher(InnerMatcher) {}
+
+ virtual bool matches(const T &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ bool Result = InnerMatcher.matches(Node, Finder, Builder);
+ if (Result) {
+ Builder->setBinding(std::pair<const std::string, const T*>(ID, &Node));
+ }
+ return Result;
+ }
+
+private:
+ const std::string ID;
+ const Matcher<T> InnerMatcher;
+};
+
+/// \brief Matches nodes of type T that have child nodes of type ChildT for
+/// which a specified child matcher matches.
+///
+/// ChildT must be an AST base type.
+template <typename T, typename ChildT>
+class HasMatcher : public MatcherInterface<T> {
+ TOOLING_COMPILE_ASSERT(IsBaseType<ChildT>::value,
+ has_only_accepts_base_type_matcher);
+public:
+ explicit HasMatcher(const Matcher<ChildT> &ChildMatcher)
+ : ChildMatcher(ChildMatcher) {}
+
+ virtual bool matches(const T &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return Finder->matchesChildOf(
+ Node, ChildMatcher, Builder,
+ ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
+ ASTMatchFinder::BK_First);
+ }
+
+ private:
+ const TypedBaseMatcher<ChildT> ChildMatcher;
+};
+
+/// \brief Matches nodes of type T that have child nodes of type ChildT for
+/// which a specified child matcher matches. ChildT must be an AST base
+/// type.
+/// As opposed to the HasMatcher, the ForEachMatcher will produce a match
+/// for each child that matches.
+template <typename T, typename ChildT>
+class ForEachMatcher : public MatcherInterface<T> {
+ TOOLING_COMPILE_ASSERT(IsBaseType<ChildT>::value,
+ for_each_only_accepts_base_type_matcher);
+ public:
+ explicit ForEachMatcher(const Matcher<ChildT> &ChildMatcher)
+ : ChildMatcher(ChildMatcher) {}
+
+ virtual bool matches(const T& Node,
+ ASTMatchFinder* Finder,
+ BoundNodesTreeBuilder* Builder) const {
+ return Finder->matchesChildOf(
+ Node, ChildMatcher, Builder,
+ ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
+ ASTMatchFinder::BK_All);
+ }
+
+private:
+ const TypedBaseMatcher<ChildT> ChildMatcher;
+};
+
+/// \brief Matches nodes of type T if the given Matcher<T> does not match.
+///
+/// Type argument MatcherT is required by PolymorphicMatcherWithParam1
+/// but not actually used. It will always be instantiated with a type
+/// convertible to Matcher<T>.
+template <typename T, typename MatcherT>
+class NotMatcher : public MatcherInterface<T> {
+public:
+ explicit NotMatcher(const Matcher<T> &InnerMatcher)
+ : InnerMatcher(InnerMatcher) {}
+
+ virtual bool matches(const T &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return !InnerMatcher.matches(Node, Finder, Builder);
+ }
+
+private:
+ const Matcher<T> InnerMatcher;
+};
+
+/// \brief Matches nodes of type T for which both provided matchers match.
+///
+/// Type arguments MatcherT1 and MatcherT2 are required by
+/// PolymorphicMatcherWithParam2 but not actually used. They will
+/// always be instantiated with types convertible to Matcher<T>.
+template <typename T, typename MatcherT1, typename MatcherT2>
+class AllOfMatcher : public MatcherInterface<T> {
+public:
+ AllOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2)
+ : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {}
+
+ virtual bool matches(const T &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return InnerMatcher1.matches(Node, Finder, Builder) &&
+ InnerMatcher2.matches(Node, Finder, Builder);
+ }
+
+private:
+ const Matcher<T> InnerMatcher1;
+ const Matcher<T> InnerMatcher2;
+};
+
+/// \brief Matches nodes of type T for which at least one of the two provided
+/// matchers matches.
+///
+/// Type arguments MatcherT1 and MatcherT2 are
+/// required by PolymorphicMatcherWithParam2 but not actually
+/// used. They will always be instantiated with types convertible to
+/// Matcher<T>.
+template <typename T, typename MatcherT1, typename MatcherT2>
+class AnyOfMatcher : public MatcherInterface<T> {
+public:
+ AnyOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2)
+ : InnerMatcher1(InnerMatcher1), InnertMatcher2(InnerMatcher2) {}
+
+ virtual bool matches(const T &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return InnerMatcher1.matches(Node, Finder, Builder) ||
+ InnertMatcher2.matches(Node, Finder, Builder);
+ }
+
+private:
+ const Matcher<T> InnerMatcher1;
+ const Matcher<T> InnertMatcher2;
+};
+
+/// \brief Creates a Matcher<T> that matches if
+/// T is dyn_cast'able into InnerT and all inner matchers match.
+template<typename T, typename InnerT>
+Matcher<T> makeDynCastAllOfComposite(
+ ArrayRef<const Matcher<InnerT> *> InnerMatchers) {
+ if (InnerMatchers.empty()) {
+ return ArgumentAdaptingMatcher<DynCastMatcher, InnerT>(
+ makeMatcher(new TrueMatcher<InnerT>));
+ }
+ Matcher<InnerT> InnerMatcher = *InnerMatchers.back();
+ for (int i = InnerMatchers.size() - 2; i >= 0; --i) {
+ InnerMatcher = makeMatcher(
+ new AllOfMatcher<InnerT, Matcher<InnerT>, Matcher<InnerT> >(
+ *InnerMatchers[i], InnerMatcher));
+ }
+ return ArgumentAdaptingMatcher<DynCastMatcher, InnerT>(InnerMatcher);
+}
+
+/// \brief Matches nodes of type T that have at least one descendant node of
+/// type DescendantT for which the given inner matcher matches.
+///
+/// DescendantT must be an AST base type.
+template <typename T, typename DescendantT>
+class HasDescendantMatcher : public MatcherInterface<T> {
+ TOOLING_COMPILE_ASSERT(IsBaseType<DescendantT>::value,
+ has_descendant_only_accepts_base_type_matcher);
+public:
+ explicit HasDescendantMatcher(const Matcher<DescendantT> &DescendantMatcher)
+ : DescendantMatcher(DescendantMatcher) {}
+
+ virtual bool matches(const T &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return Finder->matchesDescendantOf(
+ Node, DescendantMatcher, Builder, ASTMatchFinder::BK_First);
+ }
+
+ private:
+ const TypedBaseMatcher<DescendantT> DescendantMatcher;
+};
+
+/// \brief Matches nodes of type T that have at least one descendant node of
+/// type DescendantT for which the given inner matcher matches.
+///
+/// DescendantT must be an AST base type.
+/// As opposed to HasDescendantMatcher, ForEachDescendantMatcher will match
+/// for each descendant node that matches instead of only for the first.
+template <typename T, typename DescendantT>
+class ForEachDescendantMatcher : public MatcherInterface<T> {
+ TOOLING_COMPILE_ASSERT(IsBaseType<DescendantT>::value,
+ for_each_descendant_only_accepts_base_type_matcher);
+ public:
+ explicit ForEachDescendantMatcher(
+ const Matcher<DescendantT>& DescendantMatcher)
+ : DescendantMatcher(DescendantMatcher) {}
+
+ virtual bool matches(const T& Node,
+ ASTMatchFinder* Finder,
+ BoundNodesTreeBuilder* Builder) const {
+ return Finder->matchesDescendantOf(Node, DescendantMatcher, Builder,
+ ASTMatchFinder::BK_All);
+ }
+
+private:
+ const TypedBaseMatcher<DescendantT> DescendantMatcher;
+};
+
+/// \brief Matches on nodes that have a getValue() method if getValue() equals
+/// the value the ValueEqualsMatcher was constructed with.
+template <typename T, typename ValueT>
+class ValueEqualsMatcher : public SingleNodeMatcherInterface<T> {
+ TOOLING_COMPILE_ASSERT((llvm::is_base_of<clang::CharacterLiteral, T>::value ||
+ llvm::is_base_of<clang::CXXBoolLiteralExpr,
+ T>::value ||
+ llvm::is_base_of<clang::FloatingLiteral, T>::value ||
+ llvm::is_base_of<clang::IntegerLiteral, T>::value),
+ the_node_must_have_a_getValue_method);
+public:
+ explicit ValueEqualsMatcher(const ValueT &ExpectedValue)
+ : ExpectedValue(ExpectedValue) {}
+
+ virtual bool matchesNode(const T &Node) const {
+ return Node.getValue() == ExpectedValue;
+ }
+
+private:
+ const ValueT ExpectedValue;
+};
+
+template <typename T>
+class IsDefinitionMatcher : public SingleNodeMatcherInterface<T> {
+ TOOLING_COMPILE_ASSERT(
+ (llvm::is_base_of<clang::TagDecl, T>::value) ||
+ (llvm::is_base_of<clang::VarDecl, T>::value) ||
+ (llvm::is_base_of<clang::FunctionDecl, T>::value),
+ is_definition_requires_isThisDeclarationADefinition_method);
+public:
+ virtual bool matchesNode(const T &Node) const {
+ return Node.isThisDeclarationADefinition();
+ }
+};
+
+/// \brief Matches on template instantiations for FunctionDecl, VarDecl or
+/// CXXRecordDecl nodes.
+template <typename T>
+class IsTemplateInstantiationMatcher : public MatcherInterface<T> {
+ TOOLING_COMPILE_ASSERT((llvm::is_base_of<clang::FunctionDecl, T>::value) ||
+ (llvm::is_base_of<clang::VarDecl, T>::value) ||
+ (llvm::is_base_of<clang::CXXRecordDecl, T>::value),
+ requires_getTemplateSpecializationKind_method);
+ public:
+ virtual bool matches(const T& Node,
+ ASTMatchFinder* Finder,
+ BoundNodesTreeBuilder* Builder) const {
+ return (Node.getTemplateSpecializationKind() ==
+ clang::TSK_ImplicitInstantiation ||
+ Node.getTemplateSpecializationKind() ==
+ clang::TSK_ExplicitInstantiationDefinition);
+ }
+};
+
+class IsArrowMatcher : public SingleNodeMatcherInterface<clang::MemberExpr> {
+public:
+ virtual bool matchesNode(const clang::MemberExpr &Node) const {
+ return Node.isArrow();
+ }
+};
+
+class IsConstQualifiedMatcher
+ : public SingleNodeMatcherInterface<clang::QualType> {
+ public:
+ virtual bool matchesNode(const clang::QualType& Node) const {
+ return Node.isConstQualified();
+ }
+};
+
+/// \brief A VariadicDynCastAllOfMatcher<SourceT, TargetT> object is a
+/// variadic functor that takes a number of Matcher<TargetT> and returns a
+/// Matcher<SourceT> that matches TargetT nodes that are matched by all of the
+/// given matchers, if SourceT can be dynamically casted into TargetT.
+///
+/// For example:
+/// const VariadicDynCastAllOfMatcher<
+/// clang::Decl, clang::CXXRecordDecl> record;
+/// Creates a functor record(...) that creates a Matcher<clang::Decl> given
+/// a variable number of arguments of type Matcher<clang::CXXRecordDecl>.
+/// The returned matcher matches if the given clang::Decl can by dynamically
+/// casted to clang::CXXRecordDecl and all given matchers match.
+template <typename SourceT, typename TargetT>
+class VariadicDynCastAllOfMatcher
+ : public llvm::VariadicFunction<
+ Matcher<SourceT>, Matcher<TargetT>,
+ makeDynCastAllOfComposite<SourceT, TargetT> > {
+public:
+ VariadicDynCastAllOfMatcher() {}
+};
+
+} // end namespace internal
+} // end namespace ast_matchers
+} // end namespace clang
+
+#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
diff --git a/include/clang/ASTMatchers/ASTMatchersMacros.h b/include/clang/ASTMatchers/ASTMatchersMacros.h
new file mode 100644
index 0000000000..c68534acae
--- /dev/null
+++ b/include/clang/ASTMatchers/ASTMatchersMacros.h
@@ -0,0 +1,224 @@
+//===--- ASTMatchersMacros.h - Structural query framework -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines macros that enable us to define new matchers in a single place.
+// Since a matcher is a function which returns a Matcher<T> object, where
+// T is the type of the actual implementation of the matcher, the macros allow
+// us to write matchers like functions and take care of the definition of the
+// class boilerplate.
+//
+// Note that when you define a matcher with an AST_MATCHER* macro, only the
+// function which creates the matcher goes into the current namespace - the
+// class that implements the actual matcher, which gets returned by the
+// generator function, is put into the 'internal' namespace. This allows us
+// to only have the functions (which is all the user cares about) in the
+// 'ast_matchers' namespace and hide the boilerplate.
+//
+// To define a matcher in user code, always put it into the clang::ast_matchers
+// namespace and refer to the internal types via the 'internal::':
+//
+// namespace clang {
+// namespace ast_matchers {
+// AST_MATCHER_P(MemberExpr, Member,
+// internal::Matcher<ValueDecl>, InnerMatcher) {
+// return InnerMatcher.matches(*Node.getMemberDecl(), Finder, Builder);
+// }
+// } // end namespace ast_matchers
+// } // end namespace clang
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
+#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
+
+/// \brief AST_MATCHER(Type, DefineMatcher) { ... }
+/// defines a zero parameter function named DefineMatcher() that returns a
+/// Matcher<Type> object.
+///
+/// The code between the curly braces has access to the following variables:
+///
+/// Node: the AST node being matched; its type is Type.
+/// Finder: an ASTMatchFinder*.
+/// Builder: a BoundNodesTreeBuilder*.
+///
+/// The code should return true if 'Node' matches.
+#define AST_MATCHER(Type, DefineMatcher) \
+ namespace internal { \
+ class matcher_##DefineMatcher##Matcher \
+ : public MatcherInterface<Type> { \
+ public: \
+ explicit matcher_##DefineMatcher##Matcher() {} \
+ virtual bool matches( \
+ const Type &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const; \
+ }; \
+ } \
+ inline internal::Matcher<Type> DefineMatcher() { \
+ return internal::makeMatcher( \
+ new internal::matcher_##DefineMatcher##Matcher()); \
+ } \
+ inline bool internal::matcher_##DefineMatcher##Matcher::matches( \
+ const Type &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const
+
+/// \brief AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) { ... }
+/// defines a single-parameter function named DefineMatcher() that returns a
+/// Matcher<Type> object.
+///
+/// The code between the curly braces has access to the following variables:
+///
+/// Node: the AST node being matched; its type is Type.
+/// Param: the parameter passed to the function; its type
+/// is ParamType.
+/// Finder: an ASTMatchFinder*.
+/// Builder: a BoundNodesTreeBuilder*.
+///
+/// The code should return true if 'Node' matches.
+#define AST_MATCHER_P(Type, DefineMatcher, ParamType, Param) \
+ namespace internal { \
+ class matcher_##DefineMatcher##Matcher \
+ : public MatcherInterface<Type> { \
+ public: \
+ explicit matcher_##DefineMatcher##Matcher( \
+ const ParamType &A##Param) : Param(A##Param) {} \
+ virtual bool matches( \
+ const Type &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const; \
+ private: \
+ const ParamType Param; \
+ }; \
+ } \
+ inline internal::Matcher<Type> DefineMatcher(const ParamType &Param) { \
+ return internal::makeMatcher( \
+ new internal::matcher_##DefineMatcher##Matcher(Param)); \
+ } \
+ inline bool internal::matcher_##DefineMatcher##Matcher::matches( \
+ const Type &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const
+
+/// \brief AST_MATCHER_P2(
+/// Type, DefineMatcher, ParamType1, Param1, ParamType2, Param2) { ... }
+/// defines a two-parameter function named DefineMatcher() that returns a
+/// Matcher<Type> object.
+///
+/// The code between the curly braces has access to the following variables:
+///
+/// Node: the AST node being matched; its type is Type.
+/// Param1, Param2: the parameters passed to the function; their types
+/// are ParamType1 and ParamType2.
+/// Finder: an ASTMatchFinder*.
+/// Builder: a BoundNodesTreeBuilder*.
+///
+/// The code should return true if 'Node' matches.
+#define AST_MATCHER_P2( \
+ Type, DefineMatcher, ParamType1, Param1, ParamType2, Param2) \
+ namespace internal { \
+ class matcher_##DefineMatcher##Matcher \
+ : public MatcherInterface<Type> { \
+ public: \
+ matcher_##DefineMatcher##Matcher( \
+ const ParamType1 &A##Param1, const ParamType2 &A##Param2) \
+ : Param1(A##Param1), Param2(A##Param2) {} \
+ virtual bool matches( \
+ const Type &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const; \
+ private: \
+ const ParamType1 Param1; \
+ const ParamType2 Param2; \
+ }; \
+ } \
+ inline internal::Matcher<Type> DefineMatcher( \
+ const ParamType1 &Param1, const ParamType2 &Param2) { \
+ return internal::makeMatcher( \
+ new internal::matcher_##DefineMatcher##Matcher( \
+ Param1, Param2)); \
+ } \
+ inline bool internal::matcher_##DefineMatcher##Matcher::matches( \
+ const Type &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const
+
+/// \brief AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) { ... }
+/// defines a single-parameter function named DefineMatcher() that is
+/// polymorphic in the return type.
+///
+/// The variables are the same as for
+/// AST_MATCHER_P, with the addition of NodeType, which specifies the node type
+/// of the matcher Matcher<NodeType> returned by the function matcher().
+///
+/// FIXME: Pull out common code with above macro?
+#define AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) \
+ namespace internal { \
+ template <typename NodeType, typename ParamT> \
+ class matcher_##DefineMatcher##Matcher \
+ : public MatcherInterface<NodeType> { \
+ public: \
+ explicit matcher_##DefineMatcher##Matcher( \
+ const ParamType &A##Param) : Param(A##Param) {} \
+ virtual bool matches( \
+ const NodeType &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const; \
+ private: \
+ const ParamType Param; \
+ }; \
+ } \
+ inline internal::PolymorphicMatcherWithParam1< \
+ internal::matcher_##DefineMatcher##Matcher, \
+ ParamType > \
+ DefineMatcher(const ParamType &Param) { \
+ return internal::PolymorphicMatcherWithParam1< \
+ internal::matcher_##DefineMatcher##Matcher, \
+ ParamType >(Param); \
+ } \
+ template <typename NodeType, typename ParamT> \
+ bool internal::matcher_##DefineMatcher##Matcher<NodeType, ParamT>::matches( \
+ const NodeType &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const
+
+/// \brief AST_POLYMORPHIC_MATCHER_P2(
+/// DefineMatcher, ParamType1, Param1, ParamType2, Param2) { ... }
+/// defines a two-parameter function named matcher() that is polymorphic in
+/// the return type.
+///
+/// The variables are the same as for AST_MATCHER_P2, with the
+/// addition of NodeType, which specifies the node type of the matcher
+/// Matcher<NodeType> returned by the function DefineMatcher().
+#define AST_POLYMORPHIC_MATCHER_P2( \
+ DefineMatcher, ParamType1, Param1, ParamType2, Param2) \
+ namespace internal { \
+ template <typename NodeType, typename ParamT1, typename ParamT2> \
+ class matcher_##DefineMatcher##Matcher \
+ : public MatcherInterface<NodeType> { \
+ public: \
+ matcher_##DefineMatcher##Matcher( \
+ const ParamType1 &A##Param1, const ParamType2 &A##Param2) \
+ : Param1(A##Param1), Param2(A##Param2) {} \
+ virtual bool matches( \
+ const NodeType &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const; \
+ private: \
+ const ParamType1 Param1; \
+ const ParamType2 Param2; \
+ }; \
+ } \
+ inline internal::PolymorphicMatcherWithParam2< \
+ internal::matcher_##DefineMatcher##Matcher, \
+ ParamType1, ParamType2 > \
+ DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) { \
+ return internal::PolymorphicMatcherWithParam2< \
+ internal::matcher_##DefineMatcher##Matcher, \
+ ParamType1, ParamType2 >( \
+ Param1, Param2); \
+ } \
+ template <typename NodeType, typename ParamT1, typename ParamT2> \
+ bool internal::matcher_##DefineMatcher##Matcher< \
+ NodeType, ParamT1, ParamT2>::matches( \
+ const NodeType &Node, ASTMatchFinder *Finder, \
+ BoundNodesTreeBuilder *Builder) const
+
+#endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
new file mode 100644
index 0000000000..e4e44a32b6
--- /dev/null
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -0,0 +1,556 @@
+//===--- ASTMatchFinder.cpp - Structural query framework ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements an algorithm to efficiently search for matches on AST nodes.
+// Uses memoization to support recursive matches like HasDescendant.
+//
+// The general idea is to visit all AST nodes with a RecursiveASTVisitor,
+// calling the Matches(...) method of each matcher we are running on each
+// AST node. The matcher can recurse via the ASTMatchFinder interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include <set>
+
+namespace clang {
+namespace ast_matchers {
+namespace internal {
+namespace {
+
+// Returns the value that 'AMap' maps 'Key' to, or NULL if 'Key' is
+// not in 'AMap'.
+template <typename Map>
+static const typename Map::mapped_type *
+find(const Map &AMap, const typename Map::key_type &Key) {
+ typename Map::const_iterator It = AMap.find(Key);
+ return It == AMap.end() ? NULL : &It->second;
+}
+
+// We use memoization to avoid running the same matcher on the same
+// AST node twice. This pair is the key for looking up match
+// result. It consists of an ID of the MatcherInterface (for
+// identifying the matcher) and a pointer to the AST node.
+typedef std::pair<uint64_t, const void*> UntypedMatchInput;
+
+// Used to store the result of a match and possibly bound nodes.
+struct MemoizedMatchResult {
+ bool ResultOfMatch;
+ BoundNodesTree Nodes;
+};
+
+// A RecursiveASTVisitor that traverses all children or all descendants of
+// a node.
+class MatchChildASTVisitor
+ : public clang::RecursiveASTVisitor<MatchChildASTVisitor> {
+public:
+ typedef clang::RecursiveASTVisitor<MatchChildASTVisitor> VisitorBase;
+
+ // Creates an AST visitor that matches 'matcher' on all children or
+ // descendants of a traversed node. max_depth is the maximum depth
+ // to traverse: use 1 for matching the children and INT_MAX for
+ // matching the descendants.
+ MatchChildASTVisitor(const UntypedBaseMatcher *BaseMatcher,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder,
+ int MaxDepth,
+ ASTMatchFinder::TraversalKind Traversal,
+ ASTMatchFinder::BindKind Bind)
+ : BaseMatcher(BaseMatcher),
+ Finder(Finder),
+ Builder(Builder),
+ CurrentDepth(-1),
+ MaxDepth(MaxDepth),
+ Traversal(Traversal),
+ Bind(Bind),
+ Matches(false) {}
+
+ // Returns true if a match is found in the subtree rooted at the
+ // given AST node. This is done via a set of mutually recursive
+ // functions. Here's how the recursion is done (the *wildcard can
+ // actually be Decl, Stmt, or Type):
+ //
+ // - Traverse(node) calls BaseTraverse(node) when it needs
+ // to visit the descendants of node.
+ // - BaseTraverse(node) then calls (via VisitorBase::Traverse*(node))
+ // Traverse*(c) for each child c of 'node'.
+ // - Traverse*(c) in turn calls Traverse(c), completing the
+ // recursion.
+ template <typename T>
+ bool findMatch(const T &Node) {
+ reset();
+ traverse(Node);
+ return Matches;
+ }
+
+ // 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) {
+ return (DeclNode == NULL) || traverse(*DeclNode);
+ }
+ bool TraverseStmt(clang::Stmt *StmtNode) {
+ const clang::Stmt *StmtToTraverse = StmtNode;
+ if (Traversal ==
+ ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses) {
+ const clang::Expr *ExprNode = dyn_cast_or_null<clang::Expr>(StmtNode);
+ if (ExprNode != NULL) {
+ StmtToTraverse = ExprNode->IgnoreParenImpCasts();
+ }
+ }
+ return (StmtToTraverse == NULL) || traverse(*StmtToTraverse);
+ }
+ bool TraverseType(clang::QualType TypeNode) {
+ return traverse(TypeNode);
+ }
+
+ bool shouldVisitTemplateInstantiations() const { return true; }
+ bool shouldVisitImplicitCode() const { return true; }
+
+private:
+ // Used for updating the depth during traversal.
+ struct ScopedIncrement {
+ explicit ScopedIncrement(int *Depth) : Depth(Depth) { ++(*Depth); }
+ ~ScopedIncrement() { --(*Depth); }
+
+ private:
+ int *Depth;
+ };
+
+ // Resets the state of this object.
+ void reset() {
+ Matches = false;
+ CurrentDepth = -1;
+ }
+
+ // Forwards the call to the corresponding Traverse*() method in the
+ // base visitor class.
+ bool baseTraverse(const clang::Decl &DeclNode) {
+ return VisitorBase::TraverseDecl(const_cast<clang::Decl*>(&DeclNode));
+ }
+ bool baseTraverse(const clang::Stmt &StmtNode) {
+ return VisitorBase::TraverseStmt(const_cast<clang::Stmt*>(&StmtNode));
+ }
+ bool baseTraverse(clang::QualType TypeNode) {
+ return VisitorBase::TraverseType(TypeNode);
+ }
+
+ // Traverses the subtree rooted at 'node'; returns true if the
+ // traversal should continue after this function returns; also sets
+ // matched_ to true if a match is found during the traversal.
+ template <typename T>
+ bool traverse(const T &Node) {
+ TOOLING_COMPILE_ASSERT(IsBaseType<T>::value,
+ traverse_can_only_be_instantiated_with_base_type);
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+ if (CurrentDepth == 0) {
+ // We don't want to match the root node, so just recurse.
+ return baseTraverse(Node);
+ }
+ if (Bind != ASTMatchFinder::BK_All) {
+ if (BaseMatcher->matches(Node, Finder, Builder)) {
+ Matches = true;
+ return false; // Abort as soon as a match is found.
+ }
+ if (CurrentDepth < MaxDepth) {
+ // The current node doesn't match, and we haven't reached the
+ // maximum depth yet, so recurse.
+ return baseTraverse(Node);
+ }
+ // The current node doesn't match, and we have reached the
+ // maximum depth, so don't recurse (but continue the traversal
+ // such that other nodes at the current level can be visited).
+ return true;
+ } else {
+ BoundNodesTreeBuilder RecursiveBuilder;
+ if (BaseMatcher->matches(Node, Finder, &RecursiveBuilder)) {
+ // After the first match the matcher succeeds.
+ Matches = true;
+ Builder->addMatch(RecursiveBuilder.build());
+ }
+ if (CurrentDepth < MaxDepth) {
+ baseTraverse(Node);
+ }
+ // In kBindAll mode we always search for more matches.
+ return true;
+ }
+ }
+
+ const UntypedBaseMatcher *const BaseMatcher;
+ ASTMatchFinder *const Finder;
+ BoundNodesTreeBuilder *const Builder;
+ int CurrentDepth;
+ const int MaxDepth;
+ const ASTMatchFinder::TraversalKind Traversal;
+ const ASTMatchFinder::BindKind Bind;
+ bool Matches;
+};
+
+// Controls the outermost traversal of the AST and allows to match multiple
+// matchers.
+class MatchASTVisitor : public clang::RecursiveASTVisitor<MatchASTVisitor>,
+ public ASTMatchFinder {
+public:
+ MatchASTVisitor(std::vector< std::pair<const UntypedBaseMatcher*,
+ MatchFinder::MatchCallback*> > *Triggers)
+ : Triggers(Triggers),
+ ActiveASTContext(NULL) {
+ }
+
+ void set_active_ast_context(clang::ASTContext *NewActiveASTContext) {
+ ActiveASTContext = NewActiveASTContext;
+ }
+
+ // The following Visit*() and Traverse*() functions "override"
+ // methods in RecursiveASTVisitor.
+
+ bool VisitTypedefDecl(clang::TypedefDecl *DeclNode) {
+ // When we see 'typedef A B', we add name 'B' to the set of names
+ // A's canonical type maps to. This is necessary for implementing
+ // IsDerivedFrom(x) properly, where x can be the name of the base
+ // class or any of its aliases.
+ //
+ // In general, the is-alias-of (as defined by typedefs) relation
+ // is tree-shaped, as you can typedef a type more than once. For
+ // example,
+ //
+ // typedef A B;
+ // typedef A C;
+ // typedef C D;
+ // typedef C E;
+ //
+ // gives you
+ //
+ // A
+ // |- B
+ // `- C
+ // |- D
+ // `- E
+ //
+ // It is wrong to assume that the relation is a chain. A correct
+ // implementation of IsDerivedFrom() needs to recognize that B and
+ // E are aliases, even though neither is a typedef of the other.
+ // Therefore, we cannot simply walk through one typedef chain to
+ // find out whether the type name matches.
+ const clang::Type *TypeNode = DeclNode->getUnderlyingType().getTypePtr();
+ const clang::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);
+
+ // Matches children or descendants of 'Node' with 'BaseMatcher'.
+ template <typename T>
+ bool memoizedMatchesRecursively(const T &Node,
+ const UntypedBaseMatcher &BaseMatcher,
+ BoundNodesTreeBuilder *Builder, int MaxDepth,
+ TraversalKind Traversal, BindKind Bind) {
+ TOOLING_COMPILE_ASSERT((llvm::is_same<T, clang::Decl>::value) ||
+ (llvm::is_same<T, clang::Stmt>::value),
+ type_does_not_support_memoization);
+ const UntypedMatchInput input(BaseMatcher.getID(), &Node);
+ std::pair<MemoizationMap::iterator, bool> InsertResult
+ = ResultCache.insert(std::make_pair(input, MemoizedMatchResult()));
+ if (InsertResult.second) {
+ BoundNodesTreeBuilder DescendantBoundNodesBuilder;
+ InsertResult.first->second.ResultOfMatch =
+ matchesRecursively(Node, BaseMatcher, &DescendantBoundNodesBuilder,
+ MaxDepth, Traversal, Bind);
+ InsertResult.first->second.Nodes =
+ DescendantBoundNodesBuilder.build();
+ }
+ InsertResult.first->second.Nodes.copyTo(Builder);
+ return InsertResult.first->second.ResultOfMatch;
+ }
+
+ // Matches children or descendants of 'Node' with 'BaseMatcher'.
+ template <typename T>
+ bool matchesRecursively(const T &Node, const UntypedBaseMatcher &BaseMatcher,
+ BoundNodesTreeBuilder *Builder, int MaxDepth,
+ TraversalKind Traversal, BindKind Bind) {
+ MatchChildASTVisitor Visitor(
+ &BaseMatcher, this, Builder, MaxDepth, Traversal, Bind);
+ return Visitor.findMatch(Node);
+ }
+
+ virtual bool classIsDerivedFrom(const clang::CXXRecordDecl *Declaration,
+ StringRef BaseName) const;
+
+ // Implements ASTMatchFinder::MatchesChildOf.
+ virtual bool matchesChildOf(const clang::Decl &DeclNode,
+ const UntypedBaseMatcher &BaseMatcher,
+ BoundNodesTreeBuilder *Builder,
+ TraversalKind Traversal,
+ BindKind Bind) {
+ return matchesRecursively(DeclNode, BaseMatcher, Builder, 1, Traversal,
+ Bind);
+ }
+ virtual bool matchesChildOf(const clang::Stmt &StmtNode,
+ const UntypedBaseMatcher &BaseMatcher,
+ BoundNodesTreeBuilder *Builder,
+ TraversalKind Traversal,
+ BindKind Bind) {
+ return matchesRecursively(StmtNode, BaseMatcher, Builder, 1, Traversal,
+ Bind);
+ }
+
+ // Implements ASTMatchFinder::MatchesDescendantOf.
+ virtual bool matchesDescendantOf(const clang::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,
+ const UntypedBaseMatcher &BaseMatcher,
+ BoundNodesTreeBuilder *Builder,
+ BindKind Bind) {
+ return memoizedMatchesRecursively(StmtNode, BaseMatcher, Builder, INT_MAX,
+ TK_AsIs, Bind);
+ }
+
+ bool shouldVisitTemplateInstantiations() const { return true; }
+ bool shouldVisitImplicitCode() const { return true; }
+
+private:
+ // Implements a BoundNodesTree::Visitor that calls a MatchCallback with
+ // the aggregated bound nodes for each match.
+ class MatchVisitor : public BoundNodesTree::Visitor {
+ public:
+ MatchVisitor(clang::ASTContext* Context,
+ MatchFinder::MatchCallback* Callback)
+ : Context(Context),
+ Callback(Callback) {}
+
+ virtual void visitMatch(const BoundNodes& BoundNodesView) {
+ Callback->run(MatchFinder::MatchResult(BoundNodesView, Context));
+ }
+
+ private:
+ clang::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,
+ StringRef Name) const {
+ const clang::Type *const CanonicalType =
+ ActiveASTContext->getCanonicalType(TypeNode);
+ const std::set<std::string> *UnqualifiedAlias =
+ find(TypeToUnqualifiedAliases, CanonicalType);
+ return UnqualifiedAlias != NULL && UnqualifiedAlias->count(Name) > 0;
+ }
+
+ // Matches all registered matchers on the given node and calls the
+ // result callback for every node that matches.
+ template <typename T>
+ void match(const T &node) {
+ for (std::vector< std::pair<const UntypedBaseMatcher*,
+ MatchFinder::MatchCallback*> >::const_iterator
+ It = Triggers->begin(), End = Triggers->end();
+ It != End; ++It) {
+ BoundNodesTreeBuilder Builder;
+ if (It->first->matches(node, this, &Builder)) {
+ BoundNodesTree BoundNodes = Builder.build();
+ MatchVisitor Visitor(ActiveASTContext, It->second);
+ BoundNodes.visitMatches(&Visitor);
+ }
+ }
+ }
+
+ std::vector< std::pair<const UntypedBaseMatcher*,
+ MatchFinder::MatchCallback*> > *const Triggers;
+ clang::ASTContext *ActiveASTContext;
+
+ // Maps a canonical type to the names of its typedefs.
+ llvm::DenseMap<const clang::Type*, std::set<std::string> >
+ TypeToUnqualifiedAliases;
+
+ // Maps (matcher, node) -> the match result for memoization.
+ typedef llvm::DenseMap<UntypedMatchInput, MemoizedMatchResult> MemoizationMap;
+ MemoizationMap ResultCache;
+};
+
+// Returns true if the given class is directly or indirectly derived
+// 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,
+ StringRef BaseName) const {
+ if (Declaration->getName() == BaseName) {
+ return true;
+ }
+ if (!Declaration->hasDefinition()) {
+ return false;
+ }
+ typedef clang::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();
+
+ if (typeHasAlias(TypeNode, BaseName))
+ return true;
+
+ // clang::Type::getAs<...>() drills through typedefs.
+ if (TypeNode->getAs<clang::DependentNameType>() != NULL ||
+ TypeNode->getAs<clang::TemplateTypeParmType>() != 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<clang::TemplateSpecializationType>();
+ if (TemplateType != NULL) {
+ if (TemplateType->getTemplateName().isDependent()) {
+ // Dependent template specializations will be matched when the
+ // template is instantiated.
+ continue;
+ }
+ // For template specialization types which are specializing a template
+ // declaration which is an explicit or partial specialization of another
+ // template declaration, getAsCXXRecordDecl() returns the corresponding
+ // ClassTemplateSpecializationDecl.
+ //
+ // For template specialization types which are specializing a template
+ // 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 =
+ TemplateType->getAsCXXRecordDecl();
+ if (SpecializationDecl != NULL) {
+ ClassDecl = SpecializationDecl;
+ } else {
+ ClassDecl = llvm::dyn_cast<clang::CXXRecordDecl>(
+ TemplateType->getTemplateName()
+ .getAsTemplateDecl()->getTemplatedDecl());
+ }
+ } else {
+ ClassDecl = TypeNode->getAsCXXRecordDecl();
+ }
+ assert(ClassDecl != NULL);
+ assert(ClassDecl != Declaration);
+ if (classIsDerivedFrom(ClassDecl, BaseName)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool MatchASTVisitor::TraverseDecl(clang::Decl *DeclNode) {
+ if (DeclNode == NULL) {
+ return true;
+ }
+ match(*DeclNode);
+ return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseDecl(DeclNode);
+}
+
+bool MatchASTVisitor::TraverseStmt(clang::Stmt *StmtNode) {
+ if (StmtNode == NULL) {
+ return true;
+ }
+ match(*StmtNode);
+ return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseStmt(StmtNode);
+}
+
+bool MatchASTVisitor::TraverseType(clang::QualType TypeNode) {
+ match(TypeNode);
+ return clang::RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode);
+}
+
+bool MatchASTVisitor::TraverseTypeLoc(clang::TypeLoc TypeLoc) {
+ return clang::RecursiveASTVisitor<MatchASTVisitor>::
+ TraverseType(TypeLoc.getType());
+}
+
+class MatchASTConsumer : public clang::ASTConsumer {
+public:
+ MatchASTConsumer(std::vector< std::pair<const UntypedBaseMatcher*,
+ MatchFinder::MatchCallback*> > *Triggers,
+ MatchFinder::ParsingDoneTestCallback *ParsingDone)
+ : Visitor(Triggers),
+ ParsingDone(ParsingDone) {}
+
+private:
+ virtual void HandleTranslationUnit(clang::ASTContext &Context) {
+ if (ParsingDone != NULL) {
+ ParsingDone->run();
+ }
+ Visitor.set_active_ast_context(&Context);
+ Visitor.TraverseDecl(Context.getTranslationUnitDecl());
+ Visitor.set_active_ast_context(NULL);
+ }
+
+ MatchASTVisitor Visitor;
+ MatchFinder::ParsingDoneTestCallback *ParsingDone;
+};
+
+} // end namespace
+} // end namespace internal
+
+MatchFinder::MatchResult::MatchResult(const BoundNodes &Nodes,
+ clang::ASTContext *Context)
+ : Nodes(Nodes), Context(Context),
+ SourceManager(&Context->getSourceManager()) {}
+
+MatchFinder::MatchCallback::~MatchCallback() {}
+MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}
+
+MatchFinder::MatchFinder() : ParsingDone(NULL) {}
+
+MatchFinder::~MatchFinder() {
+ for (std::vector< std::pair<const internal::UntypedBaseMatcher*,
+ MatchFinder::MatchCallback*> >::const_iterator
+ It = Triggers.begin(), End = Triggers.end();
+ It != End; ++It) {
+ delete It->first;
+ }
+}
+
+void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch,
+ MatchCallback *Action) {
+ Triggers.push_back(std::make_pair(
+ new internal::TypedBaseMatcher<clang::Decl>(NodeMatch), Action));
+}
+
+void MatchFinder::addMatcher(const TypeMatcher &NodeMatch,
+ MatchCallback *Action) {
+ Triggers.push_back(std::make_pair(
+ new internal::TypedBaseMatcher<clang::QualType>(NodeMatch), Action));
+}
+
+void MatchFinder::addMatcher(const StatementMatcher &NodeMatch,
+ MatchCallback *Action) {
+ Triggers.push_back(std::make_pair(
+ new internal::TypedBaseMatcher<clang::Stmt>(NodeMatch), Action));
+}
+
+clang::ASTConsumer *MatchFinder::newASTConsumer() {
+ return new internal::MatchASTConsumer(&Triggers, ParsingDone);
+}
+
+void MatchFinder::registerTestCallbackAfterParsing(
+ MatchFinder::ParsingDoneTestCallback *NewParsingDone) {
+ ParsingDone = NewParsingDone;
+}
+
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp
new file mode 100644
index 0000000000..c864e31cb1
--- /dev/null
+++ b/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -0,0 +1,102 @@
+//===--- ASTMatchersInternal.cpp - Structural query framework -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements the base layer of the matcher framework.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
+
+namespace clang {
+namespace ast_matchers {
+namespace internal {
+
+BoundNodesTree::BoundNodesTree() {}
+
+BoundNodesTree::BoundNodesTree(
+ const std::map<std::string, const clang::Decl*>& DeclBindings,
+ const std::map<std::string, const clang::Stmt*>& StmtBindings,
+ const std::vector<BoundNodesTree> RecursiveBindings)
+ : DeclBindings(DeclBindings), StmtBindings(StmtBindings),
+ RecursiveBindings(RecursiveBindings) {}
+
+void BoundNodesTree::copyTo(BoundNodesTreeBuilder* Builder) const {
+ copyBindingsTo(DeclBindings, Builder);
+ copyBindingsTo(StmtBindings, Builder);
+ for (std::vector<BoundNodesTree>::const_iterator
+ I = RecursiveBindings.begin(),
+ E = RecursiveBindings.end();
+ I != E; ++I) {
+ Builder->addMatch(*I);
+ }
+}
+
+template <typename T>
+void BoundNodesTree::copyBindingsTo(
+ const T& Bindings, BoundNodesTreeBuilder* Builder) const {
+ for (typename T::const_iterator I = Bindings.begin(),
+ E = Bindings.end();
+ I != E; ++I) {
+ Builder->setBinding(*I);
+ }
+}
+
+void BoundNodesTree::visitMatches(Visitor* ResultVisitor) {
+ std::map<std::string, const clang::Decl*> AggregatedDeclBindings;
+ std::map<std::string, const clang::Stmt*> AggregatedStmtBindings;
+ visitMatchesRecursively(ResultVisitor, AggregatedDeclBindings,
+ AggregatedStmtBindings);
+}
+
+void BoundNodesTree::
+visitMatchesRecursively(Visitor* ResultVisitor,
+ std::map<std::string, const clang::Decl*>
+ AggregatedDeclBindings,
+ std::map<std::string, const clang::Stmt*>
+ AggregatedStmtBindings) {
+ copy(DeclBindings.begin(), DeclBindings.end(),
+ inserter(AggregatedDeclBindings, AggregatedDeclBindings.begin()));
+ copy(StmtBindings.begin(), StmtBindings.end(),
+ inserter(AggregatedStmtBindings, AggregatedStmtBindings.begin()));
+ if (RecursiveBindings.empty()) {
+ ResultVisitor->visitMatch(BoundNodes(AggregatedDeclBindings,
+ AggregatedStmtBindings));
+ } else {
+ for (unsigned I = 0; I < RecursiveBindings.size(); ++I) {
+ RecursiveBindings[I].visitMatchesRecursively(ResultVisitor,
+ AggregatedDeclBindings,
+ AggregatedStmtBindings);
+ }
+ }
+}
+
+BoundNodesTreeBuilder::BoundNodesTreeBuilder() {}
+
+void BoundNodesTreeBuilder::
+setBinding(const std::pair<const std::string, const clang::Decl*>& Binding) {
+ DeclBindings.insert(Binding);
+}
+
+void BoundNodesTreeBuilder::
+setBinding(const std::pair<const std::string, const clang::Stmt*>& Binding) {
+ StmtBindings.insert(Binding);
+}
+
+void BoundNodesTreeBuilder::addMatch(const BoundNodesTree& Bindings) {
+ RecursiveBindings.push_back(Bindings);
+}
+
+BoundNodesTree BoundNodesTreeBuilder::build() const {
+ return BoundNodesTree(DeclBindings, StmtBindings, RecursiveBindings);
+}
+
+} // end namespace internal
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/lib/ASTMatchers/CMakeLists.txt b/lib/ASTMatchers/CMakeLists.txt
new file mode 100644
index 0000000000..c27a37edd8
--- /dev/null
+++ b/lib/ASTMatchers/CMakeLists.txt
@@ -0,0 +1,7 @@
+set(LLVM_LINK_COMPONENTS support)
+set(LLVM_USED_LIBS clangBasic clangAST)
+
+add_clang_library(clangASTMatchers
+ ASTMatchFinder.cpp
+ ASTMatchersInternal.cpp
+ )
diff --git a/lib/ASTMatchers/Makefile b/lib/ASTMatchers/Makefile
new file mode 100644
index 0000000000..3ee9ccb580
--- /dev/null
+++ b/lib/ASTMatchers/Makefile
@@ -0,0 +1,15 @@
+##===- clang/lib/ASTMatchers/Makefile ----------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../..
+LIBRARYNAME := clangASTMatchers
+
+PARALLEL_DIRS = Dynamic
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index dfb9d61ff5..206c22818b 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -3,6 +3,7 @@ add_subdirectory(Basic)
add_subdirectory(Lex)
add_subdirectory(Parse)
add_subdirectory(AST)
+add_subdirectory(ASTMatchers)
add_subdirectory(Sema)
add_subdirectory(CodeGen)
add_subdirectory(Analysis)
diff --git a/lib/Makefile b/lib/Makefile
index 2eb72a91e6..1f14aa078e 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -8,7 +8,7 @@
##===----------------------------------------------------------------------===##
CLANG_LEVEL := ..
-PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis \
+PARALLEL_DIRS = Headers Basic Lex Parse AST ASTMatchers Sema CodeGen Analysis \
StaticAnalyzer Edit Rewrite ARCMigrate Serialization Frontend \
FrontendTool Tooling Driver
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
new file mode 100644
index 0000000000..290da9005d
--- /dev/null
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -0,0 +1,1979 @@
+//===- unittest/Tooling/ASTMatchersTest.cpp - AST matcher unit tests ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTMatchersTest.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+
+TEST(HasNameDeathTest, DiesOnEmptyName) {
+ ASSERT_DEBUG_DEATH({
+ DeclarationMatcher HasEmptyName = record(hasName(""));
+ EXPECT_TRUE(notMatches("class X {};", HasEmptyName));
+ }, "");
+}
+
+TEST(IsDerivedFromDeathTest, DiesOnEmptyBaseName) {
+ ASSERT_DEBUG_DEATH({
+ DeclarationMatcher IsDerivedFromEmpty = record(isDerivedFrom(""));
+ EXPECT_TRUE(notMatches("class X {};", IsDerivedFromEmpty));
+ }, "");
+}
+
+TEST(NameableDeclaration, MatchesVariousDecls) {
+ DeclarationMatcher NamedX = nameableDeclaration(hasName("X"));
+ EXPECT_TRUE(matches("typedef int X;", NamedX));
+ EXPECT_TRUE(matches("int X;", NamedX));
+ EXPECT_TRUE(matches("class foo { virtual void X(); };", NamedX));
+ 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(notMatches("#define X 1", NamedX));
+}
+
+TEST(DeclarationMatcher, MatchClass) {
+ DeclarationMatcher ClassMatcher(record());
+ EXPECT_FALSE(matches("", ClassMatcher));
+
+ DeclarationMatcher ClassX = record(record(hasName("X")));
+ EXPECT_TRUE(matches("class X;", ClassX));
+ EXPECT_TRUE(matches("class X {};", ClassX));
+ EXPECT_TRUE(matches("template<class T> class X {};", ClassX));
+ EXPECT_TRUE(notMatches("", ClassX));
+}
+
+TEST(DeclarationMatcher, ClassIsDerived) {
+ DeclarationMatcher IsDerivedFromX = record(isDerivedFrom("X"));
+
+ EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsDerivedFromX));
+ EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsDerivedFromX));
+ EXPECT_TRUE(matches("class X {};", IsDerivedFromX));
+ EXPECT_TRUE(matches("class X;", IsDerivedFromX));
+ EXPECT_TRUE(notMatches("class Y;", IsDerivedFromX));
+ EXPECT_TRUE(notMatches("", IsDerivedFromX));
+
+ DeclarationMatcher ZIsDerivedFromX =
+ record(hasName("Z"), isDerivedFrom("X"));
+ EXPECT_TRUE(
+ matches("class X {}; class Y : public X {}; class Z : public Y {};",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("class X {};"
+ "template<class T> class Y : public X {};"
+ "class Z : public Y<int> {};", ZIsDerivedFromX));
+ EXPECT_TRUE(matches("class X {}; template<class T> class Z : public X {};",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("template<class T> class X {}; "
+ "template<class T> class Z : public X<T> {};",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("template<class T, class U=T> class X {}; "
+ "template<class T> class Z : public X<T> {};",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ notMatches("template<class X> class A { class Z : public X {}; };",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("template<class X> class A { public: class Z : public X {}; }; "
+ "class X{}; void y() { A<X>::Z z; }", ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("template <class T> class X {}; "
+ "template<class Y> class A { class Z : public X<Y> {}; };",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ notMatches("template<template<class T> class X> class A { "
+ " class Z : public X<int> {}; };", ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("template<template<class T> class X> class A { "
+ " public: class Z : public X<int> {}; }; "
+ "template<class T> class X {}; void y() { A<X>::Z z; }",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ notMatches("template<class X> class A { class Z : public X::D {}; };",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("template<class X> class A { public: "
+ " class Z : public X::D {}; }; "
+ "class Y { public: class X {}; typedef X D; }; "
+ "void y() { A<Y>::Z z; }", ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("class X {}; typedef X Y; class Z : public Y {};",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("template<class T> class Y { typedef typename T::U X; "
+ " class Z : public X {}; };", ZIsDerivedFromX));
+ EXPECT_TRUE(matches("class X {}; class Z : public ::X {};",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ notMatches("template<class T> class X {}; "
+ "template<class T> class A { class Z : public X<T>::D {}; };",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("template<class T> class X { public: typedef X<T> D; }; "
+ "template<class T> class A { public: "
+ " class Z : public X<T>::D {}; }; void y() { A<int>::Z z; }",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ notMatches("template<class X> class A { class Z : public X::D::E {}; };",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("class X {}; typedef X V; typedef V W; class Z : public W {};",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("class X {}; class Y : public X {}; "
+ "typedef Y V; typedef V W; class Z : public W {};",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("template<class T, class U> class X {}; "
+ "template<class T> class A { class Z : public X<T, int> {}; };",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ notMatches("template<class X> class D { typedef X A; typedef A B; "
+ " typedef B C; class Z : public C {}; };",
+ ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("class X {}; typedef X A; typedef A B; "
+ "class Z : public B {};", ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("class X {}; typedef X A; typedef A B; typedef B C; "
+ "class Z : public C {};", ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("class U {}; typedef U X; typedef X V; "
+ "class Z : public V {};", ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("class Base {}; typedef Base X; "
+ "class Z : public Base {};", ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("class Base {}; typedef Base Base2; typedef Base2 X; "
+ "class Z : public Base {};", ZIsDerivedFromX));
+ EXPECT_TRUE(
+ notMatches("class Base {}; class Base2 {}; typedef Base2 X; "
+ "class Z : public Base {};", ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("class A {}; typedef A X; typedef A Y; "
+ "class Z : public Y {};", ZIsDerivedFromX));
+ EXPECT_TRUE(
+ notMatches("template <typename T> class Z;"
+ "template <> class Z<void> {};"
+ "template <typename T> class Z : public Z<void> {};",
+ IsDerivedFromX));
+ EXPECT_TRUE(
+ matches("template <typename T> class X;"
+ "template <> class X<void> {};"
+ "template <typename T> class X : public X<void> {};",
+ IsDerivedFromX));
+ EXPECT_TRUE(matches(
+ "class X {};"
+ "template <typename T> class Z;"
+ "template <> class Z<void> {};"
+ "template <typename T> class Z : public Z<void>, public X {};",
+ ZIsDerivedFromX));
+
+ // FIXME: Once we have better matchers for template type matching,
+ // get rid of the Variable(...) matching and match the right template
+ // declarations directly.
+ const char *RecursiveTemplateOneParameter =
+ "class Base1 {}; class Base2 {};"
+ "template <typename T> class Z;"
+ "template <> class Z<void> : public Base1 {};"
+ "template <> class Z<int> : public Base2 {};"
+ "template <> class Z<float> : public Z<void> {};"
+ "template <> class Z<double> : public Z<int> {};"
+ "template <typename T> class Z : public Z<float>, public Z<double> {};"
+ "void f() { Z<float> z_float; Z<double> z_double; Z<char> z_char; }";
+ EXPECT_TRUE(matches(
+ RecursiveTemplateOneParameter,
+ variable(hasName("z_float"),
+ hasInitializer(hasType(record(isDerivedFrom("Base1")))))));
+ EXPECT_TRUE(notMatches(
+ RecursiveTemplateOneParameter,
+ variable(
+ hasName("z_float"),
+ hasInitializer(hasType(record(isDerivedFrom("Base2")))))));
+ EXPECT_TRUE(matches(
+ RecursiveTemplateOneParameter,
+ variable(
+ hasName("z_char"),
+ hasInitializer(hasType(record(isDerivedFrom("Base1"),
+ isDerivedFrom("Base2")))))));
+
+ const char *RecursiveTemplateTwoParameters =
+ "class Base1 {}; class Base2 {};"
+ "template <typename T1, typename T2> class Z;"
+ "template <typename T> class Z<void, T> : public Base1 {};"
+ "template <typename T> class Z<int, T> : public Base2 {};"
+ "template <typename T> class Z<float, T> : public Z<void, T> {};"
+ "template <typename T> class Z<double, T> : public Z<int, T> {};"
+ "template <typename T1, typename T2> class Z : "
+ " public Z<float, T2>, public Z<double, T2> {};"
+ "void f() { Z<float, void> z_float; Z<double, void> z_double; "
+ " Z<char, void> z_char; }";
+ EXPECT_TRUE(matches(
+ RecursiveTemplateTwoParameters,
+ variable(
+ hasName("z_float"),
+ hasInitializer(hasType(record(isDerivedFrom("Base1")))))));
+ EXPECT_TRUE(notMatches(
+ RecursiveTemplateTwoParameters,
+ variable(
+ hasName("z_float"),
+ hasInitializer(hasType(record(isDerivedFrom("Base2")))))));
+ EXPECT_TRUE(matches(
+ RecursiveTemplateTwoParameters,
+ variable(
+ hasName("z_char"),
+ hasInitializer(hasType(record(isDerivedFrom("Base1"),
+ isDerivedFrom("Base2")))))));
+}
+
+TEST(DeclarationMatcher, MatchAnyOf) {
+ DeclarationMatcher YOrZDerivedFromX =
+ record(anyOf(hasName("Y"), allOf(isDerivedFrom("X"), hasName("Z"))));
+
+ EXPECT_TRUE(
+ matches("class X {}; class Z : public X {};", YOrZDerivedFromX));
+ EXPECT_TRUE(matches("class Y {};", YOrZDerivedFromX));
+ EXPECT_TRUE(
+ notMatches("class X {}; class W : public X {};", YOrZDerivedFromX));
+ EXPECT_TRUE(notMatches("class Z {};", YOrZDerivedFromX));
+
+ DeclarationMatcher XOrYOrZOrUOrV =
+ record(anyOf(hasName("X"), hasName("Y"), hasName("Z"), hasName("U"),
+ hasName("V")));
+
+ EXPECT_TRUE(matches("class X {};", XOrYOrZOrUOrV));
+ EXPECT_TRUE(matches("class Y {};", XOrYOrZOrUOrV));
+ EXPECT_TRUE(matches("class Z {};", XOrYOrZOrUOrV));
+ EXPECT_TRUE(matches("class U {};", XOrYOrZOrUOrV));
+ EXPECT_TRUE(matches("class V {};", XOrYOrZOrUOrV));
+ EXPECT_TRUE(notMatches("class A {};", XOrYOrZOrUOrV));
+}
+
+TEST(DeclarationMatcher, MatchHas) {
+ DeclarationMatcher HasClassX = record(has(record(hasName("X"))));
+
+ EXPECT_TRUE(matches("class Y { class X {}; };", HasClassX));
+ EXPECT_TRUE(matches("class X {};", HasClassX));
+
+ DeclarationMatcher YHasClassX =
+ record(hasName("Y"), has(record(hasName("X"))));
+ EXPECT_TRUE(matches("class Y { class X {}; };", YHasClassX));
+ EXPECT_TRUE(notMatches("class X {};", YHasClassX));
+ EXPECT_TRUE(
+ notMatches("class Y { class Z { class X {}; }; };", YHasClassX));
+}
+
+TEST(DeclarationMatcher, MatchHasRecursiveAllOf) {
+ DeclarationMatcher Recursive =
+ record(
+ has(record(
+ has(record(hasName("X"))),
+ has(record(hasName("Y"))),
+ hasName("Z"))),
+ has(record(
+ has(record(hasName("A"))),
+ has(record(hasName("B"))),
+ hasName("C"))),
+ hasName("F"));
+
+ EXPECT_TRUE(matches(
+ "class F {"
+ " class Z {"
+ " class X {};"
+ " class Y {};"
+ " };"
+ " class C {"
+ " class A {};"
+ " class B {};"
+ " };"
+ "};", Recursive));
+
+ EXPECT_TRUE(matches(
+ "class F {"
+ " class Z {"
+ " class A {};"
+ " class X {};"
+ " class Y {};"
+ " };"
+ " class C {"
+ " class X {};"
+ " class A {};"
+ " class B {};"
+ " };"
+ "};", Recursive));
+
+ EXPECT_TRUE(matches(
+ "class O1 {"
+ " class O2 {"
+ " class F {"
+ " class Z {"
+ " class A {};"
+ " class X {};"
+ " class Y {};"
+ " };"
+ " class C {"
+ " class X {};"
+ " class A {};"
+ " class B {};"
+ " };"
+ " };"
+ " };"
+ "};", Recursive));
+}
+
+TEST(DeclarationMatcher, MatchHasRecursiveAnyOf) {
+ DeclarationMatcher Recursive =
+ record(
+ anyOf(
+ has(record(
+ anyOf(
+ has(record(
+ hasName("X"))),
+ has(record(
+ hasName("Y"))),
+ hasName("Z")))),
+ has(record(
+ anyOf(
+ hasName("C"),
+ has(record(
+ hasName("A"))),
+ has(record(
+ hasName("B")))))),
+ hasName("F")));
+
+ EXPECT_TRUE(matches("class F {};", Recursive));
+ EXPECT_TRUE(matches("class Z {};", Recursive));
+ EXPECT_TRUE(matches("class C {};", Recursive));
+ EXPECT_TRUE(matches("class M { class N { class X {}; }; };", Recursive));
+ EXPECT_TRUE(matches("class M { class N { class B {}; }; };", Recursive));
+ EXPECT_TRUE(
+ matches("class O1 { class O2 {"
+ " class M { class N { class B {}; }; }; "
+ "}; };", Recursive));
+}
+
+TEST(DeclarationMatcher, MatchNot) {
+ DeclarationMatcher NotClassX =
+ record(
+ isDerivedFrom("Y"),
+ unless(hasName("Y")),
+ unless(hasName("X")));
+ EXPECT_TRUE(notMatches("", NotClassX));
+ EXPECT_TRUE(notMatches("class Y {};", NotClassX));
+ EXPECT_TRUE(matches("class Y {}; class Z : public Y {};", NotClassX));
+ EXPECT_TRUE(notMatches("class Y {}; class X : public Y {};", NotClassX));
+ EXPECT_TRUE(
+ notMatches("class Y {}; class Z {}; class X : public Y {};",
+ NotClassX));
+
+ DeclarationMatcher ClassXHasNotClassY =
+ record(
+ hasName("X"),
+ has(record(hasName("Z"))),
+ unless(
+ has(record(hasName("Y")))));
+ EXPECT_TRUE(matches("class X { class Z {}; };", ClassXHasNotClassY));
+ EXPECT_TRUE(notMatches("class X { class Y {}; class Z {}; };",
+ ClassXHasNotClassY));
+}
+
+TEST(DeclarationMatcher, HasDescendant) {
+ DeclarationMatcher ZDescendantClassX =
+ record(
+ hasDescendant(record(hasName("X"))),
+ hasName("Z"));
+ EXPECT_TRUE(matches("class Z { class X {}; };", ZDescendantClassX));
+ EXPECT_TRUE(
+ matches("class Z { class Y { class X {}; }; };", ZDescendantClassX));
+ EXPECT_TRUE(
+ matches("class Z { class A { class Y { class X {}; }; }; };",
+ ZDescendantClassX));
+ EXPECT_TRUE(
+ matches("class Z { class A { class B { class Y { class X {}; }; }; }; };",
+ ZDescendantClassX));
+ EXPECT_TRUE(notMatches("class Z {};", ZDescendantClassX));
+
+ DeclarationMatcher ZDescendantClassXHasClassY =
+ record(
+ hasDescendant(record(has(record(hasName("Y"))),
+ hasName("X"))),
+ hasName("Z"));
+ EXPECT_TRUE(matches("class Z { class X { class Y {}; }; };",
+ ZDescendantClassXHasClassY));
+ EXPECT_TRUE(
+ matches("class Z { class A { class B { class X { class Y {}; }; }; }; };",
+ ZDescendantClassXHasClassY));
+ EXPECT_TRUE(notMatches(
+ "class Z {"
+ " class A {"
+ " class B {"
+ " class X {"
+ " class C {"
+ " class Y {};"
+ " };"
+ " };"
+ " }; "
+ " };"
+ "};", ZDescendantClassXHasClassY));
+
+ DeclarationMatcher ZDescendantClassXDescendantClassY =
+ record(
+ hasDescendant(record(hasDescendant(record(hasName("Y"))),
+ hasName("X"))),
+ hasName("Z"));
+ EXPECT_TRUE(
+ matches("class Z { class A { class X { class B { class Y {}; }; }; }; };",
+ ZDescendantClassXDescendantClassY));
+ EXPECT_TRUE(matches(
+ "class Z {"
+ " class A {"
+ " class X {"
+ " class B {"
+ " class Y {};"
+ " };"
+ " class Y {};"
+ " };"
+ " };"
+ "};", ZDescendantClassXDescendantClassY));
+}
+
+TEST(StatementMatcher, Has) {
+ StatementMatcher HasVariableI =
+ expression(
+ hasType(pointsTo(record(hasName("X")))),
+ has(declarationReference(to(variable(hasName("i"))))));
+
+ EXPECT_TRUE(matches(
+ "class X; X *x(int); void c() { int i; x(i); }", HasVariableI));
+ EXPECT_TRUE(notMatches(
+ "class X; X *x(int); void c() { int i; x(42); }", HasVariableI));
+}
+
+TEST(StatementMatcher, HasDescendant) {
+ StatementMatcher HasDescendantVariableI =
+ expression(
+ hasType(pointsTo(record(hasName("X")))),
+ hasDescendant(declarationReference(to(variable(hasName("i"))))));
+
+ EXPECT_TRUE(matches(
+ "class X; X *x(bool); bool b(int); void c() { int i; x(b(i)); }",
+ HasDescendantVariableI));
+ EXPECT_TRUE(notMatches(
+ "class X; X *x(bool); bool b(int); void c() { int i; x(b(42)); }",
+ HasDescendantVariableI));
+}
+
+TEST(TypeMatcher, MatchesClassType) {
+ TypeMatcher TypeA = hasDeclaration(record(hasName("A")));
+
+ EXPECT_TRUE(matches("class A { public: A *a; };", TypeA));
+ EXPECT_TRUE(notMatches("class A {};", TypeA));
+
+ TypeMatcher TypeDerivedFromA = hasDeclaration(record(isDerivedFrom("A")));
+
+ EXPECT_TRUE(matches("class A {}; class B : public A { public: B *b; };",
+ TypeDerivedFromA));
+ EXPECT_TRUE(notMatches("class A {};", TypeA));
+
+ TypeMatcher TypeAHasClassB = hasDeclaration(
+ record(hasName("A"), has(record(hasName("B")))));
+
+ EXPECT_TRUE(
+ matches("class A { public: A *a; class B {}; };", TypeAHasClassB));
+}
+
+// Returns from Run whether 'bound_nodes' contain a Decl bound to 'Id', which
+// can be dynamically casted to T.
+// Optionally checks that the check succeeded a specific number of times.
+template <typename T>
+class VerifyIdIsBoundToDecl : public BoundNodesCallback {
+public:
+ // Create an object that checks that a node of type 'T' was bound to 'Id'.
+ // Does not check for a certain number of matches.
+ explicit VerifyIdIsBoundToDecl(const std::string& Id)
+ : Id(Id), ExpectedCount(-1), Count(0) {}
+
+ // Create an object that checks that a node of type 'T' was bound to 'Id'.
+ // Checks that there were exactly 'ExpectedCount' matches.
+ explicit VerifyIdIsBoundToDecl(const std::string& Id, int ExpectedCount)
+ : Id(Id), ExpectedCount(ExpectedCount), Count(0) {}
+
+ ~VerifyIdIsBoundToDecl() {
+ if (ExpectedCount != -1) {
+ EXPECT_EQ(ExpectedCount, Count);
+ }
+ }
+
+ virtual bool run(const BoundNodes *Nodes) {
+ if (Nodes->getDeclAs<T>(Id) != NULL) {
+ ++Count;
+ return true;
+ }
+ return false;
+ }
+
+private:
+ const std::string Id;
+ const int ExpectedCount;
+ int Count;
+};
+template <typename T>
+class VerifyIdIsBoundToStmt : public BoundNodesCallback {
+public:
+ explicit VerifyIdIsBoundToStmt(const std::string &Id) : Id(Id) {}
+ virtual bool run(const BoundNodes *Nodes) {
+ const T *Node = Nodes->getStmtAs<T>(Id);
+ return Node != NULL;
+ }
+private:
+ const std::string Id;
+};
+
+TEST(Matcher, BindMatchedNodes) {
+ DeclarationMatcher ClassX = has(id("x", record(hasName("X"))));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue("class X {};",
+ ClassX, new VerifyIdIsBoundToDecl<clang::CXXRecordDecl>("x")));
+
+ EXPECT_TRUE(matchAndVerifyResultFalse("class X {};",
+ ClassX, new VerifyIdIsBoundToDecl<clang::CXXRecordDecl>("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<clang::Decl>("b")));
+
+ StatementMatcher MethodX = id("x", call(callee(method(hasName("x")))));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue("class A { void x() { x(); } };",
+ MethodX,
+ new VerifyIdIsBoundToStmt<clang::CXXMemberCallExpr>("x")));
+}
+
+TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) {
+ TypeMatcher ClassX = hasDeclaration(record(hasName("X")));
+ EXPECT_TRUE(
+ matches("class X {}; void y(X &x) { x; }", expression(hasType(ClassX))));
+ EXPECT_TRUE(
+ notMatches("class X {}; void y(X *x) { x; }",
+ expression(hasType(ClassX))));
+ EXPECT_TRUE(
+ matches("class X {}; void y(X *x) { x; }",
+ expression(hasType(pointsTo(ClassX)))));
+}
+
+TEST(HasType, TakesQualTypeMatcherAndMatchesValueDecl) {
+ TypeMatcher ClassX = hasDeclaration(record(hasName("X")));
+ EXPECT_TRUE(
+ matches("class X {}; void y() { X x; }", variable(hasType(ClassX))));
+ EXPECT_TRUE(
+ notMatches("class X {}; void y() { X *x; }", variable(hasType(ClassX))));
+ EXPECT_TRUE(
+ matches("class X {}; void y() { X *x; }",
+ variable(hasType(pointsTo(ClassX)))));
+}
+
+TEST(HasType, TakesDeclMatcherAndMatchesExpr) {
+ DeclarationMatcher ClassX = record(hasName("X"));
+ EXPECT_TRUE(
+ matches("class X {}; void y(X &x) { x; }", expression(hasType(ClassX))));
+ EXPECT_TRUE(
+ notMatches("class X {}; void y(X *x) { x; }",
+ expression(hasType(ClassX))));
+}
+
+TEST(HasType, TakesDeclMatcherAndMatchesValueDecl) {
+ DeclarationMatcher ClassX = record(hasName("X"));
+ EXPECT_TRUE(
+ matches("class X {}; void y() { X x; }", variable(hasType(ClassX))));
+ EXPECT_TRUE(
+ notMatches("class X {}; void y() { X *x; }", variable(hasType(ClassX))));
+}
+
+TEST(Matcher, Call) {
+ // FIXME: Do we want to overload Call() to directly take
+ // Matcher<clang::Decl>, too?
+ StatementMatcher MethodX = call(hasDeclaration(method(hasName("x"))));
+
+ EXPECT_TRUE(matches("class Y { void x() { x(); } };", MethodX));
+ EXPECT_TRUE(notMatches("class Y { void x() {} };", MethodX));
+
+ StatementMatcher MethodOnY = call(on(hasType(record(hasName("Y")))));
+
+ EXPECT_TRUE(
+ matches("class Y { public: void x(); }; void z() { Y y; y.x(); }",
+ MethodOnY));
+ EXPECT_TRUE(
+ matches("class Y { public: void x(); }; void z(Y &y) { y.x(); }",
+ MethodOnY));
+ EXPECT_TRUE(
+ notMatches("class Y { public: void x(); }; void z(Y *&y) { y->x(); }",
+ MethodOnY));
+ EXPECT_TRUE(
+ notMatches("class Y { public: void x(); }; void z(Y y[]) { y->x(); }",
+ MethodOnY));
+ EXPECT_TRUE(
+ notMatches("class Y { public: void x(); }; void z() { Y *y; y->x(); }",
+ MethodOnY));
+
+ StatementMatcher MethodOnYPointer =
+ call(on(hasType(pointsTo(record(hasName("Y"))))));
+
+ EXPECT_TRUE(
+ matches("class Y { public: void x(); }; void z() { Y *y; y->x(); }",
+ MethodOnYPointer));
+ EXPECT_TRUE(
+ matches("class Y { public: void x(); }; void z(Y *&y) { y->x(); }",
+ MethodOnYPointer));
+ EXPECT_TRUE(
+ matches("class Y { public: void x(); }; void z(Y y[]) { y->x(); }",
+ MethodOnYPointer));
+ EXPECT_TRUE(
+ notMatches("class Y { public: void x(); }; void z() { Y y; y.x(); }",
+ MethodOnYPointer));
+ EXPECT_TRUE(
+ notMatches("class Y { public: void x(); }; void z(Y &y) { y.x(); }",
+ MethodOnYPointer));
+}
+
+TEST(Matcher, OverloadedOperatorCall) {
+ StatementMatcher OpCall = overloadedOperatorCall();
+ // Unary operator
+ EXPECT_TRUE(matches("class Y { }; "
+ "bool operator!(Y x) { return false; }; "
+ "Y y; bool c = !y;", OpCall));
+ // No match -- special operators like "new", "delete"
+ // FIXME: operator new takes size_t, for which we need stddef.h, for which
+ // we need to figure out include paths in the test.
+ // EXPECT_TRUE(NotMatches("#include <stddef.h>\n"
+ // "class Y { }; "
+ // "void *operator new(size_t size) { return 0; } "
+ // "Y *y = new Y;", OpCall));
+ EXPECT_TRUE(notMatches("class Y { }; "
+ "void operator delete(void *p) { } "
+ "void a() {Y *y = new Y; delete y;}", OpCall));
+ // Binary operator
+ EXPECT_TRUE(matches("class Y { }; "
+ "bool operator&&(Y x, Y y) { return true; }; "
+ "Y a; Y b; bool c = a && b;",
+ OpCall));
+ // No match -- normal operator, not an overloaded one.
+ EXPECT_TRUE(notMatches("bool x = true, y = true; bool t = x && y;", OpCall));
+ EXPECT_TRUE(notMatches("int t = 5 << 2;", OpCall));
+}
+
+TEST(Matcher, HasOperatorNameForOverloadedOperatorCall) {
+ StatementMatcher OpCallAndAnd =
+ overloadedOperatorCall(hasOverloadedOperatorName("&&"));
+ EXPECT_TRUE(matches("class Y { }; "
+ "bool operator&&(Y x, Y y) { return true; }; "
+ "Y a; Y b; bool c = a && b;", OpCallAndAnd));
+ StatementMatcher OpCallLessLess =
+ overloadedOperatorCall(hasOverloadedOperatorName("<<"));
+ EXPECT_TRUE(notMatches("class Y { }; "
+ "bool operator&&(Y x, Y y) { return true; }; "
+ "Y a; Y b; bool c = a && b;",
+ OpCallLessLess));
+}
+
+TEST(Matcher, ThisPointerType) {
+ StatementMatcher MethodOnY = call(thisPointerType(record(hasName("Y"))));
+
+ EXPECT_TRUE(
+ matches("class Y { public: void x(); }; void z() { Y y; y.x(); }",
+ MethodOnY));
+ EXPECT_TRUE(
+ matches("class Y { public: void x(); }; void z(Y &y) { y.x(); }",
+ MethodOnY));
+ EXPECT_TRUE(
+ matches("class Y { public: void x(); }; void z(Y *&y) { y->x(); }",
+ MethodOnY));
+ EXPECT_TRUE(
+ matches("class Y { public: void x(); }; void z(Y y[]) { y->x(); }",
+ MethodOnY));
+ EXPECT_TRUE(
+ matches("class Y { public: void x(); }; void z() { Y *y; y->x(); }",
+ MethodOnY));
+
+ EXPECT_TRUE(matches(
+ "class Y {"
+ " public: virtual void x();"
+ "};"
+ "class X : public Y {"
+ " public: virtual void x();"
+ "};"
+ "void z() { X *x; x->Y::x(); }", MethodOnY));
+}
+
+TEST(Matcher, VariableUsage) {
+ StatementMatcher Reference =
+ declarationReference(to(
+ variable(hasInitializer(
+ call(thisPointerType(record(hasName("Y"))))))));
+
+ EXPECT_TRUE(matches(
+ "class Y {"
+ " public:"
+ " bool x() const;"
+ "};"
+ "void z(const Y &y) {"
+ " bool b = y.x();"
+ " if (b) {}"
+ "}", Reference));
+
+ EXPECT_TRUE(notMatches(
+ "class Y {"
+ " public:"
+ " bool x() const;"
+ "};"
+ "void z(const Y &y) {"
+ " bool b = y.x();"
+ "}", Reference));
+}
+
+TEST(Matcher, CalledVariable) {
+ StatementMatcher CallOnVariableY = expression(
+ call(on(declarationReference(to(variable(hasName("y")))))));
+
+ EXPECT_TRUE(matches(
+ "class Y { public: void x() { Y y; y.x(); } };", CallOnVariableY));
+ EXPECT_TRUE(matches(
+ "class Y { public: void x() const { Y y; y.x(); } };", CallOnVariableY));
+ EXPECT_TRUE(matches(
+ "class Y { public: void x(); };"
+ "class X : public Y { void z() { X y; y.x(); } };", CallOnVariableY));
+ EXPECT_TRUE(matches(
+ "class Y { public: void x(); };"
+ "class X : public Y { void z() { X *y; y->x(); } };", CallOnVariableY));
+ EXPECT_TRUE(notMatches(
+ "class Y { public: void x(); };"
+ "class X : public Y { void z() { unsigned long y; ((X*)y)->x(); } };",
+ CallOnVariableY));
+}
+
+TEST(MemberExpression, DoesNotMatchClasses) {
+ EXPECT_TRUE(notMatches("class Y { void x() {} };", memberExpression()));
+}
+
+TEST(MemberExpression, MatchesMemberFunctionCall) {
+ EXPECT_TRUE(matches("class Y { void x() { x(); } };", memberExpression()));
+}
+
+TEST(MemberExpression, MatchesVariable) {
+ EXPECT_TRUE(
+ matches("class Y { void x() { this->y; } int y; };", memberExpression()));
+ EXPECT_TRUE(
+ matches("class Y { void x() { y; } int y; };", memberExpression()));
+ EXPECT_TRUE(
+ matches("class Y { void x() { Y y; y.y; } int y; };",
+ memberExpression()));
+}
+
+TEST(MemberExpression, MatchesStaticVariable) {
+ EXPECT_TRUE(matches("class Y { void x() { this->y; } static int y; };",
+ memberExpression()));
+ EXPECT_TRUE(notMatches("class Y { void x() { y; } static int y; };",
+ memberExpression()));
+ EXPECT_TRUE(notMatches("class Y { void x() { Y::y; } static int y; };",
+ memberExpression()));
+}
+
+TEST(IsArrow, MatchesMemberVariablesViaArrow) {
+ EXPECT_TRUE(matches("class Y { void x() { this->y; } int y; };",
+ memberExpression(isArrow())));
+ EXPECT_TRUE(matches("class Y { void x() { y; } int y; };",
+ memberExpression(isArrow())));
+ EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } int y; };",
+ memberExpression(isArrow())));
+}
+
+TEST(IsArrow, MatchesStaticMemberVariablesViaArrow) {
+ EXPECT_TRUE(matches("class Y { void x() { this->y; } static int y; };",
+ memberExpression(isArrow())));
+ EXPECT_TRUE(notMatches("class Y { void x() { y; } static int y; };",
+ memberExpression(isArrow())));
+ EXPECT_TRUE(notMatches("class Y { void x() { (*this).y; } static int y; };",
+ memberExpression(isArrow())));
+}
+
+TEST(IsArrow, MatchesMemberCallsViaArrow) {
+ EXPECT_TRUE(matches("class Y { void x() { this->x(); } };",
+ memberExpression(isArrow())));
+ EXPECT_TRUE(matches("class Y { void x() { x(); } };",
+ memberExpression(isArrow())));
+ EXPECT_TRUE(notMatches("class Y { void x() { Y y; y.x(); } };",
+ memberExpression(isArrow())));
+}
+
+TEST(Callee, MatchesDeclarations) {
+ StatementMatcher CallMethodX = call(callee(method(hasName("x"))));
+
+ EXPECT_TRUE(matches("class Y { void x() { x(); } };", CallMethodX));
+ EXPECT_TRUE(notMatches("class Y { void x() {} };", CallMethodX));
+}
+
+TEST(Callee, MatchesMemberExpressions) {
+ EXPECT_TRUE(matches("class Y { void x() { this->x(); } };",
+ call(callee(memberExpression()))));
+ EXPECT_TRUE(
+ notMatches("class Y { void x() { this->x(); } };", call(callee(call()))));
+}
+
+TEST(Function, MatchesFunctionDeclarations) {
+ StatementMatcher CallFunctionF = call(callee(function(hasName("f"))));
+
+ EXPECT_TRUE(matches("void f() { f(); }", CallFunctionF));
+ EXPECT_TRUE(notMatches("void f() { }", CallFunctionF));
+
+ // Dependent contexts, but a non-dependent call.
+ EXPECT_TRUE(matches("void f(); template <int N> void g() { f(); }",
+ CallFunctionF));
+ EXPECT_TRUE(
+ matches("void f(); template <int N> struct S { void g() { f(); } };",
+ CallFunctionF));
+
+ // Depedent calls don't match.
+ EXPECT_TRUE(
+ notMatches("void f(int); template <typename T> void g(T t) { f(t); }",
+ CallFunctionF));
+ EXPECT_TRUE(
+ notMatches("void f(int);"
+ "template <typename T> struct S { void g(T t) { f(t); } };",
+ CallFunctionF));
+}
+
+TEST(Matcher, Argument) {
+ StatementMatcher CallArgumentY = expression(call(
+ hasArgument(0, declarationReference(to(variable(hasName("y")))))));
+
+ EXPECT_TRUE(matches("void x(int) { int y; x(y); }", CallArgumentY));
+ EXPECT_TRUE(
+ matches("class X { void x(int) { int y; x(y); } };", CallArgumentY));
+ EXPECT_TRUE(notMatches("void x(int) { int z; x(z); }", CallArgumentY));
+
+ StatementMatcher WrongIndex = expression(call(
+ hasArgument(42, declarationReference(to(variable(hasName("y")))))));
+ EXPECT_TRUE(notMatches("void x(int) { int y; x(y); }", WrongIndex));
+}
+
+TEST(Matcher, AnyArgument) {
+ StatementMatcher CallArgumentY = expression(call(
+ hasAnyArgument(declarationReference(to(variable(hasName("y")))))));
+ EXPECT_TRUE(matches("void x(int, int) { int y; x(1, y); }", CallArgumentY));
+ EXPECT_TRUE(matches("void x(int, int) { int y; x(y, 42); }", CallArgumentY));
+ EXPECT_TRUE(notMatches("void x(int, int) { x(1, 2); }", CallArgumentY));
+}
+
+TEST(Matcher, ArgumentCount) {
+ StatementMatcher Call1Arg = expression(call(argumentCountIs(1)));
+
+ EXPECT_TRUE(matches("void x(int) { x(0); }", Call1Arg));
+ EXPECT_TRUE(matches("class X { void x(int) { x(0); } };", Call1Arg));
+ EXPECT_TRUE(notMatches("void x(int, int) { x(0, 0); }", Call1Arg));
+}
+
+TEST(Matcher, References) {
+ DeclarationMatcher ReferenceClassX = variable(
+ hasType(references(record(hasName("X")))));
+ EXPECT_TRUE(matches("class X {}; void y(X y) { X &x = y; }",
+ ReferenceClassX));
+ EXPECT_TRUE(
+ matches("class X {}; void y(X y) { const X &x = y; }", ReferenceClassX));
+ EXPECT_TRUE(
+ notMatches("class X {}; void y(X y) { X x = y; }", ReferenceClassX));
+ EXPECT_TRUE(
+ notMatches("class X {}; void y(X *y) { X *&x = y; }", ReferenceClassX));
+}
+
+TEST(HasParameter, CallsInnerMatcher) {
+ EXPECT_TRUE(matches("class X { void x(int) {} };",
+ method(hasParameter(0, variable()))));
+ EXPECT_TRUE(notMatches("class X { void x(int) {} };",
+ method(hasParameter(0, hasName("x")))));
+}
+
+TEST(HasParameter, DoesNotMatchIfIndexOutOfBounds) {
+ EXPECT_TRUE(notMatches("class X { void x(int) {} };",
+ method(hasParameter(42, variable()))));
+}
+
+TEST(HasType, MatchesParameterVariableTypesStrictly) {
+ EXPECT_TRUE(matches("class X { void x(X x) {} };",
+ method(hasParameter(0, hasType(record(hasName("X")))))));
+ EXPECT_TRUE(notMatches("class X { void x(const X &x) {} };",
+ method(hasParameter(0, hasType(record(hasName("X")))))));
+ EXPECT_TRUE(matches("class X { void x(const X *x) {} };",
+ method(hasParameter(0, hasType(pointsTo(record(hasName("X"))))))));
+ EXPECT_TRUE(matches("class X { void x(const X &x) {} };",
+ method(hasParameter(0, hasType(references(record(hasName("X"))))))));
+}
+
+TEST(HasAnyParameter, MatchesIndependentlyOfPosition) {
+ EXPECT_TRUE(matches("class Y {}; class X { void x(X x, Y y) {} };",
+ method(hasAnyParameter(hasType(record(hasName("X")))))));
+ EXPECT_TRUE(matches("class Y {}; class X { void x(Y y, X x) {} };",
+ method(hasAnyParameter(hasType(record(hasName("X")))))));
+}
+
+TEST(HasAnyParameter, DoesntMatchIfInnerMatcherDoesntMatch) {
+ EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };",
+ method(hasAnyParameter(hasType(record(hasName("X")))))));
+}
+
+TEST(HasAnyParameter, DoesNotMatchThisPointer) {
+ EXPECT_TRUE(notMatches("class Y {}; class X { void x() {} };",
+ method(hasAnyParameter(hasType(pointsTo(record(hasName("X"))))))));
+}
+
+TEST(HasName, MatchesParameterVariableDeclartions) {
+ EXPECT_TRUE(matches("class Y {}; class X { void x(int x) {} };",
+ method(hasAnyParameter(hasName("x")))));
+ EXPECT_TRUE(notMatches("class Y {}; class X { void x(int) {} };",
+ method(hasAnyParameter(hasName("x")))));
+}
+
+TEST(Matcher, ConstructorCall) {
+ StatementMatcher Constructor = expression(constructorCall());
+
+ EXPECT_TRUE(
+ matches("class X { public: X(); }; void x() { X x; }", Constructor));
+ EXPECT_TRUE(
+ matches("class X { public: X(); }; void x() { X x = X(); }",
+ Constructor));
+ EXPECT_TRUE(
+ matches("class X { public: X(int); }; void x() { X x = 0; }",
+ Constructor));
+ EXPECT_TRUE(matches("class X {}; void x(int) { X x; }", Constructor));
+}
+
+TEST(Matcher, ConstructorArgument) {
+ StatementMatcher Constructor = expression(constructorCall(
+ hasArgument(0, declarationReference(to(variable(hasName("y")))))));
+
+ EXPECT_TRUE(
+ matches("class X { public: X(int); }; void x() { int y; X x(y); }",
+ Constructor));
+ EXPECT_TRUE(
+ matches("class X { public: X(int); }; void x() { int y; X x = X(y); }",
+ Constructor));
+ EXPECT_TRUE(
+ matches("class X { public: X(int); }; void x() { int y; X x = y; }",
+ Constructor));
+ EXPECT_TRUE(
+ notMatches("class X { public: X(int); }; void x() { int z; X x(z); }",
+ Constructor));
+
+ StatementMatcher WrongIndex = expression(constructorCall(
+ hasArgument(42, declarationReference(to(variable(hasName("y")))))));
+ EXPECT_TRUE(
+ notMatches("class X { public: X(int); }; void x() { int y; X x(y); }",
+ WrongIndex));
+}
+
+TEST(Matcher, ConstructorArgumentCount) {
+ StatementMatcher Constructor1Arg =
+ expression(constructorCall(argumentCountIs(1)));
+
+ EXPECT_TRUE(
+ matches("class X { public: X(int); }; void x() { X x(0); }",
+ Constructor1Arg));
+ EXPECT_TRUE(
+ matches("class X { public: X(int); }; void x() { X x = X(0); }",
+ Constructor1Arg));
+ EXPECT_TRUE(
+ matches("class X { public: X(int); }; void x() { X x = 0; }",
+ Constructor1Arg));
+ EXPECT_TRUE(
+ notMatches("class X { public: X(int, int); }; void x() { X x(0, 0); }",
+ Constructor1Arg));
+}
+
+TEST(Matcher, BindTemporaryExpression) {
+ StatementMatcher TempExpression = expression(bindTemporaryExpression());
+
+ std::string ClassString = "class string { public: string(); ~string(); }; ";
+
+ EXPECT_TRUE(
+ matches(ClassString +
+ "string GetStringByValue();"
+ "void FunctionTakesString(string s);"
+ "void run() { FunctionTakesString(GetStringByValue()); }",
+ TempExpression));
+
+ EXPECT_TRUE(
+ notMatches(ClassString +
+ "string* GetStringPointer(); "
+ "void FunctionTakesStringPtr(string* s);"
+ "void run() {"
+ " string* s = GetStringPointer();"
+ " FunctionTakesStringPtr(GetStringPointer());"
+ " FunctionTakesStringPtr(s);"
+ "}",
+ TempExpression));
+
+ EXPECT_TRUE(
+ notMatches("class no_dtor {};"
+ "no_dtor GetObjByValue();"
+ "void ConsumeObj(no_dtor param);"
+ "void run() { ConsumeObj(GetObjByValue()); }",
+ TempExpression));
+}
+
+TEST(ConstructorDeclaration, SimpleCase) {
+ EXPECT_TRUE(matches("class Foo { Foo(int i); };",
+ constructor(ofClass(hasName("Foo")))));
+ EXPECT_TRUE(notMatches("class Foo { Foo(int i); };",
+ constructor(ofClass(hasName("Bar")))));
+}
+
+TEST(ConstructorDeclaration, IsImplicit) {
+ // This one doesn't match because the constructor is not added by the
+ // compiler (it is not needed).
+ EXPECT_TRUE(notMatches("class Foo { };",
+ constructor(isImplicit())));
+ // The compiler added the implicit default constructor.
+ EXPECT_TRUE(matches("class Foo { }; Foo* f = new Foo();",
+ constructor(isImplicit())));
+ EXPECT_TRUE(matches("class Foo { Foo(){} };",
+ constructor(unless(isImplicit()))));
+}
+
+TEST(HasAnyConstructorInitializer, SimpleCase) {
+ EXPECT_TRUE(notMatches(
+ "class Foo { Foo() { } };",
+ constructor(hasAnyConstructorInitializer(anything()))));
+ EXPECT_TRUE(matches(
+ "class Foo {"
+ " Foo() : foo_() { }"
+ " int foo_;"
+ "};",
+ constructor(hasAnyConstructorInitializer(anything()))));
+}
+
+TEST(HasAnyConstructorInitializer, ForField) {
+ static const char Code[] =
+ "class Baz { };"
+ "class Foo {"
+ " Foo() : foo_() { }"
+ " Baz foo_;"
+ " Baz bar_;"
+ "};";
+ EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer(
+ forField(hasType(record(hasName("Baz"))))))));
+ EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer(
+ forField(hasName("foo_"))))));
+ EXPECT_TRUE(notMatches(Code, constructor(hasAnyConstructorInitializer(
+ forField(hasType(record(hasName("Bar"))))))));
+}
+
+TEST(HasAnyConstructorInitializer, WithInitializer) {
+ static const char Code[] =
+ "class Foo {"
+ " Foo() : foo_(0) { }"
+ " int foo_;"
+ "};";
+ EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer(
+ withInitializer(integerLiteral(equals(0)))))));
+ EXPECT_TRUE(notMatches(Code, constructor(hasAnyConstructorInitializer(
+ withInitializer(integerLiteral(equals(1)))))));
+}
+
+TEST(HasAnyConstructorInitializer, IsWritten) {
+ static const char Code[] =
+ "struct Bar { Bar(){} };"
+ "class Foo {"
+ " Foo() : foo_() { }"
+ " Bar foo_;"
+ " Bar bar_;"
+ "};";
+ EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer(
+ allOf(forField(hasName("foo_")), isWritten())))));
+ EXPECT_TRUE(notMatches(Code, constructor(hasAnyConstructorInitializer(
+ allOf(forField(hasName("bar_")), isWritten())))));
+ EXPECT_TRUE(matches(Code, constructor(hasAnyConstructorInitializer(
+ allOf(forField(hasName("bar_")), unless(isWritten()))))));
+}
+
+TEST(Matcher, NewExpression) {
+ StatementMatcher New = expression(newExpression());
+
+ EXPECT_TRUE(matches("class X { public: X(); }; void x() { new X; }", New));
+ EXPECT_TRUE(
+ matches("class X { public: X(); }; void x() { new X(); }", New));
+ EXPECT_TRUE(
+ matches("class X { public: X(int); }; void x() { new X(0); }", New));
+ EXPECT_TRUE(matches("class X {}; void x(int) { new X; }", New));
+}
+
+TEST(Matcher, NewExpressionArgument) {
+ StatementMatcher New = expression(constructorCall(
+ hasArgument(
+ 0, declarationReference(to(variable(hasName("y")))))));
+
+ EXPECT_TRUE(
+ matches("class X { public: X(int); }; void x() { int y; new X(y); }",
+ New));
+ EXPECT_TRUE(
+ matches("class X { public: X(int); }; void x() { int y; new X(y); }",
+ New));
+ EXPECT_TRUE(
+ notMatches("class X { public: X(int); }; void x() { int z; new X(z); }",
+ New));
+
+ StatementMatcher WrongIndex = expression(constructorCall(
+ hasArgument(
+ 42, declarationReference(to(variable(hasName("y")))))));
+ EXPECT_TRUE(
+ notMatches("class X { public: X(int); }; void x() { int y; new X(y); }",
+ WrongIndex));
+}
+
+TEST(Matcher, NewExpressionArgumentCount) {
+ StatementMatcher New = constructorCall(argumentCountIs(1));
+
+ EXPECT_TRUE(
+ matches("class X { public: X(int); }; void x() { new X(0); }", New));
+ EXPECT_TRUE(
+ notMatches("class X { public: X(int, int); }; void x() { new X(0, 0); }",
+ New));
+}
+
+TEST(Matcher, DefaultArgument) {
+ StatementMatcher Arg = defaultArgument();
+
+ EXPECT_TRUE(matches("void x(int, int = 0) { int y; x(y); }", Arg));
+ EXPECT_TRUE(
+ matches("class X { void x(int, int = 0) { int y; x(y); } };", Arg));
+ EXPECT_TRUE(notMatches("void x(int, int = 0) { int y; x(y, 0); }", Arg));
+}
+
+TEST(Matcher, StringLiterals) {
+ StatementMatcher Literal = expression(stringLiteral());
+ EXPECT_TRUE(matches("const char *s = \"string\";", Literal));
+ // wide string
+ EXPECT_TRUE(matches("const wchar_t *s = L\"string\";", Literal));
+ // with escaped characters
+ EXPECT_TRUE(matches("const char *s = \"\x05five\";", Literal));
+ // no matching -- though the data type is the same, there is no string literal
+ EXPECT_TRUE(notMatches("const char s[1] = {'a'};", Literal));
+}
+
+TEST(Matcher, CharacterLiterals) {
+ StatementMatcher CharLiteral = expression(characterLiteral());
+ EXPECT_TRUE(matches("const char c = 'c';", CharLiteral));
+ // wide character
+ EXPECT_TRUE(matches("const char c = L'c';", CharLiteral));
+ // wide character, Hex encoded, NOT MATCHED!
+ EXPECT_TRUE(notMatches("const wchar_t c = 0x2126;", CharLiteral));
+ EXPECT_TRUE(notMatches("const char c = 0x1;", CharLiteral));
+}
+
+TEST(Matcher, IntegerLiterals) {
+ StatementMatcher HasIntLiteral = expression(integerLiteral());
+ EXPECT_TRUE(matches("int i = 10;", HasIntLiteral));
+ EXPECT_TRUE(matches("int i = 0x1AB;", HasIntLiteral));
+ EXPECT_TRUE(matches("int i = 10L;", HasIntLiteral));
+ EXPECT_TRUE(matches("int i = 10U;", HasIntLiteral));
+
+ // Non-matching cases (character literals, float and double)
+ EXPECT_TRUE(notMatches("int i = L'a';",
+ HasIntLiteral)); // this is actually a character
+ // literal cast to int
+ EXPECT_TRUE(notMatches("int i = 'a';", HasIntLiteral));
+ EXPECT_TRUE(notMatches("int i = 1e10;", HasIntLiteral));
+ EXPECT_TRUE(notMatches("int i = 10.0;", HasIntLiteral));
+}
+
+TEST(Matcher, Conditions) {
+ StatementMatcher Condition = ifStmt(hasCondition(boolLiteral(equals(true))));
+
+ EXPECT_TRUE(matches("void x() { if (true) {} }", Condition));
+ EXPECT_TRUE(notMatches("void x() { if (false) {} }", Condition));
+ EXPECT_TRUE(notMatches("void x() { bool a = true; if (a) {} }", Condition));
+ EXPECT_TRUE(notMatches("void x() { if (true || false) {} }", Condition));
+ EXPECT_TRUE(notMatches("void x() { if (1) {} }", Condition));
+}
+
+TEST(MatchBinaryOperator, HasOperatorName) {
+ StatementMatcher OperatorOr = binaryOperator(hasOperatorName("||"));
+
+ EXPECT_TRUE(matches("void x() { true || false; }", OperatorOr));
+ EXPECT_TRUE(notMatches("void x() { true && false; }", OperatorOr));
+}
+
+TEST(MatchBinaryOperator, HasLHSAndHasRHS) {
+ StatementMatcher OperatorTrueFalse =
+ binaryOperator(hasLHS(boolLiteral(equals(true))),
+ hasRHS(boolLiteral(equals(false))));
+
+ EXPECT_TRUE(matches("void x() { true || false; }", OperatorTrueFalse));
+ EXPECT_TRUE(matches("void x() { true && false; }", OperatorTrueFalse));
+ EXPECT_TRUE(notMatches("void x() { false || true; }", OperatorTrueFalse));
+}
+
+TEST(MatchBinaryOperator, HasEitherOperand) {
+ StatementMatcher HasOperand =
+ binaryOperator(hasEitherOperand(boolLiteral(equals(false))));
+
+ EXPECT_TRUE(matches("void x() { true || false; }", HasOperand));
+ EXPECT_TRUE(matches("void x() { false && true; }", HasOperand));
+ EXPECT_TRUE(notMatches("void x() { true || true; }", HasOperand));
+}
+
+TEST(Matcher, BinaryOperatorTypes) {
+ // Integration test that verifies the AST provides all binary operators in
+ // a way we expect.
+ // FIXME: Operator ','
+ EXPECT_TRUE(
+ matches("void x() { 3, 4; }", binaryOperator(hasOperatorName(","))));
+ EXPECT_TRUE(
+ matches("bool b; bool c = (b = true);",
+ binaryOperator(hasOperatorName("="))));
+ EXPECT_TRUE(
+ matches("bool b = 1 != 2;", binaryOperator(hasOperatorName("!="))));
+ EXPECT_TRUE(
+ matches("bool b = 1 == 2;", binaryOperator(hasOperatorName("=="))));
+ EXPECT_TRUE(matches("bool b = 1 < 2;", binaryOperator(hasOperatorName("<"))));
+ EXPECT_TRUE(
+ matches("bool b = 1 <= 2;", binaryOperator(hasOperatorName("<="))));
+ EXPECT_TRUE(
+ matches("int i = 1 << 2;", binaryOperator(hasOperatorName("<<"))));
+ EXPECT_TRUE(
+ matches("int i = 1; int j = (i <<= 2);",
+ binaryOperator(hasOperatorName("<<="))));
+ EXPECT_TRUE(matches("bool b = 1 > 2;", binaryOperator(hasOperatorName(">"))));
+ EXPECT_TRUE(
+ matches("bool b = 1 >= 2;", binaryOperator(hasOperatorName(">="))));
+ EXPECT_TRUE(
+ matches("int i = 1 >> 2;", binaryOperator(hasOperatorName(">>"))));
+ EXPECT_TRUE(
+ matches("int i = 1; int j = (i >>= 2);",
+ binaryOperator(hasOperatorName(">>="))));
+ EXPECT_TRUE(
+ matches("int i = 42 ^ 23;", binaryOperator(hasOperatorName("^"))));
+ EXPECT_TRUE(
+ matches("int i = 42; int j = (i ^= 42);",
+ binaryOperator(hasOperatorName("^="))));
+ EXPECT_TRUE(
+ matches("int i = 42 % 23;", binaryOperator(hasOperatorName("%"))));
+ EXPECT_TRUE(
+ matches("int i = 42; int j = (i %= 42);",
+ binaryOperator(hasOperatorName("%="))));
+ EXPECT_TRUE(
+ matches("bool b = 42 &23;", binaryOperator(hasOperatorName("&"))));
+ EXPECT_TRUE(
+ matches("bool b = true && false;",
+ binaryOperator(hasOperatorName("&&"))));
+ EXPECT_TRUE(
+ matches("bool b = true; bool c = (b &= false);",
+ binaryOperator(hasOperatorName("&="))));
+ EXPECT_TRUE(
+ matches("bool b = 42 | 23;", binaryOperator(hasOperatorName("|"))));
+ EXPECT_TRUE(
+ matches("bool b = true || false;",
+ binaryOperator(hasOperatorName("||"))));
+ EXPECT_TRUE(
+ matches("bool b = true; bool c = (b |= false);",
+ binaryOperator(hasOperatorName("|="))));
+ EXPECT_TRUE(
+ matches("int i = 42 *23;", binaryOperator(hasOperatorName("*"))));
+ EXPECT_TRUE(
+ matches("int i = 42; int j = (i *= 23);",
+ binaryOperator(hasOperatorName("*="))));
+ EXPECT_TRUE(
+ matches("int i = 42 / 23;", binaryOperator(hasOperatorName("/"))));
+ EXPECT_TRUE(
+ matches("int i = 42; int j = (i /= 23);",
+ binaryOperator(hasOperatorName("/="))));
+ EXPECT_TRUE(
+ matches("int i = 42 + 23;", binaryOperator(hasOperatorName("+"))));
+ EXPECT_TRUE(
+ matches("int i = 42; int j = (i += 23);",
+ binaryOperator(hasOperatorName("+="))));
+ EXPECT_TRUE(
+ matches("int i = 42 - 23;", binaryOperator(hasOperatorName("-"))));
+ EXPECT_TRUE(
+ matches("int i = 42; int j = (i -= 23);",
+ binaryOperator(hasOperatorName("-="))));
+ EXPECT_TRUE(
+ matches("struct A { void x() { void (A::*a)(); (this->*a)(); } };",
+ binaryOperator(hasOperatorName("->*"))));
+ EXPECT_TRUE(
+ matches("struct A { void x() { void (A::*a)(); ((*this).*a)(); } };",
+ binaryOperator(hasOperatorName(".*"))));
+
+ // Member expressions as operators are not supported in matches.
+ EXPECT_TRUE(
+ notMatches("struct A { void x(A *a) { a->x(this); } };",
+ binaryOperator(hasOperatorName("->"))));
+
+ // Initializer assignments are not represented as operator equals.
+ EXPECT_TRUE(
+ notMatches("bool b = true;", binaryOperator(hasOperatorName("="))));
+
+ // Array indexing is not represented as operator.
+ EXPECT_TRUE(notMatches("int a[42]; void x() { a[23]; }", unaryOperator()));
+
+ // Overloaded operators do not match at all.
+ EXPECT_TRUE(notMatches(
+ "struct A { bool operator&&(const A &a) const { return false; } };"
+ "void x() { A a, b; a && b; }",
+ binaryOperator()));
+}
+
+TEST(MatchUnaryOperator, HasOperatorName) {
+ StatementMatcher OperatorNot = unaryOperator(hasOperatorName("!"));
+
+ EXPECT_TRUE(matches("void x() { !true; } ", OperatorNot));
+ EXPECT_TRUE(notMatches("void x() { true; } ", OperatorNot));
+}
+
+TEST(MatchUnaryOperator, HasUnaryOperand) {
+ StatementMatcher OperatorOnFalse =
+ unaryOperator(hasUnaryOperand(boolLiteral(equals(false))));
+
+ EXPECT_TRUE(matches("void x() { !false; }", OperatorOnFalse));
+ EXPECT_TRUE(notMatches("void x() { !true; }", OperatorOnFalse));
+}
+
+TEST(Matcher, UnaryOperatorTypes) {
+ // Integration test that verifies the AST provides all unary operators in
+ // a way we expect.
+ EXPECT_TRUE(matches("bool b = !true;", unaryOperator(hasOperatorName("!"))));
+ EXPECT_TRUE(
+ matches("bool b; bool *p = &b;", unaryOperator(hasOperatorName("&"))));
+ EXPECT_TRUE(matches("int i = ~ 1;", unaryOperator(hasOperatorName("~"))));
+ EXPECT_TRUE(
+ matches("bool *p; bool b = *p;", unaryOperator(hasOperatorName("*"))));
+ EXPECT_TRUE(
+ matches("int i; int j = +i;", unaryOperator(hasOperatorName("+"))));
+ EXPECT_TRUE(
+ matches("int i; int j = -i;", unaryOperator(hasOperatorName("-"))));
+ EXPECT_TRUE(
+ matches("int i; int j = ++i;", unaryOperator(hasOperatorName("++"))));
+ EXPECT_TRUE(
+ matches("int i; int j = i++;", unaryOperator(hasOperatorName("++"))));
+ EXPECT_TRUE(
+ matches("int i; int j = --i;", unaryOperator(hasOperatorName("--"))));
+ EXPECT_TRUE(
+ matches("int i; int j = i--;", unaryOperator(hasOperatorName("--"))));
+
+ // We don't match conversion operators.
+ EXPECT_TRUE(notMatches("int i; double d = (double)i;", unaryOperator()));
+
+ // Function calls are not represented as operator.
+ EXPECT_TRUE(notMatches("void f(); void x() { f(); }", unaryOperator()));
+
+ // Overloaded operators do not match at all.
+ // FIXME: We probably want to add that.
+ EXPECT_TRUE(notMatches(
+ "struct A { bool operator!() const { return false; } };"
+ "void x() { A a; !a; }", unaryOperator(hasOperatorName("!"))));
+}
+
+TEST(Matcher, ConditionalOperator) {
+ StatementMatcher Conditional = conditionalOperator(
+ hasCondition(boolLiteral(equals(true))),
+ hasTrueExpression(boolLiteral(equals(false))));
+
+ EXPECT_TRUE(matches("void x() { true ? false : true; }", Conditional));
+ EXPECT_TRUE(notMatches("void x() { false ? false : true; }", Conditional));
+ EXPECT_TRUE(notMatches("void x() { true ? true : false; }", Conditional));
+
+ StatementMatcher ConditionalFalse = conditionalOperator(
+ hasFalseExpression(boolLiteral(equals(false))));
+
+ EXPECT_TRUE(matches("void x() { true ? true : false; }", ConditionalFalse));
+ EXPECT_TRUE(
+ notMatches("void x() { true ? false : true; }", ConditionalFalse));
+}
+
+TEST(Matcher, HasNameSupportsNamespaces) {
+ EXPECT_TRUE(matches("namespace a { namespace b { class C; } }",
+ record(hasName("a::b::C"))));
+ EXPECT_TRUE(matches("namespace a { namespace b { class C; } }",
+ record(hasName("::a::b::C"))));
+ EXPECT_TRUE(matches("namespace a { namespace b { class C; } }",
+ record(hasName("b::C"))));
+ EXPECT_TRUE(matches("namespace a { namespace b { class C; } }",
+ record(hasName("C"))));
+ EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
+ record(hasName("c::b::C"))));
+ EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
+ record(hasName("a::c::C"))));
+ EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
+ record(hasName("a::b::A"))));
+ EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
+ record(hasName("::C"))));
+ EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
+ record(hasName("::b::C"))));
+ EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
+ record(hasName("z::a::b::C"))));
+ EXPECT_TRUE(notMatches("namespace a { namespace b { class C; } }",
+ record(hasName("a+b::C"))));
+ EXPECT_TRUE(notMatches("namespace a { namespace b { class AC; } }",
+ record(hasName("C"))));
+}
+
+TEST(Matcher, HasNameSupportsOuterClasses) {
+ EXPECT_TRUE(
+ matches("class A { class B { class C; }; };", record(hasName("A::B::C"))));
+ EXPECT_TRUE(
+ matches("class A { class B { class C; }; };",
+ record(hasName("::A::B::C"))));
+ EXPECT_TRUE(
+ matches("class A { class B { class C; }; };", record(hasName("B::C"))));
+ EXPECT_TRUE(
+ matches("class A { class B { class C; }; };", record(hasName("C"))));
+ EXPECT_TRUE(
+ notMatches("class A { class B { class C; }; };",
+ record(hasName("c::B::C"))));
+ EXPECT_TRUE(
+ notMatches("class A { class B { class C; }; };",
+ record(hasName("A::c::C"))));
+ EXPECT_TRUE(
+ notMatches("class A { class B { class C; }; };",
+ record(hasName("A::B::A"))));
+ EXPECT_TRUE(
+ notMatches("class A { class B { class C; }; };", record(hasName("::C"))));
+ EXPECT_TRUE(
+ notMatches("class A { class B { class C; }; };",
+ record(hasName("::B::C"))));
+ EXPECT_TRUE(notMatches("class A { class B { class C; }; };",
+ record(hasName("z::A::B::C"))));
+ EXPECT_TRUE(
+ notMatches("class A { class B { class C; }; };",
+ record(hasName("A+B::C"))));
+}
+
+TEST(Matcher, IsDefinition) {
+ DeclarationMatcher DefinitionOfClassA =
+ record(hasName("A"), isDefinition());
+ EXPECT_TRUE(matches("class A {};", DefinitionOfClassA));
+ EXPECT_TRUE(notMatches("class A;", DefinitionOfClassA));
+
+ DeclarationMatcher DefinitionOfVariableA =
+ variable(hasName("a"), isDefinition());
+ EXPECT_TRUE(matches("int a;", DefinitionOfVariableA));
+ EXPECT_TRUE(notMatches("extern int a;", DefinitionOfVariableA));
+
+ DeclarationMatcher DefinitionOfMethodA =
+ method(hasName("a"), isDefinition());
+ EXPECT_TRUE(matches("class A { void a() {} };", DefinitionOfMethodA));
+ EXPECT_TRUE(notMatches("class A { void a(); };", DefinitionOfMethodA));
+}
+
+TEST(Matcher, OfClass) {
+ StatementMatcher Constructor = constructorCall(hasDeclaration(method(
+ ofClass(hasName("X")))));
+
+ EXPECT_TRUE(
+ matches("class X { public: X(); }; void x(int) { X x; }", Constructor));
+ EXPECT_TRUE(
+ matches("class X { public: X(); }; void x(int) { X x = X(); }",
+ Constructor));
+ EXPECT_TRUE(
+ notMatches("class Y { public: Y(); }; void x(int) { Y y; }",
+ Constructor));
+}
+
+TEST(Matcher, VisitsTemplateInstantiations) {
+ EXPECT_TRUE(matches(
+ "class A { public: void x(); };"
+ "template <typename T> class B { public: void y() { T t; t.x(); } };"
+ "void f() { B<A> b; b.y(); }", call(callee(method(hasName("x"))))));
+
+ EXPECT_TRUE(matches(
+ "class A { public: void x(); };"
+ "class C {"
+ " public:"
+ " template <typename T> class B { public: void y() { T t; t.x(); } };"
+ "};"
+ "void f() {"
+ " C::B<A> b; b.y();"
+ "}", record(hasName("C"),
+ hasDescendant(call(callee(method(hasName("x"))))))));
+}
+
+// For testing AST_MATCHER_P().
+AST_MATCHER_P(clang::Decl, just, internal::Matcher<clang::Decl>, 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);
+}
+
+TEST(AstMatcherPMacro, Works) {
+ DeclarationMatcher HasClassB = just(has(id("b", record(hasName("B")))));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
+ HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b")));
+
+ EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
+ HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("a")));
+
+ EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
+ HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b")));
+}
+
+AST_POLYMORPHIC_MATCHER_P(
+ polymorphicHas, internal::Matcher<clang::Decl>, AMatcher) {
+ TOOLING_COMPILE_ASSERT((llvm::is_same<NodeType, clang::Decl>::value) ||
+ (llvm::is_same<NodeType, clang::Stmt>::value),
+ assert_node_type_is_accessible);
+ internal::TypedBaseMatcher<clang::Decl> ChildMatcher(AMatcher);
+ return Finder->matchesChildOf(
+ Node, ChildMatcher, Builder,
+ ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
+ ASTMatchFinder::BK_First);
+}
+
+TEST(AstPolymorphicMatcherPMacro, Works) {
+ DeclarationMatcher HasClassB = polymorphicHas(id("b", record(hasName("B"))));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
+ HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b")));
+
+ EXPECT_TRUE(matchAndVerifyResultFalse("class A { class B {}; };",
+ HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("a")));
+
+ EXPECT_TRUE(matchAndVerifyResultFalse("class A { class C {}; };",
+ HasClassB, new VerifyIdIsBoundToDecl<clang::Decl>("b")));
+
+ StatementMatcher StatementHasClassB =
+ polymorphicHas(record(hasName("B")));
+
+ EXPECT_TRUE(matches("void x() { class B {}; }", StatementHasClassB));
+}
+
+TEST(For, FindsForLoops) {
+ EXPECT_TRUE(matches("void f() { for(;;); }", forStmt()));
+ EXPECT_TRUE(matches("void f() { if(true) for(;;); }", forStmt()));
+}
+
+TEST(For, ReportsNoFalsePositives) {
+ EXPECT_TRUE(notMatches("void f() { ; }", forStmt()));
+ EXPECT_TRUE(notMatches("void f() { if(true); }", forStmt()));
+}
+
+TEST(CompoundStatement, HandlesSimpleCases) {
+ EXPECT_TRUE(notMatches("void f();", compoundStatement()));
+ EXPECT_TRUE(matches("void f() {}", compoundStatement()));
+ EXPECT_TRUE(matches("void f() {{}}", compoundStatement()));
+}
+
+TEST(CompoundStatement, DoesNotMatchEmptyStruct) {
+ // It's not a compound statement just because there's "{}" in the source
+ // text. This is an AST search, not grep.
+ EXPECT_TRUE(notMatches("namespace n { struct S {}; }",
+ compoundStatement()));
+ EXPECT_TRUE(matches("namespace n { struct S { void f() {{}} }; }",
+ compoundStatement()));
+}
+
+TEST(HasBody, FindsBodyOfForLoop) {
+ StatementMatcher HasCompoundStatementBody =
+ forStmt(hasBody(compoundStatement()));
+ EXPECT_TRUE(matches("void f() { for(;;) {} }",
+ HasCompoundStatementBody));
+ EXPECT_TRUE(notMatches("void f() { for(;;); }",
+ HasCompoundStatementBody));
+}
+
+TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) {
+ // The simplest case: every compound statement is in a function
+ // definition, and the function body itself must be a compound
+ // statement.
+ EXPECT_TRUE(matches("void f() { for (;;); }",
+ compoundStatement(hasAnySubstatement(forStmt()))));
+}
+
+TEST(HasAnySubstatement, IsNotRecursive) {
+ // It's really "has any immediate substatement".
+ EXPECT_TRUE(notMatches("void f() { if (true) for (;;); }",
+ compoundStatement(hasAnySubstatement(forStmt()))));
+}
+
+TEST(HasAnySubstatement, MatchesInNestedCompoundStatements) {
+ EXPECT_TRUE(matches("void f() { if (true) { for (;;); } }",
+ compoundStatement(hasAnySubstatement(forStmt()))));
+}
+
+TEST(HasAnySubstatement, FindsSubstatementBetweenOthers) {
+ EXPECT_TRUE(matches("void f() { 1; 2; 3; for (;;); 4; 5; 6; }",
+ compoundStatement(hasAnySubstatement(forStmt()))));
+}
+
+TEST(StatementCountIs, FindsNoStatementsInAnEmptyCompoundStatement) {
+ EXPECT_TRUE(matches("void f() { }",
+ compoundStatement(statementCountIs(0))));
+ EXPECT_TRUE(notMatches("void f() {}",
+ compoundStatement(statementCountIs(1))));
+}
+
+TEST(StatementCountIs, AppearsToMatchOnlyOneCount) {
+ EXPECT_TRUE(matches("void f() { 1; }",
+ compoundStatement(statementCountIs(1))));
+ EXPECT_TRUE(notMatches("void f() { 1; }",
+ compoundStatement(statementCountIs(0))));
+ EXPECT_TRUE(notMatches("void f() { 1; }",
+ compoundStatement(statementCountIs(2))));
+}
+
+TEST(StatementCountIs, WorksWithMultipleStatements) {
+ EXPECT_TRUE(matches("void f() { 1; 2; 3; }",
+ compoundStatement(statementCountIs(3))));
+}
+
+TEST(StatementCountIs, WorksWithNestedCompoundStatements) {
+ EXPECT_TRUE(matches("void f() { { 1; } { 1; 2; 3; 4; } }",
+ compoundStatement(statementCountIs(1))));
+ EXPECT_TRUE(matches("void f() { { 1; } { 1; 2; 3; 4; } }",
+ compoundStatement(statementCountIs(2))));
+ EXPECT_TRUE(notMatches("void f() { { 1; } { 1; 2; 3; 4; } }",
+ compoundStatement(statementCountIs(3))));
+ EXPECT_TRUE(matches("void f() { { 1; } { 1; 2; 3; 4; } }",
+ compoundStatement(statementCountIs(4))));
+}
+
+TEST(Member, WorksInSimplestCase) {
+ EXPECT_TRUE(matches("struct { int first; } s; int i(s.first);",
+ memberExpression(member(hasName("first")))));
+}
+
+TEST(Member, DoesNotMatchTheBaseExpression) {
+ // Don't pick out the wrong part of the member expression, this should
+ // be checking the member (name) only.
+ EXPECT_TRUE(notMatches("struct { int i; } first; int i(first.i);",
+ memberExpression(member(hasName("first")))));
+}
+
+TEST(Member, MatchesInMemberFunctionCall) {
+ EXPECT_TRUE(matches("void f() {"
+ " struct { void first() {}; } s;"
+ " s.first();"
+ "};",
+ memberExpression(member(hasName("first")))));
+}
+
+TEST(HasObjectExpression, DoesNotMatchMember) {
+ EXPECT_TRUE(notMatches(
+ "class X {}; struct Z { X m; }; void f(Z z) { z.m; }",
+ memberExpression(hasObjectExpression(hasType(record(hasName("X")))))));
+}
+
+TEST(HasObjectExpression, MatchesBaseOfVariable) {
+ EXPECT_TRUE(matches(
+ "struct X { int m; }; void f(X x) { x.m; }",
+ memberExpression(hasObjectExpression(hasType(record(hasName("X")))))));
+ EXPECT_TRUE(matches(
+ "struct X { int m; }; void f(X* x) { x->m; }",
+ memberExpression(hasObjectExpression(
+ hasType(pointsTo(record(hasName("X"))))))));
+}
+
+TEST(HasObjectExpression,
+ MatchesObjectExpressionOfImplicitlyFormedMemberExpression) {
+ EXPECT_TRUE(matches(
+ "class X {}; struct S { X m; void f() { this->m; } };",
+ memberExpression(hasObjectExpression(
+ hasType(pointsTo(record(hasName("S"))))))));
+ EXPECT_TRUE(matches(
+ "class X {}; struct S { X m; void f() { m; } };",
+ memberExpression(hasObjectExpression(
+ hasType(pointsTo(record(hasName("S"))))))));
+}
+
+TEST(Field, DoesNotMatchNonFieldMembers) {
+ EXPECT_TRUE(notMatches("class X { void m(); };", field(hasName("m"))));
+ EXPECT_TRUE(notMatches("class X { class m {}; };", field(hasName("m"))));
+ EXPECT_TRUE(notMatches("class X { enum { m }; };", field(hasName("m"))));
+ EXPECT_TRUE(notMatches("class X { enum m {}; };", field(hasName("m"))));
+}
+
+TEST(Field, MatchesField) {
+ EXPECT_TRUE(matches("class X { int m; };", field(hasName("m"))));
+}
+
+TEST(IsConstQualified, MatchesConstInt) {
+ EXPECT_TRUE(matches("const int i = 42;",
+ variable(hasType(isConstQualified()))));
+}
+
+TEST(IsConstQualified, MatchesConstPointer) {
+ EXPECT_TRUE(matches("int i = 42; int* const p(&i);",
+ variable(hasType(isConstQualified()))));
+}
+
+TEST(IsConstQualified, MatchesThroughTypedef) {
+ EXPECT_TRUE(matches("typedef const int const_int; const_int i = 42;",
+ variable(hasType(isConstQualified()))));
+ EXPECT_TRUE(matches("typedef int* int_ptr; const int_ptr p(0);",
+ variable(hasType(isConstQualified()))));
+}
+
+TEST(IsConstQualified, DoesNotMatchInappropriately) {
+ EXPECT_TRUE(notMatches("typedef int nonconst_int; nonconst_int i = 42;",
+ variable(hasType(isConstQualified()))));
+ EXPECT_TRUE(notMatches("int const* p;",
+ variable(hasType(isConstQualified()))));
+}
+
+TEST(ReinterpretCast, MatchesSimpleCase) {
+ EXPECT_TRUE(matches("char* p = reinterpret_cast<char*>(&p);",
+ expression(reinterpretCast())));
+}
+
+TEST(ReinterpretCast, DoesNotMatchOtherCasts) {
+ EXPECT_TRUE(notMatches("char* p = (char*)(&p);",
+ expression(reinterpretCast())));
+ EXPECT_TRUE(notMatches("char q, *p = const_cast<char*>(&q);",
+ expression(reinterpretCast())));
+ EXPECT_TRUE(notMatches("void* p = static_cast<void*>(&p);",
+ expression(reinterpretCast())));
+ EXPECT_TRUE(notMatches("struct B { virtual ~B() {} }; struct D : B {};"
+ "B b;"
+ "D* p = dynamic_cast<D*>(&b);",
+ expression(reinterpretCast())));
+}
+
+TEST(FunctionalCast, MatchesSimpleCase) {
+ std::string foo_class = "class Foo { public: Foo(char*); };";
+ EXPECT_TRUE(matches(foo_class + "void r() { Foo f = Foo(\"hello world\"); }",
+ expression(functionalCast())));
+}
+
+TEST(FunctionalCast, DoesNotMatchOtherCasts) {
+ std::string FooClass = "class Foo { public: Foo(char*); };";
+ EXPECT_TRUE(
+ notMatches(FooClass + "void r() { Foo f = (Foo) \"hello world\"; }",
+ expression(functionalCast())));
+ EXPECT_TRUE(
+ notMatches(FooClass + "void r() { Foo f = \"hello world\"; }",
+ expression(functionalCast())));
+}
+
+TEST(DynamicCast, MatchesSimpleCase) {
+ EXPECT_TRUE(matches("struct B { virtual ~B() {} }; struct D : B {};"
+ "B b;"
+ "D* p = dynamic_cast<D*>(&b);",
+ expression(dynamicCast())));
+}
+
+TEST(StaticCast, MatchesSimpleCase) {
+ EXPECT_TRUE(matches("void* p(static_cast<void*>(&p));",
+ expression(staticCast())));
+}
+
+TEST(StaticCast, DoesNotMatchOtherCasts) {
+ EXPECT_TRUE(notMatches("char* p = (char*)(&p);",
+ expression(staticCast())));
+ EXPECT_TRUE(notMatches("char q, *p = const_cast<char*>(&q);",
+ expression(staticCast())));
+ EXPECT_TRUE(notMatches("void* p = reinterpret_cast<char*>(&p);",
+ expression(staticCast())));
+ EXPECT_TRUE(notMatches("struct B { virtual ~B() {} }; struct D : B {};"
+ "B b;"
+ "D* p = dynamic_cast<D*>(&b);",
+ expression(staticCast())));
+}
+
+TEST(HasDestinationType, MatchesSimpleCase) {
+ EXPECT_TRUE(matches("char* p = static_cast<char*>(0);",
+ expression(
+ staticCast(hasDestinationType(
+ pointsTo(TypeMatcher(anything())))))));
+}
+
+TEST(HasSourceExpression, MatchesSimpleCase) {
+ EXPECT_TRUE(matches("class string {}; class URL { public: URL(string s); };"
+ "void r() {string a_string; URL url = a_string; }",
+ expression(implicitCast(
+ hasSourceExpression(constructorCall())))));
+}
+
+TEST(Statement, DoesNotMatchDeclarations) {
+ EXPECT_TRUE(notMatches("class X {};", statement()));
+}
+
+TEST(Statement, MatchesCompoundStatments) {
+ EXPECT_TRUE(matches("void x() {}", statement()));
+}
+
+TEST(DeclarationStatement, DoesNotMatchCompoundStatements) {
+ EXPECT_TRUE(notMatches("void x() {}", declarationStatement()));
+}
+
+TEST(DeclarationStatement, MatchesVariableDeclarationStatements) {
+ EXPECT_TRUE(matches("void x() { int a; }", declarationStatement()));
+}
+
+TEST(While, MatchesWhileLoops) {
+ EXPECT_TRUE(notMatches("void x() {}", whileStmt()));
+ EXPECT_TRUE(matches("void x() { while(true); }", whileStmt()));
+ EXPECT_TRUE(notMatches("void x() { do {} while(true); }", whileStmt()));
+}
+
+TEST(Do, MatchesDoLoops) {
+ EXPECT_TRUE(matches("void x() { do {} while(true); }", doStmt()));
+ EXPECT_TRUE(matches("void x() { do ; while(false); }", doStmt()));
+}
+
+TEST(Do, DoesNotMatchWhileLoops) {
+ EXPECT_TRUE(notMatches("void x() { while(true) {} }", doStmt()));
+}
+
+TEST(SwitchCase, MatchesCase) {
+ EXPECT_TRUE(matches("void x() { switch(42) { case 42:; } }", switchCase()));
+ EXPECT_TRUE(matches("void x() { switch(42) { default:; } }", switchCase()));
+ EXPECT_TRUE(matches("void x() { switch(42) default:; }", switchCase()));
+ EXPECT_TRUE(notMatches("void x() { switch(42) {} }", switchCase()));
+}
+
+TEST(HasConditionVariableStatement, DoesNotMatchCondition) {
+ EXPECT_TRUE(notMatches(
+ "void x() { if(true) {} }",
+ ifStmt(hasConditionVariableStatement(declarationStatement()))));
+ EXPECT_TRUE(notMatches(
+ "void x() { int x; if((x = 42)) {} }",
+ ifStmt(hasConditionVariableStatement(declarationStatement()))));
+}
+
+TEST(HasConditionVariableStatement, MatchesConditionVariables) {
+ EXPECT_TRUE(matches(
+ "void x() { if(int* a = 0) {} }",
+ ifStmt(hasConditionVariableStatement(declarationStatement()))));
+}
+
+TEST(ForEach, BindsOneNode) {
+ EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; };",
+ record(hasName("C"), forEach(id("x", field(hasName("x"))))),
+ new VerifyIdIsBoundToDecl<clang::FieldDecl>("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<clang::FieldDecl>("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<clang::FieldDecl>("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<clang::FieldDecl>("x", 1)));
+}
+
+TEST(ForEachDescendant, BindsMultipleNodes) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "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<clang::FieldDecl>("f", 4)));
+}
+
+TEST(ForEachDescendant, BindsRecursiveCombinations) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class C { class D { "
+ " class E { class F { class G { int y; int z; }; }; }; }; };",
+ record(hasName("C"), forEachDescendant(record(
+ forEachDescendant(id("f", field()))))),
+ new VerifyIdIsBoundToDecl<clang::FieldDecl>("f", 8)));
+}
+
+
+TEST(IsTemplateInstantiation, MatchesImplicitClassTemplateInstantiation) {
+ // Make sure that we can both match the class by name (::X) and by the type
+ // the template was instantiated with (via a field).
+
+ EXPECT_TRUE(matches(
+ "template <typename T> class X {}; class A {}; X<A> x;",
+ record(hasName("::X"), isTemplateInstantiation())));
+
+ EXPECT_TRUE(matches(
+ "template <typename T> class X { T t; }; class A {}; X<A> x;",
+ record(isTemplateInstantiation(), hasDescendant(
+ field(hasType(record(hasName("A"))))))));
+}
+
+TEST(IsTemplateInstantiation, MatchesImplicitFunctionTemplateInstantiation) {
+ EXPECT_TRUE(matches(
+ "template <typename T> void f(T t) {} class A {}; void g() { f(A()); }",
+ function(hasParameter(0, hasType(record(hasName("A")))),
+ isTemplateInstantiation())));
+}
+
+TEST(IsTemplateInstantiation, MatchesExplicitClassTemplateInstantiation) {
+ EXPECT_TRUE(matches(
+ "template <typename T> class X { T t; }; class A {};"
+ "template class X<A>;",
+ record(isTemplateInstantiation(), hasDescendant(
+ field(hasType(record(hasName("A"))))))));
+}
+
+TEST(IsTemplateInstantiation,
+ MatchesInstantiationOfPartiallySpecializedClassTemplate) {
+ EXPECT_TRUE(matches(
+ "template <typename T> class X {};"
+ "template <typename T> class X<T*> {}; class A {}; X<A*> x;",
+ record(hasName("::X"), isTemplateInstantiation())));
+}
+
+TEST(IsTemplateInstantiation,
+ MatchesInstantiationOfClassTemplateNestedInNonTemplate) {
+ EXPECT_TRUE(matches(
+ "class A {};"
+ "class X {"
+ " template <typename U> class Y { U u; };"
+ " Y<A> y;"
+ "};",
+ record(hasName("::X::Y"), isTemplateInstantiation())));
+}
+
+TEST(IsTemplateInstantiation, DoesNotMatchInstantiationsInsideOfInstantiation) {
+ // FIXME: Figure out whether this makes sense. It doesn't affect the
+ // normal use case as long as the uppermost instantiation always is marked
+ // as template instantiation, but it might be confusing as a predicate.
+ EXPECT_TRUE(matches(
+ "class A {};"
+ "template <typename T> class X {"
+ " template <typename U> class Y { U u; };"
+ " Y<T> y;"
+ "}; X<A> x;",
+ record(hasName("::X<A>::Y"), unless(isTemplateInstantiation()))));
+}
+
+TEST(IsTemplateInstantiation, DoesNotMatchExplicitClassTemplateSpecialization) {
+ EXPECT_TRUE(notMatches(
+ "template <typename T> class X {}; class A {};"
+ "template <> class X<A> {}; X<A> x;",
+ record(hasName("::X"), isTemplateInstantiation())));
+}
+
+TEST(IsTemplateInstantiation, DoesNotMatchNonTemplate) {
+ EXPECT_TRUE(notMatches(
+ "class A {}; class Y { A a; };",
+ record(isTemplateInstantiation())));
+}
+
+} // end namespace ast_matchers
+} // end namespace clang
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
new file mode 100644
index 0000000000..64816f5d60
--- /dev/null
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -0,0 +1,128 @@
+//===- unittest/Tooling/ASTMatchersTest.h - Matcher tests helpers ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H
+#define LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H
+
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_matchers {
+
+using clang::tooling::newFrontendActionFactory;
+using clang::tooling::runToolOnCode;
+using clang::tooling::FrontendActionFactory;
+
+class BoundNodesCallback {
+public:
+ virtual ~BoundNodesCallback() {}
+ virtual bool run(const BoundNodes *BoundNodes) = 0;
+};
+
+// If 'FindResultVerifier' is not NULL, sets *Verified to the result of
+// running 'FindResultVerifier' with the bound nodes as argument.
+// If 'FindResultVerifier' is NULL, sets *Verified to true when Run is called.
+class VerifyMatch : public MatchFinder::MatchCallback {
+public:
+ VerifyMatch(BoundNodesCallback *FindResultVerifier, bool *Verified)
+ : Verified(Verified), FindResultReviewer(FindResultVerifier) {}
+
+ virtual void run(const MatchFinder::MatchResult &Result) {
+ if (FindResultReviewer != NULL) {
+ *Verified = FindResultReviewer->run(&Result.Nodes);
+ } else {
+ *Verified = true;
+ }
+ }
+
+private:
+ bool *const Verified;
+ BoundNodesCallback *const FindResultReviewer;
+};
+
+template <typename T>
+testing::AssertionResult matchesConditionally(const std::string &Code,
+ const T &AMatcher,
+ bool ExpectMatch) {
+ bool Found = false;
+ MatchFinder Finder;
+ Finder.addMatcher(AMatcher, new VerifyMatch(0, &Found));
+ OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+ if (!runToolOnCode(Factory->create(), Code)) {
+ return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
+ }
+ if (!Found && ExpectMatch) {
+ return testing::AssertionFailure()
+ << "Could not find match in \"" << Code << "\"";
+ } else if (Found && !ExpectMatch) {
+ return testing::AssertionFailure()
+ << "Found unexpected match in \"" << Code << "\"";
+ }
+ return testing::AssertionSuccess();
+}
+
+template <typename T>
+testing::AssertionResult matches(const std::string &Code, const T &AMatcher) {
+ return matchesConditionally(Code, AMatcher, true);
+}
+
+template <typename T>
+testing::AssertionResult notMatches(const std::string &Code,
+ const T &AMatcher) {
+ return matchesConditionally(Code, AMatcher, false);
+}
+
+template <typename T>
+testing::AssertionResult
+matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
+ BoundNodesCallback *FindResultVerifier,
+ bool ExpectResult) {
+ llvm::OwningPtr<BoundNodesCallback> ScopedVerifier(FindResultVerifier);
+ bool VerifiedResult = false;
+ MatchFinder Finder;
+ Finder.addMatcher(
+ AMatcher, new VerifyMatch(FindResultVerifier, &VerifiedResult));
+ OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
+ if (!runToolOnCode(Factory->create(), Code)) {
+ return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
+ }
+ if (!VerifiedResult && ExpectResult) {
+ return testing::AssertionFailure()
+ << "Could not verify result in \"" << Code << "\"";
+ } else if (VerifiedResult && !ExpectResult) {
+ return testing::AssertionFailure()
+ << "Verified unexpected result in \"" << Code << "\"";
+ }
+ return testing::AssertionSuccess();
+}
+
+// FIXME: Find better names for these functions (or document what they
+// do more precisely).
+template <typename T>
+testing::AssertionResult
+matchAndVerifyResultTrue(const std::string &Code, const T &AMatcher,
+ BoundNodesCallback *FindResultVerifier) {
+ return matchAndVerifyResultConditionally(
+ Code, AMatcher, FindResultVerifier, true);
+}
+
+template <typename T>
+testing::AssertionResult
+matchAndVerifyResultFalse(const std::string &Code, const T &AMatcher,
+ BoundNodesCallback *FindResultVerifier) {
+ return matchAndVerifyResultConditionally(
+ Code, AMatcher, FindResultVerifier, false);
+}
+
+} // end namespace ast_matchers
+} // end namespace clang
+
+#endif // LLVM_CLANG_UNITTESTS_AST_MATCHERS_AST_MATCHERS_TEST_H
diff --git a/unittests/ASTMatchers/CMakeLists.txt b/unittests/ASTMatchers/CMakeLists.txt
new file mode 100644
index 0000000000..8e61732141
--- /dev/null
+++ b/unittests/ASTMatchers/CMakeLists.txt
@@ -0,0 +1,5 @@
+add_clang_unittest(ASTMatchersTests
+ ASTMatchersTest.cpp)
+
+target_link_libraries(ASTMatchersTests
+ gtest gtest_main clangASTMatchers clangTooling)
diff --git a/unittests/ASTMatchers/Makefile b/unittests/ASTMatchers/Makefile
new file mode 100644
index 0000000000..2448a056da
--- /dev/null
+++ b/unittests/ASTMatchers/Makefile
@@ -0,0 +1,19 @@
+##===- unittests/ASTMatchers/Makefile ----------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL = ../..
+PARALLEL_DIRS = Dynamic
+
+TESTNAME = ASTMatchers
+LINK_COMPONENTS := support mc
+USEDLIBS = clangEdit.a clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
+ clangRewrite.a clangParse.a clangSema.a clangAnalysis.a \
+ clangAST.a clangASTMatchers.a clangLex.a clangBasic.a
+
+include $(CLANG_LEVEL)/unittests/Makefile
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index 3dd927d9b9..aed97c3627 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -9,6 +9,7 @@ function(add_clang_unittest test_dirname)
add_unittest(ClangUnitTests ${test_dirname} ${ARGN})
endfunction()
+add_subdirectory(ASTMatchers)
add_subdirectory(Basic)
add_subdirectory(Lex)
add_subdirectory(Frontend)
diff --git a/unittests/Makefile b/unittests/Makefile
index b9f3c3f63d..f74820b649 100644
--- a/unittests/Makefile
+++ b/unittests/Makefile
@@ -14,7 +14,7 @@ ifndef CLANG_LEVEL
IS_UNITTEST_LEVEL := 1
CLANG_LEVEL := ..
-PARALLEL_DIRS = Basic AST Frontend Lex Tooling
+PARALLEL_DIRS = ASTMatchers Basic AST Frontend Lex Tooling
endif # CLANG_LEVEL