Index: docs/LibASTMatchersReference.html =================================================================== --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -645,6 +645,19 @@ +
Matches OpenMP ``default`` clause. + +Example: + +Given, `ompDefaultClause()`: + + #pragma omp parallel default(none) // <- will match ``default(none)`` + #pragma omp parallel default(shared) // <- will match ``default(shared)`` + #pragma omp parallel // <- no match +
Matches QualTypes in the clang AST.
Matches if the OpenMP ``default`` clause has ``none`` kind specified. + +Example: + +Given, `ompDefaultClause(isNoneKind())`: + + #pragma omp parallel default(none) // <- match + #pragma omp parallel default(shared) // <- no match +
Checks that a call expression or a constructor call expression has a specific number of arguments (including absent default arguments). @@ -6159,6 +6184,39 @@
Given OpenMP directive, matches the first clause (out of all specified), +that matches InnerMatcher. + +Example: + +Given ``ompExecutableDirective(hasClause(anything()))``: + + #pragma omp parallel // <- no clauses, no match + #pragma omp parallel default(none) // <- has clauses, match +
Matches if the OpenMP directive is allowed to contain the specified OpenMP +clause kind. + +Example: + +Given, + ``ompExecutableDirective(isAllowedToContainClause(ompDefaultClause()))``: + + #pragma omp parallel // <- match + #pragma omp parallel for // <- match + #pragma omp for // <- no match + +NOTE: while the matcher takes the *matcher* for the OpenMP clause, + it does *NOT* actually match that matcher. It only fetches the + desired OpenMP clause kind out of the matchers return type, + and uses said kind for the decision. +
Matches any argument of a call expression or a constructor call
expression, or an ObjC-message-send expression.
Index: include/clang/AST/ASTTypeTraits.h
===================================================================
--- include/clang/AST/ASTTypeTraits.h
+++ include/clang/AST/ASTTypeTraits.h
@@ -18,6 +18,7 @@
#include "clang/AST/ASTFwd.h"
#include "clang/AST/Decl.h"
#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/OpenMPClause.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TypeLoc.h"
@@ -58,6 +59,7 @@
static ASTNodeKind getFromNode(const Decl &D);
static ASTNodeKind getFromNode(const Stmt &S);
static ASTNodeKind getFromNode(const Type &T);
+ static ASTNodeKind getFromNode(const OMPClause &C);
/// \}
/// Returns \c true if \c this and \c Other represent the same kind.
@@ -76,6 +78,11 @@
/// String representation of the kind.
StringRef asStringRef() const;
+ /// \{
+ /// Return the AST node kind of this ASTNodeKind.
+ OpenMPClauseKind asOMPClauseKind() const;
+ /// \}
+
/// Strict weak ordering for ASTNodeKind.
bool operator<(const ASTNodeKind &Other) const {
return KindId < Other.KindId;
@@ -136,6 +143,9 @@
NKI_Type,
#define TYPE(DERIVED, BASE) NKI_##DERIVED##Type,
#include "clang/AST/TypeNodes.def"
+ NKI_OMPClause,
+#define OPENMP_CLAUSE(TextualSpelling, Class) NKI_##Class,
+#include "clang/Basic/OpenMPKinds.def"
NKI_NumberOfKinds
};
@@ -183,12 +193,15 @@
KIND_TO_KIND_ID(Decl)
KIND_TO_KIND_ID(Stmt)
KIND_TO_KIND_ID(Type)
+KIND_TO_KIND_ID(OMPClause)
#define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl)
#include "clang/AST/DeclNodes.inc"
#define STMT(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED)
#include "clang/AST/StmtNodes.inc"
#define TYPE(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Type)
#include "clang/AST/TypeNodes.def"
+#define OPENMP_CLAUSE(TextualSpelling, Class) KIND_TO_KIND_ID(Class)
+#include "clang/Basic/OpenMPKinds.def"
#undef KIND_TO_KIND_ID
inline raw_ostream &operator<<(raw_ostream &OS, ASTNodeKind K) {
@@ -459,6 +472,11 @@
T, typename std::enable_if::value>::type>
: public DynCastPtrConverter {};
+template
+struct DynTypedNode::BaseConverter<
+ T, typename std::enable_if::value>::type>
+ : public DynCastPtrConverter {};
+
template <>
struct DynTypedNode::BaseConverter<
NestedNameSpecifier, void> : public PtrConverter {};
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -56,6 +56,7 @@
#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"
@@ -6385,6 +6386,86 @@
extern const internal::VariadicDynCastAllOfMatcher
ompExecutableDirective;
+/// Given OpenMP directive, matches the first clause (out of all specified),
+/// that matches InnerMatcher.
+///
+/// Example:
+///
+/// Given ``ompExecutableDirective(hasClause(anything()))``:
+///
+/// \code
+/// #pragma omp parallel // <- no clauses, no match
+/// #pragma omp parallel default(none) // <- has clauses, match
+/// \endcode
+AST_MATCHER_P(OMPExecutableDirective, hasClause, internal::Matcher,
+ InnerMatcher) {
+ ArrayRef Clauses = Node.clauses();
+ return matchesFirstInPointerRange(InnerMatcher, Clauses.begin(),
+ Clauses.end(), Finder, Builder);
+}
+
+/// Matches OpenMP ``default`` clause.
+///
+/// Example:
+///
+/// Given, `ompDefaultClause()`:
+///
+/// \code
+/// #pragma omp parallel default(none) // <- will match ``default(none)``
+/// #pragma omp parallel default(shared) // <- will match ``default(shared)``
+/// #pragma omp parallel // <- no match
+/// \endcode
+extern const internal::VariadicDynCastAllOfMatcher
+ ompDefaultClause;
+
+/// Matches if the OpenMP ``default`` clause has ``none`` kind specified.
+///
+/// Example:
+///
+/// Given, `ompDefaultClause(isNoneKind())`:
+///
+/// \code
+/// #pragma omp parallel default(none) // <- match
+/// #pragma omp parallel default(shared) // <- no match
+/// \endcode
+AST_MATCHER(OMPDefaultClause, isNoneKind) {
+ return Node.getDefaultKind() == OMPC_DEFAULT_none;
+}
+
+/// Matches if the OpenMP directive is allowed to contain the specified OpenMP
+/// clause kind.
+///
+/// Example:
+///
+/// Given,
+/// ``ompExecutableDirective(isAllowedToContainClause(ompDefaultClause()))``:
+///
+/// \code
+/// #pragma omp parallel // <- match
+/// #pragma omp parallel for // <- match
+/// #pragma omp for // <- no match
+/// \endcode
+///
+/// NOTE: while the matcher takes the *matcher* for the OpenMP clause,
+/// it does *NOT* actually match that matcher. It only fetches the
+/// desired OpenMP clause kind out of the matchers return type,
+/// and uses said kind for the decision.
+AST_MATCHER_P(OMPExecutableDirective, isAllowedToContainClause,
+ internal::Matcher, ClauseMatcher) {
+ // Note that we have recieved a *matcher* for the clause, not the
+ // OpenMPClauseKind. We now need to extract the 'return' type of said matcher,
+ // and convert it to the OpenMPClauseKind, so we can finally use that.
+
+ internal::DynTypedMatcher::MatcherIDType ID = ClauseMatcher.getID();
+ ast_type_traits::ASTNodeKind NodeKind = ID.first;
+ assert(!NodeKind.isNone() &&
+ "expected to have a matcher for some OpenMP clause, not the matcher "
+ "for the OMPClause itself");
+ OpenMPClauseKind CKind = NodeKind.asOMPClauseKind();
+ assert(CKind != OMPC_unknown && "Bad ClauseMatcher specified.");
+ return isAllowedClauseForDirective(Node.getDirectiveKind(), CKind);
+}
+
//----------------------------------------------------------------------------//
// End OpenMP handling.
//----------------------------------------------------------------------------//
Index: lib/AST/ASTTypeTraits.cpp
===================================================================
--- lib/AST/ASTTypeTraits.cpp
+++ lib/AST/ASTTypeTraits.cpp
@@ -37,6 +37,9 @@
{ NKI_None, "Type" },
#define TYPE(DERIVED, BASE) { NKI_##BASE, #DERIVED "Type" },
#include "clang/AST/TypeNodes.def"
+ { NKI_None, "OMPClause" },
+#define OPENMP_CLAUSE(TextualSpelling, Class) {NKI_OMPClause, #Class},
+#include "clang/Basic/OpenMPKinds.def"
};
bool ASTNodeKind::isBaseOf(ASTNodeKind Other, unsigned *Distance) const {
@@ -58,6 +61,19 @@
StringRef ASTNodeKind::asStringRef() const { return AllKindInfo[KindId].Name; }
+OpenMPClauseKind ASTNodeKind::asOMPClauseKind() const {
+ assert(isBaseOf(NKI_OMPClause, KindId, nullptr) && KindId != NKI_OMPClause &&
+ "Should be an OpenMP clause node");
+ switch (KindId) {
+ default:
+ llvm_unreachable("Unknown clause kind!");
+#define OPENMP_CLAUSE(TextualSpelling, Class) \
+ case NKI_##Class: \
+ return OMPC_##TextualSpelling;
+#include "clang/Basic/OpenMPKinds.def"
+ }
+}
+
ASTNodeKind ASTNodeKind::getMostDerivedType(ASTNodeKind Kind1,
ASTNodeKind Kind2) {
if (Kind1.isBaseOf(Kind2)) return Kind2;
@@ -103,6 +119,20 @@
#include "clang/AST/TypeNodes.def"
}
llvm_unreachable("invalid type kind");
+ }
+
+ASTNodeKind ASTNodeKind::getFromNode(const OMPClause &C) {
+ switch (C.getClauseKind()) {
+#define OPENMP_CLAUSE(Name, Class) \
+ case OMPC_##Name: return ASTNodeKind(NKI_##Class);
+#include "clang/Basic/OpenMPKinds.def"
+ case OMPC_allocate:
+ case OMPC_threadprivate:
+ case OMPC_uniform:
+ case OMPC_unknown:
+ llvm_unreachable("unexpected OpenMP clause kind");
+ }
+ llvm_unreachable("invalid stmt kind");
}
void DynTypedNode::print(llvm::raw_ostream &OS,
@@ -151,6 +181,8 @@
return D->getSourceRange();
if (const Stmt *S = get())
return S->getSourceRange();
+ if (const auto *C = get())
+ return SourceRange(C->getBeginLoc(), C->getEndLoc());
return SourceRange();
}
Index: lib/ASTMatchers/ASTMatchersInternal.cpp
===================================================================
--- lib/ASTMatchers/ASTMatchersInternal.cpp
+++ lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -847,6 +847,8 @@
const internal::VariadicDynCastAllOfMatcher
ompExecutableDirective;
+const internal::VariadicDynCastAllOfMatcher
+ ompDefaultClause;
} // end namespace ast_matchers
} // end namespace clang
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -506,6 +506,10 @@
REGISTER_MATCHER(whileStmt);
REGISTER_MATCHER(withInitializer);
REGISTER_MATCHER(ompExecutableDirective);
+ REGISTER_MATCHER(hasClause);
+ REGISTER_MATCHER(ompDefaultClause);
+ REGISTER_MATCHER(isNoneKind);
+ REGISTER_MATCHER(isAllowedToContainClause);
}
RegistryMaps::~RegistryMaps() = default;
Index: unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2274,5 +2274,117 @@
notMatches("int main2() {}", functionDecl(isMain())));
}
+TEST(OMPExecutableDirective, hasClause) {
+ auto Matcher = ompExecutableDirective(hasClause(anything()));
+
+ const std::string Source0 = R"(void x() {
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+
+ const std::string Source1 = R"(void x() {
+#pragma omp parallel
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source1, Matcher));
+
+ const std::string Source2 = R"(void x() {
+#pragma omp parallel default(none)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source2, Matcher));
+
+ const std::string Source3 = R"(void x() {
+#pragma omp parallel default(shared)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source3, Matcher));
+
+ const std::string Source4 = R"(void x(int x) {
+#pragma omp parallel num_threads(x)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source4, Matcher));
+}
+
+TEST(OMPDefaultClause, isNoneKind) {
+ auto Matcher =
+ ompExecutableDirective(hasClause(ompDefaultClause(isNoneKind())));
+
+ const std::string Source0 = R"(void x() {
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+
+ const std::string Source1 = R"(void x() {
+#pragma omp parallel
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source1, Matcher));
+
+ const std::string Source2 = R"(void x() {
+#pragma omp parallel default(none)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source2, Matcher));
+
+ const std::string Source3 = R"(void x() {
+#pragma omp parallel default(shared)
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source3, Matcher));
+
+ const std::string Source4 = R"(void x(int x) {
+#pragma omp parallel num_threads(x)
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source4, Matcher));
+}
+
+TEST(OMPExecutableDirective, isAllowedToContainClause) {
+ auto Matcher =
+ ompExecutableDirective(isAllowedToContainClause(ompDefaultClause()));
+
+ const std::string Source0 = R"(void x() {
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+
+ const std::string Source1 = R"(void x() {
+#pragma omp parallel
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source1, Matcher));
+
+ const std::string Source2 = R"(void x() {
+#pragma omp parallel default(none)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source2, Matcher));
+
+ const std::string Source3 = R"(void x() {
+#pragma omp parallel default(shared)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source3, Matcher));
+
+ const std::string Source4 = R"(void x(int x) {
+#pragma omp parallel num_threads(x)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source4, Matcher));
+
+ const std::string Source5 = R"(void x() {
+#pragma omp taskyield
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source5, Matcher));
+
+ const std::string Source6 = R"(void x() {
+#pragma omp task
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source6, Matcher));
+}
+
} // namespace ast_matchers
} // namespace clang
Index: unittests/ASTMatchers/ASTMatchersNodeTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1780,5 +1780,38 @@
EXPECT_TRUE(notMatchesWithOpenMP(SourceBad, Matcher));
}
+TEST(OMPDefaultClause, Matches) {
+ auto Matcher = ompExecutableDirective(hasClause(ompDefaultClause()));
+
+ const std::string Source0 = R"(void x() {
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+
+ const std::string Source1 = R"(void x() {
+#pragma omp parallel
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source1, Matcher));
+
+ const std::string Source2 = R"(void x() {
+#pragma omp parallel default(none)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source2, Matcher));
+
+ const std::string Source3 = R"(void x() {
+#pragma omp parallel default(shared)
+;
+})";
+ EXPECT_TRUE(matchesWithOpenMP(Source3, Matcher));
+
+ const std::string Source4 = R"(void x(int x) {
+#pragma omp parallel num_threads(x)
+;
+})";
+ EXPECT_TRUE(notMatchesWithOpenMP(Source4, Matcher));
+}
+
} // namespace ast_matchers
} // namespace clang