https://github.com/flovent updated 
https://github.com/llvm/llvm-project/pull/158462

>From a1941312179171a8752c27f886158ce4fd90db33 Mon Sep 17 00:00:00 2001
From: flovent <flb...@protonmail.com>
Date: Sun, 14 Sep 2025 14:33:59 +0800
Subject: [PATCH 1/6] [clang-tidy] Add new check
 `modernize-use-structured-binding`

---
 .../clang-tidy/modernize/CMakeLists.txt       |   1 +
 .../modernize/ModernizeTidyModule.cpp         |   3 +
 .../modernize/UseStructuredBindingCheck.cpp   | 419 ++++++++++++++++++
 .../modernize/UseStructuredBindingCheck.h     |  36 ++
 clang-tools-extra/docs/ReleaseNotes.rst       |   6 +
 .../docs/clang-tidy/checks/list.rst           |   1 +
 .../modernize/use-structured-binding.rst      |  58 +++
 .../fake_std_pair_tuple.h                     |  23 +
 .../use-structured-binding-custom.cpp         |  32 ++
 ...d-binding-skip-lambda-capture-in-cxx17.cpp |  67 +++
 .../modernize/use-structured-binding.cpp      | 216 +++++++++
 11 files changed, 862 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseStructuredBindingCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseStructuredBindingCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/use-structured-binding/fake_std_pair_tuple.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding-custom.cpp
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding-skip-lambda-capture-in-cxx17.cpp
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index 619a27b2f9bb6..094f0a72b1570 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -47,6 +47,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseStdFormatCheck.cpp
   UseStdNumbersCheck.cpp
   UseStdPrintCheck.cpp
+  UseStructuredBindingCheck.cpp
   UseTrailingReturnTypeCheck.cpp
   UseTransparentFunctorsCheck.cpp
   UseUncaughtExceptionsCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index fdf38bc4b6308..a79908500e904 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -48,6 +48,7 @@
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
 #include "UseStdPrintCheck.h"
+#include "UseStructuredBindingCheck.h"
 #include "UseTrailingReturnTypeCheck.h"
 #include "UseTransparentFunctorsCheck.h"
 #include "UseUncaughtExceptionsCheck.h"
