https://github.com/denzor200 updated 
https://github.com/llvm/llvm-project/pull/169965

>From 0476cfd46a63af25a7f12e7ece5882246208ced9 Mon Sep 17 00:00:00 2001
From: denzor200 <[email protected]>
Date: Fri, 28 Nov 2025 23:51:14 +0300
Subject: [PATCH 1/6] Implement simple matcher

---
 clang/include/clang/ASTMatchers/ASTMatchers.h | 46 +++++++++++-
 clang/lib/ASTMatchers/Dynamic/Registry.cpp    |  1 +
 .../ASTMatchers/ASTMatchersTraversalTest.cpp  | 72 +++++++++++++++++++
 3 files changed, 118 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h 
b/clang/include/clang/ASTMatchers/ASTMatchers.h
index bca2d8425b3f5..080fc47c59d94 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -5889,7 +5889,6 @@ AST_MATCHER_P(FunctionDecl, hasAnyBody,
           InnerMatcher.matches(*Statement, Finder, Builder));
 }
 
-
 /// Matches compound statements where at least one substatement matches
 /// a given matcher. Also matches StmtExprs that have CompoundStmt as children.
 ///
@@ -5911,6 +5910,51 @@ AST_POLYMORPHIC_MATCHER_P(hasAnySubstatement,
                                           Builder) != CS->body_end();
 }
 
+/// Matches compound statements that contain a PrevStmt immediately followed by
+/// NextStmt. Also matches StmtExprs that have CompoundStmt as children.
+///
+/// Given
+/// \code
+///   { {}; 1+2; }
+/// \endcode
+/// hasAdjSubstatements(compoundStmt(), binaryOperator())
+///   matches '{ {}; 1+2; }'
+/// with compoundStmt()
+///   matching '{}'
+/// with binaryOperator()
+///   matching '1+2'
+AST_POLYMORPHIC_MATCHER_P2(hasAdjSubstatements,
+                           AST_POLYMORPHIC_SUPPORTED_TYPES(CompoundStmt,
+                                                           StmtExpr),
+                           ast_matchers::internal::Matcher<Stmt>, PrevMatcher,
+                           ast_matchers::internal::Matcher<Stmt>, NextMatcher) 
{
+  const CompoundStmt *CS = CompoundStmtMatcher<NodeType>::get(Node);
+  if (!CS)
+    return false;
+
+  auto Begin = CS->body_begin();
+  auto End = CS->body_end();
+  
+  if (CS->size() < 2)
+    return false;
+
+  return std::adjacent_find(
+             Begin, End,
+             [&](const Stmt *PrevStmt, const Stmt *NextStmt) {
+               clang::ast_matchers::internal::BoundNodesTreeBuilder 
PrevBuilder;
+               if (!PrevMatcher.matches(*PrevStmt, Finder, &PrevBuilder))
+                 return false;
+
+               clang::ast_matchers::internal::BoundNodesTreeBuilder 
NextBuilder;
+               NextBuilder.addMatch(PrevBuilder);
+               if (!NextMatcher.matches(*NextStmt, Finder, &NextBuilder))
+                 return false;
+
+               Builder->addMatch(NextBuilder);
+               return true;
+             }) != End;
+}
+
 /// Checks that a compound statement contains a specific number of
 /// child statements.
 ///
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp 
b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 66848f7c42127..7b21a60c5f189 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -288,6 +288,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(hasAnyPlacementArg);
   REGISTER_MATCHER(hasAnySelector);
   REGISTER_MATCHER(hasAnySubstatement);
+  REGISTER_MATCHER(hasAdjSubstatements);
   REGISTER_MATCHER(hasAnyTemplateArgument);
   REGISTER_MATCHER(hasAnyTemplateArgumentLoc);
   REGISTER_MATCHER(hasAnyUsingShadowDecl);
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp 
b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index c0a03deb5b543..d1d468dcf3116 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -2399,6 +2399,78 @@ TEST(HasAnySubstatement, FindsSubstatementBetweenOthers) 
{
                       compoundStmt(hasAnySubstatement(forStmt()))));
 }
 
