diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -2699,6 +2699,60 @@ return Node.size() == N; } +/// Matches the attribute(s) attached to a Stmt +/// +/// Example: Matches [[likely]] and [[unlikely]] +/// \code +/// constexpr double pow(double x, long long n) noexcept { +/// if (n > 0) [[likely]] +/// return x * pow(x, n - 1); +/// else [[unlikely]] +/// return 1; +/// } +/// \endcode +extern const internal::VariadicDynCastAllOfMatcher + attributedStmt; + +/// Matches the specified attribute. +/// +/// Example: +/// \code +/// attributedStmt(isAttr(attr::Likely)) +/// \endcode +/// would only match [[likely]] here: +/// \code +/// constexpr double pow(double x, long long n) noexcept { +/// if (n > 0) [[likely]] +/// return x * pow(x, n - 1); +/// else [[unlikely]] +/// return 1; +/// } +/// \endcode +AST_MATCHER_P(AttributedStmt, isAttr, attr::Kind, AttrKind) { + for (const auto *Attr : Node.getAttrs()) { + if (Attr->getKind() == AttrKind) { + return true; + } + } + return false; +} + +/// Matches the statement an attribute is attached to. +/// +/// Example: +/// \code +/// attributedStmt(hasSubStmt(returnStmt())) +/// \endcode +/// would match return 1; here: +/// \code +/// else [[unlikely]] +/// return 1; +/// \endcode +AST_MATCHER_P(AttributedStmt, hasSubStmt, internal::Matcher, InnerMatcher) { + const Stmt *const Statement = Node.getSubStmt(); + return (Statement != nullptr && InnerMatcher.matches(*Statement, Finder, Builder)); +} + /// Matches \c QualTypes in the clang AST. extern const internal::VariadicAllOfMatcher qualType; diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3959,3 +3959,9 @@ let Args = [StringArgument<"MatcherName">]; let Documentation = [Undocumented]; } + +def MatcherBlock : StmtAttr { + let Spellings = [Clang<"matcher_block">]; + let Subjects = SubjectList<[CompoundStmt], ErrorDiag, "compound stmts">; + let Documentation = [Undocumented]; +} diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -981,6 +981,8 @@ predefinedExpr; const internal::VariadicDynCastAllOfMatcher designatedInitExpr; +const internal::VariadicDynCastAllOfMatcher + attributedStmt; const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits::max()> eachOf = {internal::DynTypedMatcher::VO_EachOf}; diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -142,6 +142,7 @@ REGISTER_MATCHER(atomicExpr); REGISTER_MATCHER(atomicType); REGISTER_MATCHER(attr); + REGISTER_MATCHER(attributedStmt); REGISTER_MATCHER(autoType); REGISTER_MATCHER(autoreleasePoolStmt) REGISTER_MATCHER(binaryConditionalOperator); @@ -355,6 +356,7 @@ REGISTER_MATCHER(hasSpecializedTemplate); REGISTER_MATCHER(hasStaticStorageDuration); REGISTER_MATCHER(hasStructuredBlock); + REGISTER_MATCHER(hasSubStmt); REGISTER_MATCHER(hasSyntacticForm); REGISTER_MATCHER(hasTargetDecl); REGISTER_MATCHER(hasTemplateArgument); @@ -395,6 +397,7 @@ REGISTER_MATCHER(isArrow); REGISTER_MATCHER(isAssignmentOperator); REGISTER_MATCHER(isAtPosition); + REGISTER_MATCHER(isAttr); REGISTER_MATCHER(isBaseInitializer); REGISTER_MATCHER(isBitField); REGISTER_MATCHER(isCatchAll); diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -233,6 +233,11 @@ return ::new (S.Context) UnlikelyAttr(S.Context, A); } +static Attr *handleMatcherBlock(Sema &S, Stmt *St, const ParsedAttr &A, + SourceRange Range) { + return ::new (S.Context) MatcherBlockAttr(S.Context, A); +} + #define WANT_STMT_MERGE_LOGIC #include "clang/Sema/AttrParsedAttrImpl.inc" #undef WANT_STMT_MERGE_LOGIC @@ -424,6 +429,8 @@ return handleLikely(S, St, A, Range); case ParsedAttr::AT_Unlikely: return handleUnlikely(S, St, A, Range); + case ParsedAttr::AT_MatcherBlock: + return handleMatcherBlock(S, St, A, Range); default: // N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a // declaration attribute is not written on a statement, but this code is