diff options
Diffstat (limited to 'include/clang/ASTMatchers')
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchFinder.h | 15 | ||||
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchers.h | 839 | ||||
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchersInternal.h | 212 |
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 |