@@ -121,6 +122,8 @@ class ModernizeModule : public ClangTidyModule {
     CheckFactories.registerCheck<UseNoexceptCheck>("modernize-use-noexcept");
     CheckFactories.registerCheck<UseNullptrCheck>("modernize-use-nullptr");
     CheckFactories.registerCheck<UseOverrideCheck>("modernize-use-override");
+    CheckFactories.registerCheck<UseStructuredBindingCheck>(
+        "modernize-use-structured-binding");
     CheckFactories.registerCheck<UseTrailingReturnTypeCheck>(
         "modernize-use-trailing-return-type");
     CheckFactories.registerCheck<UseTransparentFunctorsCheck>(
diff --git 
a/clang-tools-extra/clang-tidy/modernize/UseStructuredBindingCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStructuredBindingCheck.cpp
new file mode 100644
index 0000000000000..d6d6ae6cb83b3
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseStructuredBindingCheck.cpp
@@ -0,0 +1,419 @@
+//===--- UseStructuredBindingCheck.cpp - clang-tidy 
-----------------------===//
+//
+// 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 "../utils/OptionsUtils.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+namespace {
+constexpr const char *DefaultPairTypes = "std::pair";
+constexpr llvm::StringLiteral PairDeclName = "PairVarD";
+constexpr llvm::StringLiteral PairVarTypeName = "PairVarType";
+constexpr llvm::StringLiteral FirstVarDeclName = "FirstVarDecl";
+constexpr llvm::StringLiteral SecondVarDeclName = "SecondVarDecl";
+constexpr llvm::StringLiteral FirstDeclStmtName = "FirstDeclStmt";
+constexpr llvm::StringLiteral SecondDeclStmtName = "SecondDeclStmt";
+constexpr llvm::StringLiteral FirstTypeName = "FirstType";
+constexpr llvm::StringLiteral SecondTypeName = "SecondType";
+constexpr llvm::StringLiteral ScopeBlockName = "ScopeBlock";
+constexpr llvm::StringLiteral StdTieAssignStmtName = "StdTieAssign";
+constexpr llvm::StringLiteral StdTieExprName = "StdTieExpr";
+constexpr llvm::StringLiteral ForRangeStmtName = "ForRangeStmt";
+
+/// 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
+};
+
+/// Try to match exactly two VarDecl inside two DeclStmts, and set binding for
+/// the used DeclStmts.
+bool matchTwoVarDecl(const DeclStmt *DS1, const DeclStmt *DS2,
+                     ast_matchers::internal::Matcher<VarDecl> InnerMatcher1,
+                     ast_matchers::internal::Matcher<VarDecl> InnerMatcher2,
+                     internal::ASTMatchFinder *Finder,
+                     internal::BoundNodesTreeBuilder *Builder) {
+  SmallVector<std::pair<const VarDecl *, const DeclStmt *>, 2> Vars;
+  auto CollectVarsInDeclStmt = [&Vars](const DeclStmt *DS) -> bool {
+    if (!DS)
+      return true;
+
+    for (const auto *VD : DS->decls()) {
+      if (Vars.size() == 2)
+        return false;
+
+      if (const auto *Var = dyn_cast<VarDecl>(VD))
+        Vars.emplace_back(Var, DS);
+      else
+        return false;
+    }
+
+    return true;
+  };
+
+  if (!CollectVarsInDeclStmt(DS1) || !CollectVarsInDeclStmt(DS2))
+    return false;
+
+  if (Vars.size() != 2)
+    return false;
+
+  if (InnerMatcher1.matches(*Vars[0].first, Finder, Builder) &&
+      InnerMatcher2.matches(*Vars[1].first, Finder, Builder)) {
+    Builder->setBinding(FirstDeclStmtName,
+                        clang::DynTypedNode::create(*Vars[0].second));
+    if (Vars[0].second != Vars[1].second)
+      Builder->setBinding(SecondDeclStmtName,
+                          clang::DynTypedNode::create(*Vars[1].second));
+    return true;
+  }
+
+  return false;
+}
+
+/// Matches a Stmt whose parent is a CompoundStmt, and which is directly
+/// following two VarDecls matching the inner matcher, at the same time set
+/// binding for the CompoundStmt.
+AST_MATCHER_P2(Stmt, hasPreTwoVarDecl, 
ast_matchers::internal::Matcher<VarDecl>,
+               InnerMatcher1, ast_matchers::internal::Matcher<VarDecl>,
+               InnerMatcher2) {
+  DynTypedNodeList Parents = Finder->getASTContext().getParents(Node);
+  if (Parents.size() != 1)
+    return false;
+
+  auto *C = Parents[0].get<CompoundStmt>();
+  if (!C)
+    return false;
+
+  const auto I =
+      llvm::find(llvm::make_range(C->body_rbegin(), C->body_rend()), &Node);
+  assert(I != C->body_rend() && "C is parent of Node");
+  if ((I + 1) == C->body_rend())
+    return false;
+
+  const auto *DS2 = dyn_cast<DeclStmt>(*(I + 1));
+  if (!DS2)
+    return false;
+
+  const DeclStmt *DS1 = (!DS2->isSingleDecl() || ((I + 2) == C->body_rend())
+                             ? nullptr
+                             : dyn_cast<DeclStmt>(*(I + 2)));
+
+  if (matchTwoVarDecl(DS1, DS2, InnerMatcher1, InnerMatcher2, Finder,
+                      Builder)) {
+    Builder->setBinding(ScopeBlockName, clang::DynTypedNode::create(*C));
+    return true;
+  }
+
+  return false;
+}
+
+/// Matches a Stmt whose parent is a CompoundStmt, and which is directly
+/// followed by two VarDecls matching the inner matcher, at the same time set
+/// binding for the CompoundStmt.
+AST_MATCHER_P2(Stmt, hasNextTwoVarDecl,
+               ast_matchers::internal::Matcher<VarDecl>, InnerMatcher1,
+               ast_matchers::internal::Matcher<VarDecl>, InnerMatcher2) {
+  DynTypedNodeList Parents = Finder->getASTContext().getParents(Node);
+  if (Parents.size() != 1)
+    return false;
+
+  auto *C = Parents[0].get<CompoundStmt>();
+  if (!C)
+    return false;
+
+  const auto *I = llvm::find(C->body(), &Node);
+  assert(I != C->body_end() && "C is parent of Node");
+  if ((I + 1) == C->body_end())
+    return false;
+
+  if (matchTwoVarDecl(
+          dyn_cast<DeclStmt>(*(I + 1)),
+          ((I + 2) == C->body_end() ? nullptr : dyn_cast<DeclStmt>(*(I + 2))),
+          InnerMatcher1, InnerMatcher2, Finder, Builder)) {
+    Builder->setBinding(ScopeBlockName, clang::DynTypedNode::create(*C));
+    return true;
+  }
+
+  return false;
+}
+
+/// Matches a Stmt whose parent is a CompoundStmt, and there a two VarDecls
+/// matching the inner matcher in the beginning of CompoundStmt.
+AST_MATCHER_P2(CompoundStmt, hasFirstTwoVarDecl,
+               ast_matchers::internal::Matcher<VarDecl>, InnerMatcher1,
+               ast_matchers::internal::Matcher<VarDecl>, InnerMatcher2) {
+  const auto *I = Node.body_begin();
+  if ((I) == Node.body_end())
+    return false;
+
+  return matchTwoVarDecl(
+      dyn_cast<DeclStmt>(*(I)),
+      ((I + 1) == Node.body_end() ? nullptr : dyn_cast<DeclStmt>(*(I + 1))),
+      InnerMatcher1, InnerMatcher2, Finder, Builder);
+}
+
+/// It's not very common to have specifiers for variables used to decompose
+/// a pair, so we ignore these cases.
+AST_MATCHER(VarDecl, hasAnySpecifiersShouldBeIgnored) {
+  return Node.isStaticLocal() || Node.isConstexpr() || Node.hasAttrs() ||
+         Node.isInlineSpecified();
+}
+
+// Ignore nodes inside macros.
+AST_POLYMORPHIC_MATCHER(isInMarco,
+                        AST_POLYMORPHIC_SUPPORTED_TYPES(Stmt, Decl)) {
+  return Node.getBeginLoc().isMacroID() || Node.getEndLoc().isMacroID();
+}
+
+AST_MATCHER_P(Expr, ignoringCopyCtorAndImplicitCast,
+              ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
+  if (const auto *CtorE = dyn_cast<CXXConstructExpr>(&Node)) {
+    if (const auto *CtorD = CtorE->getConstructor();
+        CtorD->isCopyConstructor() && CtorE->getNumArgs() == 1) {
+      return InnerMatcher.matches(*CtorE->getArg(0)->IgnoreImpCasts(), Finder,
+                                  Builder);
+    }
+  }
+
+  return InnerMatcher.matches(*Node.IgnoreImpCasts(), Finder, Builder);
+}
+
+} // namespace
+
+UseStructuredBindingCheck::UseStructuredBindingCheck(StringRef Name,
+                                                     ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      PairTypes(utils::options::parseStringList(
+          Options.get("PairTypes", DefaultPairTypes))) {
+  ;
+}
+
+static auto getVarInitWithMemberMatcher(StringRef PairName,
+                                        StringRef MemberName,
+                                        StringRef TypeName,
+                                        StringRef BindingName) {
+  return varDecl(
+             unless(hasAnySpecifiersShouldBeIgnored()), unless(isInMarco()),
+             hasInitializer(
+                 ignoringImpCasts(ignoringCopyCtorAndImplicitCast(memberExpr(
+                     hasObjectExpression(ignoringImpCasts(declRefExpr(
+                         to(equalsBoundNode(std::string(PairName)))))),
+                     member(fieldDecl(hasName(MemberName),
+                                      hasType(qualType().bind(TypeName)))))))))
+      .bind(BindingName);
+}
+
+void UseStructuredBindingCheck::registerMatchers(MatchFinder *Finder) {
+  auto PairType =
+      qualType(unless(isVolatileQualified()),
+               hasUnqualifiedDesugaredType(recordType(
+                   hasDeclaration(cxxRecordDecl(hasAnyName(PairTypes))))));
+
+  auto VarInitWithFirstMember = getVarInitWithMemberMatcher(
+      PairDeclName, "first", FirstTypeName, FirstVarDeclName);
+  auto VarInitWithSecondMember = getVarInitWithMemberMatcher(
+      PairDeclName, "second", SecondTypeName, SecondVarDeclName);
+
+  // X x;
+  // Y y;
+  // std::tie(x, y) = ...;
+  Finder->addMatcher(
+      exprWithCleanups(
+          unless(isInMarco()),
+          has(cxxOperatorCallExpr(
+                  hasOverloadedOperatorName("="),
+                  hasLHS(ignoringImplicit(
+                      callExpr(
+                          callee(
+                              functionDecl(isInStdNamespace(), 
hasName("tie"))),
+                          hasArgument(
+                              0,
+                              declRefExpr(to(
+                                  varDecl(
+                                      
unless(hasAnySpecifiersShouldBeIgnored()),
+                                      unless(isInMarco()))
+                                      .bind(FirstVarDeclName)))),
+                          hasArgument(
+                              1,
+                              declRefExpr(to(
+                                  varDecl(
+                                      
unless(hasAnySpecifiersShouldBeIgnored()),
+                                      unless(isInMarco()))
+                                      .bind(SecondVarDeclName)))))
+                          .bind(StdTieExprName))),
+                  hasRHS(expr(hasType(PairType))))
+                  .bind(StdTieAssignStmtName)),
+          hasPreTwoVarDecl(
+              varDecl(equalsBoundNode(std::string(FirstVarDeclName))),
+              varDecl(equalsBoundNode(std::string(SecondVarDeclName))))),
+      this);
+
+  // pair<X, Y> p = ...;
+  // X x = p.first;
+  // Y y = p.second;
+  Finder->addMatcher(
+      declStmt(
+          unless(isInMarco()),
+          hasSingleDecl(
+              varDecl(unless(hasAnySpecifiersShouldBeIgnored()),
+                      hasType(qualType(anyOf(PairType, lValueReferenceType(
+                                                           pointee(PairType))))
+                                  .bind(PairVarTypeName)),
+                      hasInitializer(expr()))
+                  .bind(PairDeclName)),
+          hasNextTwoVarDecl(VarInitWithFirstMember, VarInitWithSecondMember)),
+      this);
+
+  // for (pair<X, Y> p : map) {
+  //    X x = p.first;
+  //    Y y = p.second;
+  // }
+  Finder->addMatcher(
+      cxxForRangeStmt(
+          unless(isInMarco()),
+          hasLoopVariable(
+              varDecl(hasType(qualType(anyOf(PairType, lValueReferenceType(
+                                                           pointee(PairType))))
+                                  .bind(PairVarTypeName)),
+                      hasInitializer(expr()))
+                  .bind(PairDeclName)),
+          hasBody(compoundStmt(hasFirstTwoVarDecl(VarInitWithFirstMember,
+                                                  VarInitWithSecondMember))
+                      .bind(ScopeBlockName)))
+          .bind(ForRangeStmtName),
+      this);
+}
+
+static std::optional<TransferType> getTransferType(const ASTContext &Ctx,
+                                                   QualType ResultType,
+                                                   QualType OriginType) {
+  ResultType = ResultType.getCanonicalType();
+  OriginType = OriginType.getCanonicalType();
+
+  if (ResultType == Ctx.getLValueReferenceType(OriginType.withConst()))
+    return TT_ByConstRef;
+
+  if (ResultType == Ctx.getLValueReferenceType(OriginType))
+    return TT_ByRef;
+
+  if (ResultType == OriginType.withConst())
+    return TT_ByConstVal;
+
+  if (ResultType == OriginType)
+    return TT_ByVal;
+
+  return std::nullopt;
+}
+
+void UseStructuredBindingCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *FirstVar = Result.Nodes.getNodeAs<VarDecl>(FirstVarDeclName);
+  const auto *SecondVar = Result.Nodes.getNodeAs<VarDecl>(SecondVarDeclName);
+
+  const auto *DS1 = Result.Nodes.getNodeAs<DeclStmt>(FirstDeclStmtName);
+  const auto *DS2 = Result.Nodes.getNodeAs<DeclStmt>(SecondDeclStmtName);
+  const auto *ScopeBlock = 
Result.Nodes.getNodeAs<CompoundStmt>(ScopeBlockName);
+
+  // Captured structured bindings are a C++20 extension
+  if (!Result.Context->getLangOpts().CPlusPlus20) {
+    if (auto Matchers = match(
+            compoundStmt(
+                hasDescendant(lambdaExpr(hasAnyCapture(capturesVar(varDecl(
+                    anyOf(equalsNode(FirstVar), equalsNode(SecondVar)))))))),
+            *ScopeBlock, *Result.Context);
+        !Matchers.empty())
+      return;
+  }
+
+  const auto *CFRS = Result.Nodes.getNodeAs<CXXForRangeStmt>(ForRangeStmtName);
+  auto DiagAndFix = [&](SourceLocation DiagLoc, SourceRange ReplaceRange,
+                        TransferType TT = TT_ByVal) {
+    StringRef Prefix;
+    switch (TT) {
+    case TT_ByVal:
+      Prefix = "auto";
+      break;
+    case TT_ByConstVal:
+      Prefix = "const auto";
+      break;
+    case TT_ByRef:
+      Prefix = "auto&";
+      break;
+    case TT_ByConstRef:
+      Prefix = "const auto&";
+      break;
+    }
+    std::vector<FixItHint> Hints;
+    if (DS1)
+      Hints.emplace_back(FixItHint::CreateRemoval(DS1->getSourceRange()));
+    if (DS2)
+      Hints.emplace_back(FixItHint::CreateRemoval(DS2->getSourceRange()));
+
+    std::string ReplacementText = Prefix.str() + " [" +
+                                  FirstVar->getNameAsString() + ", " +
+                                  SecondVar->getNameAsString() + "]";
+    if (CFRS)
+      ReplacementText += " :";
+    diag(DiagLoc, "Should use structured binding to decompose pair")
+        << FixItHint::CreateReplacement(ReplaceRange, ReplacementText) << 
Hints;
+  };
+
+  if (const auto *COCE =
+          Result.Nodes.getNodeAs<CXXOperatorCallExpr>(StdTieAssignStmtName)) {
+    DiagAndFix(COCE->getBeginLoc(),
+               Result.Nodes.getNodeAs<Expr>(StdTieExprName)->getSourceRange());
+    return;
+  }
+
+  // Check whether PairVar, FirstVar and SecondVar have the same transfer type,
+  // so they can be combined to structured binding.
+  const auto *PairVar = Result.Nodes.getNodeAs<VarDecl>(PairDeclName);
+  const Expr *InitE = PairVar->getInit();
+  if (auto Res =
+          
match(expr(ignoringCopyCtorAndImplicitCast(expr().bind("init_expr"))),
+                *InitE, *Result.Context);
+      !Res.empty())
+    InitE = Res[0].getNodeAs<Expr>("init_expr");
+
+  std::optional<TransferType> PairCaptureType =
+      getTransferType(*Result.Context, PairVar->getType(), InitE->getType());
+  std::optional<TransferType> FirstVarCaptureType =
+      getTransferType(*Result.Context, FirstVar->getType(),
+                      *Result.Nodes.getNodeAs<QualType>(FirstTypeName));
+  std::optional<TransferType> SecondVarCaptureType =
+      getTransferType(*Result.Context, SecondVar->getType(),
+                      *Result.Nodes.getNodeAs<QualType>(SecondTypeName));
+  if (!PairCaptureType || !FirstVarCaptureType || !SecondVarCaptureType ||
+      *PairCaptureType != *FirstVarCaptureType ||
+      *FirstVarCaptureType != *SecondVarCaptureType)
+    return;
+
+  // Check PairVar is not used except for assignment members to firstVar and
+  // SecondVar.
+  if (auto AllRef = utils::decl_ref_expr::allDeclRefExprs(*PairVar, 
*ScopeBlock,
+                                                          *Result.Context);
+      AllRef.size() != 2)
+    return;
+
+  DiagAndFix(PairVar->getBeginLoc(),
+             CFRS ? PairVar->getSourceRange()
+                  : SourceRange(PairVar->getBeginLoc(),
+                                Lexer::getLocForEndOfToken(
+                                    PairVar->getLocation(), 0,
+                                    Result.Context->getSourceManager(),
+                                    Result.Context->getLangOpts())),
+             *PairCaptureType);
+}
+
+} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStructuredBindingCheck.h 
b/clang-tools-extra/clang-tidy/modernize/UseStructuredBindingCheck.h
new file mode 100644
index 0000000000000..63bc0a8c3da45
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseStructuredBindingCheck.h
@@ -0,0 +1,36 @@
+//===--- UseStructuredBindingCheck.h - clang-tidy ---------------*- C++ 
-*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTRUCTUREDBINDINGCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTRUCTUREDBINDINGCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::modernize {
+
+/// Finds places where structured bindings could be used to decompose pairs and
+/// suggests replacing them.
+///
+/// For the user-facing documentation see:
+/// 
http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-structured-binding.html
+class UseStructuredBindingCheck : public ClangTidyCheck {
+public:
+  UseStructuredBindingCheck(StringRef Name, ClangTidyContext *Context);
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus17;
+  }
+
+private:
+  const std::vector<StringRef> PairTypes;
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTRUCTUREDBINDINGCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 34091906cbff2..8302cbf64f095 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -179,6 +179,12 @@ New checks
   Finds virtual function overrides with different visibility than the function
   in the base class.
 
+- New :doc:`modernize-use-structured-binding
+  <clang-tidy/checks/modernize/use-structured-binding>` check.
+
+  Finds places where structured bindings could be used to decompose pairs and
+  suggests replacing them.
+
 New check aliases
 ^^^^^^^^^^^^^^^^^
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst 
b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index c490d2ece2e0a..843a031dd2dd1 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -324,6 +324,7 @@ Clang-Tidy Checks
    :doc:`modernize-use-std-format <modernize/use-std-format>`, "Yes"
    :doc:`modernize-use-std-numbers <modernize/use-std-numbers>`, "Yes"
    :doc:`modernize-use-std-print <modernize/use-std-print>`, "Yes"
+   :doc:`modernize-use-structured-binding <modernize/use-structured-binding>`, 
"Yes"
    :doc:`modernize-use-trailing-return-type 
<modernize/use-trailing-return-type>`, "Yes"
    :doc:`modernize-use-transparent-functors 
<modernize/use-transparent-functors>`, "Yes"
    :doc:`modernize-use-uncaught-exceptions 
<modernize/use-uncaught-exceptions>`, "Yes"
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst 
b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst
new file mode 100644
index 0000000000000..66af859d4428f
--- /dev/null
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst
@@ -0,0 +1,58 @@
+.. title:: clang-tidy - modernize-use-structured-binding
+
+modernize-use-structured-binding
+================================
+
+Suggests using C++17 structured bindings to decompose pairs.
+
+This check finds three code patterns and recommends using structured bindings 
for clearer, more idiomatic C++17 code.
+
+1. Decompose a pair variable by assigning its members to separate variables 
right after its definition:
+
+.. code-block:: c++
+
+  auto p = getPair<int, int>();
+  int x = p.first;
+  int y = p.second;
+
+  into:
+
+  auto [x, y] = getPair<int, int>();
+
+2. Use `std::tie` to decompose a pair into two predefined variables:
+
+.. code-block:: c++
+
+  int a;
+  int b;
+  std::tie(a, b) = getPair<int, int>();
+
+  into:
+
+  auto [a, b] = getPair<int, int>();
+
+3. Manually decompose a pair by assigning to its members to local variables in 
a range-based for loop:
+
+.. code-block:: c++
+
+  for (autop : vecOfPairs) {
+    int x = p.first;
+    int y = p.second;
+    // ...
+  }
+
+  into:
+
+  for (auto [x, y] : vecOfPairs) {
+    // use x and y
+  }
+
+The check also supports custom pair-like types via the `PairTypes` option.
+
+Options
+-------
+
+.. option:: PairTypes
+
+   A Semicolon-separated list of type names to be treated as pair-like for 
structured binding suggestions.  
+   Example: `PairTypes=MyPairType; OtherPairType`. Default is `std::pair`.
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/use-structured-binding/fake_std_pair_tuple.h
 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/use-structured-binding/fake_std_pair_tuple.h
new file mode 100644
index 0000000000000..b77341c852edb
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/use-structured-binding/fake_std_pair_tuple.h
@@ -0,0 +1,23 @@
+namespace std {
+  template<typename T1, typename T2>
+  struct pair {
+    T1 first;
+    T2 second;
+  };
+
+  template<typename... Args>
+  struct tuple {
+    tuple(Args&...) {}
+
+    template<typename T1, typename T2>
+    tuple<T1, T2> operator=(const std::pair<T1, T2>&);
+  };
+
+  template<typename... Args>
+  tuple<Args...> tie(Args&... args) {
+    return tuple<Args...>(args...);
+  }
+}
+
+template<typename T1, typename T2>
+std::pair<T1, T2> getPair();
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding-custom.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding-custom.cpp
new file mode 100644
index 0000000000000..d6d73430d6a3c
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding-custom.cpp
@@ -0,0 +1,32 @@
+// RUN: %check_clang_tidy -std=c++17-or-later %s 
modernize-use-structured-binding %t \
+// RUN: -config="{CheckOptions: {modernize-use-structured-binding.PairTypes: 
'custom::pair; otherPair'}}"
+
+namespace custom {
+  struct pair {
+    int first;
+    int second;
+  };
+}
+
+struct otherPair {
+  int first;
+  int second;
+};
+
+void OptionTest() {
+  {
+    auto P = custom::pair();
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-FIXES: {{^}} auto [x, y] = custom::pair();
+    int x = P.first;
+    int y = P.second;
+  }
+
+  {
+    auto P = otherPair();
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-FIXES: {{^}} auto [x, y] = otherPair();
+    int x = P.first;
+    int y = P.second;
+  }
+}
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding-skip-lambda-capture-in-cxx17.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding-skip-lambda-capture-in-cxx17.cpp
new file mode 100644
index 0000000000000..57f9f3488fa21
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding-skip-lambda-capture-in-cxx17.cpp
@@ -0,0 +1,67 @@
+// RUN: %check_clang_tidy -std=c++17 %s modernize-use-structured-binding %t -- 
-- -I %S/Inputs/use-structured-binding/
+
+#include "fake_std_pair_tuple.h"
+
+void captureByVal() {
+  auto P = getPair<int, int>();
+  int x = P.first;
+  int y = P.second;
+
+  auto lambda = [x]() {
+    int y = x;
+  };
+}
+
+void captureByRef() {
+  auto P = getPair<int, int>();
+  int x = P.first;
+  int y = P.second;
+
+  auto lambda = [&x]() {
+    x = 1;
+  };
+}
+
+void captureByAllRef() {
+  auto P = getPair<int, int>();
+  int x = P.first;
+  int y = P.second;
+
+  auto lambda = [&]() {
+    x = 1;
+  };
+}
+
+void deepLambda() {
+  auto P = getPair<int, int>();
+  int x = P.first;
+  int y = P.second;
+
+  {
+    auto lambda = [x]() {
+      int y = x;
+    };
+  }
+}
+
+void forRangeNotWarn() {
+  std::pair<int, int> Pairs[10];
+  for (auto P : Pairs) {
+    int x = P.first;
+    int y = P.second;
+
+    auto lambda = [&]() {
+    x = 1;
+  };
+  }
+}
+
+void stdTieNotWarn() {
+  int x = 0;
+  int y = 0;
+  std::tie(x, y) = getPair<int, int>();
+
+  auto lambda = [&x]() {
+    x = 1;
+  };
+}
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding.cpp
new file mode 100644
index 0000000000000..97da76fea1d5f
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding.cpp
@@ -0,0 +1,216 @@
+// RUN: %check_clang_tidy -std=c++17-or-later %s 
modernize-use-structured-binding %t -- -- -I %S/Inputs/use-structured-binding/
+
+#include "fake_std_pair_tuple.h"
+
+template<typename T>
+void MarkUsed(T x);
+
+struct TestClass {
+  int a;
+  int b;
+  TestClass() : a(0), b(0) {}
+  TestClass(int x, int y) : a(x), b(y) {}
+};
+
+void DecomposeByAssignWarnCases() {
+  {
+    auto P = getPair<int, int>();
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-FIXES: {{^}} auto [x, y] = getPair<int, int>();
+    int x = P.first;
+    int y = P.second;
+  }
+
+  {
+    auto P = getPair<int, int>();
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-FIXES: {{^}} auto [x, y] = getPair<int, int>();
+    int x = P.first;
+    auto y = P.second;
+  }
+
+  {
+    const auto P = getPair<int, int>();
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-FIXES: {{^}} const auto [x, y] = getPair<int, int>();
+    const int x = P.first;
+    const auto y = P.second;
+  }
+
+  {
+    std::pair<int, int> otherP;
+    auto& P = otherP;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-FIXES: {{^}} auto& [x, y] = otherP;
+    int& x = P.first;
+    auto& y = P.second;
+  }
+
+  {
+    std::pair<int, int> otherP;
+    const auto& P = otherP;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-FIXES: {{^}} const auto& [x, y] = otherP;
+    const int& x = P.first;
+    const auto& y = P.second;
+  }
+}
+
+void forRangeWarnCases() {
+  std::pair<int, int> Pairs[10];
+  for (auto P : Pairs) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-FIXES: {{^}} for (auto [x, y] : Pairs) {
+    int x = P.first;
+    int y = P.second;
+  }
+
+  for (const auto P : Pairs) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-FIXES: {{^}} for (const auto [x, y] : Pairs) {
+    const int x = P.first;
+    const int y = P.second;
+  }
+
+  for (auto& P : Pairs) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-FIXES: {{^}} for (auto& [x, y] : Pairs) {
+    int& x = P.first;
+    int& y = P.second;
+  }
+
+  for (const auto& P : Pairs) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-FIXES: {{^}} for (const auto& [x, y] : Pairs) {
+    const int& x = P.first;
+    const int& y = P.second;
+  }
+
+  std::pair<TestClass, TestClass> ClassPairs[10];
+  for (auto P : ClassPairs) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-FIXES: {{^}} for (auto [c1, c2] : ClassPairs) {
+    TestClass c1 = P.first;
+    TestClass c2 = P.second;
+  }
+
+  for (const auto P : ClassPairs) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-FIXES: {{^}} for (const auto [c1, c2] : ClassPairs) {
+    const TestClass c1 = P.first;
+    const TestClass c2 = P.second;
+  }
+}
+
+void stdTieWarnCases() {
+  int a = 0;
+  int b = 0;
+  std::tie(a, b) = getPair<int, int>();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Should use structured binding to 
decompose pair [modernize-use-structured-binding]
+  // CHECK-FIXES: {{^}} auto [a, b] = getPair<int, int>();
+
+  int* pa = nullptr;
+  int* pb = nullptr;
+  std::tie(pa, pb) = getPair<int*, int*>();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Should use structured binding to 
decompose pair [modernize-use-structured-binding]
+  // CHECK-FIXES: {{^}} auto [pa, pb] = getPair<int*, int*>();
+
+  TestClass c1 (1, 2);
+  TestClass c2 = TestClass {3, 4};
+  std::tie(c1, c2) = getPair<TestClass, TestClass>();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Should use structured binding to 
decompose pair [modernize-use-structured-binding]
+  // CHECK-FIXES: {{^}} auto [c1, c2] = getPair<TestClass, TestClass>();
+}
+
+void stdTieNotWarnCases() {
+  int a = 0;
+  int b = 0;
+  a = 4;
+  std::tie(a, b) = getPair<int, int>(); // no warning
+
+  int* pa = nullptr;
+  int* pb = nullptr;
+  MarkUsed(pa);
+  std::tie(pa, pb) = getPair<int*, int*>(); // no warning
+
+  TestClass c1 (1, 2);
+  TestClass c2 = TestClass {3, 4};
+  MarkUsed(c2);
+  std::tie(c1, c2) = getPair<TestClass, TestClass>();
+}
+
+void NotWarnForVarHasSpecifiers() {
+  {
+    auto P = getPair<int, int>();
+    const int x = P.first;
+    int y = P.second;
+  }
+
+  {
+    auto P = getPair<int, int>();
+    volatile int x = P.first;
+    int y = P.second;
+  }
+
+  {
+    auto P = getPair<int, int>();
+    int x = P.first;
+    [[maybe_unused]] int y = P.second;
+  }
+
+  {
+    static auto P = getPair<int, int>();
+    int x = P.first;
+    int y = P.second;
+  }
+}
+
+void NotWarnForMultiUsedPairVar() {
+  {
+    auto P = getPair<int, int>();
+    int x = P.first;
+    int y = P.second;
+    MarkUsed(P);
+  }
+
+  {
+    auto P = getPair<int, int>();
+    int x = P.first;
+    MarkUsed(P);
+    int y = P.second;
+  }
+
+  {
+    auto P = getPair<int, int>();
+    MarkUsed(P);
+    int x = P.first;
+    int y = P.second;
+  }
+
+  {
+    std::pair<int, int> Pairs[10];
+    for (auto P : Pairs) {
+      int x = P.first;
+      int y = P.second;
+
+      MarkUsed(P);
+    }
+  }
+}
+
+#define DECOMPOSE(P)                                                    \
+    int x = P.first;                                                    \
+    int y = P.second;                                                   \
+
+void NotWarnForMacro1() {
+  auto P = getPair<int, int>();
+  DECOMPOSE(P);
+}
+
+#define GETPAIR auto P = getPair<int, int>()
+
+void NotWarnForMacro2() {
+  GETPAIR;
+  int x = P.first;
+  int y = P.second;
+}

