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