summaryrefslogtreecommitdiffstats
path: root/include/clang/ASTMatchers/ASTMatchers.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/ASTMatchers/ASTMatchers.h')
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h718
1 files changed, 440 insertions, 278 deletions
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index ab62dd0..0a3157d 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -45,6 +45,7 @@
#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H
#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_H
+#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/ASTMatchers/ASTMatchersInternal.h"
#include "clang/ASTMatchers/ASTMatchersMacros.h"
@@ -85,6 +86,16 @@ public:
}
/// @}
+ /// \brief Type of mapping from binding identifiers to bound nodes. This type
+ /// is an associative container with a key type of \c std::string and a value
+ /// type of \c clang::ast_type_traits::DynTypedNode
+ typedef internal::BoundNodesMap::IDToNodeMap IDToNodeMap;
+
+ /// \brief Retrieve mapping from binding identifiers to bound nodes.
+ const IDToNodeMap &getMap() const {
+ return MyBoundNodes.getMap();
+ }
+
private:
/// \brief Create BoundNodes from a pre-filled map of bindings.
BoundNodes(internal::BoundNodesMap &MyBoundNodes)
@@ -92,7 +103,7 @@ private:
internal::BoundNodesMap MyBoundNodes;
- friend class internal::BoundNodesTree;
+ friend class internal::BoundNodesTreeBuilder;
};
/// \brief If the provided matcher matches a node, binds the node to \c ID.
@@ -204,6 +215,28 @@ const internal::VariadicDynCastAllOfMatcher<
Decl,
ClassTemplateSpecializationDecl> classTemplateSpecializationDecl;
+/// \brief Matches declarator declarations (field, variable, function
+/// and non-type template parameter declarations).
+///
+/// Given
+/// \code
+/// class X { int y; };
+/// \endcode
+/// declaratorDecl()
+/// matches \c int y.
+const internal::VariadicDynCastAllOfMatcher<Decl, DeclaratorDecl>
+ declaratorDecl;
+
+/// \brief Matches parameter variable declarations.
+///
+/// Given
+/// \code
+/// void f(int x);
+/// \endcode
+/// parmVarDecl()
+/// matches \c int x.
+const internal::VariadicDynCastAllOfMatcher<Decl, ParmVarDecl> parmVarDecl;
+
/// \brief Matches C++ access specifier declarations.
///
/// Given
@@ -219,6 +252,17 @@ const internal::VariadicDynCastAllOfMatcher<
Decl,
AccessSpecDecl> accessSpecDecl;
+/// \brief Matches constructor initializers.
+///
+/// Examples matches \c i(42).
+/// \code
+/// class C {
+/// C() : i(42) {}
+/// int i;
+/// };
+/// \endcode
+const internal::VariadicAllOfMatcher<CXXCtorInitializer> ctorInitializer;
+
/// \brief Matches public C++ declarations.
///
/// Given
@@ -281,12 +325,9 @@ AST_MATCHER(Decl, isPrivate) {
/// matches the specialization \c A<int>
AST_MATCHER_P(ClassTemplateSpecializationDecl, hasAnyTemplateArgument,
internal::Matcher<TemplateArgument>, InnerMatcher) {
- const TemplateArgumentList &List = Node.getTemplateArgs();
- for (unsigned i = 0; i < List.size(); ++i) {
- if (InnerMatcher.matches(List.get(i), Finder, Builder))
- return true;
- }
- return false;
+ llvm::ArrayRef<TemplateArgument> List = Node.getTemplateArgs().asArray();
+ return matchesFirstInRange(InnerMatcher, List.begin(), List.end(), Finder,
+ Builder);
}
/// \brief Matches expressions that match InnerMatcher after any implicit casts
@@ -520,6 +561,16 @@ const internal::VariadicDynCastAllOfMatcher<
Decl,
FunctionTemplateDecl> functionTemplateDecl;
+/// \brief Matches friend declarations.
+///
+/// Given
+/// \code
+/// class X { friend void foo(); };
+/// \endcode
+/// friendDecl()
+/// matches 'friend void foo()'.
+const internal::VariadicDynCastAllOfMatcher<Decl, FriendDecl> friendDecl;
+
/// \brief Matches statements.
///
/// Given
@@ -607,6 +658,21 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, InitListExpr> initListExpr;
/// matches \code using X::x \endcode
const internal::VariadicDynCastAllOfMatcher<Decl, UsingDecl> usingDecl;
+/// \brief Matches unresolved using value declarations.
+///
+/// Given
+/// \code
+/// template<typename X>
+/// class C : private X {
+/// using X::x;
+/// };
+/// \endcode
+/// unresolvedUsingValueDecl()
+/// matches \code using X::x \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Decl,
+ UnresolvedUsingValueDecl> unresolvedUsingValueDecl;
+
/// \brief Matches constructor call expressions (including implicit ones).
///
/// Example matches string(ptr, n) and ptr within arguments of f
@@ -621,6 +687,18 @@ const internal::VariadicDynCastAllOfMatcher<
Stmt,
CXXConstructExpr> constructExpr;
+/// \brief Matches unresolved constructor call expressions.
+///
+/// Example matches T(t) in return statement of f
+/// (matcher = unresolvedConstructExpr())
+/// \code
+/// template <typename T>
+/// void f(const T& t) { return T(t); }
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ CXXUnresolvedConstructExpr> unresolvedConstructExpr;
+
/// \brief Matches implicit and explicit this expressions.
///
/// Example matches the implicit this expression in "return i".
@@ -894,6 +972,26 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchStmt> switchStmt;
/// matches 'case 42: break;' and 'default: break;'.
const internal::VariadicDynCastAllOfMatcher<Stmt, SwitchCase> switchCase;
+/// \brief Matches case statements inside switch statements.
+///
+/// Given
+/// \code
+/// switch(a) { case 42: break; default: break; }
+/// \endcode
+/// caseStmt()
+/// matches 'case 42: break;'.
+const internal::VariadicDynCastAllOfMatcher<Stmt, CaseStmt> caseStmt;
+
+/// \brief Matches default statements inside switch statements.
+///
+/// Given
+/// \code
+/// switch(a) { case 42: break; default: break; }
+/// \endcode
+/// defaultStmt()
+/// matches 'default: break;'.
+const internal::VariadicDynCastAllOfMatcher<Stmt, DefaultStmt> defaultStmt;
+
/// \brief Matches compound statements.
///
/// Example matches '{}' and '{{}}'in 'for (;;) {{}}'
@@ -981,15 +1079,25 @@ const internal::VariadicDynCastAllOfMatcher<
Stmt,
CharacterLiteral> characterLiteral;
-/// \brief Matches integer literals of all sizes / encodings.
-///
-/// Not matching character-encoded integers such as L'a'.
+/// \brief Matches integer literals of all sizes / encodings, e.g.
+/// 1, 1L, 0x1 and 1U.
///
-/// Example matches 1, 1L, 0x1, 1U
+/// Does not match character-encoded integers such as L'a'.
const internal::VariadicDynCastAllOfMatcher<
Stmt,
IntegerLiteral> integerLiteral;
+/// \brief Matches float literals of all sizes / encodings, e.g.
+/// 1.0, 1.0f, 1.0L and 1e10.
+///
+/// Does not match implicit conversions such as
+/// \code
+/// float a = 10;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ FloatingLiteral> floatLiteral;
+
/// \brief Matches user defined literal operator call.
///
/// Example match: "foo"_suffix
@@ -1171,6 +1279,16 @@ const internal::VariadicDynCastAllOfMatcher<
Stmt,
CXXFunctionalCastExpr> functionalCastExpr;
+/// \brief Matches functional cast expressions having N != 1 arguments
+///
+/// Example: Matches Foo(bar, bar)
+/// \code
+/// Foo h = Foo(bar, bar);
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ CXXTemporaryObjectExpr> temporaryObjectExpr;
+
/// \brief Matches \c QualTypes in the clang AST.
const internal::VariadicAllOfMatcher<QualType> qualType;
@@ -1199,93 +1317,23 @@ const internal::VariadicAllOfMatcher<TypeLoc> typeLoc;
/// \c b.
///
/// Usable as: Any Matcher
-template <typename M1, typename M2>
-internal::PolymorphicMatcherWithParam2<internal::EachOfMatcher, M1, M2>
-eachOf(const M1 &P1, const M2 &P2) {
- return internal::PolymorphicMatcherWithParam2<internal::EachOfMatcher, M1,
- M2>(P1, P2);
-}
-
-/// \brief Various overloads for the anyOf matcher.
-/// @{
+const internal::VariadicOperatorMatcherFunc eachOf = {
+ internal::EachOfVariadicOperator
+};
/// \brief Matches if any of the given matchers matches.
///
/// Usable as: Any Matcher
-template<typename M1, typename M2>
-internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M1, M2>
-anyOf(const M1 &P1, const M2 &P2) {
- return internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher,
- M1, M2 >(P1, P2);
-}
-template<typename M1, typename M2, typename M3>
-internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M1,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M2, M3> >
-anyOf(const M1 &P1, const M2 &P2, const M3 &P3) {
- return anyOf(P1, anyOf(P2, P3));
-}
-template<typename M1, typename M2, typename M3, typename M4>
-internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M1,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M2,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher,
- M3, M4> > >
-anyOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) {
- return anyOf(P1, anyOf(P2, anyOf(P3, P4)));
-}
-template<typename M1, typename M2, typename M3, typename M4, typename M5>
-internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M1,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M2,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher, M3,
- internal::PolymorphicMatcherWithParam2<internal::AnyOfMatcher,
- M4, M5> > > >
-anyOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5) {
- return anyOf(P1, anyOf(P2, anyOf(P3, anyOf(P4, P5))));
-}
-
-/// @}
-
-/// \brief Various overloads for the allOf matcher.
-/// @{
+const internal::VariadicOperatorMatcherFunc anyOf = {
+ internal::AnyOfVariadicOperator
+};
/// \brief Matches if all given matchers match.
///
/// Usable as: Any Matcher
-template <typename M1, typename M2>
-internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M1, M2>
-allOf(const M1 &P1, const M2 &P2) {
- return internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M1, M2>(
- P1, P2);
-}
-template <typename M1, typename M2, typename M3>
-internal::PolymorphicMatcherWithParam2<
- internal::AllOfMatcher, M1,
- internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M2, M3> >
-allOf(const M1 &P1, const M2 &P2, const M3 &P3) {
- return allOf(P1, allOf(P2, P3));
-}
-template <typename M1, typename M2, typename M3, typename M4>
-internal::PolymorphicMatcherWithParam2<
- internal::AllOfMatcher, M1,
- internal::PolymorphicMatcherWithParam2<
- internal::AllOfMatcher, M2, internal::PolymorphicMatcherWithParam2<
- internal::AllOfMatcher, M3, M4> > >
-allOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) {
- return allOf(P1, allOf(P2, P3, P4));
-}
-template <typename M1, typename M2, typename M3, typename M4, typename M5>
-internal::PolymorphicMatcherWithParam2<
- internal::AllOfMatcher, M1,
- internal::PolymorphicMatcherWithParam2<
- internal::AllOfMatcher, M2,
- internal::PolymorphicMatcherWithParam2<
- internal::AllOfMatcher, M3,
- internal::PolymorphicMatcherWithParam2<internal::AllOfMatcher, M4,
- M5> > > >
-allOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5) {
- return allOf(P1, allOf(P2, P3, P4, P5));
-}
-
-/// @}
+const internal::VariadicOperatorMatcherFunc allOf = {
+ internal::AllOfVariadicOperator
+};
/// \brief Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
///
@@ -1412,10 +1460,13 @@ AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) {
///
/// Usable as: Matcher<CXXOperatorCallExpr>, Matcher<CXXMethodDecl>
inline internal::PolymorphicMatcherWithParam1<
- internal::HasOverloadedOperatorNameMatcher, StringRef>
+ internal::HasOverloadedOperatorNameMatcher, StringRef,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, CXXMethodDecl)>
hasOverloadedOperatorName(const StringRef Name) {
return internal::PolymorphicMatcherWithParam1<
- internal::HasOverloadedOperatorNameMatcher, StringRef>(Name);
+ internal::HasOverloadedOperatorNameMatcher, StringRef,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_2(CXXOperatorCallExpr, CXXMethodDecl)>(
+ Name);
}
/// \brief Matches C++ classes that are directly or indirectly derived from
@@ -1445,24 +1496,25 @@ AST_MATCHER_P(CXXRecordDecl, isDerivedFrom,
}
/// \brief Overloaded method as shortcut for \c isDerivedFrom(hasName(...)).
-inline internal::Matcher<CXXRecordDecl> isDerivedFrom(StringRef BaseName) {
+AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDerivedFrom, StringRef, BaseName, 1) {
assert(!BaseName.empty());
- return isDerivedFrom(hasName(BaseName));
+ return isDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
}
/// \brief Similar to \c isDerivedFrom(), but also matches classes that directly
/// match \c Base.
-inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom(
- internal::Matcher<NamedDecl> Base) {
- return anyOf(Base, isDerivedFrom(Base));
+AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom,
+ internal::Matcher<NamedDecl>, Base, 0) {
+ return Matcher<CXXRecordDecl>(anyOf(Base, isDerivedFrom(Base)))
+ .matches(Node, Finder, Builder);
}
/// \brief Overloaded method as shortcut for
/// \c isSameOrDerivedFrom(hasName(...)).
-inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom(
- StringRef BaseName) {
+AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, StringRef, BaseName,
+ 1) {
assert(!BaseName.empty());
- return isSameOrDerivedFrom(hasName(BaseName));
+ return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
}
/// \brief Matches the first method of a class or struct that satisfies \c
@@ -1478,12 +1530,8 @@ inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom(
/// but not \c B.
AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher<CXXMethodDecl>,
InnerMatcher) {
- for (CXXRecordDecl::method_iterator I = Node.method_begin(),
- E = Node.method_end();
- I != E; ++I)
- if (InnerMatcher.matches(**I, Finder, Builder))
- return true;
- return false;
+ return matchesFirstInPointerRange(InnerMatcher, Node.method_begin(),
+ Node.method_end(), Finder, Builder);
}
/// \brief Matches AST nodes that have child AST nodes that match the
@@ -1499,12 +1547,8 @@ AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher<CXXMethodDecl>,
/// ChildT must be an AST base type.
///
/// Usable as: Any Matcher
-template <typename ChildT>
-internal::ArgumentAdaptingMatcher<internal::HasMatcher, ChildT> has(
- const internal::Matcher<ChildT> &ChildMatcher) {
- return internal::ArgumentAdaptingMatcher<internal::HasMatcher,
- ChildT>(ChildMatcher);
-}
+const internal::ArgumentAdaptingMatcherFunc<internal::HasMatcher>
+LLVM_ATTRIBUTE_UNUSED has = {};
/// \brief Matches AST nodes that have descendant AST nodes that match the
/// provided matcher.
@@ -1520,13 +1564,8 @@ internal::ArgumentAdaptingMatcher<internal::HasMatcher, ChildT> has(
/// DescendantT must be an AST base type.
///
/// Usable as: Any Matcher
-template <typename DescendantT>
-internal::ArgumentAdaptingMatcher<internal::HasDescendantMatcher, DescendantT>
-hasDescendant(const internal::Matcher<DescendantT> &DescendantMatcher) {
- return internal::ArgumentAdaptingMatcher<
- internal::HasDescendantMatcher,
- DescendantT>(DescendantMatcher);
-}
+const internal::ArgumentAdaptingMatcherFunc<internal::HasDescendantMatcher>
+LLVM_ATTRIBUTE_UNUSED hasDescendant = {};
/// \brief Matches AST nodes that have child AST nodes that match the
/// provided matcher.
@@ -1544,13 +1583,8 @@ hasDescendant(const internal::Matcher<DescendantT> &DescendantMatcher) {
/// matches instead of only on the first one.
///
/// Usable as: Any Matcher
-template <typename ChildT>
-internal::ArgumentAdaptingMatcher<internal::ForEachMatcher, ChildT> forEach(
- const internal::Matcher<ChildT> &ChildMatcher) {
- return internal::ArgumentAdaptingMatcher<
- internal::ForEachMatcher,
- ChildT>(ChildMatcher);
-}
+const internal::ArgumentAdaptingMatcherFunc<internal::ForEachMatcher>
+LLVM_ATTRIBUTE_UNUSED forEach = {};
/// \brief Matches AST nodes that have descendant AST nodes that match the
/// provided matcher.
@@ -1576,15 +1610,8 @@ internal::ArgumentAdaptingMatcher<internal::ForEachMatcher, ChildT> forEach(
/// \endcode
///
/// Usable as: Any Matcher
-template <typename DescendantT>
-internal::ArgumentAdaptingMatcher<internal::ForEachDescendantMatcher,
- DescendantT>
-forEachDescendant(
- const internal::Matcher<DescendantT> &DescendantMatcher) {
- return internal::ArgumentAdaptingMatcher<
- internal::ForEachDescendantMatcher,
- DescendantT>(DescendantMatcher);
-}
+const internal::ArgumentAdaptingMatcherFunc<internal::ForEachDescendantMatcher>
+LLVM_ATTRIBUTE_UNUSED forEachDescendant = {};
/// \brief Matches if the node or any descendant matches.
///
@@ -1602,10 +1629,7 @@ forEachDescendant(
///
/// Usable as: Any Matcher
template <typename T>
-internal::PolymorphicMatcherWithParam2<
- internal::EachOfMatcher, internal::Matcher<T>,
- internal::ArgumentAdaptingMatcher<internal::ForEachDescendantMatcher, T> >
-findAll(const internal::Matcher<T> &Matcher) {
+internal::Matcher<T> findAll(const internal::Matcher<T> &Matcher) {
return eachOf(Matcher, forEachDescendant(Matcher));
}
@@ -1619,13 +1643,9 @@ findAll(const internal::Matcher<T> &Matcher) {
/// \c compoundStmt(hasParent(ifStmt())) matches "{ int x = 43; }".
///
/// Usable as: Any Matcher
-template <typename ParentT>
-internal::ArgumentAdaptingMatcher<internal::HasParentMatcher, ParentT>
-hasParent(const internal::Matcher<ParentT> &ParentMatcher) {
- return internal::ArgumentAdaptingMatcher<
- internal::HasParentMatcher,
- ParentT>(ParentMatcher);
-}
+const internal::ArgumentAdaptingMatcherFunc<
+ internal::HasParentMatcher, internal::TypeList<Decl, Stmt>,
+ internal::TypeList<Decl, Stmt> > LLVM_ATTRIBUTE_UNUSED hasParent = {};
/// \brief Matches AST nodes that have an ancestor that matches the provided
/// matcher.
@@ -1638,13 +1658,9 @@ hasParent(const internal::Matcher<ParentT> &ParentMatcher) {
/// \c expr(integerLiteral(hasAncestor(ifStmt()))) matches \c 42, but not 43.
///
/// Usable as: Any Matcher
-template <typename AncestorT>
-internal::ArgumentAdaptingMatcher<internal::HasAncestorMatcher, AncestorT>
-hasAncestor(const internal::Matcher<AncestorT> &AncestorMatcher) {
- return internal::ArgumentAdaptingMatcher<
- internal::HasAncestorMatcher,
- AncestorT>(AncestorMatcher);
-}
+const internal::ArgumentAdaptingMatcherFunc<
+ internal::HasAncestorMatcher, internal::TypeList<Decl, Stmt>,
+ internal::TypeList<Decl, Stmt> > LLVM_ATTRIBUTE_UNUSED hasAncestor = {};
/// \brief Matches if the provided matcher does not match.
///
@@ -1662,22 +1678,31 @@ unless(const M &InnerMatcher) {
internal::NotMatcher, M>(InnerMatcher);
}
-/// \brief Matches a type if the declaration of the type matches the given
-/// matcher.
+/// \brief Matches a node if the declaration associated with that node
+/// matches the given matcher.
+///
+/// The associated declaration is:
+/// - for type nodes, the declaration of the underlying type
+/// - for CallExpr, the declaration of the callee
+/// - for MemberExpr, the declaration of the referenced member
+/// - for CXXConstructExpr, the declaration of the constructor
///
-/// In addition to being usable as Matcher<TypedefType>, also usable as
-/// Matcher<T> for any T supporting the getDecl() member function. e.g. various
-/// subtypes of clang::Type.
+/// Also usable as Matcher<T> for any T supporting the getDecl() member
+/// function. e.g. various subtypes of clang::Type and various expressions.
///
-/// Usable as: Matcher<QualType>, Matcher<CallExpr>, Matcher<CXXConstructExpr>,
-/// Matcher<MemberExpr>, Matcher<TypedefType>,
-/// Matcher<TemplateSpecializationType>
-inline internal::PolymorphicMatcherWithParam1< internal::HasDeclarationMatcher,
- internal::Matcher<Decl> >
- hasDeclaration(const internal::Matcher<Decl> &InnerMatcher) {
+/// Usable as: Matcher<CallExpr>, Matcher<CXXConstructExpr>,
+/// Matcher<DeclRefExpr>, Matcher<EnumType>, Matcher<InjectedClassNameType>,
+/// Matcher<LabelStmt>, Matcher<MemberExpr>, Matcher<QualType>,
+/// Matcher<RecordType>, Matcher<TagType>,
+/// Matcher<TemplateSpecializationType>, Matcher<TemplateTypeParmType>,
+/// Matcher<TypedefType>, Matcher<UnresolvedUsingType>
+inline internal::PolymorphicMatcherWithParam1<
+ internal::HasDeclarationMatcher, internal::Matcher<Decl>,
+ void(internal::HasDeclarationSupportedTypes)>
+hasDeclaration(const internal::Matcher<Decl> &InnerMatcher) {
return internal::PolymorphicMatcherWithParam1<
- internal::HasDeclarationMatcher,
- internal::Matcher<Decl> >(InnerMatcher);
+ internal::HasDeclarationMatcher, internal::Matcher<Decl>,
+ void(internal::HasDeclarationSupportedTypes)>(InnerMatcher);
}
/// \brief Matches on the implicit object argument of a member call expression.
@@ -1728,9 +1753,9 @@ AST_MATCHER_P(CallExpr, callee, internal::Matcher<Stmt>,
/// class Y { public: void x(); };
/// void z() { Y y; y.x();
/// \endcode
-inline internal::Matcher<CallExpr> callee(
- const internal::Matcher<Decl> &InnerMatcher) {
- return callExpr(hasDeclaration(InnerMatcher));
+AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher,
+ 1) {
+ return callExpr(hasDeclaration(InnerMatcher)).matches(Node, Finder, Builder);
}
/// \brief Matches if the expression's or declaration's type matches a type
@@ -1742,11 +1767,9 @@ inline internal::Matcher<CallExpr> callee(
/// class X {};
/// void y(X &x) { x; X z; }
/// \endcode
-AST_POLYMORPHIC_MATCHER_P(hasType, internal::Matcher<QualType>,
- InnerMatcher) {
- TOOLING_COMPILE_ASSERT((llvm::is_base_of<Expr, NodeType>::value ||
- llvm::is_base_of<ValueDecl, NodeType>::value),
- instantiated_with_wrong_types);
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+ hasType, AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl),
+ internal::Matcher<QualType>, InnerMatcher, 0) {
return InnerMatcher.matches(Node.getType(), Finder, Builder);
}
@@ -1767,11 +1790,27 @@ AST_POLYMORPHIC_MATCHER_P(hasType, internal::Matcher<QualType>,
/// \endcode
///
/// Usable as: Matcher<Expr>, Matcher<ValueDecl>
-inline internal::PolymorphicMatcherWithParam1<
- internal::matcher_hasType0Matcher,
- internal::Matcher<QualType> >
-hasType(const internal::Matcher<Decl> &InnerMatcher) {
- return hasType(qualType(hasDeclaration(InnerMatcher)));
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+ hasType, AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl),
+ internal::Matcher<Decl>, InnerMatcher, 1) {
+ return qualType(hasDeclaration(InnerMatcher))
+ .matches(Node.getType(), Finder, Builder);
+}
+
+/// \brief Matches if the type location of the declarator decl's type matches
+/// the inner matcher.
+///
+/// Given
+/// \code
+/// int x;
+/// \endcode
+/// declaratorDecl(hasTypeLoc(loc(asString("int"))))
+/// matches int x
+AST_MATCHER_P(DeclaratorDecl, hasTypeLoc, internal::Matcher<TypeLoc>, Inner) {
+ if (!Node.getTypeSourceInfo())
+ // This happens for example for implicit destructors.
+ return false;
+ return Inner.matches(Node.getTypeSourceInfo()->getTypeLoc(), Finder, Builder);
}
/// \brief Matches if the matched type is represented by the given string.
@@ -1804,9 +1843,10 @@ AST_MATCHER_P(
}
/// \brief Overloaded to match the pointee type's declaration.
-inline internal::Matcher<QualType> pointsTo(
- const internal::Matcher<Decl> &InnerMatcher) {
- return pointsTo(qualType(hasDeclaration(InnerMatcher)));
+AST_MATCHER_P_OVERLOAD(QualType, pointsTo, internal::Matcher<Decl>,
+ InnerMatcher, 1) {
+ return pointsTo(qualType(hasDeclaration(InnerMatcher)))
+ .matches(Node, Finder, Builder);
}
/// \brief Matches if the matched type is a reference type and the referenced
@@ -1841,13 +1881,16 @@ AST_MATCHER_P(QualType, references, internal::Matcher<QualType>,
/// varDecl(hasType(qualType(hasCanonicalType(referenceType())))))) does.
AST_MATCHER_P(QualType, hasCanonicalType, internal::Matcher<QualType>,
InnerMatcher) {
+ if (Node.isNull())
+ return false;
return InnerMatcher.matches(Node.getCanonicalType(), Finder, Builder);
}
/// \brief Overloaded to match the referenced type's declaration.
-inline internal::Matcher<QualType> references(
- const internal::Matcher<Decl> &InnerMatcher) {
- return references(qualType(hasDeclaration(InnerMatcher)));
+AST_MATCHER_P_OVERLOAD(QualType, references, internal::Matcher<Decl>,
+ InnerMatcher, 1) {
+ return references(qualType(hasDeclaration(InnerMatcher)))
+ .matches(Node, Finder, Builder);
}
AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument,
@@ -1859,17 +1902,19 @@ AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument,
/// \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<CXXMemberCallExpr> thisPointerType(
- const internal::Matcher<QualType> &InnerMatcher) {
+AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType,
+ internal::Matcher<QualType>, InnerMatcher, 0) {
return onImplicitObjectArgument(
- anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))));
+ anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))))
+ .matches(Node, Finder, Builder);
}
/// \brief Overloaded to match the type's declaration.
-inline internal::Matcher<CXXMemberCallExpr> thisPointerType(
- const internal::Matcher<Decl> &InnerMatcher) {
+AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType,
+ internal::Matcher<Decl>, InnerMatcher, 1) {
return onImplicitObjectArgument(
- anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))));
+ anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))))
+ .matches(Node, Finder, Builder);
}
/// \brief Matches a DeclRefExpr that refers to a declaration that matches the
@@ -1953,11 +1998,9 @@ AST_MATCHER_P(
/// void f(int x, int y);
/// f(0, 0);
/// \endcode
-AST_POLYMORPHIC_MATCHER_P(argumentCountIs, unsigned, N) {
- TOOLING_COMPILE_ASSERT((llvm::is_base_of<CallExpr, NodeType>::value ||
- llvm::is_base_of<CXXConstructExpr,
- NodeType>::value),
- instantiated_with_wrong_types);
+AST_POLYMORPHIC_MATCHER_P(argumentCountIs, AST_POLYMORPHIC_SUPPORTED_TYPES_2(
+ CallExpr, CXXConstructExpr),
+ unsigned, N) {
return Node.getNumArgs() == N;
}
@@ -1970,11 +2013,9 @@ AST_POLYMORPHIC_MATCHER_P(argumentCountIs, unsigned, N) {
/// void x(int) { int y; x(y); }
/// \endcode
AST_POLYMORPHIC_MATCHER_P2(
- 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);
+ hasArgument,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_2(CallExpr, CXXConstructExpr),
+ unsigned, N, internal::Matcher<Expr>, InnerMatcher) {
return (N < Node.getNumArgs() &&
InnerMatcher.matches(
*Node.getArg(N)->IgnoreParenImpCasts(), Finder, Builder));
@@ -2037,13 +2078,8 @@ AST_MATCHER_P2(DeclStmt, containsDeclaration, unsigned, N,
/// 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;
- }
- }
- return false;
+ return matchesFirstInPointerRange(InnerMatcher, Node.init_begin(),
+ Node.init_end(), Finder, Builder);
}
/// \brief Matches the field declaration of a constructor initializer.
@@ -2086,7 +2122,7 @@ AST_MATCHER_P(CXXCtorInitializer, withInitializer,
InnerMatcher.matches(*NodeAsExpr, Finder, Builder));
}
-/// \brief Matches a contructor initializer if it is explicitly written in
+/// \brief Matches a constructor initializer if it is explicitly written in
/// code (as opposed to implicitly added by the compiler).
///
/// Given
@@ -2120,15 +2156,19 @@ AST_MATCHER(CXXConstructorDecl, isImplicit) {
/// matches x(1, y, 42)
/// with hasAnyArgument(...)
/// matching y
-AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, 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);
+///
+/// FIXME: Currently this will ignore parentheses and implicit casts on
+/// the argument before applying the inner matcher. We'll want to remove
+/// this to allow for greater control by the user once \c ignoreImplicit()
+/// has been implemented.
+AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, AST_POLYMORPHIC_SUPPORTED_TYPES_2(
+ CallExpr, CXXConstructExpr),
+ internal::Matcher<Expr>, InnerMatcher) {
for (unsigned I = 0; I < Node.getNumArgs(); ++I) {
- if (InnerMatcher.matches(*Node.getArg(I)->IgnoreParenImpCasts(),
- Finder, Builder)) {
+ BoundNodesTreeBuilder Result(*Builder);
+ if (InnerMatcher.matches(*Node.getArg(I)->IgnoreParenImpCasts(), Finder,
+ &Result)) {
+ *Builder = Result;
return true;
}
}
@@ -2167,12 +2207,8 @@ AST_MATCHER_P2(FunctionDecl, hasParameter,
/// matching int y
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;
- }
- }
- return false;
+ return matchesFirstInPointerRange(InnerMatcher, Node.param_begin(),
+ Node.param_end(), Finder, Builder);
}
/// \brief Matches \c FunctionDecls that have a specific parameter count.
@@ -2222,27 +2258,68 @@ AST_MATCHER(FunctionDecl, isExternC) {
/// \code
/// if (true) {}
/// \endcode
-AST_POLYMORPHIC_MATCHER_P(hasCondition, internal::Matcher<Expr>,
- InnerMatcher) {
- TOOLING_COMPILE_ASSERT(
- (llvm::is_base_of<IfStmt, NodeType>::value) ||
- (llvm::is_base_of<ForStmt, NodeType>::value) ||
- (llvm::is_base_of<WhileStmt, NodeType>::value) ||
- (llvm::is_base_of<DoStmt, NodeType>::value) ||
- (llvm::is_base_of<ConditionalOperator, NodeType>::value),
- has_condition_requires_if_statement_conditional_operator_or_loop);
+AST_POLYMORPHIC_MATCHER_P(
+ hasCondition, AST_POLYMORPHIC_SUPPORTED_TYPES_5(
+ IfStmt, ForStmt, WhileStmt, DoStmt, ConditionalOperator),
+ internal::Matcher<Expr>, InnerMatcher) {
const Expr *const Condition = Node.getCond();
return (Condition != NULL &&
InnerMatcher.matches(*Condition, Finder, Builder));
}
+namespace internal {
+struct NotEqualsBoundNodePredicate {
+ bool operator()(const internal::BoundNodesMap &Nodes) const {
+ return Nodes.getNode(ID) != Node;
+ }
+ std::string ID;
+ ast_type_traits::DynTypedNode Node;
+};
+} // namespace internal
+
+/// \brief Matches if a node equals a previously bound node.
+///
+/// Matches a node if it equals the node previously bound to \p ID.
+///
+/// Given
+/// \code
+/// class X { int a; int b; };
+/// \endcode
+/// recordDecl(
+/// has(fieldDecl(hasName("a"), hasType(type().bind("t")))),
+/// has(fieldDecl(hasName("b"), hasType(type(equalsBoundNode("t"))))))
+/// matches the class \c X, as \c a and \c b have the same type.
+///
+/// Note that when multiple matches are involved via \c forEach* matchers,
+/// \c equalsBoundNodes acts as a filter.
+/// For example:
+/// compoundStmt(
+/// forEachDescendant(varDecl().bind("d")),
+/// forEachDescendant(declRefExpr(to(decl(equalsBoundNode("d"))))))
+/// will trigger a match for each combination of variable declaration
+/// and reference to that variable declaration within a compound statement.
+AST_POLYMORPHIC_MATCHER_P(equalsBoundNode, AST_POLYMORPHIC_SUPPORTED_TYPES_4(
+ Stmt, Decl, Type, QualType),
+ std::string, ID) {
+ // FIXME: Figure out whether it makes sense to allow this
+ // on any other node types.
+ // For *Loc it probably does not make sense, as those seem
+ // unique. For NestedNameSepcifier it might make sense, as
+ // those also have pointer identity, but I'm not sure whether
+ // they're ever reused.
+ internal::NotEqualsBoundNodePredicate Predicate;
+ Predicate.ID = ID;
+ Predicate.Node = ast_type_traits::DynTypedNode::create(Node);
+ return Builder->removeBindings(Predicate);
+}
+
/// \brief Matches the condition variable statement in an if statement.
///
/// Given
/// \code
/// if (A* a = GetAPointer()) {}
/// \endcode
-/// hasConditionVariableStatment(...)
+/// hasConditionVariableStatement(...)
/// matches 'A* a = GetAPointer()'.
AST_MATCHER_P(IfStmt, hasConditionVariableStatement,
internal::Matcher<DeclStmt>, InnerMatcher) {
@@ -2296,13 +2373,9 @@ AST_MATCHER_P(ArraySubscriptExpr, hasBase,
/// matches 'for (;;) {}'
/// with compoundStmt()
/// matching '{}'
-AST_POLYMORPHIC_MATCHER_P(hasBody, internal::Matcher<Stmt>,
- InnerMatcher) {
- TOOLING_COMPILE_ASSERT(
- (llvm::is_base_of<DoStmt, NodeType>::value) ||
- (llvm::is_base_of<ForStmt, NodeType>::value) ||
- (llvm::is_base_of<WhileStmt, NodeType>::value),
- has_body_requires_for_while_or_do_statement);
+AST_POLYMORPHIC_MATCHER_P(
+ hasBody, AST_POLYMORPHIC_SUPPORTED_TYPES_3(DoStmt, ForStmt, WhileStmt),
+ internal::Matcher<Stmt>, InnerMatcher) {
const Stmt *const Statement = Node.getBody();
return (Statement != NULL &&
InnerMatcher.matches(*Statement, Finder, Builder));
@@ -2321,12 +2394,8 @@ AST_POLYMORPHIC_MATCHER_P(hasBody, internal::Matcher<Stmt>,
/// matching '{}'
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;
- }
- return false;
+ return matchesFirstInPointerRange(InnerMatcher, Node.body_begin(),
+ Node.body_end(), Finder, Builder);
}
/// \brief Checks that a compound statement contains a specific number of
@@ -2367,11 +2436,9 @@ equals(const ValueT &Value) {
/// \code
/// !(a || b)
/// \endcode
-AST_POLYMORPHIC_MATCHER_P(hasOperatorName, std::string, Name) {
- TOOLING_COMPILE_ASSERT(
- (llvm::is_base_of<BinaryOperator, NodeType>::value) ||
- (llvm::is_base_of<UnaryOperator, NodeType>::value),
- has_condition_requires_if_statement_or_conditional_operator);
+AST_POLYMORPHIC_MATCHER_P(hasOperatorName, AST_POLYMORPHIC_SUPPORTED_TYPES_2(
+ BinaryOperator, UnaryOperator),
+ std::string, Name) {
return Name == Node.getOpcodeStr(Node.getOpcode());
}
@@ -2493,12 +2560,8 @@ AST_MATCHER_P(ConditionalOperator, hasFalseExpression,
/// \endcode
///
/// Usable as: Matcher<TagDecl>, Matcher<VarDecl>, Matcher<FunctionDecl>
-AST_POLYMORPHIC_MATCHER(isDefinition) {
- TOOLING_COMPILE_ASSERT(
- (llvm::is_base_of<TagDecl, NodeType>::value) ||
- (llvm::is_base_of<VarDecl, NodeType>::value) ||
- (llvm::is_base_of<FunctionDecl, NodeType>::value),
- is_definition_requires_isThisDeclarationADefinition_method);
+AST_POLYMORPHIC_MATCHER(isDefinition, AST_POLYMORPHIC_SUPPORTED_TYPES_3(
+ TagDecl, VarDecl, FunctionDecl)) {
return Node.isThisDeclarationADefinition();
}
@@ -2540,6 +2603,21 @@ AST_MATCHER(CXXMethodDecl, isVirtual) {
return Node.isVirtual();
}
+/// \brief Matches if the given method declaration is const.
+///
+/// Given
+/// \code
+/// struct A {
+/// void foo() const;
+/// void bar();
+/// };
+/// \endcode
+///
+/// methodDecl(isConst()) matches A::foo() but not A::bar()
+AST_MATCHER(CXXMethodDecl, isConst) {
+ return Node.isConst();
+}
+
/// \brief Matches if the given method declaration overrides another method.
///
/// Given
@@ -2672,12 +2750,8 @@ AST_MATCHER_P(MemberExpr, hasObjectExpression,
/// matches \code using X::b \endcode
AST_MATCHER_P(UsingDecl, hasAnyUsingShadowDecl,
internal::Matcher<UsingShadowDecl>, InnerMatcher) {
- for (UsingDecl::shadow_iterator II = Node.shadow_begin();
- II != Node.shadow_end(); ++II) {
- if (InnerMatcher.matches(**II, Finder, Builder))
- return true;
- }
- return false;
+ return matchesFirstInPointerRange(InnerMatcher, Node.shadow_begin(),
+ Node.shadow_end(), Finder, Builder);
}
/// \brief Matches a using shadow declaration where the target declaration is
@@ -2720,11 +2794,9 @@ AST_MATCHER_P(UsingShadowDecl, hasTargetDecl,
/// does not match, as X<A> is an explicit template specialization.
///
/// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
-AST_POLYMORPHIC_MATCHER(isTemplateInstantiation) {
- TOOLING_COMPILE_ASSERT((llvm::is_base_of<FunctionDecl, NodeType>::value) ||
- (llvm::is_base_of<VarDecl, NodeType>::value) ||
- (llvm::is_base_of<CXXRecordDecl, NodeType>::value),
- requires_getTemplateSpecializationKind_method);
+AST_POLYMORPHIC_MATCHER(
+ isTemplateInstantiation,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_3(FunctionDecl, VarDecl, CXXRecordDecl)) {
return (Node.getTemplateSpecializationKind() == TSK_ImplicitInstantiation ||
Node.getTemplateSpecializationKind() ==
TSK_ExplicitInstantiationDefinition);
@@ -2742,11 +2814,9 @@ AST_POLYMORPHIC_MATCHER(isTemplateInstantiation) {
/// matches the specialization A<int>().
///
/// Usable as: Matcher<FunctionDecl>, Matcher<VarDecl>, Matcher<CXXRecordDecl>
-AST_POLYMORPHIC_MATCHER(isExplicitTemplateSpecialization) {
- TOOLING_COMPILE_ASSERT((llvm::is_base_of<FunctionDecl, NodeType>::value) ||
- (llvm::is_base_of<VarDecl, NodeType>::value) ||
- (llvm::is_base_of<CXXRecordDecl, NodeType>::value),
- requires_getTemplateSpecializationKind_method);
+AST_POLYMORPHIC_MATCHER(
+ isExplicitTemplateSpecialization,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_3(FunctionDecl, VarDecl, CXXRecordDecl)) {
return (Node.getTemplateSpecializationKind() == TSK_ExplicitSpecialization);
}
@@ -2807,7 +2877,9 @@ AST_TYPE_MATCHER(ComplexType, complexType);
/// matches "int b[7]"
///
/// Usable as: Matcher<ArrayType>, Matcher<ComplexType>
-AST_TYPELOC_TRAVERSE_MATCHER(hasElementType, getElement);
+AST_TYPELOC_TRAVERSE_MATCHER(
+ hasElementType, getElement,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_2(ArrayType, ComplexType));
/// \brief Matches C arrays with a specified constant size.
///
@@ -2914,7 +2986,8 @@ AST_TYPE_MATCHER(AtomicType, atomicType);
/// matches "_Atomic(int) i"
///
/// Usable as: Matcher<AtomicType>
-AST_TYPELOC_TRAVERSE_MATCHER(hasValueType, getValue);
+AST_TYPELOC_TRAVERSE_MATCHER(hasValueType, getValue,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_1(AtomicType));
/// \brief Matches types nodes representing C++11 auto types.
///
@@ -2942,7 +3015,8 @@ AST_TYPE_MATCHER(AutoType, autoType);
/// matches "auto a"
///
/// Usable as: Matcher<AutoType>
-AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType);
+AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_1(AutoType));
/// \brief Matches \c FunctionType nodes.
///
@@ -2979,7 +3053,8 @@ AST_TYPE_MATCHER(ParenType, parenType);
/// \c ptr_to_func but not \c ptr_to_array.
///
/// Usable as: Matcher<ParenType>
-AST_TYPE_TRAVERSE_MATCHER(innerType, getInnerType);
+AST_TYPE_TRAVERSE_MATCHER(innerType, getInnerType,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_1(ParenType));
/// \brief Matches block pointer types, i.e. types syntactically represented as
/// "void (^)(int)".
@@ -3073,7 +3148,10 @@ AST_TYPE_MATCHER(RValueReferenceType, rValueReferenceType);
///
/// Usable as: Matcher<BlockPointerType>, Matcher<MemberPointerType>,
/// Matcher<PointerType>, Matcher<ReferenceType>
-AST_TYPELOC_TRAVERSE_MATCHER(pointee, getPointee);
+AST_TYPELOC_TRAVERSE_MATCHER(
+ pointee, getPointee,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_4(BlockPointerType, MemberPointerType,
+ PointerType, ReferenceType));
/// \brief Matches typedef types.
///
@@ -3100,6 +3178,16 @@ AST_TYPE_MATCHER(TypedefType, typedefType);
/// instantiation in \c A and the type of the variable declaration in \c B.
AST_TYPE_MATCHER(TemplateSpecializationType, templateSpecializationType);
+/// \brief Matches types nodes representing unary type transformations.
+///
+/// Given:
+/// \code
+/// typedef __underlying_type(T) type;
+/// \endcode
+/// unaryTransformType()
+/// matches "__underlying_type(T)"
+AST_TYPE_MATCHER(UnaryTransformType, unaryTransformType);
+
/// \brief Matches record types (e.g. structs, classes).
///
/// Given
@@ -3331,6 +3419,80 @@ AST_MATCHER_P_OVERLOAD(Stmt, equalsNode, Stmt*, Other, 1) {
/// @}
+/// \brief Matches each case or default statement belonging to the given switch
+/// statement. This matcher may produce multiple matches.
+///
+/// Given
+/// \code
+/// switch (1) { case 1: case 2: default: switch (2) { case 3: case 4: ; } }
+/// \endcode
+/// switchStmt(forEachSwitchCase(caseStmt().bind("c"))).bind("s")
+/// matches four times, with "c" binding each of "case 1:", "case 2:",
+/// "case 3:" and "case 4:", and "s" respectively binding "switch (1)",
+/// "switch (1)", "switch (2)" and "switch (2)".
+AST_MATCHER_P(SwitchStmt, forEachSwitchCase, internal::Matcher<SwitchCase>,
+ InnerMatcher) {
+ BoundNodesTreeBuilder Result;
+ // FIXME: getSwitchCaseList() does not necessarily guarantee a stable
+ // iteration order. We should use the more general iterating matchers once
+ // they are capable of expressing this matcher (for example, it should ignore
+ // case statements belonging to nested switch statements).
+ bool Matched = false;
+ for (const SwitchCase *SC = Node.getSwitchCaseList(); SC;
+ SC = SC->getNextSwitchCase()) {
+ BoundNodesTreeBuilder CaseBuilder(*Builder);
+ bool CaseMatched = InnerMatcher.matches(*SC, Finder, &CaseBuilder);
+ if (CaseMatched) {
+ Matched = true;
+ Result.addMatch(CaseBuilder);
+ }
+ }
+ *Builder = Result;
+ return Matched;
+}
+
+/// \brief Matches each constructor initializer in a constructor definition.
+///
+/// Given
+/// \code
+/// class A { A() : i(42), j(42) {} int i; int j; };
+/// \endcode
+/// constructorDecl(forEachConstructorInitializer(forField(decl().bind("x"))))
+/// will trigger two matches, binding for 'i' and 'j' respectively.
+AST_MATCHER_P(CXXConstructorDecl, forEachConstructorInitializer,
+ internal::Matcher<CXXCtorInitializer>, InnerMatcher) {
+ BoundNodesTreeBuilder Result;
+ bool Matched = false;
+ for (CXXConstructorDecl::init_const_iterator I = Node.init_begin(),
+ E = Node.init_end();
+ I != E; ++I) {
+ BoundNodesTreeBuilder InitBuilder(*Builder);
+ if (InnerMatcher.matches(**I, Finder, &InitBuilder)) {
+ Matched = true;
+ Result.addMatch(InitBuilder);
+ }
+ }
+ *Builder = Result;
+ return Matched;
+}
+
+/// \brief If the given case statement does not use the GNU case range
+/// extension, matches the constant given in the statement.
+///
+/// Given
+/// \code
+/// switch (1) { case 1: case 1+1: case 3 ... 4: ; }
+/// \endcode
+/// caseStmt(hasCaseConstant(integerLiteral()))
+/// matches "case 1:"
+AST_MATCHER_P(CaseStmt, hasCaseConstant, internal::Matcher<Expr>,
+ InnerMatcher) {
+ if (Node.getRHS())
+ return false;
+
+ return InnerMatcher.matches(*Node.getLHS(), Finder, Builder);
+}
+
} // end namespace ast_matchers
} // end namespace clang
OpenPOWER on IntegriCloud