diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -1283,6 +1283,21 @@ +
Matches the attribute(s) attached to a Stmt
+
+Given:
+ constexpr double pow(double x, long long n) noexcept {
+ if (n > 0) [[likely]]
+ return x * pow(x, n - 1);
+ else [[unlikely]]
+ return 1;
+ }
+attributedStmt() matches "[[likely]] return ...;" and
+"[[unlikely]] return 1;"
+Matches an Objective-C autorelease pool statement. @@ -2852,6 +2867,21 @@
Matches the specified attribute.
+
+Example:
+ attributedStmt(isAttr(attr::Likely))
+would only match "[[likely]] return ...;" here:
+ constexpr double pow(double x, long long n) noexcept {
+ if (n > 0) [[likely]]
+ return x * pow(x, n - 1);
+ else [[unlikely]]
+ return 1;
+ }
+Matches an entity that has been implicitly added by the compiler (e.g. implicit default/copy constructors). @@ -3037,6 +3067,17 @@
Checks that a call expression or a constructor call expression has +a specific number of arguments (EXCLUDING absent default arguments). + +Example matches f(0, 0) but not f(0) (matcher = callExpr(argumentsGivenCountIs(2))) + void f(int x, int y = 0); + f(0, 0); + f(0); +
Matches a constructor call expression which uses list initialization.
Checks that a call expression or a constructor call expression has +a specific number of arguments (EXCLUDING absent default arguments). + +Example matches f(0, 0) but not f(0) (matcher = callExpr(argumentsGivenCountIs(2))) + void f(int x, int y = 0); + f(0, 0); + f(0); +
Checks that a call expression or a constructor call expression has a specific number of arguments (including absent default arguments). @@ -3704,6 +3756,17 @@
Checks that a call expression or a constructor call expression has +a specific number of arguments (EXCLUDING absent default arguments). + +Example matches f(0, 0) but not f(0) (matcher = callExpr(argumentsGivenCountIs(2))) + void f(int x, int y = 0); + f(0, 0); + f(0); +
Matches call expressions which were resolved using ADL. @@ -4815,6 +4878,17 @@
Checks that a call expression or a constructor call expression has +a specific number of arguments (EXCLUDING absent default arguments). + +Example matches f(0, 0) but not f(0) (matcher = callExpr(argumentsGivenCountIs(2))) + void f(int x, int y = 0); + f(0, 0); + f(0); +
Matches when at least one of the supplied string equals to the Selector.getAsString() @@ -6214,6 +6288,17 @@
Matches the statement an attribute is attached to. + +Example: + attributedStmt(hasSubStmt(returnStmt())) +would match "return 1;" here: + else [[unlikely]] + return 1; +
Matches AutoType nodes where the deduced type is a specific type. @@ -6385,6 +6470,46 @@
Matches the second argument (block dim) in <<<>>> on CUDA kernel calls. + +Example: will match j in + kernel<<<i,j>>>(); +
Matches the first argument (grid dim) in <<<>>> on CUDA kernel calls. + +Example: will match i in + kernel<<<i,j>>>(); +
Matches the third argument (shared mem size) in <<<>>> on CUDA kernel calls. + +Example: will match mem in + kernel<<<i, j, mem, 0>>>(); +
Matches the fourth argument (CUDA stream) in <<<>>> on CUDA kernel calls. + +Example: will match 0 in + kernel<<<i, j, mem, 0>>>(); +
Matches the config in <<<>>> on CUDA kernel calls. + +Example: will match <<<i,j>>> in + kernel<<<i,j>>>(); +
Matches if the type location of a node matches the inner matcher. @@ -9086,6 +9211,10 @@
Matches the return value expression of a return statement
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,61 @@
return Node.size() == N;
}
+/// Matches the attribute(s) attached to a Stmt
+///
+/// Given:
+/// \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
+/// attributedStmt() matches "[[likely]] return ...;" and
+/// "[[unlikely]] return 1;"
+extern const internal::VariadicDynCastAllOfMatcher
+ attributedStmt;
+
+/// Matches the specified attribute.
+///
+/// Example:
+/// \code
+/// attributedStmt(isAttr(attr::Likely))
+/// \endcode
+/// would only match "[[likely]] return ...;" 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) {
+ return llvm::any_of(Node.getAttrs(), [&](const Attr *A) {
+ return A->getKind() == AttrKind;
+ });
+}
+
+/// 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 *Statement = Node.getSubStmt();
+ return Statement != nullptr &&
+ InnerMatcher.matches(*Statement, Finder, Builder);
+}
+
/// Matches \c QualTypes in the clang AST.
extern const internal::VariadicAllOfMatcher qualType;
@@ -3911,6 +3966,44 @@
return false;
}
+/// Matches the type of a return statement as declared by the enclosing
+/// function.
+///
+/// Example: returnStmt(hasExpectedReturnType(asString("int *"))) will match
+/// return 0; in
+/// \code
+/// int* foo() {
+/// return 0;
+/// }
+/// \endcode
+/// despite the return value being an IntegerLiteral.
+
+AST_MATCHER_P(ReturnStmt, hasExpectedReturnType, internal::Matcher,
+ InnerMatcher) {
+ const auto &Parents = Finder->getASTContext().getParents(Node);
+
+ llvm::SmallVector Stack(Parents.begin(), Parents.end());
+ const FunctionDecl* FuncDeclNode;
+ while (!Stack.empty()) {
+ const auto &CurNode = Stack.back();
+ Stack.pop_back();
+ FuncDeclNode = CurNode.get();
+ if (FuncDeclNode != nullptr) {
+ break;
+ }
+ else {
+ for (const auto &Parent : Finder->getASTContext().getParents(CurNode))
+ Stack.push_back(Parent);
+ }
+ }
+ if (FuncDeclNode == nullptr) {
+ return false;
+ }
+ else {
+ return InnerMatcher.matches(FuncDeclNode->getReturnType(), Finder, Builder);
+ }
+}
+
/// Matches if the type location of a node matches the inner matcher.
///
/// Examples:
@@ -4386,6 +4479,29 @@
return NumArgs == N;
}
+/// Checks that a call expression or a constructor call expression has
+/// a specific number of arguments (EXCLUDING absent default arguments).
+///
+/// Example matches f(0, 0) but not f(0) (matcher = callExpr(argumentsGivenCountIs(2)))
+/// \code
+/// void f(int x, int y = 0);
+/// f(0, 0);
+/// f(0);
+/// \endcode
+AST_POLYMORPHIC_MATCHER_P(argumentsGivenCountIs,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(
+ CallExpr, CXXConstructExpr,
+ CXXUnresolvedConstructExpr, ObjCMessageExpr),
+ unsigned, N) {
+ unsigned NumArgs = Node.getNumArgs();
+ while (NumArgs) {
+ if (!isa(Node.getArg(NumArgs - 1)))
+ break;
+ --NumArgs;
+ }
+ return NumArgs == N;
+}
+
/// Matches the n'th argument of a call expression or a constructor
/// call expression.
///
@@ -7794,6 +7910,80 @@
extern const internal::VariadicDynCastAllOfMatcher
cudaKernelCallExpr;
+/// Matches the config in <<<>>> on CUDA kernel calls.
+///
+/// Example: will match <<>> in
+/// \code
+/// kernel<<>>();
+/// \endcode
+AST_MATCHER_P(CUDAKernelCallExpr, hasKernelConfig, internal::Matcher,
+ InnerMatcher) {
+ if (const CallExpr *Config = Node.getConfig()) {
+ return InnerMatcher.matches(*Config, Finder, Builder);
+ }
+ return false;
+}
+
+/// Matches the first argument (grid dim) in <<<>>> on CUDA kernel calls.
+///
+/// Example: will match i in
+/// \code
+/// kernel<<>>();
+/// \endcode
+AST_MATCHER_P(CUDAKernelCallExpr, cudaGridDim, internal::Matcher,
+ InnerMatcher) {
+ const CallExpr *Config = Node.getConfig();
+ if (Config && Config->getNumArgs() > 0) {
+ return InnerMatcher.matches(*(Config->getArg(0)), Finder, Builder);
+ }
+ return false;
+}
+
+/// Matches the second argument (block dim) in <<<>>> on CUDA kernel calls.
+///
+/// Example: will match j in
+/// \code
+/// kernel<<>>();
+/// \endcode
+AST_MATCHER_P(CUDAKernelCallExpr, cudaBlockDim, internal::Matcher,
+ InnerMatcher) {
+ const CallExpr *Config = Node.getConfig();
+ if (Config && Config->getNumArgs() > 1) {
+ return InnerMatcher.matches(*(Config->getArg(1)), Finder, Builder);
+ }
+ return false;
+}
+
+/// Matches the third argument (shared mem size) in <<<>>> on CUDA kernel calls.
+///
+/// Example: will match mem in
+/// \code
+/// kernel<<>>();
+/// \endcode
+AST_MATCHER_P(CUDAKernelCallExpr, cudaSharedMemPerBlock, internal::Matcher,
+ InnerMatcher) {
+ const CallExpr *Config = Node.getConfig();
+ if (Config && Config->getNumArgs() > 2) {
+ return InnerMatcher.matches(*(Config->getArg(2)), Finder, Builder);
+ }
+ return false;
+}
+
+/// Matches the fourth argument (CUDA stream) in <<<>>> on CUDA kernel calls.
+///
+/// Example: will match 0 in
+/// \code
+/// kernel<<>>();
+/// \endcode
+AST_MATCHER_P(CUDAKernelCallExpr, cudaStream, internal::Matcher,
+ InnerMatcher) {
+ const CallExpr *Config = Node.getConfig();
+ if (Config && Config->getNumArgs() > 3) {
+ return InnerMatcher.matches(*(Config->getArg(3)), Finder, Builder);
+ }
+ return false;
+}
+
/// Matches expressions that resolve to a null pointer constant, such as
/// GNU's __null, C++11's nullptr, or C's NULL macro.
///
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/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
--- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -2509,6 +2509,28 @@
EXPECT_FALSE(Finder.addDynamicMatcher(hasName("x"), nullptr));
}
+TEST(ASTMatchersTest, AttributedStmtBasic) {
+ StringRef Code = "int foo() { [[likely]] return 1; }";
+ EXPECT_TRUE(matchesConditionally(Code, attributedStmt(),
+ true, {"-std=c++20"}));
+}
+
+TEST(ASTMatchersTest, AttributedStmt_isAttr) {
+ StringRef Code = "int foo() { [[unlikely]] return 1; }";
+ EXPECT_TRUE(matchesConditionally(Code, attributedStmt(isAttr(attr::Unlikely)),
+ true, {"-std=c++20"}));
+ EXPECT_FALSE(matchesConditionally(Code, attributedStmt(isAttr(attr::Builtin)),
+ true, {"-std=c++20"}));
+}
+
+TEST(ASTMatchersTest, AttributedStmt_hasSubStmt) {
+ StringRef Code = "int foo() { [[likely]] return 1; }";
+ EXPECT_TRUE(matchesConditionally(Code,
+ attributedStmt(hasSubStmt(returnStmt())), true, {"-std=c++20"}));
+ EXPECT_FALSE(matchesConditionally(Code,
+ attributedStmt(hasSubStmt(ifStmt())), true, {"-std=c++20"}));
+}
+
TEST(MatchFinderAPI, MatchesDynamic) {
StringRef SourceCode = "struct A { void f() {} };";
auto Matcher = functionDecl(isDefinition()).bind("method");