llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Denis Mikhailov (denzor200)

<details>
<summary>Changes</summary>

Implementation of this matcher was mostly generated by Cursor.
This matcher(like 
[hasAdjacentSubstatements](https://github.com/llvm/llvm-project/pull/169965)) 
needed for me at least to implement 
https://github.com/llvm/llvm-project/issues/133110 and 
https://github.com/llvm/llvm-project/issues/38471
Also maybe we will use it in https://github.com/llvm/llvm-project/pull/158462


---

Patch is 33.91 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/173587.diff


8 Files Affected:

- (modified) clang/docs/LibASTMatchersReference.html (+31) 
- (modified) clang/docs/ReleaseNotes.rst (+1) 
- (modified) clang/include/clang/ASTMatchers/ASTMatchers.h (+20) 
- (modified) clang/include/clang/ASTMatchers/ASTMatchersInternal.h (+61-5) 
- (modified) clang/lib/ASTMatchers/ASTMatchFinder.cpp (+31-12) 
- (modified) clang/lib/ASTMatchers/ASTMatchersInternal.cpp (+95-4) 
- (modified) clang/lib/ASTMatchers/Dynamic/Registry.cpp (+1) 
- (modified) clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp (+254) 


``````````diff
diff --git a/clang/docs/LibASTMatchersReference.html 
b/clang/docs/LibASTMatchersReference.html
index e34ac30b8f5a4..cb65552751485 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -8211,6 +8211,22 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
 </pre></td></tr>
 
 
+<tr><td>Matcher&lt;<a 
href="https://clang.llvm.org/doxygen/classclang_1_1CompoundStmt.html";>CompoundStmt</a>&gt;</td><td
 class="name" onclick="toggle('forEachAdjacentSubstatements0')"><a 
name="forEachAdjacentSubstatements0Anchor">forEachAdjacentSubstatements</a></td><td>Matcher&lt;<a
 href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html";>Stmt</a>&gt;, 
..., Matcher&lt;<a 
href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html";>Stmt</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" 
id="forEachAdjacentSubstatements0"><pre>Matches compound statements where all 
sets of adjacent substatements
+matching the provided sequence of matchers are found. Also matches
+StmtExprs that have CompoundStmt as children.
+
+Given
+  { {}; 1+2; {}; 3+4; }
+forEachAdjacentSubstatements(compoundStmt(), binaryOperator())
+  matches '{ {}; 1+2; {}; 3+4; }' twice
+with compoundStmt()
+  matching '{}' (first match) and '{}' (second match)
+with binaryOperator()
+  matching '1+2' (first match) and '3+4' (second match)
+</pre></td></tr>
+
+
 <tr><td>Matcher&lt;<a 
href="https://clang.llvm.org/doxygen/classclang_1_1CoroutineBodyStmt.html";>CoroutineBodyStmt</a>&gt;</td><td
 class="name" onclick="toggle('hasBody5')"><a 
name="hasBody5Anchor">hasBody</a></td><td>Matcher&lt;<a 
href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html";>Stmt</a>&gt; 
InnerMatcher</td></tr>
 <tr><td colspan="4" class="doc" id="hasBody5"><pre>Matches a 'for', 'while', 
'while' statement or a function or coroutine
 definition that has a given body. Note that in case of functions or
@@ -9991,6 +10007,21 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
 </pre></td></tr>
 
 
+<tr><td>Matcher&lt;<a 
href="https://clang.llvm.org/doxygen/classclang_1_1StmtExpr.html";>StmtExpr</a>&gt;</td><td
 class="name" onclick="toggle('forEachAdjacentSubstatements1')"><a 
name="forEachAdjacentSubstatements1Anchor">forEachAdjacentSubstatements</a></td><td>Matcher&lt;<a
 href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html";>Stmt</a>&gt;, 
..., Matcher&lt;<a 
href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html";>Stmt</a>&gt;</td></tr>
+<tr><td colspan="4" class="doc" 
id="forEachAdjacentSubstatements1"><pre>Matches StmtExprs with compound 
statements containing all sets of
+adjacent substatements that match the provided sequence of matchers.
+
+Given
+  int x = ({ {}; 1+2; {}; 3+4; });
+forEachAdjacentSubstatements(compoundStmt(), binaryOperator())
+  matches '({ {}; 1+2; {}; 3+4; })' twice
+with compoundStmt()
+  matching '{}' (first match) and '{}' (second match)
+with binaryOperator()
+  matching '1+2' (first match) and '3+4' (second match)
+</pre></td></tr>
+
+
 <tr><td>Matcher&lt;<a 
href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html";>Stmt</a>&gt;</td><td
 class="name" onclick="toggle('alignOfExpr0')"><a 
name="alignOfExpr0Anchor">alignOfExpr</a></td><td>Matcher&lt;<a 
href="https://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html";>UnaryExprOrTypeTraitExpr</a>&gt;
  InnerMatcher</td></tr>
 <tr><td colspan="4" class="doc" id="alignOfExpr0"><pre>Same as 
unaryExprOrTypeTraitExpr, but only matching
 alignof.
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index feaf92ad4415f..6c925412fc334 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -753,6 +753,7 @@ AST Matchers
 - Added ``hasExplicitParameters`` for ``LambdaExpr`` as an output attribute to
   AST JSON dumps.
 - Add ``arrayTypeLoc`` matcher for matching ``ArrayTypeLoc``.
+- Add ``forEachAdjacentSubstatements``.
 
 clang-format
 ------------
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h 
b/clang/include/clang/ASTMatchers/ASTMatchers.h
index e3ec26207d2bc..5da86716587e5 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -5911,6 +5911,26 @@ AST_POLYMORPHIC_MATCHER_P(hasAnySubstatement,
                                           Builder) != CS->body_end();
 }
 
+
+/// Matches compound statements where one ore more sets of adjacent
+/// substatements matching the provided sequence of matchers. Also matches
+/// StmtExprs that have CompoundStmt as children.
+///
+/// Given
+/// \code
+///   { {}; 1+2; {}; 3+4; }
+/// \endcode
+/// forEachAdjacentSubstatements(compoundStmt(), binaryOperator())
+///   matches '{ {}; 1+2; {}; 3+4; }' twice
+/// with compoundStmt()
+///   matching '{}' (first match) and '{}' (second match)
+/// with binaryOperator()
+///   matching '1+2' (first match) and '3+4' (second match)
+extern const internal::VariadicFunction<
+    internal::ForEachAdjacentSubstatementsMatcherType, internal::Matcher<Stmt>,
+    internal::forEachAdjSubstatementsFunc>
+    forEachAdjacentSubstatements;
+
 /// Checks that a compound statement contains a specific number of
 /// child statements.
 ///
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h 
b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
index c050fb7d797e3..f16c2e32cb6c2 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -47,6 +47,7 @@
 #include "clang/AST/TemplateName.h"
 #include "clang/AST/Type.h"
 #include "clang/AST/TypeLoc.h"
+#include "clang/ASTMatchers/ASTMatchersMacros.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/OperatorKinds.h"
 #include "llvm/ADT/APFloat.h"
@@ -410,9 +411,10 @@ class DynTypedMatcher {
 public:
   /// Takes ownership of the provided implementation pointer.
   template <typename T>
-  DynTypedMatcher(MatcherInterface<T> *Implementation)
+  DynTypedMatcher(const MatcherInterface<T> *Implementation)
       : SupportedKind(ASTNodeKind::getFromNodeKind<T>()),
-        RestrictKind(SupportedKind), Implementation(Implementation) {}
+        RestrictKind(SupportedKind),
+        Implementation(Implementation) {}
 
   /// Construct from a variadic function.
   enum VariadicOperator {
@@ -541,7 +543,7 @@ class DynTypedMatcher {
 
 private:
   DynTypedMatcher(ASTNodeKind SupportedKind, ASTNodeKind RestrictKind,
-                  IntrusiveRefCntPtr<DynMatcherInterface> Implementation)
+                  IntrusiveRefCntPtr<const DynMatcherInterface> Implementation)
       : SupportedKind(SupportedKind), RestrictKind(RestrictKind),
         Implementation(std::move(Implementation)) {}
 
@@ -553,7 +555,7 @@ class DynTypedMatcher {
   /// It allows to perform implicit and dynamic cast of matchers without
   /// needing to change \c Implementation.
   ASTNodeKind RestrictKind;
-  IntrusiveRefCntPtr<DynMatcherInterface> Implementation;
+  IntrusiveRefCntPtr<const DynMatcherInterface> Implementation;
 };
 
 /// Wrapper of a MatcherInterface<T> *that allows copying.
@@ -743,7 +745,8 @@ class ASTMatchFinder {
 
   template <typename T>
   bool matchesChildOf(const T &Node, const DynTypedMatcher &Matcher,
-                      BoundNodesTreeBuilder *Builder, BindKind Bind) {
+                      BoundNodesTreeBuilder *Builder, BindKind Bind,
+                      llvm::function_ref<bool(BoundNodesTreeBuilder*)> 
MatchCallback) {
     static_assert(std::is_base_of<Decl, T>::value ||
                       std::is_base_of<Stmt, T>::value ||
                       std::is_base_of<NestedNameSpecifier, T>::value ||
@@ -752,6 +755,21 @@ class ASTMatchFinder {
                       std::is_base_of<QualType, T>::value ||
                       std::is_base_of<Attr, T>::value,
                   "unsupported type for recursive matching");
+    return matchesChildOf(DynTypedNode::create(Node), getASTContext(), Matcher,
+                          Builder, Bind, MatchCallback);
+  }
+
+  template <typename T>
+  bool matchesChildOf(const T &Node, const DynTypedMatcher &Matcher,
+                      BoundNodesTreeBuilder *Builder, BindKind Bind) {
+    static_assert(std::is_base_of<Decl, T>::value ||
+                  std::is_base_of<Stmt, T>::value ||
+                  std::is_base_of<NestedNameSpecifier, T>::value ||
+                  std::is_base_of<NestedNameSpecifierLoc, T>::value ||
+                  std::is_base_of<TypeLoc, T>::value ||
+                  std::is_base_of<QualType, T>::value ||
+                  std::is_base_of<Attr, T>::value,
+                  "unsupported type for recursive matching");
     return matchesChildOf(DynTypedNode::create(Node), getASTContext(), Matcher,
                           Builder, Bind);
   }
@@ -795,6 +813,12 @@ class ASTMatchFinder {
   bool isTraversalIgnoringImplicitNodes() const;
 
 protected:
+  virtual bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,
+                              const DynTypedMatcher &Matcher,
+                              BoundNodesTreeBuilder *Builder,
+                              BindKind Bind,
+                              llvm::function_ref<bool(BoundNodesTreeBuilder 
*)> MatchCallback) = 0;
+
   virtual bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,
                               const DynTypedMatcher &Matcher,
                               BoundNodesTreeBuilder *Builder,
@@ -809,6 +833,7 @@ class ASTMatchFinder {
                                  const DynTypedMatcher &Matcher,
                                  BoundNodesTreeBuilder *Builder,
                                  AncestorMatchMode MatchMode) = 0;
+
 private:
   friend struct ASTChildrenNotSpelledInSourceScope;
   virtual bool isMatchingChildrenNotSpelledInSource() const = 0;
@@ -2283,6 +2308,37 @@ using HasOpNameMatcher =
 
 HasOpNameMatcher hasAnyOperatorNameFunc(ArrayRef<const StringRef *> NameRefs);
 
+/// Matches nodes of type T (CompoundStmt or StmtExpr) that contain sequences
+/// of consecutive substatements matching the provided matchers in order.
+///
+/// See \c forEachAdjacentSubstatements() in ASTMatchers.h for details.
+template <typename T, typename ArgT = std::vector<Matcher<Stmt>>>
+class ForEachAdjacentSubstatementsMatcher : public MatcherInterface<T> {
+  static_assert(std::is_same<T, CompoundStmt>::value ||
+                    std::is_same<T, StmtExpr>::value,
+                "Matcher only supports `CompoundStmt` and `StmtExpr`");
+  static_assert(std::is_same<ArgT, std::vector<Matcher<Stmt>>>::value,
+                "Matcher ArgT must be std::vector<Matcher<Stmt>>");
+
+public:
+  explicit ForEachAdjacentSubstatementsMatcher(std::vector<Matcher<Stmt>> 
Matchers)
+      : Matchers(std::move(Matchers)) {}
+
+  bool matches(const T &Node, ASTMatchFinder *Finder,
+               BoundNodesTreeBuilder *Builder) const override;
+
+private:
+  std::vector<Matcher<Stmt>> Matchers;
+};
+
+using ForEachAdjacentSubstatementsMatcherType =
+    PolymorphicMatcher<ForEachAdjacentSubstatementsMatcher,
+                       AST_POLYMORPHIC_SUPPORTED_TYPES(CompoundStmt, StmtExpr),
+                       std::vector<Matcher<Stmt>>>;
+
+ForEachAdjacentSubstatementsMatcherType
+forEachAdjSubstatementsFunc(ArrayRef<const Matcher<Stmt> *> MatcherRefs);
+
 using HasOverloadOpNameMatcher =
     PolymorphicMatcher<HasOverloadedOperatorNameMatcher,
                        void(TypeList<CXXOperatorCallExpr, FunctionDecl>),
diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp 
b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
index e8a0004c2e187..7739d45377416 100644
--- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -593,14 +593,15 @@ class MatchASTVisitor : public 
RecursiveASTVisitor<MatchASTVisitor>,
     return RecursiveASTVisitor<MatchASTVisitor>::dataTraverseNode(S, Queue);
   }
 
-  // Matches children or descendants of 'Node' with 'BaseMatcher'.
-  bool memoizedMatchesRecursively(const DynTypedNode &Node, ASTContext &Ctx,
-                                  const DynTypedMatcher &Matcher,
-                                  BoundNodesTreeBuilder *Builder, int MaxDepth,
-                                  BindKind Bind) {
+  // Matches children or descendants of 'Node' with a custom callback.
+  bool memoizedMatchesRecursively(
+      const DynTypedNode &Node, ASTContext &Ctx,
+      const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder,
+      int MaxDepth, BindKind Bind,
+      llvm::function_ref<bool(BoundNodesTreeBuilder *)> MatchCallback) {
     // For AST-nodes that don't have an identity, we can't memoize.
     if (!Node.getMemoizationData() || !Builder->isComparable())
-      return matchesRecursively(Node, Matcher, Builder, MaxDepth, Bind);
+      return MatchCallback(Builder);
 
     MatchKey Key;
     Key.MatcherID = Matcher.getID();
@@ -618,8 +619,7 @@ class MatchASTVisitor : public 
RecursiveASTVisitor<MatchASTVisitor>,
 
     MemoizedMatchResult Result;
     Result.Nodes = *Builder;
-    Result.ResultOfMatch =
-        matchesRecursively(Node, Matcher, &Result.Nodes, MaxDepth, Bind);
+    Result.ResultOfMatch = MatchCallback(&Result.Nodes);
 
     MemoizedMatchResult &CachedResult = ResultCache[Key];
     CachedResult = std::move(Result);
@@ -668,13 +668,27 @@ class MatchASTVisitor : public 
RecursiveASTVisitor<MatchASTVisitor>,
                               bool Directly) override;
 
 public:
-  // Implements ASTMatchFinder::matchesChildOf.
+  // Implements ASTMatchFinder::matchesChildOf (with callback).
   bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,
                       const DynTypedMatcher &Matcher,
-                      BoundNodesTreeBuilder *Builder, BindKind Bind) override {
+                      BoundNodesTreeBuilder *Builder, BindKind Bind,
+                      llvm::function_ref<bool(BoundNodesTreeBuilder *)>
+                          MatchCallback) override {
     if (ResultCache.size() > MaxMemoizationEntries)
       ResultCache.clear();
-    return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1, Bind);
+    return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1, Bind,
+                                      MatchCallback);
+  }
+
+  // Implements ASTMatchFinder::matchesChildOf (without callback).
+  bool matchesChildOf(const DynTypedNode &Node, ASTContext &Ctx,
+                      const DynTypedMatcher &Matcher,
+                      BoundNodesTreeBuilder *Builder, BindKind Bind) override {
+    return matchesChildOf(Node, Ctx, Matcher, Builder, Bind,
+                         [this, &Node, &Matcher, Bind](
+                            BoundNodesTreeBuilder* Nodes) -> bool {
+                           return matchesRecursively(Node, Matcher, Nodes, 1, 
Bind);
+                         });
   }
   // Implements ASTMatchFinder::matchesDescendantOf.
   bool matchesDescendantOf(const DynTypedNode &Node, ASTContext &Ctx,
@@ -684,7 +698,11 @@ class MatchASTVisitor : public 
RecursiveASTVisitor<MatchASTVisitor>,
     if (ResultCache.size() > MaxMemoizationEntries)
       ResultCache.clear();
     return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, INT_MAX,
-                                      Bind);
+                                      Bind,
+                                      [this, &Node, &Matcher, Bind](
+                                          BoundNodesTreeBuilder* Nodes) -> 
bool {
+                                        return matchesRecursively(Node, 
Matcher, Nodes, INT_MAX, Bind);
+                                      });
   }
   // Implements ASTMatchFinder::matchesAncestorOf.
   bool matchesAncestorOf(const DynTypedNode &Node, ASTContext &Ctx,
@@ -700,6 +718,7 @@ class MatchASTVisitor : public 
RecursiveASTVisitor<MatchASTVisitor>,
     return matchesAnyAncestorOf(Node, Ctx, Matcher, Builder);
   }
 