+TEST(HasAdjSubstatements, MatchesAdjacentSubstatements) {
+  // Basic case: compound statement followed by binary operator
+  EXPECT_TRUE(matches("void f() { {} 1+2; }",
+                      compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                        binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, DoesNotMatchNonAdjacentSubstatements) {
+  // Statements exist but not adjacent
+  EXPECT_TRUE(notMatches("void f() { {} 1; 1+2; }",
+                         compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                          binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, MatchesInNestedCompoundStatements) {
+  // Should match in nested compound statements
+  EXPECT_TRUE(matches("void f() { if (true) { {} 1+2; } }",
+                      compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                      binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, MatchesFirstAdjacentPair) {
+  // When multiple adjacent pairs exist, should match the first one
+  EXPECT_TRUE(matches("void f() { {} 1+2; {} 3+4; }",
+                      compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                      binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, DoesNotMatchEmptyCompound) {
+  // Empty compound statement has no adjacent pairs
+  EXPECT_TRUE(notMatches("void f() { }",
+                         compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                         binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, DoesNotMatchSingleStatement) {
+  // Single statement has no adjacent pairs
+  EXPECT_TRUE(notMatches("void f() { 1+2; }",
+                         compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                        binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, MatchesDifferentStatementTypes) {
+  // Test with different statement types
+  EXPECT_TRUE(matches("void f() { for (;;); while (true); }",
+                      compoundStmt(hasAdjSubstatements(forStmt(), 
whileStmt()))));
+  
+  EXPECT_TRUE(matches("void f() { int x; return; }",
+                      compoundStmt(hasAdjSubstatements(declStmt(), 
returnStmt()))));
+}
+
+TEST(HasAdjSubstatements, WorksWithStmtExpr) {
+  // Test that it works with StmtExpr (polymorphic support)
+  EXPECT_TRUE(matches("void f() { int x = ({ {} 1+2; }); }",
+                      stmtExpr(hasAdjSubstatements(compoundStmt(),
+                                                   binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, DoesNotMatchWrongOrder) {
+  // The order matters - binaryOperator must come after compoundStmt
+  EXPECT_TRUE(notMatches("void f() { 1+2; {} }",
+                         compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                         binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, MatchesWithStatementsBetween) {
+  // Should still match even if there are other statements before/after
+  EXPECT_TRUE(matches("void f() { int x; {} 1+2; int y; }",
+                      compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                     binaryOperator()))));
+}
+
 TEST(Member, MatchesMemberAllocationFunction) {
   // Fails in C++11 mode
   EXPECT_TRUE(matchesConditionally(

>From 56bf3da670afb8d2ae99bbc0d0d9d82f2cc58975 Mon Sep 17 00:00:00 2001
From: denzor200 <[email protected]>
Date: Sat, 29 Nov 2025 00:28:56 +0300
Subject: [PATCH 2/6] make matcher variadic

---
 clang/include/clang/ASTMatchers/ASTMatchers.h |  54 +++-----
 .../clang/ASTMatchers/ASTMatchersInternal.h   |  27 ++++
 clang/lib/ASTMatchers/ASTMatchersInternal.cpp |  65 +++++++++
 .../ASTMatchers/ASTMatchersTraversalTest.cpp  | 128 ++++++++++++++++++
 4 files changed, 241 insertions(+), 33 deletions(-)

diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h 
b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 080fc47c59d94..03b369dccc11e 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -95,6 +95,7 @@
 #include <limits>
 #include <optional>
 #include <string>
+#include <tuple>
 #include <utility>
 #include <vector>
 
@@ -5910,8 +5911,9 @@ AST_POLYMORPHIC_MATCHER_P(hasAnySubstatement,
                                           Builder) != CS->body_end();
 }
 
-/// Matches compound statements that contain a PrevStmt immediately followed by
-/// NextStmt. Also matches StmtExprs that have CompoundStmt as children.
+/// Matches compound statements that contain adjacent substatements matching
+/// the provided sequence of matchers. Also matches StmtExprs that have
+/// CompoundStmt as children.
 ///
 /// Given
 /// \code
@@ -5923,37 +5925,23 @@ AST_POLYMORPHIC_MATCHER_P(hasAnySubstatement,
 ///   matching '{}'
 /// with binaryOperator()
 ///   matching '1+2'
-AST_POLYMORPHIC_MATCHER_P2(hasAdjSubstatements,
-                           AST_POLYMORPHIC_SUPPORTED_TYPES(CompoundStmt,
-                                                           StmtExpr),
-                           ast_matchers::internal::Matcher<Stmt>, PrevMatcher,
-                           ast_matchers::internal::Matcher<Stmt>, NextMatcher) 
{
-  const CompoundStmt *CS = CompoundStmtMatcher<NodeType>::get(Node);
-  if (!CS)
-    return false;
-
-  auto Begin = CS->body_begin();
-  auto End = CS->body_end();
-  
-  if (CS->size() < 2)
-    return false;
-
-  return std::adjacent_find(
-             Begin, End,
-             [&](const Stmt *PrevStmt, const Stmt *NextStmt) {
-               clang::ast_matchers::internal::BoundNodesTreeBuilder 
PrevBuilder;
-               if (!PrevMatcher.matches(*PrevStmt, Finder, &PrevBuilder))
-                 return false;
-
-               clang::ast_matchers::internal::BoundNodesTreeBuilder 
NextBuilder;
-               NextBuilder.addMatch(PrevBuilder);
-               if (!NextMatcher.matches(*NextStmt, Finder, &NextBuilder))
-                 return false;
-
-               Builder->addMatch(NextBuilder);
-               return true;
-             }) != End;
-}
+///
+/// Given
+/// \code
+///   { {}; 1+2; 3+4; }
+/// \endcode
+/// hasAdjSubstatements(compoundStmt(), binaryOperator(), binaryOperator())
+///   matches '{ {}; 1+2; 3+4; }'
+/// with the matchers matching the three consecutive statements in order.
+///
+///    hasAdjSubstatements(compoundStmt(), binaryOperator(), returnStmt())
+///  Is equivalent to matching a compound statement that contains
+///  a compound statement immediately followed by a binary operator
+///  immediately followed by a return statement.
+extern const internal::VariadicFunction<
+    internal::HasAdjSubstatementsMatcherType,
+    internal::Matcher<Stmt>, internal::hasAdjSubstatementsFunc>
+    hasAdjSubstatements;
 
 /// 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..4a8cfe381175c 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -2283,6 +2283,33 @@ using HasOpNameMatcher =
 
 HasOpNameMatcher hasAnyOperatorNameFunc(ArrayRef<const StringRef *> NameRefs);
 
+template <typename T, typename ArgT = std::vector<Matcher<Stmt>>>
+class HasAdjSubstatementsMatcher : 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 HasAdjSubstatementsMatcher(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 HasAdjSubstatementsMatcherType =
+    PolymorphicMatcher<HasAdjSubstatementsMatcher,
+                       void(TypeList<CompoundStmt, StmtExpr>),
+                       std::vector<Matcher<Stmt>>>;
+
+HasAdjSubstatementsMatcherType
+hasAdjSubstatementsFunc(ArrayRef<const Matcher<Stmt> *> MatcherRefs);
+
 using HasOverloadOpNameMatcher =
     PolymorphicMatcher<HasOverloadedOperatorNameMatcher,
                        void(TypeList<CXXOperatorCallExpr, FunctionDecl>),
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp 
b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 0874b3d0c45f5..8f5ec1c27181d 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -467,6 +467,67 @@ 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;
+}
+
+HasAdjSubstatementsMatcherType
+hasAdjSubstatementsFunc(ArrayRef<const Matcher<Stmt> *> MatcherRefs) {
+  return HasAdjSubstatementsMatcherType(vectorFromMatcherRefs(MatcherRefs));
+}
+
+template <typename T, typename ArgT>
+bool HasAdjSubstatementsMatcher<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;
+
+  auto Begin = CS->body_begin();
+  auto End = CS->body_end();
+  size_t NumMatchers = Matchers.size();
+
+  if (CS->size() < NumMatchers)
+    return false;
+
+  // Try to find a sequence of consecutive statements matching all matchers
+  for (auto It = Begin; It + NumMatchers <= End; ++It) {
+    BoundNodesTreeBuilder CurrentBuilder;
+    bool AllMatch = true;
+
+    for (size_t i = 0; i < NumMatchers; ++i) {
+      BoundNodesTreeBuilder StepBuilder;
+      StepBuilder.addMatch(CurrentBuilder);
+      if (!Matchers[i].matches(**(It + i), Finder, &StepBuilder)) {
+        AllMatch = false;
+        break;
+      }
+      CurrentBuilder = StepBuilder;
+    }
+
+    if (AllMatch) {
+      Builder->addMatch(CurrentBuilder);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+template bool HasAdjSubstatementsMatcher<CompoundStmt>::matches(
+    const CompoundStmt &, ASTMatchFinder *, BoundNodesTreeBuilder *) const;
+template bool HasAdjSubstatementsMatcher<StmtExpr>::matches(
+    const StmtExpr &, ASTMatchFinder *, BoundNodesTreeBuilder *) const;
+
 HasNameMatcher::HasNameMatcher(std::vector<std::string> N)
     : UseUnqualifiedMatch(
           llvm::all_of(N, [](StringRef Name) { return !Name.contains("::"); 
})),
@@ -1046,6 +1107,10 @@ const 
internal::VariadicFunction<internal::Matcher<NamedDecl>, StringRef,
 const internal::VariadicFunction<internal::HasOpNameMatcher, StringRef,
                                  internal::hasAnyOperatorNameFunc>
     hasAnyOperatorName = {};
+const internal::VariadicFunction<internal::HasAdjSubstatementsMatcherType,
+                                 internal::Matcher<Stmt>,
+                                 internal::hasAdjSubstatementsFunc>
+    hasAdjSubstatements = {};
 const internal::VariadicFunction<internal::HasOverloadOpNameMatcher, StringRef,
                                  internal::hasAnyOverloadedOperatorNameFunc>
     hasAnyOverloadedOperatorName = {};
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp 
b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index d1d468dcf3116..1c86b16037d0f 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -2471,6 +2471,134 @@ TEST(HasAdjSubstatements, MatchesWithStatementsBetween) 
{
                                                      binaryOperator()))));
 }
 
+TEST(HasAdjSubstatements, VariadicMatchesThreeAdjacentSubstatements) {
+  // Test variadic version with 3 matchers
+  EXPECT_TRUE(matches("void f() { {} 1+2; 3+4; }",
+                      compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                       binaryOperator(),
+                                                       binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, VariadicMatchesFourAdjacentSubstatements) {
+  // Test variadic version with 4 matchers
+  EXPECT_TRUE(matches("void f() { int x; return; {} 1+2; }",
+                      compoundStmt(hasAdjSubstatements(declStmt(),
+                                                       returnStmt(),
+                                                       compoundStmt(),
+                                                       binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, VariadicMatchesFiveAdjacentSubstatements) {
+  // Test variadic version with 5 matchers
+  EXPECT_TRUE(matches("void f() { for (;;); while (true); if (true) {} return; 
1+2; }",
+                      compoundStmt(hasAdjSubstatements(forStmt(),
+                                                       whileStmt(),
+                                                       ifStmt(),
+                                                       returnStmt(),
+                                                       binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, VariadicDoesNotMatchNonAdjacentSequence) {
+  // Three matchers but statements are not all adjacent
+  EXPECT_TRUE(notMatches("void f() { {} 1; 1+2; 3+4; }",
+                         compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                         binaryOperator(),
+                                                         binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, VariadicDoesNotMatchPartialSequence) {
+  // First two match but third doesn't
+  EXPECT_TRUE(notMatches("void f() { {} 1+2; return; }",
+                         compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                         binaryOperator(),
+                                                         binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, VariadicMatchesInNestedCompound) {
+  // Test variadic version in nested compound statements
+  EXPECT_TRUE(matches("void f() { if (true) { {} 1+2; 3+4; } }",
+                      compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                      binaryOperator(),
+                                                      binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, VariadicMatchesWithDifferentTypes) {
+  // Test variadic version with different statement types
+  EXPECT_TRUE(matches("void f() { for (;;); while (true); if (true) {} }",
+                      compoundStmt(hasAdjSubstatements(forStmt(),
+                                                       whileStmt(),
+                                                       ifStmt()))));
+}
+
+TEST(HasAdjSubstatements, VariadicDoesNotMatchWrongOrder) {
+  // Order matters in variadic version
+  EXPECT_TRUE(notMatches("void f() { 1+2; {} 3+4; }",
+                         compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                          binaryOperator(),
+                                                          binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, VariadicMatchesFirstSequence) {
+  // When multiple sequences exist, should match the first one
+  EXPECT_TRUE(matches("void f() { {} 1+2; 3+4; {} 5+6; 7+8; }",
+                      compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                      binaryOperator(),
+                                                      binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, VariadicWorksWithStmtExpr) {
+  // Test variadic version with StmtExpr
+  EXPECT_TRUE(matches("void f() { int x = ({ {} 1+2; 3+4; }); }",
+                      stmtExpr(hasAdjSubstatements(compoundStmt(),
+                                                   binaryOperator(),
+                                                   binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, VariadicRequiresMinimumStatements) {
+  // Need at least as many statements as matchers
+  EXPECT_TRUE(notMatches("void f() { {} 1+2; }",
+                         compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                          binaryOperator(),
+                                                          binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, VariadicMatchesWithStatementsBetween) {
+  // Should still match even if there are other statements before/after
+  EXPECT_TRUE(matches("void f() { int x; {} 1+2; 3+4; int y; }",
+                      compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                       binaryOperator(),
+                                                       binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, VariadicMatchesComplexSequence) {
+  // Test with a complex sequence of different statement types
+  EXPECT_TRUE(matches("void f() { int a; int b; return; {} 1+2; }",
+                      compoundStmt(hasAdjSubstatements(declStmt(),
+                                                       declStmt(),
+                                                       returnStmt(),
+                                                       compoundStmt(),
+                                                       binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, VariadicDoesNotMatchGapInSequence) {
+  // Sequence has a gap in the middle
+  EXPECT_TRUE(notMatches("void f() { {} 1+2; int x; 3+4; }",
+                         compoundStmt(hasAdjSubstatements(compoundStmt(),
+                                                         binaryOperator(),
+                                                         binaryOperator()))));
+}
+
+TEST(HasAdjSubstatements, VariadicMatchesLongSequence) {
+  // Test with a longer sequence (6 statements)
+  EXPECT_TRUE(matches("void f() { int a; int b; int c; return; {} 1+2; }",
+                      compoundStmt(hasAdjSubstatements(declStmt(),
+                                                       declStmt(),
+                                                       declStmt(),
+                                                       returnStmt(),
+                                                       compoundStmt(),
+                                                       binaryOperator()))));
+}
+
 TEST(Member, MatchesMemberAllocationFunction) {
   // Fails in C++11 mode
   EXPECT_TRUE(matchesConditionally(

>From 4493ad80b429e0d9e2e43286a84cf809274d29c5 Mon Sep 17 00:00:00 2001
From: denzor200 <[email protected]>
Date: Sat, 29 Nov 2025 02:07:11 +0300
Subject: [PATCH 3/6] refactor - step 1

---
 clang/include/clang/ASTMatchers/ASTMatchers.h |  8 -----
 .../clang/ASTMatchers/ASTMatchersInternal.h   |  4 +++
 clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 30 ++++++++-----------
 3 files changed, 17 insertions(+), 25 deletions(-)

diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h 
b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 03b369dccc11e..87d6bd7e1b9a3 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -5926,14 +5926,6 @@ AST_POLYMORPHIC_MATCHER_P(hasAnySubstatement,
 /// with binaryOperator()
 ///   matching '1+2'
 ///
-/// Given
-/// \code
-///   { {}; 1+2; 3+4; }
-/// \endcode
-/// hasAdjSubstatements(compoundStmt(), binaryOperator(), binaryOperator())
-///   matches '{ {}; 1+2; 3+4; }'
-/// with the matchers matching the three consecutive statements in order.
-///
 ///    hasAdjSubstatements(compoundStmt(), binaryOperator(), returnStmt())
 ///  Is equivalent to matching a compound statement that contains
 ///  a compound statement immediately followed by a binary operator
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h 
b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
index 4a8cfe381175c..5fb63af28dc1b 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -2283,6 +2283,10 @@ using HasOpNameMatcher =
 
 HasOpNameMatcher hasAnyOperatorNameFunc(ArrayRef<const StringRef *> NameRefs);
 
+/// Matches nodes of type T (CompoundStmt or StmtExpr) that contain a sequence
+/// of consecutive substatements matching the provided matchers in order.
+///
+/// See \c hasAdjSubstatements() in ASTMatchers.h for details.
 template <typename T, typename ArgT = std::vector<Matcher<Stmt>>>
 class HasAdjSubstatementsMatcher : public MatcherInterface<T> {
   static_assert(std::is_same<T, CompoundStmt>::value ||
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp 
b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 8f5ec1c27181d..48f3ed8e6318d 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -439,9 +439,14 @@ optionallyVariadicOperator(const DynTypedNode &DynNode, 
ASTMatchFinder *Finder,
   return true;
 }
 
-inline static
-std::vector<std::string> vectorFromRefs(ArrayRef<const StringRef *> NameRefs) {
-  std::vector<std::string> Names;
+template<typename T, typename T1>
+using replace_void_t = typename std::conditional<
+    std::is_void_v<T>, T1, T
+>::type;
+
+template<typename To=void, typename From>
+static auto convertRefsToVector(ArrayRef<const From *> NameRefs) {
+  std::vector<replace_void_t<To, From>> Names;
   Names.reserve(NameRefs.size());
   for (auto *Name : NameRefs)
     Names.emplace_back(*Name);
@@ -450,35 +455,26 @@ std::vector<std::string> vectorFromRefs(ArrayRef<const 
StringRef *> NameRefs) {
 
 Matcher<NamedDecl> hasAnyNameFunc(ArrayRef<const StringRef *> NameRefs) {
   return internal::Matcher<NamedDecl>(
-      new internal::HasNameMatcher(vectorFromRefs(NameRefs)));
+      new 
internal::HasNameMatcher(convertRefsToVector<std::string>(NameRefs)));
 }
 
 Matcher<ObjCMessageExpr> hasAnySelectorFunc(
     ArrayRef<const StringRef *> NameRefs) {
-  return hasAnySelectorMatcher(vectorFromRefs(NameRefs));
+  return hasAnySelectorMatcher(convertRefsToVector<std::string>(NameRefs));
 }
 
 HasOpNameMatcher hasAnyOperatorNameFunc(ArrayRef<const StringRef *> NameRefs) {
-  return HasOpNameMatcher(vectorFromRefs(NameRefs));
+  return HasOpNameMatcher(convertRefsToVector<std::string>(NameRefs));
 }
 
 HasOverloadOpNameMatcher
 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;
+  return HasOverloadOpNameMatcher(convertRefsToVector<std::string>(NameRefs));
 }
 
 HasAdjSubstatementsMatcherType
 hasAdjSubstatementsFunc(ArrayRef<const Matcher<Stmt> *> MatcherRefs) {
-  return HasAdjSubstatementsMatcherType(vectorFromMatcherRefs(MatcherRefs));
+  return HasAdjSubstatementsMatcherType(convertRefsToVector(MatcherRefs));
 }
 
 template <typename T, typename ArgT>

>From 73edaf80e49aee5d6614bea9380bc1188963658e Mon Sep 17 00:00:00 2001
From: denzor200 <[email protected]>
Date: Sat, 29 Nov 2025 02:35:46 +0300
Subject: [PATCH 4/6] refactor - step 2

---
 clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 78 +++++++++++--------
 1 file changed, 46 insertions(+), 32 deletions(-)

diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp 
b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 48f3ed8e6318d..281b0e8a2a3d6 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -31,6 +31,7 @@
 #include "llvm/Support/Regex.h"
 #include "llvm/Support/WithColor.h"
 #include "llvm/Support/raw_ostream.h"
+#include <algorithm>
 #include <cassert>
 #include <cstddef>
 #include <optional>
@@ -439,14 +440,9 @@ optionallyVariadicOperator(const DynTypedNode &DynNode, 
ASTMatchFinder *Finder,
   return true;
 }
 
-template<typename T, typename T1>
-using replace_void_t = typename std::conditional<
-    std::is_void_v<T>, T1, T
->::type;
-
-template<typename To=void, typename From>
-static auto convertRefsToVector(ArrayRef<const From *> NameRefs) {
-  std::vector<replace_void_t<To, From>> Names;
+inline static
+std::vector<std::string> vectorFromRefs(ArrayRef<const StringRef *> NameRefs) {
+  std::vector<std::string> Names;
   Names.reserve(NameRefs.size());
   for (auto *Name : NameRefs)
     Names.emplace_back(*Name);
@@ -455,26 +451,35 @@ static auto convertRefsToVector(ArrayRef<const From *> 
NameRefs) {
 
 Matcher<NamedDecl> hasAnyNameFunc(ArrayRef<const StringRef *> NameRefs) {
   return internal::Matcher<NamedDecl>(
-      new 
internal::HasNameMatcher(convertRefsToVector<std::string>(NameRefs)));
+      new internal::HasNameMatcher(vectorFromRefs(NameRefs)));
 }
 
 Matcher<ObjCMessageExpr> hasAnySelectorFunc(
     ArrayRef<const StringRef *> NameRefs) {
-  return hasAnySelectorMatcher(convertRefsToVector<std::string>(NameRefs));
+  return hasAnySelectorMatcher(vectorFromRefs(NameRefs));
 }
 
 HasOpNameMatcher hasAnyOperatorNameFunc(ArrayRef<const StringRef *> NameRefs) {
-  return HasOpNameMatcher(convertRefsToVector<std::string>(NameRefs));
+  return HasOpNameMatcher(vectorFromRefs(NameRefs));
 }
 
 HasOverloadOpNameMatcher
 hasAnyOverloadedOperatorNameFunc(ArrayRef<const StringRef *> NameRefs) {
-  return HasOverloadOpNameMatcher(convertRefsToVector<std::string>(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;
 }
 
 HasAdjSubstatementsMatcherType
 hasAdjSubstatementsFunc(ArrayRef<const Matcher<Stmt> *> MatcherRefs) {
-  return HasAdjSubstatementsMatcherType(convertRefsToVector(MatcherRefs));
+  return HasAdjSubstatementsMatcherType(vectorFromMatcherRefs(MatcherRefs));
 }
 
 template <typename T, typename ArgT>
@@ -495,28 +500,37 @@ bool HasAdjSubstatementsMatcher<T, ArgT>::matches(
   if (CS->size() < NumMatchers)
     return false;
 
-  // Try to find a sequence of consecutive statements matching all matchers
-  for (auto It = Begin; It + NumMatchers <= End; ++It) {
-    BoundNodesTreeBuilder CurrentBuilder;
-    bool AllMatch = true;
-
-    for (size_t i = 0; i < NumMatchers; ++i) {
-      BoundNodesTreeBuilder StepBuilder;
-      StepBuilder.addMatch(CurrentBuilder);
-      if (!Matchers[i].matches(**(It + i), Finder, &StepBuilder)) {
-        AllMatch = false;
-        break;
-      }
-      CurrentBuilder = StepBuilder;
-    }
+  // Use std::search with lambda predicate that matches statements against
+  // matchers and accumulates BoundNodesTreeBuilder state
+  BoundNodesTreeBuilder CurrentBuilder;
+  size_t ChainLength = 0;
 
-    if (AllMatch) {
-      Builder->addMatch(CurrentBuilder);
-      return true;
+  auto Pred = [&](
+                  Stmt *const &StmtPtr, const Matcher<Stmt> &Matcher) mutable {
+    if (ChainLength >= Matchers.size())
+      return false;
+
+    BoundNodesTreeBuilder StepBuilder;
+    StepBuilder.addMatch(CurrentBuilder);
+    if (!Matcher.matches(*StmtPtr, Finder, &StepBuilder)) {
+      // Reset on mismatch
+      CurrentBuilder = BoundNodesTreeBuilder();
+      ChainLength = 0;
+      return false;
     }
-  }
+    // Advance chain
+    CurrentBuilder = StepBuilder;
+    ++ChainLength;
+    return true;
+  };
 
-  return false;
+  auto Found = std::search(Begin, End, Matchers.begin(), Matchers.end(), Pred);
+
+  if (Found == End || ChainLength != NumMatchers)
+    return false;
+
+  Builder->addMatch(CurrentBuilder);
+  return true;
 }
 
 template bool HasAdjSubstatementsMatcher<CompoundStmt>::matches(

>From f6235e02f9437edd42aa5cd9f7a919f1a9529808 Mon Sep 17 00:00:00 2001
From: denzor200 <[email protected]>
Date: Sat, 29 Nov 2025 02:36:02 +0300
Subject: [PATCH 5/6] refactor - step 3

---
 clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 50 ++++++-------------
 llvm/include/llvm/ADT/STLExtras.h             |  5 ++
 2 files changed, 21 insertions(+), 34 deletions(-)

diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp 
b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
index 281b0e8a2a3d6..14ff5d919eae2 100644
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -490,43 +490,25 @@ bool HasAdjSubstatementsMatcher<T, ArgT>::matches(
   if (!CS)
     return false;
 
-  if (Matchers.empty())
-    return false;
-
-  auto Begin = CS->body_begin();
-  auto End = CS->body_end();
-  size_t NumMatchers = Matchers.size();
-
-  if (CS->size() < NumMatchers)
-    return false;
-
-  // Use std::search with lambda predicate that matches statements against
+  // Use llvm::search with lambda predicate that matches statements against
   // matchers and accumulates BoundNodesTreeBuilder state
   BoundNodesTreeBuilder CurrentBuilder;
-  size_t ChainLength = 0;
-
-  auto Pred = [&](
-                  Stmt *const &StmtPtr, const Matcher<Stmt> &Matcher) mutable {
-    if (ChainLength >= Matchers.size())
-      return false;
-
-    BoundNodesTreeBuilder StepBuilder;
-    StepBuilder.addMatch(CurrentBuilder);
-    if (!Matcher.matches(*StmtPtr, Finder, &StepBuilder)) {
-      // Reset on mismatch
-      CurrentBuilder = BoundNodesTreeBuilder();
-      ChainLength = 0;
-      return false;
-    }
-    // Advance chain
-    CurrentBuilder = StepBuilder;
-    ++ChainLength;
-    return true;
-  };
-
-  auto Found = std::search(Begin, End, Matchers.begin(), Matchers.end(), Pred);
+  const auto Found = llvm::search(
+      CS->body(), Matchers,
+      [&](const Stmt *StmtPtr, const Matcher<Stmt> &Matcher) mutable {
+        BoundNodesTreeBuilder StepBuilder;
+        StepBuilder.addMatch(CurrentBuilder);
+        if (!Matcher.matches(*StmtPtr, Finder, &StepBuilder)) {
+          // reset the state
+          CurrentBuilder = {};
+          return false;
+        }
+        // Invalidate the state
+        CurrentBuilder = StepBuilder;
+        return true;
+      });
 
-  if (Found == End || ChainLength != NumMatchers)
+  if (Found == CS->body_end())
     return false;
 
   Builder->addMatch(CurrentBuilder);
diff --git a/llvm/include/llvm/ADT/STLExtras.h 
b/llvm/include/llvm/ADT/STLExtras.h
index af0e4a36be1b1..9fc8095389860 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -1778,6 +1778,11 @@ OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate 
P) {
   return std::copy_if(adl_begin(Range), adl_end(Range), Out, P);
 }
 
+template <typename R1, typename R2, typename BinaryPredicate>
+auto search(R1 &&Range1, R2 &&Range2, BinaryPredicate P) {
+  return std::search(adl_begin(Range1), adl_end(Range1), adl_begin(Range2), 
adl_end(Range2), P);
+}
+
 /// Return the single value in \p Range that satisfies
 /// \p P(<member of \p Range> *, AllowRepeats)->T * returning nullptr
 /// when no values or multiple values were found.

>From ef4fd5653e59f884c7ae32b5a6ba5e253ab2a914 Mon Sep 17 00:00:00 2001
From: denzor200 <[email protected]>
Date: Sat, 29 Nov 2025 02:55:53 +0300
Subject: [PATCH 6/6] format

---
 clang/include/clang/ASTMatchers/ASTMatchers.h |   4 +-
 .../ASTMatchers/ASTMatchersTraversalTest.cpp  | 191 +++++++++---------
 llvm/include/llvm/ADT/STLExtras.h             |   3 +-
 3 files changed, 96 insertions(+), 102 deletions(-)

diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h 
b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 87d6bd7e1b9a3..3e874b37c05c1 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -5931,8 +5931,8 @@ AST_POLYMORPHIC_MATCHER_P(hasAnySubstatement,
 ///  a compound statement immediately followed by a binary operator
 ///  immediately followed by a return statement.
 extern const internal::VariadicFunction<
-    internal::HasAdjSubstatementsMatcherType,
-    internal::Matcher<Stmt>, internal::hasAdjSubstatementsFunc>
+    internal::HasAdjSubstatementsMatcherType, internal::Matcher<Stmt>,
+    internal::hasAdjSubstatementsFunc>
     hasAdjSubstatements;
 
 /// Checks that a compound statement contains a specific number of
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp 
b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index 1c86b16037d0f..f113f2a114757 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -2401,202 +2401,195 @@ TEST(HasAnySubstatement, 
FindsSubstatementBetweenOthers) {
 
 TEST(HasAdjSubstatements, MatchesAdjacentSubstatements) {
   // Basic case: compound statement followed by binary operator
-  EXPECT_TRUE(matches("void f() { {} 1+2; }",
-                      compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                        binaryOperator()))));
+  EXPECT_TRUE(matches(
+      "void f() { {} 1+2; }",
+      compoundStmt(hasAdjSubstatements(compoundStmt(), binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, DoesNotMatchNonAdjacentSubstatements) {
   // Statements exist but not adjacent
-  EXPECT_TRUE(notMatches("void f() { {} 1; 1+2; }",
-                         compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                          binaryOperator()))));
+  EXPECT_TRUE(notMatches(
+      "void f() { {} 1; 1+2; }",
+      compoundStmt(hasAdjSubstatements(compoundStmt(), binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, MatchesInNestedCompoundStatements) {
   // Should match in nested compound statements
-  EXPECT_TRUE(matches("void f() { if (true) { {} 1+2; } }",
-                      compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                      binaryOperator()))));
+  EXPECT_TRUE(matches(
+      "void f() { if (true) { {} 1+2; } }",
+      compoundStmt(hasAdjSubstatements(compoundStmt(), binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, MatchesFirstAdjacentPair) {
   // When multiple adjacent pairs exist, should match the first one
-  EXPECT_TRUE(matches("void f() { {} 1+2; {} 3+4; }",
-                      compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                      binaryOperator()))));
+  EXPECT_TRUE(matches(
+      "void f() { {} 1+2; {} 3+4; }",
+      compoundStmt(hasAdjSubstatements(compoundStmt(), binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, DoesNotMatchEmptyCompound) {
   // Empty compound statement has no adjacent pairs
-  EXPECT_TRUE(notMatches("void f() { }",
-                         compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                         binaryOperator()))));
+  EXPECT_TRUE(notMatches(
+      "void f() { }",
+      compoundStmt(hasAdjSubstatements(compoundStmt(), binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, DoesNotMatchSingleStatement) {
   // Single statement has no adjacent pairs
-  EXPECT_TRUE(notMatches("void f() { 1+2; }",
-                         compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                        binaryOperator()))));
+  EXPECT_TRUE(notMatches(
+      "void f() { 1+2; }",
+      compoundStmt(hasAdjSubstatements(compoundStmt(), binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, MatchesDifferentStatementTypes) {
   // Test with different statement types
-  EXPECT_TRUE(matches("void f() { for (;;); while (true); }",
-                      compoundStmt(hasAdjSubstatements(forStmt(), 
whileStmt()))));
-  
-  EXPECT_TRUE(matches("void f() { int x; return; }",
-                      compoundStmt(hasAdjSubstatements(declStmt(), 
returnStmt()))));
+  EXPECT_TRUE(
+      matches("void f() { for (;;); while (true); }",
+              compoundStmt(hasAdjSubstatements(forStmt(), whileStmt()))));
+
+  EXPECT_TRUE(
+      matches("void f() { int x; return; }",
+              compoundStmt(hasAdjSubstatements(declStmt(), returnStmt()))));
 }
 
 TEST(HasAdjSubstatements, WorksWithStmtExpr) {
   // Test that it works with StmtExpr (polymorphic support)
-  EXPECT_TRUE(matches("void f() { int x = ({ {} 1+2; }); }",
-                      stmtExpr(hasAdjSubstatements(compoundStmt(),
-                                                   binaryOperator()))));
+  EXPECT_TRUE(
+      matches("void f() { int x = ({ {} 1+2; }); }",
+              stmtExpr(hasAdjSubstatements(compoundStmt(), 
binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, DoesNotMatchWrongOrder) {
   // The order matters - binaryOperator must come after compoundStmt
-  EXPECT_TRUE(notMatches("void f() { 1+2; {} }",
-                         compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                         binaryOperator()))));
+  EXPECT_TRUE(notMatches(
+      "void f() { 1+2; {} }",
+      compoundStmt(hasAdjSubstatements(compoundStmt(), binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, MatchesWithStatementsBetween) {
   // Should still match even if there are other statements before/after
-  EXPECT_TRUE(matches("void f() { int x; {} 1+2; int y; }",
-                      compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                     binaryOperator()))));
+  EXPECT_TRUE(matches(
+      "void f() { int x; {} 1+2; int y; }",
+      compoundStmt(hasAdjSubstatements(compoundStmt(), binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, VariadicMatchesThreeAdjacentSubstatements) {
   // Test variadic version with 3 matchers
-  EXPECT_TRUE(matches("void f() { {} 1+2; 3+4; }",
-                      compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                       binaryOperator(),
-                                                       binaryOperator()))));
+  EXPECT_TRUE(
+      matches("void f() { {} 1+2; 3+4; }",
+              compoundStmt(hasAdjSubstatements(compoundStmt(), 
binaryOperator(),
+                                               binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, VariadicMatchesFourAdjacentSubstatements) {
   // Test variadic version with 4 matchers
-  EXPECT_TRUE(matches("void f() { int x; return; {} 1+2; }",
-                      compoundStmt(hasAdjSubstatements(declStmt(),
-                                                       returnStmt(),
-                                                       compoundStmt(),
-                                                       binaryOperator()))));
+  EXPECT_TRUE(matches(
+      "void f() { int x; return; {} 1+2; }",
+      compoundStmt(hasAdjSubstatements(declStmt(), returnStmt(), 
compoundStmt(),
+                                       binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, VariadicMatchesFiveAdjacentSubstatements) {
   // Test variadic version with 5 matchers
-  EXPECT_TRUE(matches("void f() { for (;;); while (true); if (true) {} return; 
1+2; }",
-                      compoundStmt(hasAdjSubstatements(forStmt(),
-                                                       whileStmt(),
-                                                       ifStmt(),
-                                                       returnStmt(),
-                                                       binaryOperator()))));
+  EXPECT_TRUE(matches(
+      "void f() { for (;;); while (true); if (true) {} return; 1+2; }",
+      compoundStmt(hasAdjSubstatements(forStmt(), whileStmt(), ifStmt(),
+                                       returnStmt(), binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, VariadicDoesNotMatchNonAdjacentSequence) {
   // Three matchers but statements are not all adjacent
-  EXPECT_TRUE(notMatches("void f() { {} 1; 1+2; 3+4; }",
-                         compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                         binaryOperator(),
-                                                         binaryOperator()))));
+  EXPECT_TRUE(
+      notMatches("void f() { {} 1; 1+2; 3+4; }",
+                 compoundStmt(hasAdjSubstatements(
+                     compoundStmt(), binaryOperator(), binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, VariadicDoesNotMatchPartialSequence) {
   // First two match but third doesn't
-  EXPECT_TRUE(notMatches("void f() { {} 1+2; return; }",
-                         compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                         binaryOperator(),
-                                                         binaryOperator()))));
+  EXPECT_TRUE(
+      notMatches("void f() { {} 1+2; return; }",
+                 compoundStmt(hasAdjSubstatements(
+                     compoundStmt(), binaryOperator(), binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, VariadicMatchesInNestedCompound) {
   // Test variadic version in nested compound statements
-  EXPECT_TRUE(matches("void f() { if (true) { {} 1+2; 3+4; } }",
-                      compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                      binaryOperator(),
-                                                      binaryOperator()))));
+  EXPECT_TRUE(
+      matches("void f() { if (true) { {} 1+2; 3+4; } }",
+              compoundStmt(hasAdjSubstatements(compoundStmt(), 
binaryOperator(),
+                                               binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, VariadicMatchesWithDifferentTypes) {
   // Test variadic version with different statement types
-  EXPECT_TRUE(matches("void f() { for (;;); while (true); if (true) {} }",
-                      compoundStmt(hasAdjSubstatements(forStmt(),
-                                                       whileStmt(),
-                                                       ifStmt()))));
+  EXPECT_TRUE(matches(
+      "void f() { for (;;); while (true); if (true) {} }",
+      compoundStmt(hasAdjSubstatements(forStmt(), whileStmt(), ifStmt()))));
 }
 
 TEST(HasAdjSubstatements, VariadicDoesNotMatchWrongOrder) {
   // Order matters in variadic version
-  EXPECT_TRUE(notMatches("void f() { 1+2; {} 3+4; }",
-                         compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                          binaryOperator(),
-                                                          binaryOperator()))));
+  EXPECT_TRUE(
+      notMatches("void f() { 1+2; {} 3+4; }",
+                 compoundStmt(hasAdjSubstatements(
+                     compoundStmt(), binaryOperator(), binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, VariadicMatchesFirstSequence) {
   // When multiple sequences exist, should match the first one
-  EXPECT_TRUE(matches("void f() { {} 1+2; 3+4; {} 5+6; 7+8; }",
-                      compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                      binaryOperator(),
-                                                      binaryOperator()))));
+  EXPECT_TRUE(
+      matches("void f() { {} 1+2; 3+4; {} 5+6; 7+8; }",
+              compoundStmt(hasAdjSubstatements(compoundStmt(), 
binaryOperator(),
+                                               binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, VariadicWorksWithStmtExpr) {
   // Test variadic version with StmtExpr
-  EXPECT_TRUE(matches("void f() { int x = ({ {} 1+2; 3+4; }); }",
-                      stmtExpr(hasAdjSubstatements(compoundStmt(),
-                                                   binaryOperator(),
-                                                   binaryOperator()))));
+  EXPECT_TRUE(
+      matches("void f() { int x = ({ {} 1+2; 3+4; }); }",
+              stmtExpr(hasAdjSubstatements(compoundStmt(), binaryOperator(),
+                                           binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, VariadicRequiresMinimumStatements) {
   // Need at least as many statements as matchers
-  EXPECT_TRUE(notMatches("void f() { {} 1+2; }",
-                         compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                          binaryOperator(),
-                                                          binaryOperator()))));
+  EXPECT_TRUE(
+      notMatches("void f() { {} 1+2; }",
+                 compoundStmt(hasAdjSubstatements(
+                     compoundStmt(), binaryOperator(), binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, VariadicMatchesWithStatementsBetween) {
   // Should still match even if there are other statements before/after
-  EXPECT_TRUE(matches("void f() { int x; {} 1+2; 3+4; int y; }",
-                      compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                       binaryOperator(),
-                                                       binaryOperator()))));
+  EXPECT_TRUE(
+      matches("void f() { int x; {} 1+2; 3+4; int y; }",
+              compoundStmt(hasAdjSubstatements(compoundStmt(), 
binaryOperator(),
+                                               binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, VariadicMatchesComplexSequence) {
   // Test with a complex sequence of different statement types
-  EXPECT_TRUE(matches("void f() { int a; int b; return; {} 1+2; }",
-                      compoundStmt(hasAdjSubstatements(declStmt(),
-                                                       declStmt(),
-                                                       returnStmt(),
-                                                       compoundStmt(),
-                                                       binaryOperator()))));
+  EXPECT_TRUE(matches(
+      "void f() { int a; int b; return; {} 1+2; }",
+      compoundStmt(hasAdjSubstatements(declStmt(), declStmt(), returnStmt(),
+                                       compoundStmt(), binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, VariadicDoesNotMatchGapInSequence) {
   // Sequence has a gap in the middle
-  EXPECT_TRUE(notMatches("void f() { {} 1+2; int x; 3+4; }",
-                         compoundStmt(hasAdjSubstatements(compoundStmt(),
-                                                         binaryOperator(),
-                                                         binaryOperator()))));
+  EXPECT_TRUE(
+      notMatches("void f() { {} 1+2; int x; 3+4; }",
+                 compoundStmt(hasAdjSubstatements(
+                     compoundStmt(), binaryOperator(), binaryOperator()))));
 }
 
 TEST(HasAdjSubstatements, VariadicMatchesLongSequence) {
   // Test with a longer sequence (6 statements)
   EXPECT_TRUE(matches("void f() { int a; int b; int c; return; {} 1+2; }",
-                      compoundStmt(hasAdjSubstatements(declStmt(),
-                                                       declStmt(),
-                                                       declStmt(),
-                                                       returnStmt(),
-                                                       compoundStmt(),
-                                                       binaryOperator()))));
+                      compoundStmt(hasAdjSubstatements(
+                          declStmt(), declStmt(), declStmt(), returnStmt(),
+                          compoundStmt(), binaryOperator()))));
 }
 
 TEST(Member, MatchesMemberAllocationFunction) {
diff --git a/llvm/include/llvm/ADT/STLExtras.h 
b/llvm/include/llvm/ADT/STLExtras.h
index 9fc8095389860..f75830ecc53a8 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -1780,7 +1780,8 @@ OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate 
P) {
 
 template <typename R1, typename R2, typename BinaryPredicate>
 auto search(R1 &&Range1, R2 &&Range2, BinaryPredicate P) {
-  return std::search(adl_begin(Range1), adl_end(Range1), adl_begin(Range2), 
adl_end(Range2), P);
+  return std::search(adl_begin(Range1), adl_end(Range1), adl_begin(Range2),
+                     adl_end(Range2), P);
 }
 
 /// Return the single value in \p Range that satisfies

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

Reply via email to