diff options
Diffstat (limited to 'include/clang/ASTMatchers/ASTMatchers.h')
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchers.h | 331 |
1 files changed, 308 insertions, 23 deletions
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index 5cdb964a92..0e4b9f7233 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -1,9 +1,8 @@ //===- ASTMatchers.h - Structural query framework ---------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -57,10 +56,12 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/OpenMPClause.h" #include "clang/AST/OperationKinds.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtOpenMP.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" @@ -2159,6 +2160,10 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundLiteralExpr> extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNullPtrLiteralExpr> cxxNullPtrLiteralExpr; +/// Matches GNU __builtin_choose_expr. +extern const internal::VariadicDynCastAllOfMatcher<Stmt, ChooseExpr> + chooseExpr; + /// Matches GNU __null expression. extern const internal::VariadicDynCastAllOfMatcher<Stmt, GNUNullExpr> gnuNullExpr; @@ -2487,6 +2492,9 @@ AST_MATCHER_P(UnaryExprOrTypeTraitExpr, hasArgumentOfType, /// \endcode /// unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf)) /// matches \c sizeof(x) +/// +/// If the matcher is use from clang-query, UnaryExprOrTypeTrait parameter +/// should be passed as a quoted string. e.g., ofKind("UETT_SizeOf"). AST_MATCHER_P(UnaryExprOrTypeTraitExpr, ofKind, UnaryExprOrTypeTrait, Kind) { return Node.getKind() == Kind; } @@ -2887,14 +2895,22 @@ AST_MATCHER_P(NamedDecl, hasUnderlyingDecl, internal::Matcher<NamedDecl>, InnerMatcher.matches(*UnderlyingDecl, Finder, Builder); } -/// Matches on the implicit object argument of a member call expression. +/// Matches on the implicit object argument of a member call expression, after +/// stripping off any parentheses or implicit casts. /// -/// Example matches y.x() -/// (matcher = cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("Y")))))) +/// Given /// \code -/// class Y { public: void x(); }; -/// void z() { Y y; y.x(); } +/// class Y { public: void m(); }; +/// Y g(); +/// class X : public Y {}; +/// void z(Y y, X x) { y.m(); (g()).m(); x.m(); } /// \endcode +/// cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("Y"))))) +/// matches `y.m()` and `(g()).m()`. +/// cxxMemberCallExpr(on(hasType(cxxRecordDecl(hasName("X"))))) +/// matches `x.m()`. +/// cxxMemberCallExpr(on(callExpr())) +/// matches `(g()).m()`. /// /// FIXME: Overload to allow directly matching types? AST_MATCHER_P(CXXMemberCallExpr, on, internal::Matcher<Expr>, @@ -2922,10 +2938,59 @@ AST_MATCHER_P(ObjCMessageExpr, hasReceiverType, internal::Matcher<QualType>, return InnerMatcher.matches(TypeDecl, Finder, Builder); } +/// Returns true when the Objective-C method declaration is a class method. +/// +/// Example +/// matcher = objcMethodDecl(isClassMethod()) +/// matches +/// \code +/// @interface I + (void)foo; @end +/// \endcode +/// but not +/// \code +/// @interface I - (void)bar; @end +/// \endcode +AST_MATCHER(ObjCMethodDecl, isClassMethod) { + return Node.isClassMethod(); +} + +/// Returns true when the Objective-C method declaration is an instance method. +/// +/// Example +/// matcher = objcMethodDecl(isInstanceMethod()) +/// matches +/// \code +/// @interface I - (void)bar; @end +/// \endcode +/// but not +/// \code +/// @interface I + (void)foo; @end +/// \endcode +AST_MATCHER(ObjCMethodDecl, isInstanceMethod) { + return Node.isInstanceMethod(); +} + +/// Returns true when the Objective-C message is sent to a class. +/// +/// Example +/// matcher = objcMessageExpr(isClassMessage()) +/// matches +/// \code +/// [NSString stringWithFormat:@"format"]; +/// \endcode +/// but not +/// \code +/// NSString *x = @"hello"; +/// [x containsString:@"h"]; +/// \endcode +AST_MATCHER(ObjCMessageExpr, isClassMessage) { + return Node.isClassMessage(); +} + /// Returns true when the Objective-C message is sent to an instance. /// /// Example -/// matcher = objcMessagaeExpr(isInstanceMessage()) +/// matcher = objcMessageExpr(isInstanceMessage()) /// matches /// \code /// NSString *x = @"hello"; @@ -3254,6 +3319,23 @@ AST_MATCHER_P_OVERLOAD(QualType, references, internal::Matcher<Decl>, .matches(Node, Finder, Builder); } +/// Matches on the implicit object argument of a member call expression. Unlike +/// `on`, matches the argument directly without stripping away anything. +/// +/// Given +/// \code +/// class Y { public: void m(); }; +/// Y g(); +/// class X : public Y { void g(); }; +/// void z(Y y, X x) { y.m(); x.m(); x.g(); (g()).m(); } +/// \endcode +/// cxxMemberCallExpr(onImplicitObjectArgument(hasType( +/// cxxRecordDecl(hasName("Y"))))) +/// matches `y.m()`, `x.m()` and (g()).m(), but not `x.g()`. +/// cxxMemberCallExpr(on(callExpr())) +/// does not match `(g()).m()`, because the parens are not ignored. +/// +/// FIXME: Overload to allow directly matching types? AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument, internal::Matcher<Expr>, InnerMatcher) { const Expr *ExprNode = Node.getImplicitObjectArgument(); @@ -3261,8 +3343,22 @@ AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument, InnerMatcher.matches(*ExprNode, Finder, Builder)); } -/// Matches if the expression's type either matches the specified -/// matcher, or is a pointer to a type that matches the InnerMatcher. +/// Matches if the type of the expression's implicit object argument either +/// matches the InnerMatcher, or is a pointer to a type that matches the +/// InnerMatcher. +/// +/// Given +/// \code +/// class Y { public: void m(); }; +/// class X : public Y { void g(); }; +/// void z() { Y y; y.m(); Y *p; p->m(); X x; x.m(); x.g(); } +/// \endcode +/// cxxMemberCallExpr(thisPointerType(hasDeclaration( +/// cxxRecordDecl(hasName("Y"))))) +/// matches `y.m()`, `p->m()` and `x.m()`. +/// cxxMemberCallExpr(thisPointerType(hasDeclaration( +/// cxxRecordDecl(hasName("X"))))) +/// matches `x.g()`. AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType, internal::Matcher<QualType>, InnerMatcher, 0) { return onImplicitObjectArgument( @@ -4439,6 +4535,9 @@ AST_POLYMORPHIC_MATCHER_P(hasSourceExpression, /// \code /// int *p = 0; /// \endcode +/// +/// If the matcher is use from clang-query, CastKind parameter +/// should be passed as a quoted string. e.g., ofKind("CK_NullToPointer"). AST_MATCHER_P(CastExpr, hasCastKind, CastKind, Kind) { return Node.getCastKind() == Kind; } @@ -4964,18 +5063,22 @@ AST_MATCHER_P(MemberExpr, member, return InnerMatcher.matches(*Node.getMemberDecl(), Finder, Builder); } -/// Matches a member expression where the object expression is -/// matched by a given matcher. +/// Matches a member expression where the object expression is matched by a +/// given matcher. Implicit object expressions are included; that is, it matches +/// use of implicit `this`. /// /// Given /// \code -/// struct X { int m; }; -/// void f(X x) { x.m; m; } +/// struct X { +/// int m; +/// int f(X x) { x.m; return m; } +/// }; /// \endcode -/// memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X"))))))) -/// matches "x.m" and "m" -/// with hasObjectExpression(...) -/// matching "x" and the implicit object expression of "m" which has type X*. +/// memberExpr(hasObjectExpression(hasType(cxxRecordDecl(hasName("X"))))) +/// matches `x.m`, but not `m`; however, +/// memberExpr(hasObjectExpression(hasType(pointsTo( +// cxxRecordDecl(hasName("X")))))) +/// matches `m` (aka. `this->m`), but not `x.m`. AST_POLYMORPHIC_MATCHER_P( hasObjectExpression, AST_POLYMORPHIC_SUPPORTED_TYPES(MemberExpr, UnresolvedMemberExpr, @@ -6109,6 +6212,29 @@ AST_MATCHER(NamespaceDecl, isAnonymous) { return Node.isAnonymousNamespace(); } +/// Matches declarations in the namespace `std`, but not in nested namespaces. +/// +/// Given +/// \code +/// class vector {}; +/// namespace foo { +/// class vector {}; +/// namespace std { +/// class vector {}; +/// } +/// } +/// namespace std { +/// inline namespace __1 { +/// class vector {}; // #1 +/// namespace experimental { +/// class vector {}; +/// } +/// } +/// } +/// \endcode +/// cxxRecordDecl(hasName("vector"), isInStdNamespace()) will match only #1. +AST_MATCHER(Decl, isInStdNamespace) { return Node.isInStdNamespace(); } + /// If the given case statement does not use the GNU case range /// extension, matches the constant given in the statement. /// @@ -6133,7 +6259,7 @@ AST_MATCHER_P(CaseStmt, hasCaseConstant, internal::Matcher<Expr>, /// __attribute__((device)) void f() { ... } /// \endcode /// decl(hasAttr(clang::attr::CUDADevice)) matches the function declaration of -/// f. If the matcher is use from clang-query, attr::Kind parameter should be +/// f. If the matcher is used from clang-query, attr::Kind parameter should be /// passed as a quoted string. e.g., hasAttr("attr::CUDADevice"). AST_MATCHER_P(Decl, hasAttr, attr::Kind, AttrKind) { for (const auto *Attr : Node.attrs()) { @@ -6284,8 +6410,8 @@ AST_MATCHER(CXXNewExpr, isArray) { /// cxxNewExpr(hasArraySize(intgerLiteral(equals(10)))) /// matches the expression 'new MyClass[10]'. AST_MATCHER_P(CXXNewExpr, hasArraySize, internal::Matcher<Expr>, InnerMatcher) { - return Node.isArray() && - InnerMatcher.matches(*Node.getArraySize(), Finder, Builder); + return Node.isArray() && *Node.getArraySize() && + InnerMatcher.matches(**Node.getArraySize(), Finder, Builder); } /// Matches a class declaration that is defined. @@ -6323,6 +6449,165 @@ AST_MATCHER(FunctionDecl, hasTrailingReturn) { return false; } +//----------------------------------------------------------------------------// +// OpenMP handling. +//----------------------------------------------------------------------------// + +/// Matches any ``#pragma omp`` executable directive. +/// +/// Given +/// +/// \code +/// #pragma omp parallel +/// #pragma omp parallel default(none) +/// #pragma omp taskyield +/// \endcode +/// +/// ``ompExecutableDirective()`` matches ``omp parallel``, +/// ``omp parallel default(none)`` and ``omp taskyield``. +extern const internal::VariadicDynCastAllOfMatcher<Stmt, OMPExecutableDirective> + ompExecutableDirective; + +/// Matches standalone OpenMP directives, +/// i.e., directives that can't have a structured block. +/// +/// Given +/// +/// \code +/// #pragma omp parallel +/// {} +/// #pragma omp taskyield +/// \endcode +/// +/// ``ompExecutableDirective(isStandaloneDirective()))`` matches +/// ``omp taskyield``. +AST_MATCHER(OMPExecutableDirective, isStandaloneDirective) { + return Node.isStandaloneDirective(); +} + +/// Matches the Stmt AST node that is marked as being the structured-block +/// of an OpenMP executable directive. +/// +/// Given +/// +/// \code +/// #pragma omp parallel +/// {} +/// \endcode +/// +/// ``stmt(isOMPStructuredBlock()))`` matches ``{}``. +AST_MATCHER(Stmt, isOMPStructuredBlock) { return Node.isOMPStructuredBlock(); } + +/// Matches the structured-block of the OpenMP executable directive +/// +/// Prerequisite: the executable directive must not be standalone directive. +/// If it is, it will never match. +/// +/// Given +/// +/// \code +/// #pragma omp parallel +/// ; +/// #pragma omp parallel +/// {} +/// \endcode +/// +/// ``ompExecutableDirective(hasStructuredBlock(nullStmt()))`` will match ``;`` +AST_MATCHER_P(OMPExecutableDirective, hasStructuredBlock, + internal::Matcher<Stmt>, InnerMatcher) { + if (Node.isStandaloneDirective()) + return false; // Standalone directives have no structured blocks. + return InnerMatcher.matches(*Node.getStructuredBlock(), Finder, Builder); +} + +/// Matches any clause in an OpenMP directive. +/// +/// Given +/// +/// \code +/// #pragma omp parallel +/// #pragma omp parallel default(none) +/// \endcode +/// +/// ``ompExecutableDirective(hasAnyClause(anything()))`` matches +/// ``omp parallel default(none)``. +AST_MATCHER_P(OMPExecutableDirective, hasAnyClause, + internal::Matcher<OMPClause>, InnerMatcher) { + ArrayRef<OMPClause *> Clauses = Node.clauses(); + return matchesFirstInPointerRange(InnerMatcher, Clauses.begin(), + Clauses.end(), Finder, Builder); +} + +/// Matches OpenMP ``default`` clause. +/// +/// Given +/// +/// \code +/// #pragma omp parallel default(none) +/// #pragma omp parallel default(shared) +/// #pragma omp parallel +/// \endcode +/// +/// ``ompDefaultClause()`` matches ``default(none)`` and ``default(shared)``. +extern const internal::VariadicDynCastAllOfMatcher<OMPClause, OMPDefaultClause> + ompDefaultClause; + +/// Matches if the OpenMP ``default`` clause has ``none`` kind specified. +/// +/// Given +/// +/// \code +/// #pragma omp parallel +/// #pragma omp parallel default(none) +/// #pragma omp parallel default(shared) +/// \endcode +/// +/// ``ompDefaultClause(isNoneKind())`` matches only ``default(none)``. +AST_MATCHER(OMPDefaultClause, isNoneKind) { + return Node.getDefaultKind() == OMPC_DEFAULT_none; +} + +/// Matches if the OpenMP ``default`` clause has ``shared`` kind specified. +/// +/// Given +/// +/// \code +/// #pragma omp parallel +/// #pragma omp parallel default(none) +/// #pragma omp parallel default(shared) +/// \endcode +/// +/// ``ompDefaultClause(isSharedKind())`` matches only ``default(shared)``. +AST_MATCHER(OMPDefaultClause, isSharedKind) { + return Node.getDefaultKind() == OMPC_DEFAULT_shared; +} + +/// Matches if the OpenMP directive is allowed to contain the specified OpenMP +/// clause kind. +/// +/// Given +/// +/// \code +/// #pragma omp parallel +/// #pragma omp parallel for +/// #pragma omp for +/// \endcode +/// +/// `ompExecutableDirective(isAllowedToContainClause(OMPC_default))`` matches +/// ``omp parallel`` and ``omp parallel for``. +/// +/// If the matcher is use from clang-query, ``OpenMPClauseKind`` parameter +/// should be passed as a quoted string. e.g., +/// ``isAllowedToContainClauseKind("OMPC_default").`` +AST_MATCHER_P(OMPExecutableDirective, isAllowedToContainClauseKind, + OpenMPClauseKind, CKind) { + return isAllowedClauseForDirective(Node.getDirectiveKind(), CKind); +} + +//----------------------------------------------------------------------------// +// End OpenMP handling. +//----------------------------------------------------------------------------// + } // namespace ast_matchers } // namespace clang |