+
   // Matches all registered matchers on the given node and calls the
   // result callback for every node that matches.
   void match(const DynTypedNode &Node) {
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp 
b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index a556ffca96903..022d24738bc57 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -129,7 +129,7 @@ class VariadicMatcher : public DynMatcherInterface {
 class IdDynMatcher : public DynMatcherInterface {
 public:
   IdDynMatcher(StringRef ID,
-               IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher)
+               IntrusiveRefCntPtr<const DynMatcherInterface> InnerMatcher)
       : ID(ID), InnerMatcher(std::move(InnerMatcher)) {}
 
   bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder,
@@ -145,7 +145,7 @@ class IdDynMatcher : public DynMatcherInterface {
 
 private:
   const std::string ID;
-  const IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher;
+  const IntrusiveRefCntPtr<const DynMatcherInterface> InnerMatcher;
 };
 
 /// A matcher that always returns true.
@@ -167,7 +167,7 @@ class DynTraversalMatcherImpl : public DynMatcherInterface {
 public:
   explicit DynTraversalMatcherImpl(
       clang::TraversalKind TK,
-      IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher)
+      IntrusiveRefCntPtr<const DynMatcherInterface> InnerMatcher)
       : TK(TK), InnerMatcher(std::move(InnerMatcher)) {}
 
   bool dynMatches(const DynTypedNode &DynNode, ASTMatchFinder *Finder,
@@ -181,7 +181,7 @@ class DynTraversalMatcherImpl : public DynMatcherInterface {
 
 private:
   clang::TraversalKind TK;
-  IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher;
+  IntrusiveRefCntPtr<const DynMatcherInterface> InnerMatcher;
 };
 
 } // namespace
@@ -467,6 +467,93 @@ hasAnyOverloadedOperatorNameFunc(ArrayRef<const StringRef 
*> NameRefs) {
   return HasOverloadOpNameMatcher(vectorFromRefs(NameRefs));
 }
 
+static std::vector<Matcher<Stmt>>
+vectorFromMatcherRefs(ArrayRef<const Matcher<Stmt> *> MatcherRefs) {
+  std::vector<Matcher<Stmt>> Matchers;
+  Matchers.reserve(MatcherRefs.size());
+  for (auto *Matcher : MatcherRefs)
+    Matchers.push_back(*Matcher);
+  return Matchers;
+}
+
+/// Creates a new BoundNodesTreeBuilder that extends the given builder.
+/// This is a helper to simplify the pattern of creating a new builder,
+/// adding the current builder's matches to it, and then using it for matching.
+static BoundNodesTreeBuilder extendBuilder(BoundNodesTreeBuilder &&Builder) {
+  BoundNodesTreeBuilder Extended;
+  Extended.addMatch(std::move(Builder));
+  return Extended;
+}
+
+ForEachAdjacentSubstatementsMatcherType
+forEachAdjSubstatementsFunc(ArrayRef<const Matcher<Stmt> *> MatcherRefs) {
+  return 
ForEachAdjacentSubstatementsMatcherType(vectorFromMatcherRefs(MatcherRefs));
+}
+
+template <typename T, typename ArgT>
+bool ForEachAdjacentSubstatementsMatcher<T, ArgT>::matches(
+    const T &Node, ASTMatchFinder *Finder,
+    BoundNodesTreeBuilder *Builder) const {
+  const CompoundStmt *CS = CompoundStmtMatcher<T>::get(Node);
+  if (!CS)
+    return false;
+
+  if (Matchers.empty())
+    return false;
+
+  // Create a DynTypedMatcher wrapper for this matcher instance to use for
+  // memoization. The matcher sequence is implicitly part of the matcher
+  // instance, so using 'this' pointer provides a unique identifier.
+  DynTypedMatcher MatcherWrapper(this);
+
+  // Use memoization to avoid re-running the same matcher on the same node.
+  return Finder->matchesChildOf(static_cast<const Stmt&>(*CS),
+      MatcherWrapper, Builder, ASTMatchFinder::BK_All,
+      [this, CS, Finder](BoundNodesTreeBuilder *MemoBuilder) -> bool {
+        // Search for all sequences of adjacent substatements that match the
+        // matchers
+        const auto BodyBegin = CS->body_begin();
+        const auto BodyEnd = CS->body_end();
+
+        bool FoundAny = false;
+
+        // Try each possible starting position
+        for (auto StartIt = BodyBegin; StartIt != BodyEnd; ++StartIt) {
+          // Check if there are enough statements remaining
+          if (std::distance(StartIt, BodyEnd) <
+              static_cast<ptrdiff_t>(Matchers.size()))
+            break;
+
+          // Start with a fresh builder for this sequence
+          BoundNodesTreeBuilder SequenceBuilder;
+
+          // Use enumerate to iterate over matchers and statements 
simultaneously
+          auto StmtRange =
+              llvm::make_range(StartIt, StartIt + Matchers.size());
+          for (auto [Idx...
[truncated]

``````````

</details>


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

Reply via email to