>From dd9bb2a4c980877f384d8159233c1fb75d3217fc Mon Sep 17 00:00:00 2001
From: flovent <flb...@protonmail.com>
Date: Sun, 14 Sep 2025 16:40:16 +0800
Subject: [PATCH 2/6] Update
 clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst

Co-authored-by: Baranov Victor <bar.victor.2...@gmail.com>
---
 .../docs/clang-tidy/checks/modernize/use-structured-binding.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst 
b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst
index 66af859d4428f..e25dd8e2130f3 100644
--- 
a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst
@@ -55,4 +55,4 @@ Options
 .. option:: PairTypes
 
    A Semicolon-separated list of type names to be treated as pair-like for 
structured binding suggestions.  
-   Example: `PairTypes=MyPairType; OtherPairType`. Default is `std::pair`.
+   Example: `MyPairType;OtherPairType`. Default is `std::pair`.

>From e37026ab52eb32b9b49aa50e1def060a0be0e51c Mon Sep 17 00:00:00 2001
From: flovent <flb...@protonmail.com>
Date: Sun, 14 Sep 2025 16:40:26 +0800
Subject: [PATCH 3/6] Update
 clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst

Co-authored-by: Baranov Victor <bar.victor.2...@gmail.com>
---
 .../clang-tidy/checks/modernize/use-structured-binding.rst     | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst 
b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst
index e25dd8e2130f3..377f48b822ded 100644
--- 
a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst
@@ -3,7 +3,8 @@
 modernize-use-structured-binding
 ================================
 
-Suggests using C++17 structured bindings to decompose pairs.
+Finds places where structured bindings could be used to decompose pairs and
+suggests replacing them.
 
 This check finds three code patterns and recommends using structured bindings 
for clearer, more idiomatic C++17 code.
 

>From 1d01ffd04ccb87591d88e7f56391f81982cb8c8c Mon Sep 17 00:00:00 2001
From: flovent <flb...@protonmail.com>
Date: Sun, 14 Sep 2025 16:40:48 +0800
Subject: [PATCH 4/6] Update
 clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst

Co-authored-by: Baranov Victor <bar.victor.2...@gmail.com>
---
 .../docs/clang-tidy/checks/modernize/use-structured-binding.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst 
b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst
index 377f48b822ded..38f4daaf97ec6 100644
--- 
a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst
@@ -20,7 +20,7 @@ This check finds three code patterns and recommends using 
structured bindings fo
 
   auto [x, y] = getPair<int, int>();
 
-2. Use `std::tie` to decompose a pair into two predefined variables:
+2. Use ``std::tie`` to decompose a pair into two predefined variables:
 
 .. code-block:: c++
 

