lebedev.ri updated this revision to Diff 190965. lebedev.ri marked 3 inline comments as done. lebedev.ri retitled this revision from "[ASTTypeTraits] OMPClause handling" to "[ASTTypeTraits][ASTMatchers][OpenMP] OMPClause handling". lebedev.ri edited the summary of this revision. lebedev.ri added reviewers: aaron.ballman, george.karpenkov. lebedev.ri added a comment. Herald added a subscriber: guansong.
Split off matchers from from D57113 <https://reviews.llvm.org/D57113>, added tests. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D57112/new/ https://reviews.llvm.org/D57112 Files: docs/LibASTMatchersReference.html include/clang/AST/ASTTypeTraits.h include/clang/ASTMatchers/ASTMatchers.h lib/AST/ASTTypeTraits.cpp lib/ASTMatchers/ASTMatchersInternal.cpp lib/ASTMatchers/Dynamic/Registry.cpp unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp unittests/ASTMatchers/ASTMatchersNodeTest.cpp
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 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: 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: lib/ASTMatchers/ASTMatchersInternal.cpp =================================================================== --- lib/ASTMatchers/ASTMatchersInternal.cpp +++ lib/ASTMatchers/ASTMatchersInternal.cpp @@ -847,6 +847,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, OMPExecutableDirective> ompExecutableDirective; +const internal::VariadicDynCastAllOfMatcher<OMPClause, OMPDefaultClause> + ompDefaultClause; } // end namespace ast_matchers } // end namespace clang 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<Stmt>()) return S->getSourceRange(); + if (const auto *C = get<OMPClause>()) + return SourceRange(C->getBeginLoc(), C->getEndLoc()); return SourceRange(); } 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<Stmt, OMPExecutableDirective> 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<OMPClause>, + InnerMatcher) { + ArrayRef<OMPClause *> 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<OMPClause, OMPDefaultClause> + 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<OMPClause>, 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: 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<std::is_base_of<Type, T>::value>::type> : public DynCastPtrConverter<T, Type> {}; +template <typename T> +struct DynTypedNode::BaseConverter< + T, typename std::enable_if<std::is_base_of<OMPClause, T>::value>::type> + : public DynCastPtrConverter<T, OMPClause> {}; + template <> struct DynTypedNode::BaseConverter< NestedNameSpecifier, void> : public PtrConverter<NestedNameSpecifier> {}; Index: docs/LibASTMatchersReference.html =================================================================== --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -645,6 +645,19 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPClause.html">OMPClause</a>></td><td class="name" onclick="toggle('ompDefaultClause0')"><a name="ompDefaultClause0Anchor">ompDefaultClause</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html">OMPDefaultClause</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="ompDefaultClause0"><pre>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 +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>></td><td class="name" onclick="toggle('qualType0')"><a name="qualType0Anchor">qualType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>>...</td></tr> <tr><td colspan="4" class="doc" id="qualType0"><pre>Matches QualTypes in the clang AST. </pre></td></tr> @@ -3435,6 +3448,18 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html">OMPDefaultClause</a>></td><td class="name" onclick="toggle('isNoneKind0')"><a name="isNoneKind0Anchor">isNoneKind</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="isNoneKind0"><pre>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 +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('argumentCountIs2')"><a name="argumentCountIs2Anchor">argumentCountIs</a></td><td>unsigned N</td></tr> <tr><td colspan="4" class="doc" id="argumentCountIs2"><pre>Checks that a call expression or a constructor call expression has a specific number of arguments (including absent default arguments). @@ -6159,6 +6184,39 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPExecutableDirective.html">OMPExecutableDirective</a>></td><td class="name" onclick="toggle('hasClause0')"><a name="hasClause0Anchor">hasClause</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPClause.html">OMPClause</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasClause0"><pre>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 +</pre></td></tr> + + +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPExecutableDirective.html">OMPExecutableDirective</a>></td><td class="name" onclick="toggle('isAllowedToContainClause0')"><a name="isAllowedToContainClause0Anchor">isAllowedToContainClause</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPClause.html">OMPClause</a>> ClauseMatcher</td></tr> +<tr><td colspan="4" class="doc" id="isAllowedToContainClause0"><pre>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. +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasAnyArgument3')"><a name="hasAnyArgument3Anchor">hasAnyArgument</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="hasAnyArgument3"><pre>Matches any argument of a call expression or a constructor call expression, or an ObjC-message-send expression.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits