================
@@ -0,0 +1,409 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseStructuredBindingCheck.h"
+#include "../utils/DeclRefExprUtils.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+static constexpr llvm::StringLiteral PairDeclName = "PairVarD";
+static constexpr llvm::StringLiteral PairVarTypeName = "PairVarType";
+static constexpr llvm::StringLiteral FirstVarDeclName = "FirstVarDecl";
+static constexpr llvm::StringLiteral SecondVarDeclName = "SecondVarDecl";
+static constexpr llvm::StringLiteral BeginDeclStmtName = "BeginDeclStmt";
+static constexpr llvm::StringLiteral EndDeclStmtName = "EndDeclStmt";
+static constexpr llvm::StringLiteral FirstTypeName = "FirstType";
+static constexpr llvm::StringLiteral SecondTypeName = "SecondType";
+static constexpr llvm::StringLiteral ScopeBlockName = "ScopeBlock";
+static constexpr llvm::StringLiteral StdTieAssignStmtName = "StdTieAssign";
+static constexpr llvm::StringLiteral StdTieExprName = "StdTieExpr";
+static constexpr llvm::StringLiteral ForRangeStmtName = "ForRangeStmt";
+static constexpr llvm::StringLiteral InitExprName = "init_expr";
+
+/// Matches a sequence of VarDecls matching the inner matchers, starting from
+/// the \p Iter to \p EndIter and set bindings for the first DeclStmt and the
+/// last DeclStmt if matched.
+///
+/// \p Backwards indicates whether to match the VarDecls in reverse order.
+template <typename Iterator>
+static bool matchNVarDeclStartingWith(
+    Iterator Iter, Iterator EndIter,
+    ArrayRef<ast_matchers::internal::Matcher<VarDecl>> InnerMatchers,
+    ast_matchers::internal::ASTMatchFinder *Finder,
+    ast_matchers::internal::BoundNodesTreeBuilder *Builder,
+    bool Backwards = false) {
+  const DeclStmt *BeginDS = nullptr;
+  const DeclStmt *EndDS = nullptr;
+  size_t N = InnerMatchers.size();
+  size_t Count = 0;
+  for (; Iter != EndIter; ++Iter) {
+    EndDS = dyn_cast<DeclStmt>(*Iter);
+    if (!EndDS)
+      break;
+
+    if (!BeginDS)
+      BeginDS = EndDS;
+
+    auto Matches = [&](const Decl *VD) {
+      // We don't want redundant decls in DeclStmt.
+      if (Count == N)
+        return false;
+
+      if (const auto *Var = dyn_cast<VarDecl>(VD);
+          Var && InnerMatchers[Backwards ? N - Count - 1 : Count].matches(
+                     *Var, Finder, Builder)) {
+        ++Count;
+        return true;
+      }
+
+      return false;
+    };
+
+    if (Backwards) {
+      for (const auto *VD : llvm::reverse(EndDS->decls())) {
+        if (!Matches(VD))
+          return false;
+      }
+    } else {
+      for (const auto *VD : EndDS->decls()) {
+        if (!Matches(VD))
+          return false;
+      }
+    }
+
+    // All the matchers is satisfied in those DeclStmts.
+    if (Count == N) {
+      Builder->setBinding(
+          BeginDeclStmtName,
+          clang::DynTypedNode::create(Backwards ? *EndDS : *BeginDS));
+      Builder->setBinding(EndDeclStmtName, clang::DynTypedNode::create(
+                                               Backwards ? *BeginDS : *EndDS));
+      return true;
+    }
+  }
+
+  return false;
+}
+
+namespace {
+/// What qualifiers and specifiers are used to create structured binding
+/// declaration, it only supports the following four cases now.
+enum TransferType : uint8_t {
+  TT_ByVal,
+  TT_ByConstVal,
+  TT_ByRef,
+  TT_ByConstRef
+};
+
+/// Matches a Stmt whose parent is a CompoundStmt, and which is directly
+/// following two VarDecls matching the inner matcher.
+AST_MATCHER_P(Stmt, hasPreTwoVarDecl,
----------------
vbvictor wrote:

We generally check for `CompoundStmt` 2 times: one in this matcher, other in 
`registerMatchers` with `compoundStmt`. I think we can restructure this a bit 
to check of `CompoundStmt` only one time:

First make `Finder->addMatcher(compoundStmt(declStmt(...), ...).bind(stmt))` 
this will avoid `hasParent` in matchers which will make everything faster.

Then, in `hasPreTwoVarDecl` pass ID (`stmt`) of matched `compoundStmt` and 
retrieve it with `Nodes.getNodeAs<CompoundStmt>(ID)` instead of doing 
`Finder->getASTContext().getParents(Node)`. You can see this trick in 
`modernize\UseStartsEndsWithCheck.cpp` with `NotLengthExprForStringNode` class.

It may not be a trivial rewrite, so I don't enforce it to do right away, but 
first part seem not very hard and `Finder->addMatcher` would look more natural 
and faster

https://github.com/llvm/llvm-project/pull/158462
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to