>From 4127b7b7c73720c0a170cf4b334d7de687bdccf7 Mon Sep 17 00:00:00 2001
From: flovent <flb...@protonmail.com>
Date: Sun, 14 Sep 2025 16:41:17 +0800
Subject: [PATCH 5/6] Update
 clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst

Co-authored-by: Baranov Victor <bar.victor.2...@gmail.com>
---
 .../docs/clang-tidy/checks/modernize/use-structured-binding.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst 
b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst
index 38f4daaf97ec6..0d227b75968a7 100644
--- 
a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-structured-binding.rst
@@ -48,7 +48,7 @@ This check finds three code patterns and recommends using 
structured bindings fo
     // use x and y
   }
 
-The check also supports custom pair-like types via the `PairTypes` option.
+The check also supports custom pair-like types via the :option:`PairTypes` 
option.
 
 Options
 -------

>From f6c129b090262365fe0db9073a4a5a2ef9a73da0 Mon Sep 17 00:00:00 2001
From: flovent <flb...@protonmail.com>
Date: Sun, 14 Sep 2025 16:44:32 +0800
Subject: [PATCH 6/6] [NFC] Change warning message to 'use structured binding
 to decompose a pair'

---
 .../modernize/UseStructuredBindingCheck.cpp   |  2 +-
 .../use-structured-binding-custom.cpp         |  4 +--
 .../modernize/use-structured-binding.cpp      | 28 +++++++++----------
 3 files changed, 17 insertions(+), 17 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/modernize/UseStructuredBindingCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseStructuredBindingCheck.cpp
