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&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPClause.html";>OMPClause</a>&gt;</td><td class="name" onclick="toggle('ompDefaultClause0')"><a name="ompDefaultClause0Anchor">ompDefaultClause</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html";>OMPDefaultClause</a>&gt;...</td></tr>
+<tr><td colspan="4" class="doc" id="ompDefaultClause0"><pre>Matches OpenMP ``default`` clause.
+
+Example:
+
+Given, `ompDefaultClause()`:
+
+  #pragma omp parallel default(none)   // &lt;- will match ``default(none)``
+  #pragma omp parallel default(shared) // &lt;- will match ``default(shared)``
+  #pragma omp parallel                 // &lt;- no match
+</pre></td></tr>
+
+
 <tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html";>QualType</a>&gt;</td><td class="name" onclick="toggle('qualType0')"><a name="qualType0Anchor">qualType</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1QualType.html";>QualType</a>&gt;...</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&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html";>OMPDefaultClause</a>&gt;</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)   // &lt;- match
+  #pragma omp parallel default(shared) // &lt;- no match
+</pre></td></tr>
+
+
 <tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html";>ObjCMessageExpr</a>&gt;</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&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPExecutableDirective.html";>OMPExecutableDirective</a>&gt;</td><td class="name" onclick="toggle('hasClause0')"><a name="hasClause0Anchor">hasClause</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPClause.html";>OMPClause</a>&gt; 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               // &lt;- no clauses, no match
+  #pragma omp parallel default(none) // &lt;- has clauses, match
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPExecutableDirective.html";>OMPExecutableDirective</a>&gt;</td><td class="name" onclick="toggle('isAllowedToContainClause0')"><a name="isAllowedToContainClause0Anchor">isAllowedToContainClause</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPClause.html";>OMPClause</a>&gt; 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     // &lt;- match
+  #pragma omp parallel for // &lt;- match
+  #pragma omp          for // &lt;- 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&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html";>ObjCMessageExpr</a>&gt;</td><td class="name" onclick="toggle('hasAnyArgument3')"><a name="hasAnyArgument3Anchor">hasAnyArgument</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html";>Expr</a>&gt; 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

Reply via email to