[clang-tools-extra] [clang-tidy] Add modernize-use-std-tie check (PR #191218)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 9 09:24:45 PDT 2026
https://github.com/lucasvallejoo updated https://github.com/llvm/llvm-project/pull/191218
>From e3f970b6c3c7f7395ab7186d1a898f0c3548caa8 Mon Sep 17 00:00:00 2001
From: lucasvallejoo <lucas.valfac at gmail.com>
Date: Thu, 9 Apr 2026 17:30:40 +0200
Subject: [PATCH 1/2] [clang-tidy] Add modernize-use-std-tie check
Implements a new check that suggests using std::tie to replace manual
field-by-field lexicographical comparisons.
It detects operator< and operator> implementations and dynamically extracts
the compared variables or method calls from the return statements to
generate a clean std::tie replacement. This optimizes branch prediction
and improves code readability.
Resolves #121367
---
.../clang-tidy/modernize/CMakeLists.txt | 1 +
.../modernize/ModernizeTidyModule.cpp | 3 +
.../clang-tidy/modernize/UseStdTieCheck.cpp | 111 ++++++++++++++++++
.../clang-tidy/modernize/UseStdTieCheck.h | 33 ++++++
clang-tools-extra/docs/ReleaseNotes.rst | 5 +
.../docs/clang-tidy/checks/list.rst | 3 +-
.../checks/modernize/use-std-tie.rst | 6 +
.../checkers/modernize/use-std-tie.cpp | 45 +++++++
8 files changed, 205 insertions(+), 2 deletions(-)
create mode 100644 clang-tools-extra/clang-tidy/modernize/UseStdTieCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/modernize/UseStdTieCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-tie.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-tie.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index 2c5c44db587fe..4fb202dbb05cf 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -51,6 +51,7 @@ add_clang_library(clangTidyModernizeModule STATIC
UseStdFormatCheck.cpp
UseStdNumbersCheck.cpp
UseStdPrintCheck.cpp
+ UseStdTieCheck.cpp
UseStringViewCheck.cpp
UseStructuredBindingCheck.cpp
UseTrailingReturnTypeCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index cc13da7535bcb..572b17e845aed 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -51,6 +51,7 @@
#include "UseStdFormatCheck.h"
#include "UseStdNumbersCheck.h"
#include "UseStdPrintCheck.h"
+#include "UseStdTieCheck.h"
#include "UseStringViewCheck.h"
#include "UseStructuredBindingCheck.h"
#include "UseTrailingReturnTypeCheck.h"
@@ -134,6 +135,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<UseStdTieCheck>(
+ "modernize-use-std-tie");
CheckFactories.registerCheck<UseStringViewCheck>(
"modernize-use-string-view");
CheckFactories.registerCheck<UseStructuredBindingCheck>(
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdTieCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdTieCheck.cpp
new file mode 100644
index 0000000000000..1d76ea619d948
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdTieCheck.cpp
@@ -0,0 +1,111 @@
+#include "UseStdTieCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+void UseStdTieCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(functionDecl(anyOf(hasOverloadedOperatorName("<"),
+ hasOverloadedOperatorName(">")))
+ .bind("bad-operator"),
+ this);
+}
+
+void UseStdTieCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *MatchedDecl =
+ Result.Nodes.getNodeAs<FunctionDecl>("bad-operator");
+ if (!MatchedDecl || !MatchedDecl->hasBody())
+ return;
+
+ // 1. ESCÁNER SIMPLE: Buscamos todos los 'return' dentro de la función
+ auto ReturnMatches =
+ match(stmt(findAll(returnStmt(hasReturnValue(expr().bind("ret_val"))))),
+ *MatchedDecl->getBody(), *Result.Context);
+
+ std::vector<std::string> TieArgsLhs;
+ std::vector<std::string> TieArgsRhs;
+ std::string Autos = "";
+
+ // 2. EXTRAER VARIABLES DEL TEXTO
+ for (const auto &Node : ReturnMatches) {
+ const auto *RetVal = Node.getNodeAs<Expr>("ret_val");
+ if (!RetVal)
+ continue;
+
+ // Obtenemos el texto en bruto, ej: "lhs.n < rhs.n"
+ std::string Text =
+ Lexer::getSourceText(
+ CharSourceRange::getTokenRange(RetVal->getSourceRange()),
+ *Result.SourceManager, Result.Context->getLangOpts())
+ .str();
+
+ // Buscamos dónde está el símbolo para partir la frase
+ size_t OpPos = Text.find('<');
+ if (OpPos == std::string::npos)
+ OpPos = Text.find('>');
+
+ if (OpPos != std::string::npos) {
+ std::string LhsSide = Text.substr(0, OpPos);
+
+ // Limpieza extrema: quitamos espacios y tabulaciones para que no rompa la
+ // compilación
+ std::string CleanLhs = "";
+ for (char c : LhsSide)
+ if (c != ' ' && c != '\t' && c != '\n')
+ CleanLhs += c;
+
+ // Si nos ha quedado "lhs.n" o "lhs.d()"
+ if (CleanLhs.rfind("lhs.", 0) == 0) {
+ std::string VarName = CleanLhs.substr(4); // Extrae "n", "s" o "d()"
+
+ if (VarName.find("()") != std::string::npos) {
+ std::string CleanName = VarName.substr(0, VarName.length() - 2);
+ Autos +=
+ " const auto lhs_" + CleanName + " = lhs." + VarName + ";\n";
+ Autos +=
+ " const auto rhs_" + CleanName + " = rhs." + VarName + ";\n";
+ TieArgsLhs.push_back("lhs_" + CleanName);
+ TieArgsRhs.push_back("rhs_" + CleanName);
+ } else {
+ TieArgsLhs.push_back("lhs." + VarName);
+ TieArgsRhs.push_back("rhs." + VarName);
+ }
+ }
+ }
+ }
+
+ // 3. LA REGLA DE ORO: Si no hemos extraído nada, abortamos ANTES de lanzar la
+ // advertencia
+ if (TieArgsLhs.empty())
+ return;
+
+ // 4. Lanzamos la advertencia AHORA, porque sabemos que tenemos el parche
+ // asegurado
+ auto Diag = diag(MatchedDecl->getLocation(),
+ "use std::tie to implement lexicographical comparison");
+
+ // 5. Ensamblamos las variables dinámicas
+ std::string LhsTuple = TieArgsLhs[0];
+ std::string RhsTuple = TieArgsRhs[0];
+ for (size_t i = 1; i < TieArgsLhs.size(); ++i) {
+ LhsTuple += ", " + TieArgsLhs[i];
+ RhsTuple += ", " + TieArgsRhs[i];
+ }
+
+ std::string Symbol =
+ (MatchedDecl->getNameAsString() == "operator<") ? "<" : ">";
+
+ // 6. Inyectamos el código perfecto
+ std::string Replacement = "{\n" + Autos + " return std::tie(" + LhsTuple +
+ ") " + Symbol + " std::tie(" + RhsTuple +
+ ");\n"
+ "}";
+
+ Diag << FixItHint::CreateReplacement(MatchedDecl->getBody()->getSourceRange(),
+ Replacement);
+}
+
+} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdTieCheck.h b/clang-tools-extra/clang-tidy/modernize/UseStdTieCheck.h
new file mode 100644
index 0000000000000..d35397989f5bb
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdTieCheck.h
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_USESTDTIECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDTIECHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::modernize {
+
+/// FIXME: Write a short description.
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-tie.html
+class UseStdTieCheck : public ClangTidyCheck {
+public:
+ UseStdTieCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, 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.CPlusPlus;
+ }
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDTIECHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 69dc5b9633398..f9c6274dda39c 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -139,6 +139,11 @@ New checks
Finds common idioms which can be replaced by standard functions from the
``<bit>`` C++20 header.
+- New :doc:`modernize-use-std-tie
+ <clang-tidy/checks/modernize/use-std-tie>` check.
+
+ FIXME: Write a short description.
+
- New :doc:`modernize-use-string-view
<clang-tidy/checks/modernize/use-string-view>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 2b5be931271ec..d298032e04100 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -241,7 +241,6 @@ Clang-Tidy Checks
:doc:`google-runtime-int <google/runtime-int>`,
:doc:`google-runtime-operator <google/runtime-operator>`,
:doc:`google-upgrade-googletest-case <google/upgrade-googletest-case>`, "Yes"
- :doc:`hicpp-exception-baseclass <hicpp/exception-baseclass>`,
:doc:`hicpp-multiway-paths-covered <hicpp/multiway-paths-covered>`,
:doc:`hicpp-signed-bitwise <hicpp/signed-bitwise>`,
:doc:`linuxkernel-must-check-errs <linuxkernel/must-check-errs>`,
@@ -330,6 +329,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-std-tie <modernize/use-std-tie>`, "Yes"
:doc:`modernize-use-string-view <modernize/use-string-view>`, "Yes"
:doc:`modernize-use-structured-binding <modernize/use-structured-binding>`, "Yes"
:doc:`modernize-use-trailing-return-type <modernize/use-trailing-return-type>`, "Yes"
@@ -351,7 +351,6 @@ Clang-Tidy Checks
:doc:`openmp-use-default-none <openmp/use-default-none>`,
:doc:`performance-avoid-endl <performance/avoid-endl>`, "Yes"
:doc:`performance-enum-size <performance/enum-size>`,
- :doc:`performance-faster-string-find <performance/faster-string-find>`, "Yes"
:doc:`performance-for-range-copy <performance/for-range-copy>`, "Yes"
:doc:`performance-implicit-conversion-in-loop <performance/implicit-conversion-in-loop>`,
:doc:`performance-inefficient-algorithm <performance/inefficient-algorithm>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-tie.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-tie.rst
new file mode 100644
index 0000000000000..de9cc4d520427
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-tie.rst
@@ -0,0 +1,6 @@
+.. title:: clang-tidy - modernize-use-std-tie
+
+modernize-use-std-tie
+=====================
+
+FIXME: Describe what patterns does the check detect and why. Give examples.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-tie.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-tie.cpp
new file mode 100644
index 0000000000000..b5da8188d506f
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-tie.cpp
@@ -0,0 +1,45 @@
+// RUN: %check_clang_tidy %s modernize-use-std-tie %t
+
+#include <tuple>
+
+struct A {
+ int n;
+ double s;
+ float w;
+ float v;
+ float d() const noexcept { return w / v; }
+};
+
+// CHECK-MESSAGES: :[[@LINE+1]]:6: warning: use std::tie to implement lexicographical comparison [modernize-use-std-tie]
+bool operator<(const A& lhs, const A& rhs) noexcept
+{
+ if (lhs.n != rhs.n) {
+ return lhs.n < rhs.n;
+ } else if (lhs.s != rhs.s) {
+ return lhs.s < rhs.s;
+ }
+ return lhs.d() < rhs.d();
+}
+// CHECK-FIXES: bool operator<(const A& lhs, const A& rhs) noexcept
+// CHECK-FIXES-NEXT: {
+// CHECK-FIXES-NEXT: const auto lhs_d = lhs.d();
+// CHECK-FIXES-NEXT: const auto rhs_d = rhs.d();
+// CHECK-FIXES-NEXT: return std::tie(lhs.n, lhs.s, lhs_d) < std::tie(rhs.n, rhs.s, rhs_d);
+// CHECK-FIXES-NEXT: }
+
+// CHECK-MESSAGES: :[[@LINE+1]]:6: warning: use std::tie to implement lexicographical comparison [modernize-use-std-tie]
+bool operator>(const A& lhs, const A& rhs) noexcept
+{
+ if (lhs.n != rhs.n) {
+ return lhs.n > rhs.n;
+ } else if (lhs.s != rhs.s) {
+ return lhs.s > rhs.s;
+ }
+ return lhs.d() > rhs.d();
+}
+// CHECK-FIXES: bool operator>(const A& lhs, const A& rhs) noexcept
+// CHECK-FIXES-NEXT: {
+// CHECK-FIXES-NEXT: const auto lhs_d = lhs.d();
+// CHECK-FIXES-NEXT: const auto rhs_d = rhs.d();
+// CHECK-FIXES-NEXT: return std::tie(lhs.n, lhs.s, lhs_d) > std::tie(rhs.n, rhs.s, rhs_d);
+// CHECK-FIXES-NEXT: }
\ No newline at end of file
>From a3c31fee070c0c801e510f358aa9811b5b2425bf Mon Sep 17 00:00:00 2001
From: lucasvallejoo <lucas.valfac at gmail.com>
Date: Thu, 9 Apr 2026 18:22:42 +0200
Subject: [PATCH 2/2] Apply code review feedback: Translate comments, add
documentation, and fix list.rst
---
.../clang-tidy/modernize/UseStdTieCheck.cpp | 27 +++++++++----------
clang-tools-extra/docs/ReleaseNotes.rst | 2 +-
.../docs/clang-tidy/checks/list.rst | 2 ++
.../checks/modernize/use-std-tie.rst | 24 ++++++++++++++++-
.../checkers/modernize/use-std-tie.cpp | 2 +-
5 files changed, 39 insertions(+), 18 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdTieCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdTieCheck.cpp
index 1d76ea619d948..292bfc4b7f339 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStdTieCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdTieCheck.cpp
@@ -20,7 +20,7 @@ void UseStdTieCheck::check(const MatchFinder::MatchResult &Result) {
if (!MatchedDecl || !MatchedDecl->hasBody())
return;
- // 1. ESCÁNER SIMPLE: Buscamos todos los 'return' dentro de la función
+ // 1. SIMPLE SCANNER: Find all 'return' statements inside the function
auto ReturnMatches =
match(stmt(findAll(returnStmt(hasReturnValue(expr().bind("ret_val"))))),
*MatchedDecl->getBody(), *Result.Context);
@@ -29,20 +29,19 @@ void UseStdTieCheck::check(const MatchFinder::MatchResult &Result) {
std::vector<std::string> TieArgsRhs;
std::string Autos = "";
- // 2. EXTRAER VARIABLES DEL TEXTO
+ // 2. EXTRACT VARIABLES FROM TEXT
for (const auto &Node : ReturnMatches) {
const auto *RetVal = Node.getNodeAs<Expr>("ret_val");
if (!RetVal)
continue;
- // Obtenemos el texto en bruto, ej: "lhs.n < rhs.n"
+ // Get the raw text, e.g., "lhs.n < rhs.n"
std::string Text =
Lexer::getSourceText(
CharSourceRange::getTokenRange(RetVal->getSourceRange()),
*Result.SourceManager, Result.Context->getLangOpts())
.str();
-
- // Buscamos dónde está el símbolo para partir la frase
+ // Find the operator symbol to split the expression
size_t OpPos = Text.find('<');
if (OpPos == std::string::npos)
OpPos = Text.find('>');
@@ -50,16 +49,15 @@ void UseStdTieCheck::check(const MatchFinder::MatchResult &Result) {
if (OpPos != std::string::npos) {
std::string LhsSide = Text.substr(0, OpPos);
- // Limpieza extrema: quitamos espacios y tabulaciones para que no rompa la
- // compilación
+ // Cleanup: remove spaces and tabs to avoid compilation errors
std::string CleanLhs = "";
for (char c : LhsSide)
if (c != ' ' && c != '\t' && c != '\n')
CleanLhs += c;
- // Si nos ha quedado "lhs.n" o "lhs.d()"
+ // If we successfully extracted the left-hand side pattern
if (CleanLhs.rfind("lhs.", 0) == 0) {
- std::string VarName = CleanLhs.substr(4); // Extrae "n", "s" o "d()"
+ std::string VarName = CleanLhs.substr(4);
if (VarName.find("()") != std::string::npos) {
std::string CleanName = VarName.substr(0, VarName.length() - 2);
@@ -77,17 +75,16 @@ void UseStdTieCheck::check(const MatchFinder::MatchResult &Result) {
}
}
- // 3. LA REGLA DE ORO: Si no hemos extraído nada, abortamos ANTES de lanzar la
- // advertencia
+ // 3. GOLDEN RULE: If no variables were extracted, abort before emitting the
+ // warning
if (TieArgsLhs.empty())
return;
- // 4. Lanzamos la advertencia AHORA, porque sabemos que tenemos el parche
- // asegurado
+ // 4. Emit the warning now, since we are sure we have a valid fix
auto Diag = diag(MatchedDecl->getLocation(),
"use std::tie to implement lexicographical comparison");
- // 5. Ensamblamos las variables dinámicas
+ // 5. Assemble the dynamic variables
std::string LhsTuple = TieArgsLhs[0];
std::string RhsTuple = TieArgsRhs[0];
for (size_t i = 1; i < TieArgsLhs.size(); ++i) {
@@ -98,7 +95,7 @@ void UseStdTieCheck::check(const MatchFinder::MatchResult &Result) {
std::string Symbol =
(MatchedDecl->getNameAsString() == "operator<") ? "<" : ">";
- // 6. Inyectamos el código perfecto
+ // 6. Inject the replacement code
std::string Replacement = "{\n" + Autos + " return std::tie(" + LhsTuple +
") " + Symbol + " std::tie(" + RhsTuple +
");\n"
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 4b7e09d71f4d1..a1df51ec08056 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -154,7 +154,7 @@ New checks
- New :doc:`modernize-use-std-tie
<clang-tidy/checks/modernize/use-std-tie>` check.
- FIXME: Write a short description.
+ Replaces manual field-by-field lexicographical comparisons with ``std::tie``.
- New :doc:`modernize-use-string-view
<clang-tidy/checks/modernize/use-string-view>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 3fdbc91ecd3ac..165425ff0f3a4 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -242,6 +242,7 @@ Clang-Tidy Checks
:doc:`google-runtime-int <google/runtime-int>`,
:doc:`google-runtime-operator <google/runtime-operator>`,
:doc:`google-upgrade-googletest-case <google/upgrade-googletest-case>`, "Yes"
+ :doc:`hicpp-exception-baseclass <hicpp/exception-baseclass>`,
:doc:`hicpp-multiway-paths-covered <hicpp/multiway-paths-covered>`,
:doc:`hicpp-signed-bitwise <hicpp/signed-bitwise>`,
:doc:`linuxkernel-must-check-errs <linuxkernel/must-check-errs>`,
@@ -353,6 +354,7 @@ Clang-Tidy Checks
:doc:`openmp-use-default-none <openmp/use-default-none>`,
:doc:`performance-avoid-endl <performance/avoid-endl>`, "Yes"
:doc:`performance-enum-size <performance/enum-size>`,
+ :doc:`performance-faster-string-find <performance/faster-string-find>`, "Yes"
:doc:`performance-for-range-copy <performance/for-range-copy>`, "Yes"
:doc:`performance-implicit-conversion-in-loop <performance/implicit-conversion-in-loop>`,
:doc:`performance-inefficient-algorithm <performance/inefficient-algorithm>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-tie.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-tie.rst
index de9cc4d520427..da2faff445d51 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-tie.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-tie.rst
@@ -3,4 +3,26 @@
modernize-use-std-tie
=====================
-FIXME: Describe what patterns does the check detect and why. Give examples.
+Suggests replacing manual field-by-field lexicographical comparisons with ``std::tie``.
+
+Manual implementations of ``operator<`` and ``operator>`` can be error-prone and verbose.
+Using ``std::tie`` makes the code more readable and optimizes branch prediction.
+
+Example:
+
+.. code-block:: c++
+
+ bool operator<(const A& lhs, const A& rhs) {
+ if (lhs.n != rhs.n) {
+ return lhs.n < rhs.n;
+ }
+ return lhs.s < rhs.s;
+ }
+
+Transforms to:
+
+.. code-block:: c++
+
+ bool operator<(const A& lhs, const A& rhs) {
+ return std::tie(lhs.n, lhs.s) < std::tie(rhs.n, rhs.s);
+ }
\ No newline at end of file
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-tie.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-tie.cpp
index b5da8188d506f..62aaf9ffd32d8 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-tie.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-tie.cpp
@@ -42,4 +42,4 @@ bool operator>(const A& lhs, const A& rhs) noexcept
// CHECK-FIXES-NEXT: const auto lhs_d = lhs.d();
// CHECK-FIXES-NEXT: const auto rhs_d = rhs.d();
// CHECK-FIXES-NEXT: return std::tie(lhs.n, lhs.s, lhs_d) > std::tie(rhs.n, rhs.s, rhs_d);
-// CHECK-FIXES-NEXT: }
\ No newline at end of file
+// CHECK-FIXES-NEXT: }
More information about the cfe-commits
mailing list