index d6d6ae6cb83b3..fab4e8dc16cf1 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStructuredBindingCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStructuredBindingCheck.cpp
@@ -365,7 +365,7 @@ void UseStructuredBindingCheck::check(const 
MatchFinder::MatchResult &Result) {
                                   SecondVar->getNameAsString() + "]";
     if (CFRS)
       ReplacementText += " :";
-    diag(DiagLoc, "Should use structured binding to decompose pair")
+    diag(DiagLoc, "use structured binding to decompose a pair")
         << FixItHint::CreateReplacement(ReplaceRange, ReplacementText) << 
Hints;
   };
 
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding-custom.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding-custom.cpp
index d6d73430d6a3c..a007447d172b7 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding-custom.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding-custom.cpp
@@ -16,7 +16,7 @@ struct otherPair {
 void OptionTest() {
   {
     auto P = custom::pair();
-    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
     // CHECK-FIXES: {{^}} auto [x, y] = custom::pair();
     int x = P.first;
     int y = P.second;
@@ -24,7 +24,7 @@ void OptionTest() {
 
   {
     auto P = otherPair();
-    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
     // CHECK-FIXES: {{^}} auto [x, y] = otherPair();
     int x = P.first;
     int y = P.second;
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding.cpp
index 97da76fea1d5f..a4016397f52ef 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-structured-binding.cpp
@@ -15,7 +15,7 @@ struct TestClass {
 void DecomposeByAssignWarnCases() {
   {
     auto P = getPair<int, int>();
-    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
     // CHECK-FIXES: {{^}} auto [x, y] = getPair<int, int>();
     int x = P.first;
     int y = P.second;
@@ -23,7 +23,7 @@ void DecomposeByAssignWarnCases() {
 
   {
     auto P = getPair<int, int>();
-    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
     // CHECK-FIXES: {{^}} auto [x, y] = getPair<int, int>();
     int x = P.first;
     auto y = P.second;
@@ -31,7 +31,7 @@ void DecomposeByAssignWarnCases() {
 
   {
     const auto P = getPair<int, int>();
-    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
     // CHECK-FIXES: {{^}} const auto [x, y] = getPair<int, int>();
     const int x = P.first;
     const auto y = P.second;
@@ -40,7 +40,7 @@ void DecomposeByAssignWarnCases() {
   {
     std::pair<int, int> otherP;
     auto& P = otherP;
-    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
     // CHECK-FIXES: {{^}} auto& [x, y] = otherP;
     int& x = P.first;
     auto& y = P.second;
@@ -49,7 +49,7 @@ void DecomposeByAssignWarnCases() {
   {
     std::pair<int, int> otherP;
     const auto& P = otherP;
-    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
     // CHECK-FIXES: {{^}} const auto& [x, y] = otherP;
     const int& x = P.first;
     const auto& y = P.second;
@@ -59,28 +59,28 @@ void DecomposeByAssignWarnCases() {
 void forRangeWarnCases() {
   std::pair<int, int> Pairs[10];
   for (auto P : Pairs) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
     // CHECK-FIXES: {{^}} for (auto [x, y] : Pairs) {
     int x = P.first;
     int y = P.second;
   }
 
   for (const auto P : Pairs) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
     // CHECK-FIXES: {{^}} for (const auto [x, y] : Pairs) {
     const int x = P.first;
     const int y = P.second;
   }
 
   for (auto& P : Pairs) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
     // CHECK-FIXES: {{^}} for (auto& [x, y] : Pairs) {
     int& x = P.first;
     int& y = P.second;
   }
 
   for (const auto& P : Pairs) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
     // CHECK-FIXES: {{^}} for (const auto& [x, y] : Pairs) {
     const int& x = P.first;
     const int& y = P.second;
@@ -88,14 +88,14 @@ void forRangeWarnCases() {
 
   std::pair<TestClass, TestClass> ClassPairs[10];
   for (auto P : ClassPairs) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
     // CHECK-FIXES: {{^}} for (auto [c1, c2] : ClassPairs) {
     TestClass c1 = P.first;
     TestClass c2 = P.second;
   }
 
   for (const auto P : ClassPairs) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Should use structured binding 
to decompose pair [modernize-use-structured-binding]
+    // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
     // CHECK-FIXES: {{^}} for (const auto [c1, c2] : ClassPairs) {
     const TestClass c1 = P.first;
     const TestClass c2 = P.second;
@@ -106,19 +106,19 @@ void stdTieWarnCases() {
   int a = 0;
   int b = 0;
   std::tie(a, b) = getPair<int, int>();
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Should use structured binding to 
decompose pair [modernize-use-structured-binding]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
   // CHECK-FIXES: {{^}} auto [a, b] = getPair<int, int>();
 
   int* pa = nullptr;
   int* pb = nullptr;
   std::tie(pa, pb) = getPair<int*, int*>();
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Should use structured binding to 
decompose pair [modernize-use-structured-binding]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
   // CHECK-FIXES: {{^}} auto [pa, pb] = getPair<int*, int*>();
 
   TestClass c1 (1, 2);
   TestClass c2 = TestClass {3, 4};
   std::tie(c1, c2) = getPair<TestClass, TestClass>();
-  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: Should use structured binding to 
decompose pair [modernize-use-structured-binding]
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use structured binding to 
decompose a pair [modernize-use-structured-binding]
   // CHECK-FIXES: {{^}} auto [c1, c2] = getPair<TestClass, TestClass>();
 }
 

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to