https://github.com/amitamd7 updated 
https://github.com/llvm/llvm-project/pull/150580

>From a7a8256e75aa6670f417540fc61998469b032596 Mon Sep 17 00:00:00 2001
From: amtiwari <[email protected]>
Date: Fri, 25 Jul 2025 02:45:34 -0400
Subject: [PATCH 1/3] support_for_target_directive_clang_unittests

---
 clang/include/clang/ASTMatchers/ASTMatchers.h | 27 +++++
 clang/lib/ASTMatchers/ASTMatchersInternal.cpp |  4 +
 clang/lib/ASTMatchers/Dynamic/Registry.cpp    |  2 +
 .../ASTMatchers/ASTMatchersNarrowingTest.cpp  | 99 +++++++++++++++++++
 .../ASTMatchers/ASTMatchersNodeTest.cpp       | 67 +++++++++++++
 5 files changed, 199 insertions(+)

diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h 
b/clang/include/clang/ASTMatchers/ASTMatchers.h
index f1d88a9523838..0ddf29095c548 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -8723,6 +8723,21 @@ AST_MATCHER_P(OMPExecutableDirective, hasAnyClause,
                                     Builder) != Clauses.end();
 }
 
+/// Matches any ``#pragma omp target update`` executable directive.
+///
+/// Given
+///
+/// \code
+///   #pragma omp target update from(a)
+///   #pragma omp target update to(b)
+/// \endcode
+///
+/// ``ompTargetUpdateDirective()`` matches both ``omp target update from(a)``
+/// and ``omp target update to(b)``.
+extern const internal::VariadicDynCastAllOfMatcher<Stmt,
+                                                   OMPTargetUpdateDirective>
+    ompTargetUpdateDirective;
+
 /// Matches OpenMP ``default`` clause.
 ///
 /// Given
@@ -8836,6 +8851,18 @@ AST_MATCHER_P(OMPExecutableDirective, 
isAllowedToContainClauseKind,
       Finder->getASTContext().getLangOpts().OpenMP);
 }
 
+/// Matches OpenMP ``from`` clause.
+///
+/// Given
+///
+/// \code
+///   #pragma omp target update from(a)
+/// \endcode
+///
+/// ``ompFromClause()`` matches ``from(a)``.
+extern const internal::VariadicDynCastAllOfMatcher<OMPClause, OMPFromClause>
+    ompFromClause;
+
 
//----------------------------------------------------------------------------//
 // End OpenMP handling.
 
