summaryrefslogtreecommitdiff
path: root/include/clang/ASTMatchers
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/ASTMatchers')
-rw-r--r--include/clang/ASTMatchers/ASTMatchFinder.h15
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h839
-rw-r--r--include/clang/ASTMatchers/ASTMatchersInternal.h212
3 files changed, 960 insertions, 106 deletions
diff --git a/include/clang/ASTMatchers/ASTMatchFinder.h b/include/clang/ASTMatchers/ASTMatchFinder.h
index 92ec92c299c57..042408859c9de 100644
--- a/include/clang/ASTMatchers/ASTMatchFinder.h
+++ b/include/clang/ASTMatchers/ASTMatchFinder.h
@@ -241,6 +241,11 @@ match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node,
ASTContext &Context);
/// @}
+/// \brief Returns the results of matching \p Matcher on the translation unit of
+/// \p Context and collects the \c BoundNodes of all callback invocations.
+template <typename MatcherT>
+SmallVector<BoundNodes, 1> match(MatcherT Matcher, ASTContext &Context);
+
/// \brief Returns the first result of type \c NodeT bound to \p BoundTo.
///
/// Returns \c NULL if there is no match, or if the matching node cannot be
@@ -288,6 +293,16 @@ match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
return match(Matcher, ast_type_traits::DynTypedNode::create(Node), Context);
}
+template <typename MatcherT>
+SmallVector<BoundNodes, 1>
+match(MatcherT Matcher, ASTContext &Context) {
+ internal::CollectMatchesCallback Callback;
+ MatchFinder Finder;
+ Finder.addMatcher(Matcher, &Callback);
+ Finder.matchAST(Context);
+ return std::move(Callback.Nodes);
+}
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index e6ba8778f249a..aef4b4eafd9ac 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -163,11 +163,35 @@ const internal::VariadicDynCastAllOfMatcher<Decl, TranslationUnitDecl>
/// Given
/// \code
/// typedef int X;
+/// using Y = int;
/// \endcode
/// typedefDecl()
-/// matches "typedef int X"
+/// matches "typedef int X", but not "using Y = int"
const internal::VariadicDynCastAllOfMatcher<Decl, TypedefDecl> typedefDecl;
+/// \brief Matches typedef name declarations.
+///
+/// Given
+/// \code
+/// typedef int X;
+/// using Y = int;
+/// \endcode
+/// typedefNameDecl()
+/// matches "typedef int X" and "using Y = int"
+const internal::VariadicDynCastAllOfMatcher<Decl, TypedefNameDecl>
+ typedefNameDecl;
+
+/// \brief Matches type alias declarations.
+///
+/// Given
+/// \code
+/// typedef int X;
+/// using Y = int;
+/// \endcode
+/// typeAliasDecl()
+/// matches "using Y = int", but not "typedef int X"
+const internal::VariadicDynCastAllOfMatcher<Decl, TypeAliasDecl> typeAliasDecl;
+
/// \brief Matches AST nodes that were expanded within the main-file.
///
/// Example matches X but not Y
@@ -282,6 +306,17 @@ const internal::VariadicDynCastAllOfMatcher<Decl, LinkageSpecDecl>
/// \endcode
const internal::VariadicDynCastAllOfMatcher<Decl, NamedDecl> namedDecl;
+/// \brief Matches a declaration of label.
+///
+/// Given
+/// \code
+/// goto FOO;
+/// FOO: bar();
+/// \endcode
+/// labelDecl()
+/// matches 'FOO:'
+const internal::VariadicDynCastAllOfMatcher<Decl, LabelDecl> labelDecl;
+
/// \brief Matches a declaration of a namespace.
///
/// Given
@@ -447,7 +482,7 @@ const internal::VariadicDynCastAllOfMatcher<
/// };
/// \endcode
/// fieldDecl(isPublic())
-/// matches 'int a;'
+/// matches 'int a;'
AST_MATCHER(Decl, isPublic) {
return Node.getAccess() == AS_public;
}
@@ -463,7 +498,7 @@ AST_MATCHER(Decl, isPublic) {
/// };
/// \endcode
/// fieldDecl(isProtected())
-/// matches 'int b;'
+/// matches 'int b;'
AST_MATCHER(Decl, isProtected) {
return Node.getAccess() == AS_protected;
}
@@ -479,11 +514,43 @@ AST_MATCHER(Decl, isProtected) {
/// };
/// \endcode
/// fieldDecl(isPrivate())
-/// matches 'int c;'
+/// matches 'int c;'
AST_MATCHER(Decl, isPrivate) {
return Node.getAccess() == AS_private;
}
+/// \brief Matches non-static data members that are bit-fields.
+///
+/// Given
+/// \code
+/// class C {
+/// int a : 2;
+/// int b;
+/// };
+/// \endcode
+/// fieldDecl(isBitField())
+/// matches 'int a;' but not 'int b;'.
+AST_MATCHER(FieldDecl, isBitField) {
+ return Node.isBitField();
+}
+
+/// \brief Matches non-static data members that are bit-fields.
+///
+/// Given
+/// \code
+/// class C {
+/// int a : 2;
+/// int b : 4;
+/// int c : 2;
+/// };
+/// \endcode
+/// fieldDecl(isBitField())
+/// matches 'int a;' and 'int c;' but not 'int b;'.
+AST_MATCHER_P(FieldDecl, hasBitWidth, unsigned, Width) {
+ return Node.isBitField() &&
+ Node.getBitWidthValue(Finder->getASTContext()) == Width;
+}
+
/// \brief Matches a declaration that has been implicitly added
/// by the compiler (eg. implicit default/copy constructors).
AST_MATCHER(Decl, isImplicit) {
@@ -513,6 +580,32 @@ AST_POLYMORPHIC_MATCHER_P(
Builder);
}
+/// \brief Matches expressions that match InnerMatcher after any implicit AST
+/// nodes are stripped off.
+///
+/// Parentheses and explicit casts are not discarded.
+/// Given
+/// \code
+/// class C {};
+/// C a = C();
+/// C b;
+/// C c = b;
+/// \endcode
+/// The matchers
+/// \code
+/// varDecl(hasInitializer(ignoringImplicit(cxxConstructExpr())))
+/// \endcode
+/// would match the declarations for a, b, and c.
+/// While
+/// \code
+/// varDecl(hasInitializer(cxxConstructExpr()))
+/// \endcode
+/// only match the declarations for b and c.
+AST_MATCHER_P(Expr, ignoringImplicit, ast_matchers::internal::Matcher<Expr>,
+ InnerMatcher) {
+ return InnerMatcher.matches(*Node.IgnoreImplicit(), Finder, Builder);
+}
+
/// \brief Matches expressions that match InnerMatcher after any implicit casts
/// are stripped off.
///
@@ -590,6 +683,22 @@ AST_MATCHER_P(Expr, ignoringParenImpCasts,
return InnerMatcher.matches(*Node.IgnoreParenImpCasts(), Finder, Builder);
}
+/// \brief Matches types that match InnerMatcher after any parens are stripped.
+///
+/// Given
+/// \code
+/// void (*fp)(void);
+/// \endcode
+/// The matcher
+/// \code
+/// varDecl(hasType(pointerType(pointee(ignoringParens(functionType())))))
+/// \endcode
+/// would match the declaration for fp.
+AST_MATCHER_P(QualType, ignoringParens,
+ internal::Matcher<QualType>, InnerMatcher) {
+ return InnerMatcher.matches(Node.IgnoreParens(), Finder, Builder);
+}
+
/// \brief Matches classTemplateSpecializations where the n'th TemplateArgument
/// matches the given InnerMatcher.
///
@@ -976,6 +1085,43 @@ const internal::VariadicDynCastAllOfMatcher<
/// matches "{ 1, 2 }" and "{ 5, 6 }"
const internal::VariadicDynCastAllOfMatcher<Stmt, InitListExpr> initListExpr;
+/// \brief Matches the syntactic form of init list expressions
+/// (if expression have it).
+AST_MATCHER_P(InitListExpr, hasSyntacticForm,
+ internal::Matcher<Expr>, InnerMatcher) {
+ const Expr *SyntForm = Node.getSyntacticForm();
+ return (SyntForm != nullptr &&
+ InnerMatcher.matches(*SyntForm, Finder, Builder));
+}
+
+/// \brief Matches implicit initializers of init list expressions.
+///
+/// Given
+/// \code
+/// point ptarray[10] = { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 };
+/// \endcode
+/// implicitValueInitExpr()
+/// matches "[0].y" (implicitly)
+const internal::VariadicDynCastAllOfMatcher<Stmt, ImplicitValueInitExpr>
+implicitValueInitExpr;
+
+/// \brief Matches paren list expressions.
+/// ParenListExprs don't have a predefined type and are used for late parsing.
+/// In the final AST, they can be met in template declarations.
+///
+/// Given
+/// \code
+/// template<typename T> class X {
+/// void f() {
+/// X x(*this);
+/// int a = 0, b = 1; int i = (a, b);
+/// }
+/// };
+/// \endcode
+/// parenListExpr() matches "*this" but NOT matches (a, b) because (a, b)
+/// has a predefined type and is a ParenExpr, not a ParenListExpr.
+const internal::VariadicDynCastAllOfMatcher<Stmt, ParenListExpr> parenListExpr;
+
/// \brief Matches substitutions of non-type template parameters.
///
/// Given
@@ -1014,6 +1160,24 @@ const internal::VariadicDynCastAllOfMatcher<
Decl,
UsingDirectiveDecl> usingDirectiveDecl;
+/// \brief Matches reference to a name that can be looked up during parsing
+/// but could not be resolved to a specific declaration.
+///
+/// Given
+/// \code
+/// template<typename T>
+/// T foo() { T a; return a; }
+/// template<typename T>
+/// void bar() {
+/// foo<T>();
+/// }
+/// \endcode
+/// unresolvedLookupExpr()
+/// matches \code foo<T>() \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ UnresolvedLookupExpr> unresolvedLookupExpr;
+
/// \brief Matches unresolved using value declarations.
///
/// Given
@@ -1048,6 +1212,17 @@ const internal::VariadicDynCastAllOfMatcher<
Decl,
UnresolvedUsingTypenameDecl> unresolvedUsingTypenameDecl;
+/// \brief Matches parentheses used in expressions.
+///
+/// Example matches (foo() + 1)
+/// \code
+/// int foo() { return 1; }
+/// int a = (foo() + 1);
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ ParenExpr> parenExpr;
+
/// \brief Matches constructor call expressions (including implicit ones).
///
/// Example matches string(ptr, n) and ptr within arguments of f
@@ -1357,6 +1532,18 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, GotoStmt> gotoStmt;
/// matches 'FOO:'
const internal::VariadicDynCastAllOfMatcher<Stmt, LabelStmt> labelStmt;
+/// \brief Matches address of label statements (GNU extension).
+///
+/// Given
+/// \code
+/// FOO: bar();
+/// void *ptr = &&FOO;
+/// goto *bar;
+/// \endcode
+/// addrLabelExpr()
+/// matches '&&FOO'
+const internal::VariadicDynCastAllOfMatcher<Stmt, AddrLabelExpr> addrLabelExpr;
+
/// \brief Matches switch statements.
///
/// Given
@@ -1465,7 +1652,8 @@ const internal::VariadicDynCastAllOfMatcher<
///
/// Example matches "abcd", L"abcd"
/// \code
-/// char *s = "abcd"; wchar_t *ws = L"abcd"
+/// char *s = "abcd";
+/// wchar_t *ws = L"abcd";
/// \endcode
const internal::VariadicDynCastAllOfMatcher<
Stmt,
@@ -1478,7 +1666,8 @@ const internal::VariadicDynCastAllOfMatcher<
///
/// Example matches 'a', L'a'
/// \code
-/// char ch = 'a'; wchar_t chw = L'a';
+/// char ch = 'a';
+/// wchar_t chw = L'a';
/// \endcode
const internal::VariadicDynCastAllOfMatcher<
Stmt,
@@ -1514,7 +1703,8 @@ const internal::VariadicDynCastAllOfMatcher<
///
/// Example match: {1}, (1, 2)
/// \code
-/// int array[4] = {1}; vector int myvec = (vector int)(1, 2);
+/// int array[4] = {1};
+/// vector int myvec = (vector int)(1, 2);
/// \endcode
const internal::VariadicDynCastAllOfMatcher<
Stmt,
@@ -1526,9 +1716,22 @@ const internal::VariadicDynCastAllOfMatcher<
CXXNullPtrLiteralExpr> cxxNullPtrLiteralExpr;
/// \brief Matches GNU __null expression.
-const internal::VariadicDynCastAllOfMatcher<
- Stmt,
- GNUNullExpr> gnuNullExpr;
+const internal::VariadicDynCastAllOfMatcher<Stmt, GNUNullExpr> gnuNullExpr;
+
+/// \brief Matches atomic builtins.
+/// Example matches __atomic_load_n(ptr, 1)
+/// \code
+/// void foo() { int *ptr; __atomic_load_n(ptr, 1); }
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Stmt, AtomicExpr> atomicExpr;
+
+/// \brief Matches statement expression (GNU extension).
+///
+/// Example match: ({ int X = 4; X; })
+/// \code
+/// int C = ({ int X = 4; X; });
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<Stmt, StmtExpr> stmtExpr;
/// \brief Matches binary operator expressions.
///
@@ -1560,6 +1763,28 @@ const internal::VariadicDynCastAllOfMatcher<
Stmt,
ConditionalOperator> conditionalOperator;
+/// \brief Matches binary conditional operator expressions (GNU extension).
+///
+/// Example matches a ?: b
+/// \code
+/// (a ?: b) + 42;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ BinaryConditionalOperator> binaryConditionalOperator;
+
+/// \brief Matches opaque value expressions. They are used as helpers
+/// to reference another expressions and can be met
+/// in BinaryConditionalOperators, for example.
+///
+/// Example matches 'a'
+/// \code
+/// (a ?: c) + 42;
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ OpaqueValueExpr> opaqueValueExpr;
+
/// \brief Matches a C++ static_assert declaration.
///
/// Example:
@@ -1716,6 +1941,41 @@ const internal::VariadicDynCastAllOfMatcher<
Stmt,
CXXTemporaryObjectExpr> cxxTemporaryObjectExpr;
+/// \brief Matches predefined identifier expressions [C99 6.4.2.2].
+///
+/// Example: Matches __func__
+/// \code
+/// printf("%s", __func__);
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ PredefinedExpr> predefinedExpr;
+
+/// \brief Matches C99 designated initializer expressions [C99 6.7.8].
+///
+/// Example: Matches { [2].y = 1.0, [0].x = 1.0 }
+/// \code
+/// point ptarray[10] = { [2].y = 1.0, [0].x = 1.0 };
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+ Stmt,
+ DesignatedInitExpr> designatedInitExpr;
+
+/// \brief Matches designated initializer expressions that contain
+/// a specific number of designators.
+///
+/// Example: Given
+/// \code
+/// point ptarray[10] = { [2].y = 1.0, [0].x = 1.0 };
+/// point ptarray2[10] = { [2].y = 1.0, [2].x = 0.0, [0].x = 1.0 };
+/// \endcode
+/// designatorCountIs(2)
+/// matches '{ [2].y = 1.0, [0].x = 1.0 }',
+/// but not '{ [2].y = 1.0, [2].x = 0.0, [0].x = 1.0 }'.
+AST_MATCHER_P(DesignatedInitExpr, designatorCountIs, unsigned, N) {
+ return Node.size() == N;
+}
+
/// \brief Matches \c QualTypes in the clang AST.
const internal::VariadicAllOfMatcher<QualType> qualType;
@@ -1834,9 +2094,25 @@ inline internal::Matcher<Stmt> sizeOfExpr(
/// namespace a { namespace b { class X; } }
/// \endcode
inline internal::Matcher<NamedDecl> hasName(const std::string &Name) {
- return internal::Matcher<NamedDecl>(new internal::HasNameMatcher(Name));
+ std::vector<std::string> Names;
+ Names.push_back(Name);
+ return internal::Matcher<NamedDecl>(new internal::HasNameMatcher(Names));
}
+/// \brief Matches NamedDecl nodes that have any of the specified names.
+///
+/// This matcher is only provided as a performance optimization of hasName.
+/// \code
+/// hasAnyName(a, b, c)
+/// \endcode
+/// is equivalent to, but faster than
+/// \code
+/// anyOf(hasName(a), hasName(b), hasName(c))
+/// \endcode
+const internal::VariadicFunction<internal::Matcher<NamedDecl>, StringRef,
+ internal::hasAnyNameFunc>
+ hasAnyName = {};
+
/// \brief Matches NamedDecl nodes whose fully qualified names contain
/// a substring matched by the given RegExp.
///
@@ -1953,6 +2229,19 @@ AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher<CXXMethodDecl>,
Node.method_end(), Finder, Builder);
}
+/// \brief Matches the generated class of lambda expressions.
+///
+/// Given:
+/// \code
+/// auto x = []{};
+/// \endcode
+///
+/// \c cxxRecordDecl(isLambda()) matches the implicit class declaration of
+/// \c decltype(x)
+AST_MATCHER(CXXRecordDecl, isLambda) {
+ return Node.isLambda();
+}
+
/// \brief Matches AST nodes that have child AST nodes that match the
/// provided matcher.
///
@@ -1967,6 +2256,10 @@ AST_MATCHER_P(CXXRecordDecl, hasMethod, internal::Matcher<CXXMethodDecl>,
/// ChildT must be an AST base type.
///
/// Usable as: Any Matcher
+/// Note that has is direct matcher, so it also matches things like implicit
+/// casts and paren casts. If you are matching with expr then you should
+/// probably consider using ignoringParenImpCasts like:
+/// has(ignoringParenImpCasts(expr())).
const internal::ArgumentAdaptingMatcherFunc<internal::HasMatcher>
LLVM_ATTRIBUTE_UNUSED has = {};
@@ -2117,8 +2410,8 @@ const internal::VariadicOperatorMatcherFunc<1, 1> unless = {
///
/// Usable as: Matcher<CallExpr>, Matcher<CXXConstructExpr>,
/// Matcher<DeclRefExpr>, Matcher<EnumType>, Matcher<InjectedClassNameType>,
-/// Matcher<LabelStmt>, Matcher<MemberExpr>, Matcher<QualType>,
-/// Matcher<RecordType>, Matcher<TagType>,
+/// Matcher<LabelStmt>, Matcher<AddrLabelExpr>, Matcher<MemberExpr>,
+/// Matcher<QualType>, Matcher<RecordType>, Matcher<TagType>,
/// Matcher<TemplateSpecializationType>, Matcher<TemplateTypeParmType>,
/// Matcher<TypedefType>, Matcher<UnresolvedUsingType>
inline internal::PolymorphicMatcherWithParam1<
@@ -2287,14 +2580,17 @@ AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher,
///
/// Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
/// and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
+/// and U (matcher = typedefDecl(hasType(asString("int")))
/// \code
/// class X {};
/// void y(X &x) { x; X z; }
+/// typedef int U;
/// \endcode
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
- hasType, AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, ValueDecl),
+ hasType, AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, TypedefNameDecl, ValueDecl),
internal::Matcher<QualType>, InnerMatcher, 0) {
- return InnerMatcher.matches(Node.getType(), Finder, Builder);
+ return InnerMatcher.matches(internal::getUnderlyingType(Node),
+ Finder, Builder);
}
/// \brief Overloaded to match the declaration of the expression's or value
@@ -2829,18 +3125,13 @@ AST_MATCHER(CXXCtorInitializer, isMemberInitializer) {
/// matches x(1, y, 42)
/// with hasAnyArgument(...)
/// matching y
-///
-/// 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(CallExpr,
CXXConstructExpr),
internal::Matcher<Expr>, InnerMatcher) {
for (const Expr *Arg : Node.arguments()) {
BoundNodesTreeBuilder Result(*Builder);
- if (InnerMatcher.matches(*Arg->IgnoreParenImpCasts(), Finder, &Result)) {
+ if (InnerMatcher.matches(*Arg, Finder, &Result)) {
*Builder = std::move(Result);
return true;
}
@@ -2853,6 +3144,22 @@ AST_MATCHER(CXXConstructExpr, isListInitialization) {
return Node.isListInitialization();
}
+/// \brief Matches a constructor call expression which requires
+/// zero initialization.
+///
+/// Given
+/// \code
+/// void foo() {
+/// struct point { double x; double y; };
+/// point pt[2] = { { 1.0, 2.0 } };
+/// }
+/// \endcode
+/// initListExpr(has(cxxConstructExpr(requiresZeroInitialization()))
+/// will match the implicit array filler for pt[1].
+AST_MATCHER(CXXConstructExpr, requiresZeroInitialization) {
+ return Node.requiresZeroInitialization();
+}
+
/// \brief Matches the n'th parameter of a function declaration.
///
/// Given
@@ -2871,6 +3178,60 @@ AST_MATCHER_P2(FunctionDecl, hasParameter,
*Node.getParamDecl(N), Finder, Builder));
}
+/// \brief Matches all arguments and their respective ParmVarDecl.
+///
+/// Given
+/// \code
+/// void f(int i);
+/// int y;
+/// f(y);
+/// \endcode
+/// callExpr(
+/// forEachArgumentWithParam(
+/// declRefExpr(to(varDecl(hasName("y")))),
+/// parmVarDecl(hasType(isInteger()))
+/// ))
+/// matches f(y);
+/// with declRefExpr(...)
+/// matching int y
+/// and parmVarDecl(...)
+/// matching int i
+AST_POLYMORPHIC_MATCHER_P2(forEachArgumentWithParam,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr,
+ CXXConstructExpr),
+ internal::Matcher<Expr>, ArgMatcher,
+ internal::Matcher<ParmVarDecl>, ParamMatcher) {
+ BoundNodesTreeBuilder Result;
+ // The first argument of an overloaded member operator is the implicit object
+ // argument of the method which should not be matched against a parameter, so
+ // we skip over it here.
+ BoundNodesTreeBuilder Matches;
+ unsigned ArgIndex = cxxOperatorCallExpr(callee(cxxMethodDecl()))
+ .matches(Node, Finder, &Matches)
+ ? 1
+ : 0;
+ int ParamIndex = 0;
+ bool Matched = false;
+ for (; ArgIndex < Node.getNumArgs(); ++ArgIndex) {
+ BoundNodesTreeBuilder ArgMatches(*Builder);
+ if (ArgMatcher.matches(*(Node.getArg(ArgIndex)->IgnoreParenCasts()),
+ Finder, &ArgMatches)) {
+ BoundNodesTreeBuilder ParamMatches(ArgMatches);
+ if (expr(anyOf(cxxConstructExpr(hasDeclaration(cxxConstructorDecl(
+ hasParameter(ParamIndex, ParamMatcher)))),
+ callExpr(callee(functionDecl(
+ hasParameter(ParamIndex, ParamMatcher))))))
+ .matches(Node, Finder, &ParamMatches)) {
+ Result.addMatch(ParamMatches);
+ Matched = true;
+ }
+ }
+ ++ParamIndex;
+ }
+ *Builder = std::move(Result);
+ return Matched;
+}
+
/// \brief Matches any parameter of a function declaration.
///
/// Does not match the 'this' parameter of a method.
@@ -2889,16 +3250,27 @@ AST_MATCHER_P(FunctionDecl, hasAnyParameter,
Node.param_end(), Finder, Builder);
}
-/// \brief Matches \c FunctionDecls that have a specific parameter count.
+/// \brief Matches \c FunctionDecls and \c FunctionProtoTypes that have a
+/// specific parameter count.
///
/// Given
/// \code
/// void f(int i) {}
/// void g(int i, int j) {}
+/// void h(int i, int j);
+/// void j(int i);
+/// void k(int x, int y, int z, ...);
/// \endcode
/// functionDecl(parameterCountIs(2))
-/// matches g(int i, int j) {}
-AST_MATCHER_P(FunctionDecl, parameterCountIs, unsigned, N) {
+/// matches void g(int i, int j) {}
+/// functionProtoType(parameterCountIs(2))
+/// matches void h(int i, int j)
+/// functionProtoType(parameterCountIs(3))
+/// matches void k(int x, int y, int z, ...);
+AST_POLYMORPHIC_MATCHER_P(parameterCountIs,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
+ FunctionProtoType),
+ unsigned, N) {
return Node.getNumParams() == N;
}
@@ -2942,6 +3314,42 @@ AST_MATCHER(FunctionDecl, isDeleted) {
return Node.isDeleted();
}
+/// \brief Matches defaulted function declarations.
+///
+/// Given:
+/// \code
+/// class A { ~A(); };
+/// class B { ~B() = default; };
+/// \endcode
+/// functionDecl(isDefaulted())
+/// matches the declaration of ~B, but not ~A.
+AST_MATCHER(FunctionDecl, isDefaulted) {
+ return Node.isDefaulted();
+}
+
+/// \brief Matches functions that have a dynamic exception specification.
+///
+/// Given:
+/// \code
+/// void f();
+/// void g() noexcept;
+/// void h() noexcept(true);
+/// void i() noexcept(false);
+/// void j() throw();
+/// void k() throw(int);
+/// void l() throw(...);
+/// \endcode
+/// functionDecl(hasDynamicExceptionSpec()) and
+/// functionProtoType(hasDynamicExceptionSpec())
+/// match the declarations of j, k, and l, but not f, g, h, or i.
+AST_POLYMORPHIC_MATCHER(hasDynamicExceptionSpec,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
+ FunctionProtoType)) {
+ if (const FunctionProtoType *FnTy = internal::getFunctionProtoType(Node))
+ return FnTy->hasDynamicExceptionSpec();
+ return false;
+}
+
/// \brief Matches functions that have a non-throwing exception specification.
///
/// Given:
@@ -2952,10 +3360,12 @@ AST_MATCHER(FunctionDecl, isDeleted) {
/// void i() throw(int);
/// void j() noexcept(false);
/// \endcode
-/// functionDecl(isNoThrow())
-/// matches the declarations of g, and h, but not f, i or j.
-AST_MATCHER(FunctionDecl, isNoThrow) {
- const auto *FnTy = Node.getType()->getAs<FunctionProtoType>();
+/// functionDecl(isNoThrow()) and functionProtoType(isNoThrow())
+/// match the declarations of g, and h, but not f, i or j.
+AST_POLYMORPHIC_MATCHER(isNoThrow,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
+ FunctionProtoType)) {
+ const FunctionProtoType *FnTy = internal::getFunctionProtoType(Node);
// If the function does not have a prototype, then it is assumed to be a
// throwing function (as it would if the function did not have any exception
@@ -2967,7 +3377,7 @@ AST_MATCHER(FunctionDecl, isNoThrow) {
if (isUnresolvedExceptionSpec(FnTy->getExceptionSpecType()))
return true;
- return FnTy->isNothrow(Node.getASTContext());
+ return FnTy->isNothrow(Finder->getASTContext());
}
/// \brief Matches constexpr variable and function declarations.
@@ -2988,17 +3398,17 @@ AST_POLYMORPHIC_MATCHER(isConstexpr,
}
/// \brief Matches the condition expression of an if statement, for loop,
-/// or conditional operator.
+/// switch statement or conditional operator.
///
/// Example matches true (matcher = hasCondition(cxxBoolLiteral(equals(true))))
/// \code
/// if (true) {}
/// \endcode
-AST_POLYMORPHIC_MATCHER_P(hasCondition,
- AST_POLYMORPHIC_SUPPORTED_TYPES(IfStmt, ForStmt,
- WhileStmt, DoStmt,
- ConditionalOperator),
- internal::Matcher<Expr>, InnerMatcher) {
+AST_POLYMORPHIC_MATCHER_P(
+ hasCondition,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(IfStmt, ForStmt, WhileStmt, DoStmt,
+ SwitchStmt, AbstractConditionalOperator),
+ internal::Matcher<Expr>, InnerMatcher) {
const Expr *const Condition = Node.getCond();
return (Condition != nullptr &&
InnerMatcher.matches(*Condition, Finder, Builder));
@@ -3114,8 +3524,8 @@ AST_MATCHER_P(ArraySubscriptExpr, hasBase,
return false;
}
-/// \brief Matches a 'for', 'while', or 'do while' statement that has
-/// a given body.
+/// \brief Matches a 'for', 'while', 'do while' statement or a function
+/// definition that has a given body.
///
/// Given
/// \code
@@ -3128,15 +3538,16 @@ AST_MATCHER_P(ArraySubscriptExpr, hasBase,
AST_POLYMORPHIC_MATCHER_P(hasBody,
AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, ForStmt,
WhileStmt,
- CXXForRangeStmt),
+ CXXForRangeStmt,
+ FunctionDecl),
internal::Matcher<Stmt>, InnerMatcher) {
- const Stmt *const Statement = Node.getBody();
+ const Stmt *const Statement = internal::GetBodyMatcher<NodeType>::get(Node);
return (Statement != nullptr &&
InnerMatcher.matches(*Statement, Finder, Builder));
}
/// \brief Matches compound statements where at least one substatement matches
-/// a given matcher.
+/// a given matcher. Also matches StmtExprs that have CompoundStmt as children.
///
/// Given
/// \code
@@ -3146,10 +3557,13 @@ AST_POLYMORPHIC_MATCHER_P(hasBody,
/// matches '{ {}; 1+2; }'
/// with compoundStmt()
/// matching '{}'
-AST_MATCHER_P(CompoundStmt, hasAnySubstatement,
- internal::Matcher<Stmt>, InnerMatcher) {
- return matchesFirstInPointerRange(InnerMatcher, Node.body_begin(),
- Node.body_end(), Finder, Builder);
+AST_POLYMORPHIC_MATCHER_P(hasAnySubstatement,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CompoundStmt,
+ StmtExpr),
+ internal::Matcher<Stmt>, InnerMatcher) {
+ const CompoundStmt *CS = CompoundStmtMatcher<NodeType>::get(Node);
+ return CS && matchesFirstInPointerRange(InnerMatcher, CS->body_begin(),
+ CS->body_end(), Finder, Builder);
}
/// \brief Checks that a compound statement contains a specific number of
@@ -3248,21 +3662,43 @@ AST_MATCHER_P(UnaryOperator, hasUnaryOperand,
InnerMatcher.matches(*Operand, Finder, Builder));
}
-/// \brief Matches if the cast's source expression matches the given matcher.
+/// \brief Matches if the cast's source expression
+/// or opaque value's source expression matches the given matcher.
///
-/// Example: matches "a string" (matcher =
-/// hasSourceExpression(cxxConstructExpr()))
+/// Example 1: matches "a string"
+/// (matcher = castExpr(hasSourceExpression(cxxConstructExpr())))
/// \code
/// class URL { URL(string); };
/// URL url = "a string";
/// \endcode
-AST_MATCHER_P(CastExpr, hasSourceExpression,
- internal::Matcher<Expr>, InnerMatcher) {
- const Expr* const SubExpression = Node.getSubExpr();
+///
+/// Example 2: matches 'b' (matcher =
+/// opaqueValueExpr(hasSourceExpression(implicitCastExpr(declRefExpr())))
+/// \code
+/// int a = b ?: 1;
+/// \endcode
+
+AST_POLYMORPHIC_MATCHER_P(hasSourceExpression,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(CastExpr,
+ OpaqueValueExpr),
+ internal::Matcher<Expr>, InnerMatcher) {
+ const Expr *const SubExpression =
+ internal::GetSourceExpressionMatcher<NodeType>::get(Node);
return (SubExpression != nullptr &&
InnerMatcher.matches(*SubExpression, Finder, Builder));
}
+/// \brief Matches casts that has a given cast kind.
+///
+/// Example: matches the implicit cast around \c 0
+/// (matcher = castExpr(hasCastKind(CK_NullToPointer)))
+/// \code
+/// int *p = 0;
+/// \endcode
+AST_MATCHER_P(CastExpr, hasCastKind, CastKind, Kind) {
+ return Node.getCastKind() == Kind;
+}
+
/// \brief Matches casts whose destination type matches a given matcher.
///
/// (Note: Clang's AST refers to other conversions as "casts" too, and calls
@@ -3320,24 +3756,31 @@ AST_MATCHER(RecordDecl, isClass) {
/// \brief Matches the true branch expression of a conditional operator.
///
-/// Example matches a
+/// Example 1 (conditional ternary operator): matches a
/// \code
/// condition ? a : b
/// \endcode
-AST_MATCHER_P(ConditionalOperator, hasTrueExpression,
+///
+/// Example 2 (conditional binary operator): matches opaqueValueExpr(condition)
+/// \code
+/// condition ?: b
+/// \endcode
+AST_MATCHER_P(AbstractConditionalOperator, hasTrueExpression,
internal::Matcher<Expr>, InnerMatcher) {
const Expr *Expression = Node.getTrueExpr();
return (Expression != nullptr &&
InnerMatcher.matches(*Expression, Finder, Builder));
}
-/// \brief Matches the false branch expression of a conditional operator.
+/// \brief Matches the false branch expression of a conditional operator
+/// (binary or ternary).
///
/// Example matches b
/// \code
/// condition ? a : b
+/// condition ?: b
/// \endcode
-AST_MATCHER_P(ConditionalOperator, hasFalseExpression,
+AST_MATCHER_P(AbstractConditionalOperator, hasFalseExpression,
internal::Matcher<Expr>, InnerMatcher) {
const Expr *Expression = Node.getFalseExpr();
return (Expression != nullptr &&
@@ -3401,6 +3844,47 @@ AST_MATCHER_P(CXXMethodDecl, ofClass,
InnerMatcher.matches(*Parent, Finder, Builder));
}
+/// \brief Matches each method overriden by the given method. This matcher may
+/// produce multiple matches.
+///
+/// Given
+/// \code
+/// class A { virtual void f(); };
+/// class B : public A { void f(); };
+/// class C : public B { void f(); };
+/// \endcode
+/// cxxMethodDecl(ofClass(hasName("C")),
+/// forEachOverridden(cxxMethodDecl().bind("b"))).bind("d")
+/// matches once, with "b" binding "A::f" and "d" binding "C::f" (Note
+/// that B::f is not overridden by C::f).
+///
+/// The check can produce multiple matches in case of multiple inheritance, e.g.
+/// \code
+/// class A1 { virtual void f(); };
+/// class A2 { virtual void f(); };
+/// class C : public A1, public A2 { void f(); };
+/// \endcode
+/// cxxMethodDecl(ofClass(hasName("C")),
+/// forEachOverridden(cxxMethodDecl().bind("b"))).bind("d")
+/// matches twice, once with "b" binding "A1::f" and "d" binding "C::f", and
+/// once with "b" binding "A2::f" and "d" binding "C::f".
+AST_MATCHER_P(CXXMethodDecl, forEachOverridden,
+ internal::Matcher<CXXMethodDecl>, InnerMatcher) {
+ BoundNodesTreeBuilder Result;
+ bool Matched = false;
+ for (const auto *Overridden : Node.overridden_methods()) {
+ BoundNodesTreeBuilder OverriddenBuilder(*Builder);
+ const bool OverriddenMatched =
+ InnerMatcher.matches(*Overridden, Finder, &OverriddenBuilder);
+ if (OverriddenMatched) {
+ Matched = true;
+ Result.addMatch(OverriddenBuilder);
+ }
+ }
+ *Builder = std::move(Result);
+ return Matched;
+}
+
/// \brief Matches if the given method declaration is virtual.
///
/// Given
@@ -3415,6 +3899,24 @@ AST_MATCHER(CXXMethodDecl, isVirtual) {
return Node.isVirtual();
}
+/// \brief Matches if the given method declaration has an explicit "virtual".
+///
+/// Given
+/// \code
+/// class A {
+/// public:
+/// virtual void x();
+/// };
+/// class B : public A {
+/// public:
+/// void x();
+/// };
+/// \endcode
+/// matches A::x but not B::x
+AST_MATCHER(CXXMethodDecl, isVirtualAsWritten) {
+ return Node.isVirtualAsWritten();
+}
+
/// \brief Matches if the given method or class declaration is final.
///
/// Given:
@@ -3482,6 +3984,23 @@ AST_MATCHER(CXXMethodDecl, isCopyAssignmentOperator) {
return Node.isCopyAssignmentOperator();
}
+/// \brief Matches if the given method declaration declares a move assignment
+/// operator.
+///
+/// Given
+/// \code
+/// struct A {
+/// A &operator=(const A &);
+/// A &operator=(A &&);
+/// };
+/// \endcode
+///
+/// cxxMethodDecl(isMoveAssignmentOperator()) matches the second method but not
+/// the first one.
+AST_MATCHER(CXXMethodDecl, isMoveAssignmentOperator) {
+ return Node.isMoveAssignmentOperator();
+}
+
/// \brief Matches if the given method declaration overrides another method.
///
/// Given
@@ -3500,6 +4019,21 @@ AST_MATCHER(CXXMethodDecl, isOverride) {
return Node.size_overridden_methods() > 0 || Node.hasAttr<OverrideAttr>();
}
+/// \brief Matches method declarations that are user-provided.
+///
+/// Given
+/// \code
+/// struct S {
+/// S(); // #1
+/// S(const S &) = default; // #2
+/// S(S &&) = delete; // #3
+/// };
+/// \endcode
+/// cxxConstructorDecl(isUserProvided()) will match #1, but not #2 or #3.
+AST_MATCHER(CXXMethodDecl, isUserProvided) {
+ return Node.isUserProvided();
+}
+
/// \brief Matches member expressions that are called with '->' as opposed
/// to '.'.
///
@@ -3533,6 +4067,34 @@ AST_MATCHER(QualType, isInteger) {
return Node->isIntegerType();
}
+/// \brief Matches QualType nodes that are of unsigned integer type.
+///
+/// Given
+/// \code
+/// void a(int);
+/// void b(unsigned long);
+/// void c(double);
+/// \endcode
+/// functionDecl(hasAnyParameter(hasType(isInteger())))
+/// matches "b(unsigned long)", but not "a(int)" and "c(double)".
+AST_MATCHER(QualType, isUnsignedInteger) {
+ return Node->isUnsignedIntegerType();
+}
+
+/// \brief Matches QualType nodes that are of signed integer type.
+///
+/// Given
+/// \code
+/// void a(int);
+/// void b(unsigned long);
+/// void c(double);
+/// \endcode
+/// functionDecl(hasAnyParameter(hasType(isInteger())))
+/// matches "a(int)", but not "b(unsigned long)" and "c(double)".
+AST_MATCHER(QualType, isSignedInteger) {
+ return Node->isSignedIntegerType();
+}
+
/// \brief Matches QualType nodes that are of character type.
///
/// Given
@@ -3547,6 +4109,26 @@ AST_MATCHER(QualType, isAnyCharacter) {
return Node->isAnyCharacterType();
}
+/// \brief Matches QualType nodes that are of any pointer type; this includes
+/// the Objective-C object pointer type, which is different despite being
+/// syntactically similar.
+///
+/// Given
+/// \code
+/// int *i = nullptr;
+///
+/// @interface Foo
+/// @end
+/// Foo *f;
+///
+/// int j;
+/// \endcode
+/// varDecl(hasType(isAnyPointer()))
+/// matches "int *i" and "Foo *f", but not "int j".
+AST_MATCHER(QualType, isAnyPointer) {
+ return Node->isAnyPointerType();
+}
+
/// \brief Matches QualType nodes that are const-qualified, i.e., that
/// include "top-level" const.
///
@@ -3822,6 +4404,19 @@ AST_TYPE_MATCHER(ArrayType, arrayType);
/// matches "_Complex float f"
AST_TYPE_MATCHER(ComplexType, complexType);
+/// \brief Matches any real floating-point type (float, double, long double).
+///
+/// Given
+/// \code
+/// int i;
+/// float f;
+/// \endcode
+/// realFloatingPointType()
+/// matches "float f" but not "int i"
+AST_MATCHER(Type, realFloatingPointType) {
+ return Node.isRealFloatingType();
+}
+
/// \brief Matches arrays and C99 complex types that have a specific element
/// type.
///
@@ -3853,18 +4448,26 @@ AST_TYPELOC_TRAVERSE_MATCHER(hasElementType, getElement,
/// matches "int a[2]"
AST_TYPE_MATCHER(ConstantArrayType, constantArrayType);
-/// \brief Matches \c ConstantArrayType nodes that have the specified size.
+/// \brief Matches nodes that have the specified size.
///
/// Given
/// \code
/// int a[42];
/// int b[2 * 21];
/// int c[41], d[43];
+/// char *s = "abcd";
+/// wchar_t *ws = L"abcd";
+/// char *w = "a";
/// \endcode
/// constantArrayType(hasSize(42))
/// matches "int a[42]" and "int b[2 * 21]"
-AST_MATCHER_P(ConstantArrayType, hasSize, unsigned, N) {
- return Node.getSize() == N;
+/// stringLiteral(hasSize(4))
+/// matches "abcd", L"abcd"
+AST_POLYMORPHIC_MATCHER_P(hasSize,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(ConstantArrayType,
+ StringLiteral),
+ unsigned, N) {
+ return internal::HasSizeMatcher<NodeType>::hasSize(Node, N);
}
/// \brief Matches C++ arrays whose size is a value-dependent expression.
@@ -3988,6 +4591,18 @@ AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType,
/// matches "int (*f)(int)" and the type of "g".
AST_TYPE_MATCHER(FunctionType, functionType);
+/// \brief Matches \c FunctionProtoType nodes.
+///
+/// Given
+/// \code
+/// int (*f)(int);
+/// void g();
+/// \endcode
+/// functionProtoType()
+/// matches "int (*f)(int)" and the type of "g" in C++ mode.
+/// In C mode, "g" is not matched because it does not contain a prototype.
+AST_TYPE_MATCHER(FunctionProtoType, functionProtoType);
+
/// \brief Matches \c ParenType nodes.
///
/// Given
@@ -4143,6 +4758,21 @@ AST_TYPELOC_TRAVERSE_MATCHER(pointee, getPointee,
/// matches "typedef int X"
AST_TYPE_MATCHER(TypedefType, typedefType);
+/// \brief Matches enum types.
+///
+/// Given
+/// \code
+/// enum C { Green };
+/// enum class S { Red };
+///
+/// C c;
+/// S s;
+/// \endcode
+//
+/// \c enumType() matches the type of the variable declarations of both \c c and
+/// \c s.
+AST_TYPE_MATCHER(EnumType, enumType);
+
/// \brief Matches template specialization types.
///
/// Given
@@ -4563,6 +5193,23 @@ AST_MATCHER(CXXConstructorDecl, isDefaultConstructor) {
return Node.isDefaultConstructor();
}
+/// \brief Matches constructors that delegate to another constructor.
+///
+/// Given
+/// \code
+/// struct S {
+/// S(); // #1
+/// S(int) {} // #2
+/// S(S &&) : S() {} // #3
+/// };
+/// S::S() : S(0) {} // #4
+/// \endcode
+/// cxxConstructorDecl(isDelegatingConstructor()) will match #3 and #4, but not
+/// #1 or #2.
+AST_MATCHER(CXXConstructorDecl, isDelegatingConstructor) {
+ return Node.isDelegatingConstructor();
+}
+
/// \brief Matches constructor and conversion declarations that are marked with
/// the explicit keyword.
///
@@ -4655,6 +5302,24 @@ AST_MATCHER_P(Decl, hasAttr, attr::Kind, AttrKind) {
return false;
}
+/// \brief Matches the return value expression of a return statement
+///
+/// Given
+/// \code
+/// return a + b;
+/// \endcode
+/// hasReturnValue(binaryOperator())
+/// matches 'return a + b'
+/// with binaryOperator()
+/// matching 'a + b'
+AST_MATCHER_P(ReturnStmt, hasReturnValue, internal::Matcher<Expr>,
+ InnerMatcher) {
+ if (const auto *RetValue = Node.getRetValue())
+ return InnerMatcher.matches(*RetValue, Finder, Builder);
+ return false;
+}
+
+
/// \brief Matches CUDA kernel call expression.
///
/// Example matches,
@@ -4665,6 +5330,66 @@ const internal::VariadicDynCastAllOfMatcher<
Stmt,
CUDAKernelCallExpr> cudaKernelCallExpr;
+
+/// \brief Matches expressions that resolve to a null pointer constant, such as
+/// GNU's __null, C++11's nullptr, or C's NULL macro.
+///
+/// Given:
+/// \code
+/// void *v1 = NULL;
+/// void *v2 = nullptr;
+/// void *v3 = __null; // GNU extension
+/// char *cp = (char *)0;
+/// int *ip = 0;
+/// int i = 0;
+/// \endcode
+/// expr(nullPointerConstant())
+/// matches the initializer for v1, v2, v3, cp, and ip. Does not match the
+/// initializer for i.
+AST_MATCHER_FUNCTION(internal::Matcher<Expr>, nullPointerConstant) {
+ return anyOf(
+ gnuNullExpr(), cxxNullPtrLiteralExpr(),
+ integerLiteral(equals(0), hasParent(expr(hasType(pointerType())))));
+}
+
+/// \brief Matches declaration of the function the statemenet belongs to
+///
+/// Given:
+/// \code
+/// F& operator=(const F& o) {
+/// std::copy_if(o.begin(), o.end(), begin(), [](V v) { return v > 0; });
+/// return *this;
+/// }
+/// \endcode
+/// returnStmt(forFunction(hasName("operator=")))
+/// matches 'return *this'
+/// but does match 'return > 0'
+AST_MATCHER_P(Stmt, forFunction, internal::Matcher<FunctionDecl>,
+ InnerMatcher) {
+ const auto &Parents = Finder->getASTContext().getParents(Node);
+
+ llvm::SmallVector<ast_type_traits::DynTypedNode, 8> Stack(Parents.begin(),
+ Parents.end());
+ while(!Stack.empty()) {
+ const auto &CurNode = Stack.back();
+ Stack.pop_back();
+ if(const auto *FuncDeclNode = CurNode.get<FunctionDecl>()) {
+ if(InnerMatcher.matches(*FuncDeclNode, Finder, Builder)) {
+ return true;
+ }
+ } else if(const auto *LambdaExprNode = CurNode.get<LambdaExpr>()) {
+ if(InnerMatcher.matches(*LambdaExprNode->getCallOperator(),
+ Finder, Builder)) {
+ return true;
+ }
+ } else {
+ for(const auto &Parent: Finder->getASTContext().getParents(CurNode))
+ Stack.push_back(Parent);
+ }
+ }
+ return false;
+}
+
} // end namespace ast_matchers
} // end namespace clang
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index 1d1d7952c1667..c2c01fbd78ea3 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -46,8 +46,9 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/Type.h"
+#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/VariadicFunction.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/ManagedStatic.h"
#include <map>
#include <string>
@@ -60,6 +61,62 @@ class BoundNodes;
namespace internal {
+/// \brief Variadic function object.
+///
+/// Most of the functions below that use VariadicFunction could be implemented
+/// using plain C++11 variadic functions, but the function object allows us to
+/// capture it on the dynamic matcher registry.
+template <typename ResultT, typename ArgT,
+ ResultT (*Func)(ArrayRef<const ArgT *>)>
+struct VariadicFunction {
+ ResultT operator()() const { return Func(None); }
+
+ template <typename... ArgsT>
+ ResultT operator()(const ArgT &Arg1, const ArgsT &... Args) const {
+ return Execute(Arg1, static_cast<const ArgT &>(Args)...);
+ }
+
+ // We also allow calls with an already created array, in case the caller
+ // already had it.
+ ResultT operator()(ArrayRef<ArgT> Args) const {
+ SmallVector<const ArgT*, 8> InnerArgs;
+ for (const ArgT &Arg : Args)
+ InnerArgs.push_back(&Arg);
+ return Func(InnerArgs);
+ }
+
+private:
+ // Trampoline function to allow for implicit conversions to take place
+ // before we make the array.
+ template <typename... ArgsT> ResultT Execute(const ArgsT &... Args) const {
+ const ArgT *const ArgsArray[] = {&Args...};
+ return Func(ArrayRef<const ArgT *>(ArgsArray, sizeof...(ArgsT)));
+ }
+};
+
+/// \brief Unifies obtaining the underlying type of a regular node through
+/// `getType` and a TypedefNameDecl node through `getUnderlyingType`.
+inline QualType getUnderlyingType(const Expr &Node) { return Node.getType(); }
+
+inline QualType getUnderlyingType(const ValueDecl &Node) {
+ return Node.getType();
+}
+
+inline QualType getUnderlyingType(const TypedefNameDecl &Node) {
+ return Node.getUnderlyingType();
+}
+
+/// \brief Unifies obtaining the FunctionProtoType pointer from both
+/// FunctionProtoType and FunctionDecl nodes..
+inline const FunctionProtoType *
+getFunctionProtoType(const FunctionProtoType &Node) {
+ return &Node;
+}
+
+inline const FunctionProtoType *getFunctionProtoType(const FunctionDecl &Node) {
+ return Node.getType()->getAs<FunctionProtoType>();
+}
+
/// \brief Internal version of BoundNodes. Holds all the bound nodes.
class BoundNodesMap {
public:
@@ -420,7 +477,7 @@ public:
template <typename From>
Matcher(const Matcher<From> &Other,
typename std::enable_if<std::is_base_of<From, T>::value &&
- !std::is_same<From, T>::value>::type * = 0)
+ !std::is_same<From, T>::value>::type * = nullptr)
: Implementation(restrictMatcher(Other.Implementation)) {
assert(Implementation.getSupportedKind().isSame(
ast_type_traits::ASTNodeKind::getFromNodeKind<T>()));
@@ -433,7 +490,7 @@ public:
Matcher(const Matcher<TypeT> &Other,
typename std::enable_if<
std::is_same<T, QualType>::value &&
- std::is_same<TypeT, Type>::value>::type* = 0)
+ std::is_same<TypeT, Type>::value>::type* = nullptr)
: Implementation(new TypeToQualType<TypeT>(Other)) {}
/// \brief Convert \c this into a \c Matcher<T> by applying dyn_cast<> to the
@@ -558,32 +615,21 @@ bool matchesFirstInPointerRange(const MatcherT &Matcher, IteratorT Start,
return false;
}
-// Metafunction to determine if type T has a member called
-// getDecl.
-#if defined(_MSC_VER) && !defined(__clang__)
-// For MSVC, we use a weird nonstandard __if_exists statement, as it
-// is not standards-conformant enough to properly compile the standard
-// code below. (At least up through MSVC 2015 require this workaround)
-template <typename T> struct has_getDecl {
- __if_exists(T::getDecl) {
- enum { value = 1 };
- }
- __if_not_exists(T::getDecl) {
- enum { value = 0 };
- }
+// Metafunction to determine if type T has a member called getDecl.
+template <typename Ty>
+class has_getDecl {
+ typedef char yes[1];
+ typedef char no[2];
+
+ template <typename Inner>
+ static yes& test(Inner *I, decltype(I->getDecl()) * = nullptr);
+
+ template <typename>
+ static no& test(...);
+
+public:
+ static const bool value = sizeof(test<Ty>(nullptr)) == sizeof(yes);
};
-#else
-// There is a default template inheriting from "false_type". Then, a
-// partial specialization inherits from "true_type". However, this
-// specialization will only exist when the call to getDecl() isn't an
-// error -- it vanishes by SFINAE when the member doesn't exist.
-template <typename> struct type_sink_to_void { typedef void type; };
-template <typename T, typename = void> struct has_getDecl : std::false_type {};
-template <typename T>
-struct has_getDecl<
- T, typename type_sink_to_void<decltype(std::declval<T>().getDecl())>::type>
- : std::true_type {};
-#endif
/// \brief Matches overloaded operators with a specific name.
///
@@ -626,10 +672,10 @@ private:
/// \brief Matches named declarations with a specific name.
///
-/// See \c hasName() in ASTMatchers.h for details.
+/// See \c hasName() and \c hasAnyName() in ASTMatchers.h for details.
class HasNameMatcher : public SingleNodeMatcherInterface<NamedDecl> {
public:
- explicit HasNameMatcher(StringRef Name);
+ explicit HasNameMatcher(std::vector<std::string> Names);
bool matchesNode(const NamedDecl &Node) const override;
@@ -642,15 +688,27 @@ class HasNameMatcher : public SingleNodeMatcherInterface<NamedDecl> {
/// \brief Full match routine
///
+ /// Fast implementation for the simple case of a named declaration at
+ /// namespace or RecordDecl scope.
+ /// It is slower than matchesNodeUnqualified, but faster than
+ /// matchesNodeFullSlow.
+ bool matchesNodeFullFast(const NamedDecl &Node) const;
+
+ /// \brief Full match routine
+ ///
/// It generates the fully qualified name of the declaration (which is
/// expensive) before trying to match.
/// It is slower but simple and works on all cases.
- bool matchesNodeFull(const NamedDecl &Node) const;
+ bool matchesNodeFullSlow(const NamedDecl &Node) const;
const bool UseUnqualifiedMatch;
- const std::string Name;
+ const std::vector<std::string> Names;
};
+/// \brief Trampoline function to use VariadicFunction<> to construct a
+/// HasNameMatcher.
+Matcher<NamedDecl> hasAnyNameFunc(ArrayRef<const StringRef *> NameRefs);
+
/// \brief Matches declarations for QualType and CallExpr.
///
/// Type argument DeclMatcherT is required by PolymorphicMatcherWithParam1 but
@@ -737,6 +795,14 @@ private:
return matchesDecl(Node.getMemberDecl(), Finder, Builder);
}
+ /// \brief Extracts the \c LabelDecl a \c AddrLabelExpr refers to and returns
+ /// whether the inner matcher matches on it.
+ bool matchesSpecialized(const AddrLabelExpr &Node,
+ ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ return matchesDecl(Node.getLabel(), Finder, Builder);
+ }
+
/// \brief Returns whether the inner matcher \c Node. Returns false if \c Node
/// is \c NULL.
bool matchesDecl(const Decl *Node, ASTMatchFinder *Finder,
@@ -942,8 +1008,8 @@ typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc,
/// \brief All types that are supported by HasDeclarationMatcher above.
typedef TypeList<CallExpr, CXXConstructExpr, DeclRefExpr, EnumType,
- InjectedClassNameType, LabelStmt, MemberExpr, QualType,
- RecordType, TagType, TemplateSpecializationType,
+ InjectedClassNameType, LabelStmt, AddrLabelExpr, MemberExpr,
+ QualType, RecordType, TagType, TemplateSpecializationType,
TemplateTypeParmType, TypedefType,
UnresolvedUsingType> HasDeclarationSupportedTypes;
@@ -1110,8 +1176,6 @@ public:
/// ChildT must be an AST base type.
template <typename T, typename ChildT>
class HasMatcher : public WrapperMatcherInterface<T> {
- static_assert(IsBaseType<ChildT>::value,
- "has only accepts base type matcher");
public:
explicit HasMatcher(const Matcher<ChildT> &ChildMatcher)
@@ -1119,10 +1183,9 @@ public:
bool matches(const T &Node, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const override {
- return Finder->matchesChildOf(
- Node, this->InnerMatcher, Builder,
- ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
- ASTMatchFinder::BK_First);
+ return Finder->matchesChildOf(Node, this->InnerMatcher, Builder,
+ ASTMatchFinder::TK_AsIs,
+ ASTMatchFinder::BK_First);
}
};
@@ -1385,9 +1448,8 @@ inline bool ValueEqualsMatcher<FloatingLiteral, llvm::APFloat>::matchesNode(
/// casted to CXXRecordDecl and all given matchers match.
template <typename SourceT, typename TargetT>
class VariadicDynCastAllOfMatcher
- : public llvm::VariadicFunction<
- BindableMatcher<SourceT>, Matcher<TargetT>,
- makeDynCastAllOfComposite<SourceT, TargetT> > {
+ : public VariadicFunction<BindableMatcher<SourceT>, Matcher<TargetT>,
+ makeDynCastAllOfComposite<SourceT, TargetT>> {
public:
VariadicDynCastAllOfMatcher() {}
};
@@ -1403,9 +1465,9 @@ public:
/// \c Matcher<NestedNameSpecifier>.
/// The returned matcher matches if all given matchers match.
template <typename T>
-class VariadicAllOfMatcher : public llvm::VariadicFunction<
- BindableMatcher<T>, Matcher<T>,
- makeAllOfComposite<T> > {
+class VariadicAllOfMatcher
+ : public VariadicFunction<BindableMatcher<T>, Matcher<T>,
+ makeAllOfComposite<T>> {
public:
VariadicAllOfMatcher() {}
};
@@ -1526,8 +1588,8 @@ public:
new MatcherImpl<OuterT>(InnerMatcher, Getter<OuterT>::value()));
}
- struct Func : public llvm::VariadicFunction<Self, Matcher<InnerTBase>,
- &Self::create> {
+ struct Func
+ : public VariadicFunction<Self, Matcher<InnerTBase>, &Self::create> {
Func() {}
};
@@ -1584,8 +1646,60 @@ struct NotEqualsBoundNodePredicate {
ast_type_traits::DynTypedNode Node;
};
+template <typename Ty>
+struct GetBodyMatcher {
+ static const Stmt *get(const Ty &Node) {
+ return Node.getBody();
+ }
+};
+
+template <>
+inline const Stmt *GetBodyMatcher<FunctionDecl>::get(const FunctionDecl &Node) {
+ return Node.doesThisDeclarationHaveABody() ? Node.getBody() : nullptr;
+}
+
+template <typename Ty>
+struct HasSizeMatcher {
+ static bool hasSize(const Ty &Node, unsigned int N) {
+ return Node.getSize() == N;
+ }
+};
+
+template <>
+inline bool HasSizeMatcher<StringLiteral>::hasSize(
+ const StringLiteral &Node, unsigned int N) {
+ return Node.getLength() == N;
+}
+
+template <typename Ty>
+struct GetSourceExpressionMatcher {
+ static const Expr *get(const Ty &Node) {
+ return Node.getSubExpr();
+ }
+};
+
+template <>
+inline const Expr *GetSourceExpressionMatcher<OpaqueValueExpr>::get(
+ const OpaqueValueExpr &Node) {
+ return Node.getSourceExpr();
+}
+
+template <typename Ty>
+struct CompoundStmtMatcher {
+ static const CompoundStmt *get(const Ty &Node) {
+ return &Node;
+ }
+};
+
+template <>
+inline const CompoundStmt *
+CompoundStmtMatcher<StmtExpr>::get(const StmtExpr &Node) {
+ return Node.getSubStmt();
+}
+
+
} // end namespace internal
} // end namespace ast_matchers
} // end namespace clang
-#endif
+#endif // LLVM_CLANG_ASTMATCHERS_ASTMATCHERSINTERNAL_H