//----------------------------------------------------------------------------//
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp 
b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 653b3810cb68b..1b01be069d9aa 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -1124,8 +1124,12 @@ AST_TYPELOC_TRAVERSE_MATCHER_DEF(
 
 const internal::VariadicDynCastAllOfMatcher<Stmt, OMPExecutableDirective>
     ompExecutableDirective;
+const internal::VariadicDynCastAllOfMatcher<Stmt, OMPTargetUpdateDirective>
+    ompTargetUpdateDirective;
 const internal::VariadicDynCastAllOfMatcher<OMPClause, OMPDefaultClause>
     ompDefaultClause;
+const internal::VariadicDynCastAllOfMatcher<OMPClause, OMPFromClause>
+    ompFromClause;
 const internal::VariadicDynCastAllOfMatcher<Decl, CXXDeductionGuideDecl>
     cxxDeductionGuideDecl;
 
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp 
b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 48a7b91969aef..a268e97f7aa18 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -528,7 +528,9 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(ofClass);
   REGISTER_MATCHER(ofKind);
   REGISTER_MATCHER(ompDefaultClause);
+  REGISTER_MATCHER(ompFromClause);
   REGISTER_MATCHER(ompExecutableDirective);
+  REGISTER_MATCHER(ompTargetUpdateDirective);
   REGISTER_MATCHER(on);
   REGISTER_MATCHER(onImplicitObjectArgument);
   REGISTER_MATCHER(opaqueValueExpr);
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp 
b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index 8a957864cdd12..c30398605af5d 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -4734,6 +4734,105 @@ void x() {
   EXPECT_TRUE(matchesWithOpenMP(Source8, Matcher));
 }
 
+TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_IsStandaloneDirective) {
+  auto Matcher = ompTargetUpdateDirective(isStandaloneDirective());
+
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update from(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(matchesWithOpenMP(Source0, Matcher));
+}
+
+TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_HasStructuredBlock) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update from(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(notMatchesWithOpenMP(
+      Source0, ompTargetUpdateDirective(hasStructuredBlock(nullStmt()))));
+}
+
+TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_HasClause) {
+  auto Matcher = ompTargetUpdateDirective(hasAnyClause(ompFromClause()));
+
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update from(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(matchesWithOpenMP(Source0, Matcher));
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPFromClause *FromClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((FromClause = dyn_cast<OMPFromClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(FromClause);
+
+  for (const auto *VarExpr : FromClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+    // base (arr)
+    const Expr *Base = ArraySection->getBase();
+    ASSERT_TRUE(Base);
+
+    // lower bound (0)
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+
+    // length (8)
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+
+    // stride (2)
+    const Expr *Stride = ArraySection->getStride();
+    ASSERT_TRUE(Stride);
+  }
+}
+
+TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_IsAllowedToContainClauseKind) 
{
+  auto Matcher = ompTargetUpdateDirective(
+      isAllowedToContainClauseKind(llvm::omp::OMPC_from));
+
+  StringRef Source0 = R"(
+    void x() {
+      ;
+    }
+  )";
+  EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+
+  StringRef Source1 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update from(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(matchesWithOpenMP(Source1, Matcher));
+}
+
 TEST_P(ASTMatchersTest, HasAnyBase_DirectBase) {
   if (!GetParam().isCXX()) {
     return;
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp 
b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index d7df9cae01f33..f2155a92a88e8 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -2742,6 +2742,73 @@ void x() {
   EXPECT_TRUE(notMatchesWithOpenMP(Source2, Matcher));
 }
 
+TEST(ASTMatchersTestOpenMP, OMPTargetUpdateDirective) {
+  auto Matcher = stmt(ompTargetUpdateDirective());
+
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update from(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(matchesWithOpenMP(Source0, Matcher));
+}
+
+TEST(ASTMatchersTestOpenMP, OMPFromClause) {
+  auto Matcher = ompTargetUpdateDirective(hasAnyClause(ompFromClause()));
+
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update from(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(matchesWithOpenMP(Source0, Matcher));
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPFromClause *FromClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((FromClause = dyn_cast<OMPFromClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(FromClause);
+
+  for (const auto *VarExpr : FromClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // base (arr)
+    const Expr *Base = ArraySection->getBase();
+    ASSERT_TRUE(Base);
+
+    // lower bound (0)
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+
+    // length (8)
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+
+    // stride (2)
+    const Expr *Stride = ArraySection->getStride();
+    ASSERT_TRUE(Stride);
+  }
+}
+
 TEST(ASTMatchersTestOpenMP, OMPDefaultClause) {
   auto Matcher = ompExecutableDirective(hasAnyClause(ompDefaultClause()));
 

>From b60f187f75c5167cfa980b7779b2d2f985f4ff2c Mon Sep 17 00:00:00 2001
From: amtiwari <[email protected]>
Date: Fri, 5 Dec 2025 02:58:08 -0500
Subject: [PATCH 2/3] update_to clause support

---
 clang/include/clang/ASTMatchers/ASTMatchers.h |  12 ++
 clang/lib/ASTMatchers/ASTMatchersInternal.cpp |   1 +
 clang/lib/ASTMatchers/Dynamic/Registry.cpp    |   1 +
 .../ASTMatchers/ASTMatchersNarrowingTest.cpp  | 106 +++++++++++++++++-
 .../ASTMatchers/ASTMatchersNodeTest.cpp       |  69 +++++++++++-
 5 files changed, 184 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h 
b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 0ddf29095c548..f007ef3bdf88d 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -8863,6 +8863,18 @@ AST_MATCHER_P(OMPExecutableDirective, 
isAllowedToContainClauseKind,
 extern const internal::VariadicDynCastAllOfMatcher<OMPClause, OMPFromClause>
     ompFromClause;
 
+/// Matches OpenMP ``to`` clause.
+///
+/// Given
+///
+/// \code
+///   #pragma omp target update to(a)
+/// \endcode
+///
+/// ``ompToClause()`` matches ``to(a)``.
+extern const internal::VariadicDynCastAllOfMatcher<OMPClause, OMPToClause>
+    ompToClause;
+
 
//----------------------------------------------------------------------------//
 // End OpenMP handling.
 
//----------------------------------------------------------------------------//
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp 
b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 1b01be069d9aa..5efa7f162789c 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -1130,6 +1130,7 @@ const internal::VariadicDynCastAllOfMatcher<OMPClause, 
OMPDefaultClause>
     ompDefaultClause;
 const internal::VariadicDynCastAllOfMatcher<OMPClause, OMPFromClause>
     ompFromClause;
+const internal::VariadicDynCastAllOfMatcher<OMPClause, OMPToClause> 
ompToClause;
 const internal::VariadicDynCastAllOfMatcher<Decl, CXXDeductionGuideDecl>
     cxxDeductionGuideDecl;
 
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp 
b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index a268e97f7aa18..447c70dc6f9af 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -529,6 +529,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(ofKind);
   REGISTER_MATCHER(ompDefaultClause);
   REGISTER_MATCHER(ompFromClause);
+  REGISTER_MATCHER(ompToClause);
   REGISTER_MATCHER(ompExecutableDirective);
   REGISTER_MATCHER(ompTargetUpdateDirective);
   REGISTER_MATCHER(on);
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp 
b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index c30398605af5d..63639cc890ec9 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -4734,7 +4734,7 @@ void x() {
   EXPECT_TRUE(matchesWithOpenMP(Source8, Matcher));
 }
 
-TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_IsStandaloneDirective) {
+TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_From_IsStandaloneDirective) {
   auto Matcher = ompTargetUpdateDirective(isStandaloneDirective());
 
   StringRef Source0 = R"(
@@ -4747,7 +4747,20 @@ TEST_P(ASTMatchersTest, 
OMPTargetUpdateDirective_IsStandaloneDirective) {
   EXPECT_TRUE(matchesWithOpenMP(Source0, Matcher));
 }
 
-TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_HasStructuredBlock) {
+TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_To_IsStandaloneDirective) {
+  auto Matcher = ompTargetUpdateDirective(isStandaloneDirective());
+
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update to(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(matchesWithOpenMP(Source0, Matcher));
+}
+
+TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_From_HasStructuredBlock) {
   StringRef Source0 = R"(
     void foo() {
       int arr[8];
@@ -4759,7 +4772,19 @@ TEST_P(ASTMatchersTest, 
OMPTargetUpdateDirective_HasStructuredBlock) {
       Source0, ompTargetUpdateDirective(hasStructuredBlock(nullStmt()))));
 }
 
-TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_HasClause) {
+TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_To_HasStructuredBlock) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update to(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(notMatchesWithOpenMP(
+      Source0, ompTargetUpdateDirective(hasStructuredBlock(nullStmt()))));
+}
+
+TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_From_HasClause) {
   auto Matcher = ompTargetUpdateDirective(hasAnyClause(ompFromClause()));
 
   StringRef Source0 = R"(
@@ -4812,7 +4837,58 @@ TEST_P(ASTMatchersTest, 
OMPTargetUpdateDirective_HasClause) {
   }
 }
 
-TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_IsAllowedToContainClauseKind) 
{
+TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_To_HasClause) {
+  auto Matcher = ompTargetUpdateDirective(hasAnyClause(ompToClause()));
+
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update to(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(matchesWithOpenMP(Source0, Matcher));
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPToClause *ToClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((ToClause = dyn_cast<OMPToClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(ToClause);
+
+  for (const auto *VarExpr : ToClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    const Expr *Base = ArraySection->getBase();
+    ASSERT_TRUE(Base);
+
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+
+    const Expr *Stride = ArraySection->getStride();
+    ASSERT_TRUE(Stride);
+  }
+}
+
+TEST_P(ASTMatchersTest,
+       OMPTargetUpdateDirective_IsAllowedToContainClauseKind_From) {
   auto Matcher = ompTargetUpdateDirective(
       isAllowedToContainClauseKind(llvm::omp::OMPC_from));
 
@@ -4833,6 +4909,28 @@ TEST_P(ASTMatchersTest, 
OMPTargetUpdateDirective_IsAllowedToContainClauseKind) {
   EXPECT_TRUE(matchesWithOpenMP(Source1, Matcher));
 }
 
+TEST_P(ASTMatchersTest,
+       OMPTargetUpdateDirective_IsAllowedToContainClauseKind_To) {
+  auto Matcher = ompTargetUpdateDirective(
+      isAllowedToContainClauseKind(llvm::omp::OMPC_to));
+
+  StringRef Source0 = R"(
+    void x() {
+      ;
+    }
+  )";
+  EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+
+  StringRef Source1 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update to(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(matchesWithOpenMP(Source1, Matcher));
+}
+
 TEST_P(ASTMatchersTest, HasAnyBase_DirectBase) {
   if (!GetParam().isCXX()) {
     return;
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp 
b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index f2155a92a88e8..edc84704b5ed2 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -2742,7 +2742,7 @@ void x() {
   EXPECT_TRUE(notMatchesWithOpenMP(Source2, Matcher));
 }
 
-TEST(ASTMatchersTestOpenMP, OMPTargetUpdateDirective) {
+TEST(ASTMatchersTestOpenMP, OMPTargetUpdateDirective_From) {
   auto Matcher = stmt(ompTargetUpdateDirective());
 
   StringRef Source0 = R"(
@@ -2755,6 +2755,19 @@ TEST(ASTMatchersTestOpenMP, OMPTargetUpdateDirective) {
   EXPECT_TRUE(matchesWithOpenMP(Source0, Matcher));
 }
 
+TEST(ASTMatchersTestOpenMP, OMPTargetUpdateDirective_To) {
+  auto Matcher = stmt(ompTargetUpdateDirective());
+
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update to(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(matchesWithOpenMP(Source0, Matcher));
+}
+
 TEST(ASTMatchersTestOpenMP, OMPFromClause) {
   auto Matcher = ompTargetUpdateDirective(hasAnyClause(ompFromClause()));
 
@@ -2809,6 +2822,60 @@ TEST(ASTMatchersTestOpenMP, OMPFromClause) {
   }
 }
 
+TEST(ASTMatchersTestOpenMP, OMPToClause) {
+  auto Matcher = ompTargetUpdateDirective(hasAnyClause(ompToClause()));
+
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update to(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(matchesWithOpenMP(Source0, Matcher));
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPToClause *ToClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((ToClause = dyn_cast<OMPToClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(ToClause);
+
+  for (const auto *VarExpr : ToClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // base (arr)
+    const Expr *Base = ArraySection->getBase();
+    ASSERT_TRUE(Base);
+
+    // lower bound (0)
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+
+    // length (8)
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+
+    // stride (2)
+    const Expr *Stride = ArraySection->getStride();
+    ASSERT_TRUE(Stride);
+  }
+}
+
 TEST(ASTMatchersTestOpenMP, OMPDefaultClause) {
   auto Matcher = ompExecutableDirective(hasAnyClause(ompDefaultClause()));
 

>From 900f8d05135702bd35772c8d45de90bc48fdbd3f Mon Sep 17 00:00:00 2001
From: amtiwari <[email protected]>
Date: Mon, 12 Jan 2026 06:56:52 -0500
Subject: [PATCH 3/3] handled_negative_checks

---
 .../ASTMatchers/ASTMatchersNarrowingTest.cpp  | 720 ++++++++++++++++++
 .../ASTMatchers/ASTMatchersNodeTest.cpp       | 302 ++++++++
 2 files changed, 1022 insertions(+)

diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp 
b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index fb93e56e8069c..0c9f074a259fd 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -4839,14 +4839,77 @@ TEST_P(ASTMatchersTest, 
OMPTargetUpdateDirective_From_HasClause) {
     // lower bound (0)
     const Expr *LowerBound = ArraySection->getLowerBound();
     ASSERT_TRUE(LowerBound);
+    if (const auto *LowerBoundLiteral = dyn_cast<IntegerLiteral>(LowerBound)) {
+      EXPECT_EQ(LowerBoundLiteral->getValue().getZExtValue(), 0u);
+    }
 
     // length (8)
     const Expr *Length = ArraySection->getLength();
     ASSERT_TRUE(Length);
+    if (const auto *LengthLiteral = dyn_cast<IntegerLiteral>(Length)) {
+      EXPECT_EQ(LengthLiteral->getValue().getZExtValue(), 8u);
+    }
 
     // stride (2)
     const Expr *Stride = ArraySection->getStride();
     ASSERT_TRUE(Stride);
+    if (const auto *StrideLiteral = dyn_cast<IntegerLiteral>(Stride)) {
+      EXPECT_EQ(StrideLiteral->getValue().getZExtValue(), 2u);
+    }
+  }
+}
+
+TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_From_ArraySection_NoStride) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      #pragma omp target update from(arr[2:10])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPFromClause *FromClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((FromClause = dyn_cast<OMPFromClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(FromClause);
+
+  for (const auto *VarExpr : FromClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+    if (const auto *LowerBoundLiteral = dyn_cast<IntegerLiteral>(LowerBound)) {
+      EXPECT_EQ(LowerBoundLiteral->getValue().getZExtValue(), 2u);
+    }
+
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+    if (const auto *LengthLiteral = dyn_cast<IntegerLiteral>(Length)) {
+      EXPECT_EQ(LengthLiteral->getValue().getZExtValue(), 10u);
+    }
+
+    const Expr *Stride = ArraySection->getStride();
+    if (Stride) {
+      if (const auto *StrideLiteral = dyn_cast<IntegerLiteral>(Stride)) {
+        EXPECT_EQ(StrideLiteral->getValue().getZExtValue(), 1u);
+      }
+    }
   }
 }
 
@@ -4891,12 +4954,75 @@ TEST_P(ASTMatchersTest, 
OMPTargetUpdateDirective_To_HasClause) {
 
     const Expr *LowerBound = ArraySection->getLowerBound();
     ASSERT_TRUE(LowerBound);
+    if (const auto *LowerBoundLiteral = dyn_cast<IntegerLiteral>(LowerBound)) {
+      EXPECT_EQ(LowerBoundLiteral->getValue().getZExtValue(), 0u);
+    }
 
     const Expr *Length = ArraySection->getLength();
     ASSERT_TRUE(Length);
+    if (const auto *LengthLiteral = dyn_cast<IntegerLiteral>(Length)) {
+      EXPECT_EQ(LengthLiteral->getValue().getZExtValue(), 8u);
+    }
 
     const Expr *Stride = ArraySection->getStride();
     ASSERT_TRUE(Stride);
+    if (const auto *StrideLiteral = dyn_cast<IntegerLiteral>(Stride)) {
+      EXPECT_EQ(StrideLiteral->getValue().getZExtValue(), 2u);
+    }
+  }
+}
+
+TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_To_ArraySection_NoStride) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      #pragma omp target update to(arr[1:15])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPToClause *ToClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((ToClause = dyn_cast<OMPToClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(ToClause);
+
+  for (const auto *VarExpr : ToClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+    if (const auto *LowerBoundLiteral = dyn_cast<IntegerLiteral>(LowerBound)) {
+      EXPECT_EQ(LowerBoundLiteral->getValue().getZExtValue(), 1u);
+    }
+
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+    if (const auto *LengthLiteral = dyn_cast<IntegerLiteral>(Length)) {
+      EXPECT_EQ(LengthLiteral->getValue().getZExtValue(), 15u);
+    }
+
+    const Expr *Stride = ArraySection->getStride();
+    if (Stride) {
+      if (const auto *StrideLiteral = dyn_cast<IntegerLiteral>(Stride)) {
+        EXPECT_EQ(StrideLiteral->getValue().getZExtValue(), 1u);
+      }
+    }
   }
 }
 
@@ -4944,6 +5070,600 @@ TEST_P(ASTMatchersTest,
   EXPECT_TRUE(matchesWithOpenMP(Source1, Matcher));
 }
 
+TEST_P(ASTMatchersTest, OMPFromClause_DoesNotMatchToClause) {
+  auto Matcher = ompTargetUpdateDirective(hasAnyClause(ompFromClause()));
+
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update to(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+}
+
+TEST_P(ASTMatchersTest, OMPToClause_DoesNotMatchFromClause) {
+  auto Matcher = ompTargetUpdateDirective(hasAnyClause(ompToClause()));
+
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update from(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+}
+
+TEST_P(ASTMatchersTest,
+       OMPTargetUpdateDirective_From_ArraySection_WrongOffset) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      #pragma omp target update from(arr[5:8:2])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPFromClause *FromClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((FromClause = dyn_cast<OMPFromClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(FromClause);
+
+  for (const auto *VarExpr : FromClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // lower bound (5, not 0)
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+    ASSERT_TRUE(isa<IntegerLiteral>(LowerBound));
+    const auto *LowerBoundLiteral = cast<IntegerLiteral>(LowerBound);
+    EXPECT_NE(LowerBoundLiteral->getValue().getZExtValue(), 0u);
+    EXPECT_EQ(LowerBoundLiteral->getValue().getZExtValue(), 5u);
+
+    // length (8)
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+
+    // stride (2)
+    const Expr *Stride = ArraySection->getStride();
+    ASSERT_TRUE(Stride);
+  }
+}
+
+TEST_P(ASTMatchersTest,
+       OMPTargetUpdateDirective_From_ArraySection_OffsetVariable) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      int offset = 5;
+      #pragma omp target update from(arr[offset:8:2])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPFromClause *FromClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((FromClause = dyn_cast<OMPFromClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(FromClause);
+
+  for (const auto *VarExpr : FromClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // lower bound (variable, not literal)
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+    EXPECT_FALSE(isa<IntegerLiteral>(LowerBound));
+    EXPECT_TRUE(isa<ImplicitCastExpr>(LowerBound) ||
+                isa<DeclRefExpr>(LowerBound));
+  }
+}
+
+TEST_P(ASTMatchersTest,
+       OMPTargetUpdateDirective_From_ArraySection_WrongLength) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      #pragma omp target update from(arr[0:10:2])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPFromClause *FromClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((FromClause = dyn_cast<OMPFromClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(FromClause);
+
+  for (const auto *VarExpr : FromClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // lower bound (0)
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+
+    // length (10, not 8)
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+    ASSERT_TRUE(isa<IntegerLiteral>(Length));
+    const auto *LengthLiteral = cast<IntegerLiteral>(Length);
+    EXPECT_NE(LengthLiteral->getValue().getZExtValue(), 8u);
+    EXPECT_EQ(LengthLiteral->getValue().getZExtValue(), 10u);
+
+    // stride (2)
+    const Expr *Stride = ArraySection->getStride();
+    ASSERT_TRUE(Stride);
+  }
+}
+
+TEST_P(ASTMatchersTest,
+       OMPTargetUpdateDirective_From_ArraySection_LengthVariable) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      int len = 10;
+      #pragma omp target update from(arr[0:len:2])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPFromClause *FromClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((FromClause = dyn_cast<OMPFromClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(FromClause);
+
+  for (const auto *VarExpr : FromClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // length (variable, not literal)
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+    EXPECT_FALSE(isa<IntegerLiteral>(Length));
+    EXPECT_TRUE(isa<ImplicitCastExpr>(Length) || isa<DeclRefExpr>(Length));
+  }
+}
+
+TEST_P(ASTMatchersTest,
+       OMPTargetUpdateDirective_From_ArraySection_WrongStride) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      #pragma omp target update from(arr[0:8:4])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPFromClause *FromClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((FromClause = dyn_cast<OMPFromClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(FromClause);
+
+  for (const auto *VarExpr : FromClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // lower bound (0)
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+
+    // length (8)
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+
+    // stride (4, not 2)
+    const Expr *Stride = ArraySection->getStride();
+    ASSERT_TRUE(Stride);
+    ASSERT_TRUE(isa<IntegerLiteral>(Stride));
+    const auto *StrideLiteral = cast<IntegerLiteral>(Stride);
+    EXPECT_NE(StrideLiteral->getValue().getZExtValue(), 2u);
+    EXPECT_EQ(StrideLiteral->getValue().getZExtValue(), 4u);
+  }
+}
+
+TEST_P(ASTMatchersTest,
+       OMPTargetUpdateDirective_From_ArraySection_StrideVariable) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      int step = 4;
+      #pragma omp target update from(arr[0:8:step])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPFromClause *FromClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((FromClause = dyn_cast<OMPFromClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(FromClause);
+
+  for (const auto *VarExpr : FromClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // stride (variable, not literal)
+    const Expr *Stride = ArraySection->getStride();
+    ASSERT_TRUE(Stride);
+    EXPECT_FALSE(isa<IntegerLiteral>(Stride));
+    EXPECT_TRUE(isa<ImplicitCastExpr>(Stride) || isa<DeclRefExpr>(Stride));
+  }
+}
+
+TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_To_ArraySection_WrongOffset) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      #pragma omp target update to(arr[3:8:2])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPToClause *ToClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((ToClause = dyn_cast<OMPToClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(ToClause);
+
+  for (const auto *VarExpr : ToClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // lower bound (3, not 0)
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+    ASSERT_TRUE(isa<IntegerLiteral>(LowerBound));
+    const auto *LowerBoundLiteral = cast<IntegerLiteral>(LowerBound);
+    EXPECT_NE(LowerBoundLiteral->getValue().getZExtValue(), 0u);
+    EXPECT_EQ(LowerBoundLiteral->getValue().getZExtValue(), 3u);
+
+    // length (8)
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+
+    // stride (2)
+    const Expr *Stride = ArraySection->getStride();
+    ASSERT_TRUE(Stride);
+  }
+}
+
+TEST_P(ASTMatchersTest,
+       OMPTargetUpdateDirective_To_ArraySection_OffsetVariable) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      int idx = 3;
+      #pragma omp target update to(arr[idx:8:2])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPToClause *ToClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((ToClause = dyn_cast<OMPToClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(ToClause);
+
+  for (const auto *VarExpr : ToClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // lower bound (variable, not literal)
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+    EXPECT_FALSE(isa<IntegerLiteral>(LowerBound));
+    EXPECT_TRUE(isa<ImplicitCastExpr>(LowerBound) ||
+                isa<DeclRefExpr>(LowerBound));
+  }
+}
+
+TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_To_ArraySection_WrongLength) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      #pragma omp target update to(arr[0:12:2])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPToClause *ToClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((ToClause = dyn_cast<OMPToClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(ToClause);
+
+  for (const auto *VarExpr : ToClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // lower bound (0)
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+
+    // length (12, not 8)
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+    ASSERT_TRUE(isa<IntegerLiteral>(Length));
+    const auto *LengthLiteral = cast<IntegerLiteral>(Length);
+    EXPECT_NE(LengthLiteral->getValue().getZExtValue(), 8u);
+    EXPECT_EQ(LengthLiteral->getValue().getZExtValue(), 12u);
+
+    // stride (2)
+    const Expr *Stride = ArraySection->getStride();
+    ASSERT_TRUE(Stride);
+  }
+}
+
+TEST_P(ASTMatchersTest,
+       OMPTargetUpdateDirective_To_ArraySection_LengthVariable) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      int count = 12;
+      #pragma omp target update to(arr[0:count:2])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPToClause *ToClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((ToClause = dyn_cast<OMPToClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(ToClause);
+
+  for (const auto *VarExpr : ToClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // length (variable, not literal)
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+    EXPECT_FALSE(isa<IntegerLiteral>(Length));
+    EXPECT_TRUE(isa<ImplicitCastExpr>(Length) || isa<DeclRefExpr>(Length));
+  }
+}
+
+TEST_P(ASTMatchersTest, OMPTargetUpdateDirective_To_ArraySection_WrongStride) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      #pragma omp target update to(arr[0:8:3])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPToClause *ToClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((ToClause = dyn_cast<OMPToClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(ToClause);
+
+  for (const auto *VarExpr : ToClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // lower bound (0)
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+
+    // length (8)
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+
+    // stride (3, not 2)
+    const Expr *Stride = ArraySection->getStride();
+    ASSERT_TRUE(Stride);
+    ASSERT_TRUE(isa<IntegerLiteral>(Stride));
+    const auto *StrideLiteral = cast<IntegerLiteral>(Stride);
+    EXPECT_NE(StrideLiteral->getValue().getZExtValue(), 2u);
+    EXPECT_EQ(StrideLiteral->getValue().getZExtValue(), 3u);
+  }
+}
+
+TEST_P(ASTMatchersTest,
+       OMPTargetUpdateDirective_To_ArraySection_StrideVariable) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      int stride = 3;
+      #pragma omp target update to(arr[0:8:stride])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPToClause *ToClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((ToClause = dyn_cast<OMPToClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(ToClause);
+
+  for (const auto *VarExpr : ToClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    const Expr *Stride = ArraySection->getStride();
+    ASSERT_TRUE(Stride);
+    EXPECT_FALSE(isa<IntegerLiteral>(Stride));
+    EXPECT_TRUE(isa<ImplicitCastExpr>(Stride) || isa<DeclRefExpr>(Stride));
+  }
+}
+
 TEST_P(ASTMatchersTest, HasAnyBase_DirectBase) {
   if (!GetParam().isCXX()) {
     return;
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp 
b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index 8bf97d1ac0a8b..b1b09cfedd4c6 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -2839,14 +2839,23 @@ TEST(ASTMatchersTestOpenMP, OMPFromClause) {
     // lower bound (0)
     const Expr *LowerBound = ArraySection->getLowerBound();
     ASSERT_TRUE(LowerBound);
+    if (const auto *LowerBoundLiteral = dyn_cast<IntegerLiteral>(LowerBound)) {
+      EXPECT_EQ(LowerBoundLiteral->getValue().getZExtValue(), 0u);
+    }
 
     // length (8)
     const Expr *Length = ArraySection->getLength();
     ASSERT_TRUE(Length);
+    if (const auto *LengthLiteral = dyn_cast<IntegerLiteral>(Length)) {
+      EXPECT_EQ(LengthLiteral->getValue().getZExtValue(), 8u);
+    }
 
     // stride (2)
     const Expr *Stride = ArraySection->getStride();
     ASSERT_TRUE(Stride);
+    if (const auto *StrideLiteral = dyn_cast<IntegerLiteral>(Stride)) {
+      EXPECT_EQ(StrideLiteral->getValue().getZExtValue(), 2u);
+    }
   }
 }
 
@@ -2893,14 +2902,307 @@ TEST(ASTMatchersTestOpenMP, OMPToClause) {
     // lower bound (0)
     const Expr *LowerBound = ArraySection->getLowerBound();
     ASSERT_TRUE(LowerBound);
+    if (const auto *LowerBoundLiteral = dyn_cast<IntegerLiteral>(LowerBound)) {
+      EXPECT_EQ(LowerBoundLiteral->getValue().getZExtValue(), 0u);
+    }
 
     // length (8)
     const Expr *Length = ArraySection->getLength();
     ASSERT_TRUE(Length);
+    if (const auto *LengthLiteral = dyn_cast<IntegerLiteral>(Length)) {
+      EXPECT_EQ(LengthLiteral->getValue().getZExtValue(), 8u);
+    }
 
     // stride (2)
     const Expr *Stride = ArraySection->getStride();
     ASSERT_TRUE(Stride);
+    if (const auto *StrideLiteral = dyn_cast<IntegerLiteral>(Stride)) {
+      EXPECT_EQ(StrideLiteral->getValue().getZExtValue(), 2u);
+    }
+  }
+}
+
+TEST(ASTMatchersTestOpenMP, OMPFromClause_DoesNotMatchToClause) {
+  auto Matcher = ompTargetUpdateDirective(hasAnyClause(ompFromClause()));
+
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update to(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+}
+
+TEST(ASTMatchersTestOpenMP, OMPToClause_DoesNotMatchFromClause) {
+  auto Matcher = ompTargetUpdateDirective(hasAnyClause(ompToClause()));
+
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[8];
+      #pragma omp target update from(arr[0:8:2])
+      ;
+    }
+  )";
+  EXPECT_TRUE(notMatchesWithOpenMP(Source0, Matcher));
+}
+
+TEST(ASTMatchersTestOpenMP, OMPFromClause_ArraySection_DifferentOffsetValue) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      #pragma omp target update from(arr[7:8:2])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPFromClause *FromClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((FromClause = dyn_cast<OMPFromClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(FromClause);
+
+  for (const auto *VarExpr : FromClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // lower bound (7, not 0)
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+    ASSERT_TRUE(isa<IntegerLiteral>(LowerBound));
+    const auto *LowerBoundLiteral = cast<IntegerLiteral>(LowerBound);
+    EXPECT_NE(LowerBoundLiteral->getValue().getZExtValue(), 0u);
+    EXPECT_EQ(LowerBoundLiteral->getValue().getZExtValue(), 7u);
+  }
+}
+
+TEST(ASTMatchersTestOpenMP, OMPFromClause_ArraySection_DifferentLengthValue) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      #pragma omp target update from(arr[0:15:2])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPFromClause *FromClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((FromClause = dyn_cast<OMPFromClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(FromClause);
+
+  for (const auto *VarExpr : FromClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // length (15, not 8)
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+    ASSERT_TRUE(isa<IntegerLiteral>(Length));
+    const auto *LengthLiteral = cast<IntegerLiteral>(Length);
+    EXPECT_NE(LengthLiteral->getValue().getZExtValue(), 8u);
+    EXPECT_EQ(LengthLiteral->getValue().getZExtValue(), 15u);
+  }
+}
+
+TEST(ASTMatchersTestOpenMP, OMPFromClause_ArraySection_DifferentStrideValue) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      #pragma omp target update from(arr[0:8:5])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPFromClause *FromClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((FromClause = dyn_cast<OMPFromClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(FromClause);
+
+  for (const auto *VarExpr : FromClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // stride (5, not 2)
+    const Expr *Stride = ArraySection->getStride();
+    ASSERT_TRUE(Stride);
+    ASSERT_TRUE(isa<IntegerLiteral>(Stride));
+    const auto *StrideLiteral = cast<IntegerLiteral>(Stride);
+    EXPECT_NE(StrideLiteral->getValue().getZExtValue(), 2u);
+    EXPECT_EQ(StrideLiteral->getValue().getZExtValue(), 5u);
+  }
+}
+
+TEST(ASTMatchersTestOpenMP, OMPToClause_ArraySection_DifferentOffsetValue) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      #pragma omp target update to(arr[4:8:2])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPToClause *ToClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((ToClause = dyn_cast<OMPToClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(ToClause);
+
+  for (const auto *VarExpr : ToClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // lower bound (4, not 0)
+    const Expr *LowerBound = ArraySection->getLowerBound();
+    ASSERT_TRUE(LowerBound);
+    ASSERT_TRUE(isa<IntegerLiteral>(LowerBound));
+    const auto *LowerBoundLiteral = cast<IntegerLiteral>(LowerBound);
+    EXPECT_NE(LowerBoundLiteral->getValue().getZExtValue(), 0u);
+    EXPECT_EQ(LowerBoundLiteral->getValue().getZExtValue(), 4u);
+  }
+}
+
+TEST(ASTMatchersTestOpenMP, OMPToClause_ArraySection_DifferentLengthValue) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      #pragma omp target update to(arr[0:20:2])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPToClause *ToClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((ToClause = dyn_cast<OMPToClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(ToClause);
+
+  for (const auto *VarExpr : ToClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // length (20, not 8)
+    const Expr *Length = ArraySection->getLength();
+    ASSERT_TRUE(Length);
+    ASSERT_TRUE(isa<IntegerLiteral>(Length));
+    const auto *LengthLiteral = cast<IntegerLiteral>(Length);
+    EXPECT_NE(LengthLiteral->getValue().getZExtValue(), 8u);
+    EXPECT_EQ(LengthLiteral->getValue().getZExtValue(), 20u);
+  }
+}
+
+TEST(ASTMatchersTestOpenMP, OMPToClause_ArraySection_DifferentStrideValue) {
+  StringRef Source0 = R"(
+    void foo() {
+      int arr[20];
+      #pragma omp target update to(arr[0:8:6])
+      ;
+    }
+  )";
+
+  auto astUnit = tooling::buildASTFromCodeWithArgs(Source0, {"-fopenmp"});
+  ASSERT_TRUE(astUnit);
+
+  auto Results = match(ompTargetUpdateDirective().bind("directive"),
+                       astUnit->getASTContext());
+  ASSERT_FALSE(Results.empty());
+
+  const auto *Directive =
+      Results[0].getNodeAs<OMPTargetUpdateDirective>("directive");
+  ASSERT_TRUE(Directive);
+
+  OMPToClause *ToClause = nullptr;
+  for (auto *Clause : Directive->clauses()) {
+    if ((ToClause = dyn_cast<OMPToClause>(Clause))) {
+      break;
+    }
+  }
+  ASSERT_TRUE(ToClause);
+
+  for (const auto *VarExpr : ToClause->varlist()) {
+    const auto *ArraySection = dyn_cast<ArraySectionExpr>(VarExpr);
+    if (!ArraySection)
+      continue;
+
+    // stride (6, not 2)
+    const Expr *Stride = ArraySection->getStride();
+    ASSERT_TRUE(Stride);
+    ASSERT_TRUE(isa<IntegerLiteral>(Stride));
+    const auto *StrideLiteral = cast<IntegerLiteral>(Stride);
+    EXPECT_NE(StrideLiteral->getValue().getZExtValue(), 2u);
+    EXPECT_EQ(StrideLiteral->getValue().getZExtValue(), 6u);
   }
 }
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to