https://github.com/vbvictor updated 
https://github.com/llvm/llvm-project/pull/126434

>From 92588a7eb3f87e74887e94f88d3402ec25c6ee53 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2...@gmail.com>
Date: Sun, 9 Feb 2025 22:34:26 +0300
Subject: [PATCH 1/7] [clang-tidy] add modernize-use-scoped-lock check

---
 .../clang-tidy/modernize/CMakeLists.txt       |   1 +
 .../modernize/ModernizeTidyModule.cpp         |   3 +
 .../modernize/UseScopedLockCheck.cpp          | 234 ++++++++++++++
 .../clang-tidy/modernize/UseScopedLockCheck.h |  50 +++
 clang-tools-extra/docs/ReleaseNotes.rst       |   6 +
 .../docs/clang-tidy/checks/list.rst           |   1 +
 .../checks/modernize/use-scoped-lock.rst      |  81 +++++
 .../use-scoped-lock-only-warn-on-multiple.cpp | 122 ++++++++
 .../checkers/modernize/use-scoped-lock.cpp    | 290 ++++++++++++++++++
 9 files changed, 788 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/modernize/use-scoped-lock.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index bab1167fb15ff..619a27b2f9bb6 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -42,6 +42,7 @@ add_clang_library(clangTidyModernizeModule STATIC
   UseNullptrCheck.cpp
   UseOverrideCheck.cpp
   UseRangesCheck.cpp
+  UseScopedLockCheck.cpp
   UseStartsEndsWithCheck.cpp
   UseStdFormatCheck.cpp
   UseStdNumbersCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp 
b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index fc46c72982fdc..b2d4ddd667502 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -43,6 +43,7 @@
 #include "UseNullptrCheck.h"
 #include "UseOverrideCheck.h"
 #include "UseRangesCheck.h"
+#include "UseScopedLockCheck.h"
 #include "UseStartsEndsWithCheck.h"
 #include "UseStdFormatCheck.h"
 #include "UseStdNumbersCheck.h"
@@ -80,6 +81,8 @@ class ModernizeModule : public ClangTidyModule {
     CheckFactories.registerCheck<UseIntegerSignComparisonCheck>(
         "modernize-use-integer-sign-comparison");
     CheckFactories.registerCheck<UseRangesCheck>("modernize-use-ranges");
+    CheckFactories.registerCheck<UseScopedLockCheck>(
+        "modernize-use-scoped-lock");
     CheckFactories.registerCheck<UseStartsEndsWithCheck>(
         "modernize-use-starts-ends-with");
     
CheckFactories.registerCheck<UseStdFormatCheck>("modernize-use-std-format");
diff --git a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
new file mode 100644
index 0000000000000..af2fea5ad310e
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
@@ -0,0 +1,234 @@
+//===--- UseScopedLockCheck.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 "UseScopedLockCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/Type.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/ADT/Twine.h"
+#include <iterator>
+#include <optional>
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+namespace {
+
+bool isLockGuard(const QualType &Type) {
+  if (const auto *RecordTy = Type->getAs<RecordType>()) {
+    if (const auto *RecordDecl = RecordTy->getDecl()) {
+      return RecordDecl->getQualifiedNameAsString() == "std::lock_guard";
+    }
+  }
+
+  if (const auto *TemplateSpecType =
+          Type->getAs<TemplateSpecializationType>()) {
+    if (const auto *TemplateDecl =
+            TemplateSpecType->getTemplateName().getAsTemplateDecl()) {
+      return TemplateDecl->getQualifiedNameAsString() == "std::lock_guard";
+    }
+  }
+
+  return false;
+}
+
+std::vector<const VarDecl *> getLockGuardsFromDecl(const DeclStmt *DS) {
+  std::vector<const VarDecl *> LockGuards;
+
+  for (const auto *Decl : DS->decls()) {
+    if (const auto *VD = dyn_cast<VarDecl>(Decl)) {
+      const QualType Type = VD->getType().getCanonicalType();
+      if (isLockGuard(Type)) {
+        LockGuards.push_back(VD);
+      }
+    }
+  }
+
+  return LockGuards;
+}
+
+// Scans through the statements in a block and groups consecutive
+// 'std::lock_guard' variable declarations together.
+std::vector<std::vector<const VarDecl *>>
+findLocksInCompoundStmt(const CompoundStmt *Block,
+                        const ast_matchers::MatchFinder::MatchResult &Result) {
+  // store groups of consecutive 'std::lock_guard' declarations
+  std::vector<std::vector<const VarDecl *>> LockGuardGroups;
+  std::vector<const VarDecl *> CurrentLockGuardGroup;
+
+  auto AddAndClearCurrentGroup = [&]() {
+    if (!CurrentLockGuardGroup.empty()) {
+      LockGuardGroups.push_back(CurrentLockGuardGroup);
+      CurrentLockGuardGroup.clear();
+    }
+  };
+
+  for (const auto *Stmt : Block->body()) {
+    if (const auto *DS = dyn_cast<DeclStmt>(Stmt)) {
+      std::vector<const VarDecl *> LockGuards = getLockGuardsFromDecl(DS);
+
+      if (!LockGuards.empty()) {
+        CurrentLockGuardGroup.insert(
+            CurrentLockGuardGroup.end(),
+            std::make_move_iterator(LockGuards.begin()),
+            std::make_move_iterator(LockGuards.end()));
+      }
+
+      if (LockGuards.empty()) {
+        AddAndClearCurrentGroup();
+      }
+    } else {
+      AddAndClearCurrentGroup();
+    }
+  }
+
+  AddAndClearCurrentGroup();
+
+  return LockGuardGroups;
+}
+
+// Find the exact source range of the 'lock_guard<...>' token
+std::optional<SourceRange> getLockGuardRange(const VarDecl *LockGuard,
+                                             SourceManager &SM) {
+  const auto *SourceInfo = LockGuard->getTypeSourceInfo();
+  const auto TypeLoc = SourceInfo->getTypeLoc();
+
+  const auto ElaboratedLoc = TypeLoc.getAs<ElaboratedTypeLoc>();
+  if (!ElaboratedLoc)
+    return std::nullopt;
+
+  const auto TemplateLoc =
+      ElaboratedLoc.getNamedTypeLoc().getAs<TemplateSpecializationTypeLoc>();
+  if (!TemplateLoc)
+    return std::nullopt;
+
+  const SourceLocation LockGuardBeginLoc = TemplateLoc.getTemplateNameLoc();
+  const SourceLocation LockGuardRAngleLoc = TemplateLoc.getRAngleLoc();
+
+  return SourceRange(LockGuardBeginLoc, LockGuardRAngleLoc);
+}
+
+} // namespace
+
+void UseScopedLockCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "WarnOnlyMultipleLocks", WarnOnlyMultipleLocks);
+}
+
+void UseScopedLockCheck::registerMatchers(MatchFinder *Finder) {
+  auto LockGuardType = qualType(hasDeclaration(namedDecl(
+      hasName("::std::lock_guard"),
+      anyOf(classTemplateDecl(), classTemplateSpecializationDecl()))));
+  auto LockVarDecl = varDecl(hasType(LockGuardType));
+
+  // Match CompoundStmt with only one 'std::lock_guard'
+  if (!WarnOnlyMultipleLocks) {
+    Finder->addMatcher(
+        compoundStmt(has(declStmt(has(LockVarDecl.bind("lock-decl-single")))),
+                     unless(hasDescendant(declStmt(has(varDecl(
+                         hasType(LockGuardType),
+                         unless(equalsBoundNode("lock-decl-single")))))))),
+        this);
+  }
+
+  // Match CompoundStmt with multiple 'std::lock_guard'
+  Finder->addMatcher(
+      compoundStmt(has(declStmt(has(LockVarDecl.bind("lock-decl-multiple")))),
+                   hasDescendant(declStmt(has(varDecl(
+                       hasType(LockGuardType),
+                       unless(equalsBoundNode("lock-decl-multiple")))))))
+          .bind("block-multiple"),
+      this);
+}
+
+void UseScopedLockCheck::check(const MatchFinder::MatchResult &Result) {
+  if (const auto *Decl = Result.Nodes.getNodeAs<VarDecl>("lock-decl-single")) {
+    emitDiag(Decl, Result);
+  }
+
+  if (const auto *Compound =
+          Result.Nodes.getNodeAs<CompoundStmt>("block-multiple")) {
+    emitDiag(findLocksInCompoundStmt(Compound, Result), Result);
+  }
+}
+
+void UseScopedLockCheck::emitDiag(const VarDecl *LockGuard,
+                                  const MatchFinder::MatchResult &Result) {
+  auto Diag = diag(LockGuard->getBeginLoc(),
+                   "use 'std::scoped_lock' instead of 'std::lock_guard'");
+
+  const std::optional<SourceRange> LockGuardTypeRange =
+      getLockGuardRange(LockGuard, *Result.SourceManager);
+
+  if (!LockGuardTypeRange) {
+    return;
+  }
+
+  // Create Fix-its only if we can find the constructor call to handle
+  // 'std::lock_guard l(m, std::adopt_lock)' case
+  const auto *CtorCall = dyn_cast<CXXConstructExpr>(LockGuard->getInit());
+  if (!CtorCall) {
+    return;
+  }
+
+  switch (CtorCall->getNumArgs()) {
+  case 1:
+    Diag << FixItHint::CreateReplacement(LockGuardTypeRange.value(),
+                                         "scoped_lock");
+    return;
+  case 2:
+    const auto *CtorArgs = CtorCall->getArgs();
+
+    const Expr *MutexArg = CtorArgs[0];
+    const Expr *AdoptLockArg = CtorArgs[1];
+
+    const StringRef MutexSourceText = Lexer::getSourceText(
+        CharSourceRange::getTokenRange(MutexArg->getSourceRange()),
+        *Result.SourceManager, Result.Context->getLangOpts());
+    const StringRef AdoptLockSourceText = Lexer::getSourceText(
+        CharSourceRange::getTokenRange(AdoptLockArg->getSourceRange()),
+        *Result.SourceManager, Result.Context->getLangOpts());
+
+    Diag << FixItHint::CreateReplacement(LockGuardTypeRange.value(),
+                                         "scoped_lock")
+         << FixItHint::CreateReplacement(
+                SourceRange(CtorArgs[0]->getBeginLoc(),
+                            CtorArgs[1]->getEndLoc()),
+                (llvm::Twine(AdoptLockSourceText) + ", " + MutexSourceText)
+                    .str());
+    return;
+  }
+
+  llvm_unreachable("Invalid argument number of std::lock_guard constructor");
+}
+
+void UseScopedLockCheck::emitDiag(
+    const std::vector<std::vector<const VarDecl *>> &LockGuardGroups,
+    const MatchFinder::MatchResult &Result) {
+  for (const auto &Group : LockGuardGroups) {
+    if (Group.size() == 1 && !WarnOnlyMultipleLocks) {
+      emitDiag(Group[0], Result);
+    } else {
+      diag(Group[0]->getBeginLoc(),
+           "use single 'std::scoped_lock' instead of multiple "
+           "'std::lock_guard'");
+
+      for (size_t I = 1; I < Group.size(); ++I) {
+        diag(Group[I]->getLocation(),
+             "additional 'std::lock_guard' declared here", 
DiagnosticIDs::Note);
+      }
+    }
+  }
+}
+
+} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.h 
b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.h
new file mode 100644
index 0000000000000..0e1fd8067ddd1
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.h
@@ -0,0 +1,50 @@
+//===--- UseScopedLockCheck.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_USESCOPEDLOCKCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESCOPEDLOCKCHECK_H
+
+#include "../ClangTidyCheck.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/Stmt.h"
+#include <optional>
+
+namespace clang::tidy::modernize {
+
+/// Finds uses of ``std::lock_guard`` and suggests replacing them with C++17's
+/// more flexible and safer alternative ``std::scoped_lock``.
+///
+/// For the user-facing documentation see:
+/// 
http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-scoped-lock.html
+class UseScopedLockCheck : public ClangTidyCheck {
+public:
+  UseScopedLockCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context),
+        WarnOnlyMultipleLocks(Options.get("WarnOnlyMultipleLocks", false)) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus17;
+  }
+  std::optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
+
+private:
+  void emitDiag(const VarDecl *LockGuard,
+                const ast_matchers::MatchFinder::MatchResult &Result);
+  void emitDiag(const std::vector<std::vector<const VarDecl *>> &LockGroups,
+                const ast_matchers::MatchFinder::MatchResult &Result);
+
+  const bool WarnOnlyMultipleLocks;
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESCOPEDLOCKCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 3bddeeda06e06..6aefbc4737276 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -91,6 +91,12 @@ Improvements to clang-tidy
 New checks
 ^^^^^^^^^^
 
+- New :doc:`use-scoped-lock
+  <clang-tidy/checks/modernize/use-scoped-lock>` check.
+
+  Finds uses of ``std::lock_guard`` and suggests replacing them with C++17's
+  more flexible and safer alternative ``std::scoped_lock``.
+
 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 7b9b905ef7671..b21633459a95c 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -308,6 +308,7 @@ Clang-Tidy Checks
    :doc:`modernize-use-nullptr <modernize/use-nullptr>`, "Yes"
    :doc:`modernize-use-override <modernize/use-override>`, "Yes"
    :doc:`modernize-use-ranges <modernize/use-ranges>`, "Yes"
+   :doc:`modernize-use-scoped-lock <modernize/use-scoped-lock>`, "Yes"
    :doc:`modernize-use-starts-ends-with <modernize/use-starts-ends-with>`, 
"Yes"
    :doc:`modernize-use-std-format <modernize/use-std-format>`, "Yes"
    :doc:`modernize-use-std-numbers <modernize/use-std-numbers>`, "Yes"
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-scoped-lock.rst 
b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-scoped-lock.rst
new file mode 100644
index 0000000000000..04b35d0081b3c
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-scoped-lock.rst
@@ -0,0 +1,81 @@
+.. title:: clang-tidy - modernize-use-scoped-lock
+
+modernize-use-scoped-lock
+=========================
+
+Finds uses of ``std::lock_guard`` and suggests replacing them with C++17's more
+flexible and safer alternative ``std::scoped_lock``. The check will
+automatically transform only single declarations of ``std::lock_guard`` and
+emit warnings for multiple declarations of ``std::lock_guard`` that can be
+replaced with a single declaration of ``std::scoped_lock``.
+
+Examples
+--------
+
+Single ``std::lock_guard`` declaration:
+
+.. code-block:: c++
+
+  std::mutex M;
+  std::lock_guard<std::mutex> L(M);
+
+
+Transforms to:
+
+.. code-block:: c++
+
+  std::mutex m;
+  std::scoped_lock L(M);
+
+Single ``std::lock_guard`` declaration with ``std::adopt_lock``:
+
+.. code-block:: c++
+
+  std::mutex M;
+  std::lock(M);
+  std::lock_guard<std::mutex> L(M, std::adopt_lock);
+
+
+Transforms to:
+
+.. code-block:: c++
+
+  std::mutex M;
+  std::lock(M);
+  std::scoped_lock L(std::adopt_lock, M);
+
+Multiple ``std::lock_guard`` declarations only emit warnings:
+
+.. code-block:: c++
+
+  std::mutex M1, M2;
+  std::lock(M1, M2);
+  std::lock_guard Lock1(M, std::adopt_lock); // warning: use single 
'std::scoped_lock' instead of multiple 'std::lock_guard'
+  std::lock_guard Lock2(M, std::adopt_lock); // note: additional 
'std::lock_guard' declared here
+
+
+Limitations
+-----------
+
+The check will not emit warnings if ``std::lock_guard`` is used implicitly via
+``using``, ``typedef`` or ``template``.
+
+.. code-block:: c
+
+  template <template <typename> typename Lock>
+  void TemplatedLock() {
+    std::mutex m;
+    Lock<std::mutex> l(m); // no warning
+  }
+
+  void UsingLock() {
+    using Lock = std::lock_guard<std::mutex>;
+    std::mutex m;
+    Lock l(m); // no warning
+  }
+
+.. option:: WarnOnlyMultipleLocks
+
+  When `true`, the check will only emit warnings if the there are multiple
+  consecutive ``std::lock_guard`` declarations that can be replaced with a
+  single ``std::scoped_lock`` declaration. Default is `false`.
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
new file mode 100644
index 0000000000000..6d46e43bc2be4
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
@@ -0,0 +1,122 @@
+// RUN: %check_clang_tidy -std=c++17-or-later %s modernize-use-scoped-lock %t 
-- \
+// RUN:   -config="{CheckOptions: 
{modernize-use-scoped-lock.WarnOnlyMultipleLocks: true}}"
+
+namespace std {
+
+struct mutex {
+  void lock() {}
+  void unlock() {}
+};
+
+template<class Lockable1, class Lockable2, class... LockableN >
+void lock(Lockable1& lock1, Lockable2& lock2, LockableN&... lockn );
+
+struct adopt_lock_t { };
+std::adopt_lock_t adopt_lock {};
+
+template <typename Mutex>
+struct lock_guard {
+  lock_guard(Mutex &m) { }
+  lock_guard(Mutex &m, std::adopt_lock_t t) {}
+  lock_guard( const lock_guard& ) = delete;
+};
+
+template <typename... MutexTypes>
+struct scoped_lock {
+  scoped_lock(MutexTypes&... m) {}
+  scoped_lock(std::adopt_lock_t t, MutexTypes&... m) {}
+};
+
+} // namespace std
+
+
+void Positive() {
+  std::mutex m;
+
+  {
+    std::lock_guard<std::mutex> l1(m);
+    std::lock_guard<std::mutex> l2(m);
+    // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use single 'std::scoped_lock' 
instead of multiple 'std::lock_guard'
+    // CHECK-MESSAGES: :[[@LINE-2]]:33: note: additional 'std::lock_guard' 
declared here
+  }
+
+  {
+    std::lock_guard<std::mutex> l1(m), l2(m), l3(m);
+    std::lock_guard<std::mutex> l4(m);
+    // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use single 'std::scoped_lock' 
instead of multiple 'std::lock_guard'
+    // CHECK-MESSAGES: :[[@LINE-3]]:40: note: additional 'std::lock_guard' 
declared here
+    // CHECK-MESSAGES: :[[@LINE-4]]:47: note: additional 'std::lock_guard' 
declared here
+    // CHECK-MESSAGES: :[[@LINE-4]]:33: note: additional 'std::lock_guard' 
declared here
+  }
+  
+  { 
+    std::lock(m, m);
+    std::lock_guard<std::mutex> l1(m, std::adopt_lock);
+    std::lock_guard<std::mutex> l2(m, std::adopt_lock);
+    // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use single 'std::scoped_lock' 
instead of multiple 'std::lock_guard'
+    // CHECK-MESSAGES: :[[@LINE-2]]:33: note: additional 'std::lock_guard' 
declared here
+  } 
+}
+
+void Negative() {
+  std::mutex m;
+  {
+    std::lock_guard<std::mutex> l(m);
+  }
+
+  {
+    std::lock_guard<std::mutex> l(m, std::adopt_lock);
+  }
+}
+
+void PositiveInsideArg(std::mutex &m1, std::mutex &m2, std::mutex &m3) {
+  std::lock_guard<std::mutex> l1(m1);
+  std::lock_guard<std::mutex> l2(m2);
+  // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use single 'std::scoped_lock' 
instead of multiple 'std::lock_guard'
+  // CHECK-MESSAGES: :[[@LINE-2]]:31: note: additional 'std::lock_guard' 
declared here
+}
+
+
+void NegativeInsideArg(std::mutex &m1, std::mutex &m2, std::mutex &m3) {
+  std::lock_guard<std::mutex> l3(m3);
+}
+
+template <typename T>
+void PositiveTemplated() {
+  std::mutex m1, m2;
+  
+  std::lock_guard<std::mutex> l1(m1);
+  std::lock_guard<std::mutex> l2(m2);
+  // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use single 'std::scoped_lock' 
instead of multiple 'std::lock_guard'
+  // CHECK-MESSAGES: :[[@LINE-2]]:31: note: additional 'std::lock_guard' 
declared here  
+}
+
+template <typename T>
+void NegativeTemplated() {
+  std::mutex m1, m2, m3;
+  std::lock_guard<std::mutex> l(m1);
+}
+
+template <typename Mutex>
+void PositiveTemplatedMutex() {
+  Mutex m1, m2;
+
+  std::lock_guard<Mutex> l1(m1);
+  std::lock_guard<Mutex> l2(m2);
+  // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use single 'std::scoped_lock' 
instead of multiple 'std::lock_guard'
+  // CHECK-MESSAGES: :[[@LINE-2]]:26: note: additional 'std::lock_guard' 
declared here
+}
+
+template <typename Mutex>
+void NegativeTemplatedMutex() {
+  Mutex m1;
+  std::lock_guard<Mutex> l(m1);
+}
+
+struct NegativeClass {
+  void Negative() {
+    std::lock_guard<std::mutex> l(m1);
+  }
+  
+  std::mutex m1;
+};
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp
new file mode 100644
index 0000000000000..87ccdf1b04227
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp
@@ -0,0 +1,290 @@
+// RUN: %check_clang_tidy -std=c++17-or-later %s modernize-use-scoped-lock %t
+
+namespace std {
+
+struct mutex {
+  void lock() {}
+  void unlock() {}
+};
+
+template<class Lockable1, class Lockable2, class... LockableN >
+void lock(Lockable1& lock1, Lockable2& lock2, LockableN&... lockn );
+
+struct adopt_lock_t { };
+std::adopt_lock_t adopt_lock {};
+
+template <typename Mutex>
+struct lock_guard {
+  lock_guard(Mutex &m) { }
+  lock_guard(Mutex &m, std::adopt_lock_t t) {}
+  lock_guard( const lock_guard& ) = delete;
+};
+
+template <typename... MutexTypes>
+struct scoped_lock {
+  scoped_lock(MutexTypes&... m) {}
+  scoped_lock(std::adopt_lock_t t, MutexTypes&... m) {}
+};
+
+} // namespace std
+
+
+void Positive() {
+  std::mutex m;
+  {
+    std::lock_guard<std::mutex> l(m);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+    // CHECK-FIXES: std::scoped_lock l(m);
+  }
+
+  {
+    std::lock_guard<std::mutex> l(m, std::adopt_lock);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+    // CHECK-FIXES: std::scoped_lock l(std::adopt_lock, m);
+  }
+
+  {
+    std::lock_guard<std::mutex> l1(m);
+    std::lock_guard<std::mutex> l2(m);
+    // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use single 'std::scoped_lock' 
instead of multiple 'std::lock_guard'
+    // CHECK-MESSAGES: :[[@LINE-2]]:33: note: additional 'std::lock_guard' 
declared here
+  }
+
+  {
+    std::lock_guard<std::mutex> l1(m), l2(m), l3(m);
+    std::lock_guard<std::mutex> l4(m);
+    // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use single 'std::scoped_lock' 
instead of multiple 'std::lock_guard'
+    // CHECK-MESSAGES: :[[@LINE-3]]:40: note: additional 'std::lock_guard' 
declared here
+    // CHECK-MESSAGES: :[[@LINE-4]]:47: note: additional 'std::lock_guard' 
declared here
+    // CHECK-MESSAGES: :[[@LINE-4]]:33: note: additional 'std::lock_guard' 
declared here
+  }
+  
+  { 
+    std::lock(m, m);
+    std::lock_guard<std::mutex> l1(m, std::adopt_lock);
+    std::lock_guard<std::mutex> l2(m, std::adopt_lock);
+    // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use single 'std::scoped_lock' 
instead of multiple 'std::lock_guard'
+    // CHECK-MESSAGES: :[[@LINE-2]]:33: note: additional 'std::lock_guard' 
declared here
+    int a = 0;
+    std::lock_guard<std::mutex> l3(m);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+    // CHECK-FIXES: std::scoped_lock l3(m);
+    int b = 0;
+    std::lock_guard<std::mutex> l4(m, std::adopt_lock);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+    // CHECK-FIXES: std::scoped_lock l4(std::adopt_lock, m);
+  }
+  
+}
+
+
+void PositiveInsideArg(std::mutex &m1, std::mutex &m2, std::mutex &m3) {
+  std::lock_guard<std::mutex> l1(m1);
+  std::lock_guard<std::mutex> l2(m2);
+  // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use single 'std::scoped_lock' 
instead of multiple 'std::lock_guard'
+  // CHECK-MESSAGES: :[[@LINE-2]]:31: note: additional 'std::lock_guard' 
declared here
+  int a = 0;
+  std::lock_guard<std::mutex> l3(m3);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+  // CHECK-FIXES: std::scoped_lock l3(m3);
+}
+
+void PositiveInsideConditional() {
+  std::mutex m1;
+  if (true) {
+    std::lock_guard<std::mutex> l1(m1);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+    // CHECK-FIXES: std::scoped_lock l1(m1);
+  } else {
+    std::lock_guard<std::mutex> l1(m1);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+    // CHECK-FIXES: std::scoped_lock l1(m1);
+  }
+
+  while (true) {
+    std::lock_guard<std::mutex> l1(m1);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+    // CHECK-FIXES: std::scoped_lock l1(m1);
+  }
+
+  for (int i = 0; i < 10; ++i) {
+    std::lock_guard<std::mutex> l1(m1);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+    // CHECK-FIXES: std::scoped_lock l1(m1);
+  }
+}
+
+template <typename T>
+void PositiveTemplated() {
+  std::mutex m1, m2, m3;
+  {
+    std::lock_guard<std::mutex> l(m1);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+    // CHECK-FIXES: std::scoped_lock l(m1);
+  }
+
+  {
+    std::lock_guard<std::mutex> l1(m1);
+    std::lock_guard<std::mutex> l2(m2);
+    // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use single 'std::scoped_lock' 
instead of multiple 'std::lock_guard'
+    // CHECK-MESSAGES: :[[@LINE-2]]:33: note: additional 'std::lock_guard' 
declared here
+  }
+
+  {
+    std::lock(m1, m2);
+    std::lock_guard<std::mutex> l1(m1, std::adopt_lock);
+    std::lock_guard<std::mutex> l2(m2, std::adopt_lock);
+    // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use single 'std::scoped_lock' 
instead of multiple 'std::lock_guard'
+    // CHECK-MESSAGES: :[[@LINE-2]]:33: note: additional 'std::lock_guard' 
declared here
+    int a = 0;
+    std::lock_guard<std::mutex> l3(m3);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+    // CHECK-FIXES: std::scoped_lock l3(m3);
+  }
+}
+
+template <typename Mutex>
+void PositiveTemplatedMutex() {
+  Mutex m1, m2, m3;
+  {
+    std::lock_guard<Mutex> l(m1);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+  }
+
+  {
+    std::lock_guard<Mutex> l1(m1);
+    std::lock_guard<Mutex> l2(m2);
+    // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use single 'std::scoped_lock' 
instead of multiple 'std::lock_guard'
+    // CHECK-MESSAGES: :[[@LINE-2]]:28: note: additional 'std::lock_guard' 
declared here
+  }
+
+  {
+    std::lock(m1, m2);
+    std::lock_guard<Mutex> l1(m1, std::adopt_lock);
+    std::lock_guard<Mutex> l2(m2, std::adopt_lock);
+    // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use single 'std::scoped_lock' 
instead of multiple 'std::lock_guard'
+    // CHECK-MESSAGES: :[[@LINE-2]]:28: note: additional 'std::lock_guard' 
declared here
+    int a = 0;
+    std::lock_guard<Mutex> l3(m3);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+  }
+}
+
+template <template <typename> typename Lock>
+void NegativeTemplate() {
+  std::mutex m1, m2;
+  {
+    Lock<std::mutex> l(m1);
+  }
+
+  {
+    Lock<std::mutex> l1(m1);
+    Lock<std::mutex> l2(m2);
+  }
+}
+
+void instantiate() {
+  NegativeTemplate<std::lock_guard>();
+}
+
+struct PositiveClass {
+  void Positive() {
+    {
+      std::lock_guard<std::mutex> l(m1);
+      // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use 'std::scoped_lock' 
instead of 'std::lock_guard'
+      // CHECK-FIXES: std::scoped_lock l(m1);
+    }
+
+    {
+      std::lock_guard<std::mutex> l1(m1);
+      std::lock_guard<std::mutex> l2(m2);
+      // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: use single 
'std::scoped_lock' instead of multiple 'std::lock_guard'
+      // CHECK-MESSAGES: :[[@LINE-2]]:35: note: additional 'std::lock_guard' 
declared here
+    }
+
+    {
+      std::lock(m1, m2);  
+      std::lock_guard<std::mutex> l1(m1, std::adopt_lock);
+      std::lock_guard<std::mutex> l2(m2, std::adopt_lock);
+      // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: use single 
'std::scoped_lock' instead of multiple 'std::lock_guard'
+      // CHECK-MESSAGES: :[[@LINE-2]]:35: note: additional 'std::lock_guard' 
declared here
+      int a = 0;
+      std::lock_guard<std::mutex> l3(m3);
+      // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use 'std::scoped_lock' 
instead of 'std::lock_guard'
+      // CHECK-FIXES: std::scoped_lock l3(m3);
+    }
+  }
+  
+  std::mutex m1;
+  std::mutex m2;
+  std::mutex m3;
+};
+
+template <typename T>
+struct PositiveTemplatedClass {
+  void Positive() {
+    {
+      std::lock_guard<std::mutex> l(m1);
+      // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use 'std::scoped_lock' 
instead of 'std::lock_guard'
+      // CHECK-FIXES: std::scoped_lock l(m1);
+    }
+
+    {
+      std::lock(m1, m2);  
+      std::lock_guard<std::mutex> l1(m1, std::adopt_lock);
+      std::lock_guard<std::mutex> l2(m2, std::adopt_lock);
+      // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: use single 
'std::scoped_lock' instead of multiple 'std::lock_guard'
+      // CHECK-MESSAGES: :[[@LINE-2]]:35: note: additional 'std::lock_guard' 
declared here
+      int a = 0;
+      std::lock_guard<std::mutex> l3(m3);
+      // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use 'std::scoped_lock' 
instead of 'std::lock_guard'
+      // CHECK-FIXES: std::scoped_lock l3(m3);
+    }
+  }
+
+  template <typename... Ts>
+  void TemplatedPositive() {
+    {
+      std::lock_guard<std::mutex> l(m1);
+      // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use 'std::scoped_lock' 
instead of 'std::lock_guard'
+      // CHECK-FIXES: std::scoped_lock l(m1);
+    }
+
+    {
+      std::lock(m1, m2);  
+      std::lock_guard<std::mutex> l1(m1, std::adopt_lock);
+      std::lock_guard<std::mutex> l2(m2, std::adopt_lock);
+      // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: use single 
'std::scoped_lock' instead of multiple 'std::lock_guard'
+      // CHECK-MESSAGES: :[[@LINE-2]]:35: note: additional 'std::lock_guard' 
declared here
+      int a = 0;
+      std::lock_guard<std::mutex> l3(m3);
+      // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use 'std::scoped_lock' 
instead of 'std::lock_guard'
+      // CHECK-FIXES: std::scoped_lock l3(m3);
+    }
+  }
+  
+  std::mutex m1;
+  std::mutex m2;
+  std::mutex m3;
+};
+
+template <typename T>
+using Lock = std::lock_guard<T>;
+using LockM = std::lock_guard<std::mutex>;
+typedef std::lock_guard<std::mutex> LockDef;
+
+void NegativeUsingTypedefs() {
+  std::mutex m;
+
+  {
+    Lock<std::mutex> l(m);
+  }
+
+  {
+    LockM l(m);
+  }
+
+  {
+    LockDef l(m);
+  }
+}

>From 068c9217436b963a0ce3fa7251e1d52e088ba73b Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2...@gmail.com>
Date: Mon, 10 Feb 2025 13:42:12 +0300
Subject: [PATCH 2/7] [clang-tidy] feat: add more tests for
 modernize-use-lock-guard

---
 .../checkers/modernize/use-scoped-lock.cpp    | 45 ++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp
index 87ccdf1b04227..dae0b72076d4b 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp
@@ -73,8 +73,44 @@ void Positive() {
     std::lock_guard<std::mutex> l4(m, std::adopt_lock);
     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
     // CHECK-FIXES: std::scoped_lock l4(std::adopt_lock, m);
+  } 
+}
+
+
+std::mutex p_m1;
+void PositiveShortFunction() {
+  std::lock_guard<std::mutex> l(p_m1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+  // CHECK-FIXES: std::scoped_lock l(p_m1);
+}
+
+
+void PositiveNested() {
+  std::mutex m1;
+  if (true) {
+    std::lock_guard<std::mutex> l(m1);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+    // CHECK-FIXES: std::scoped_lock l(m1);
+    {
+      std::lock_guard<std::mutex> l2(m1);
+      // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use 'std::scoped_lock' 
instead of 'std::lock_guard'
+      // CHECK-FIXES: std::scoped_lock l2(m1);
+      {
+        std::lock_guard<std::mutex> l3(m1);
+        std::lock_guard<std::mutex> l4(m1);
+        // CHECK-MESSAGES: :[[@LINE-2]]:9: warning: use single 
'std::scoped_lock' instead of multiple 'std::lock_guard'
+        // CHECK-MESSAGES: :[[@LINE-2]]:37: note: additional 'std::lock_guard' 
declared here
+      }
+      {
+        std::lock_guard<std::mutex> l2(m1);
+        // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use 'std::scoped_lock' 
instead of 'std::lock_guard'
+        // CHECK-FIXES: std::scoped_lock l2(m1);
+      }
+    }
   }
-  
+  std::lock_guard<std::mutex> l(m1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+  // CHECK-FIXES: std::scoped_lock l(m1);
 }
 
 
@@ -89,6 +125,7 @@ void PositiveInsideArg(std::mutex &m1, std::mutex &m2, 
std::mutex &m3) {
   // CHECK-FIXES: std::scoped_lock l3(m3);
 }
 
+
 void PositiveInsideConditional() {
   std::mutex m1;
   if (true) {
@@ -114,6 +151,7 @@ void PositiveInsideConditional() {
   }
 }
 
+
 template <typename T>
 void PositiveTemplated() {
   std::mutex m1, m2, m3;
@@ -143,6 +181,7 @@ void PositiveTemplated() {
   }
 }
 
+
 template <typename Mutex>
 void PositiveTemplatedMutex() {
   Mutex m1, m2, m3;
@@ -170,6 +209,7 @@ void PositiveTemplatedMutex() {
   }
 }
 
+
 template <template <typename> typename Lock>
 void NegativeTemplate() {
   std::mutex m1, m2;
@@ -187,6 +227,7 @@ void instantiate() {
   NegativeTemplate<std::lock_guard>();
 }
 
+
 struct PositiveClass {
   void Positive() {
     {
@@ -220,6 +261,7 @@ struct PositiveClass {
   std::mutex m3;
 };
 
+
 template <typename T>
 struct PositiveTemplatedClass {
   void Positive() {
@@ -268,6 +310,7 @@ struct PositiveTemplatedClass {
   std::mutex m3;
 };
 
+
 template <typename T>
 using Lock = std::lock_guard<T>;
 using LockM = std::lock_guard<std::mutex>;

>From 7c5c295111824b2a95b6a1412a2a8c2c7b5550d2 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2...@gmail.com>
Date: Mon, 10 Feb 2025 20:32:49 +0300
Subject: [PATCH 3/7] [clang-tidy] removed auto's and added
 no-delayed-template-parsing

---
 .../modernize/UseScopedLockCheck.cpp          | 27 +++++++++----------
 .../use-scoped-lock-only-warn-on-multiple.cpp |  2 +-
 .../checkers/modernize/use-scoped-lock.cpp    |  2 +-
 3 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
index af2fea5ad310e..5d8ece18865a2 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
@@ -26,17 +26,17 @@ namespace clang::tidy::modernize {
 namespace {
 
 bool isLockGuard(const QualType &Type) {
-  if (const auto *RecordTy = Type->getAs<RecordType>()) {
-    if (const auto *RecordDecl = RecordTy->getDecl()) {
-      return RecordDecl->getQualifiedNameAsString() == "std::lock_guard";
+  if (const auto *Record = Type->getAs<RecordType>()) {
+    if (const RecordDecl *Decl = Record->getDecl()) {
+      return Decl->getQualifiedNameAsString() == "std::lock_guard";
     }
   }
 
   if (const auto *TemplateSpecType =
           Type->getAs<TemplateSpecializationType>()) {
-    if (const auto *TemplateDecl =
+    if (const TemplateDecl *Decl =
             TemplateSpecType->getTemplateName().getAsTemplateDecl()) {
-      return TemplateDecl->getQualifiedNameAsString() == "std::lock_guard";
+      return Decl->getQualifiedNameAsString() == "std::lock_guard";
     }
   }
 
@@ -46,7 +46,7 @@ bool isLockGuard(const QualType &Type) {
 std::vector<const VarDecl *> getLockGuardsFromDecl(const DeclStmt *DS) {
   std::vector<const VarDecl *> LockGuards;
 
-  for (const auto *Decl : DS->decls()) {
+  for (const Decl *Decl : DS->decls()) {
     if (const auto *VD = dyn_cast<VarDecl>(Decl)) {
       const QualType Type = VD->getType().getCanonicalType();
       if (isLockGuard(Type)) {
@@ -74,7 +74,7 @@ findLocksInCompoundStmt(const CompoundStmt *Block,
     }
   };
 
-  for (const auto *Stmt : Block->body()) {
+  for (const Stmt *Stmt : Block->body()) {
     if (const auto *DS = dyn_cast<DeclStmt>(Stmt)) {
       std::vector<const VarDecl *> LockGuards = getLockGuardsFromDecl(DS);
 
@@ -101,10 +101,10 @@ findLocksInCompoundStmt(const CompoundStmt *Block,
 // Find the exact source range of the 'lock_guard<...>' token
 std::optional<SourceRange> getLockGuardRange(const VarDecl *LockGuard,
                                              SourceManager &SM) {
-  const auto *SourceInfo = LockGuard->getTypeSourceInfo();
-  const auto TypeLoc = SourceInfo->getTypeLoc();
+  const TypeSourceInfo *SourceInfo = LockGuard->getTypeSourceInfo();
+  const TypeLoc Loc = SourceInfo->getTypeLoc();
 
-  const auto ElaboratedLoc = TypeLoc.getAs<ElaboratedTypeLoc>();
+  const auto ElaboratedLoc = Loc.getAs<ElaboratedTypeLoc>();
   if (!ElaboratedLoc)
     return std::nullopt;
 
@@ -187,7 +187,7 @@ void UseScopedLockCheck::emitDiag(const VarDecl *LockGuard,
                                          "scoped_lock");
     return;
   case 2:
-    const auto *CtorArgs = CtorCall->getArgs();
+    const Expr *const *CtorArgs = CtorCall->getArgs();
 
     const Expr *MutexArg = CtorArgs[0];
     const Expr *AdoptLockArg = CtorArgs[1];
@@ -202,8 +202,7 @@ void UseScopedLockCheck::emitDiag(const VarDecl *LockGuard,
     Diag << FixItHint::CreateReplacement(LockGuardTypeRange.value(),
                                          "scoped_lock")
          << FixItHint::CreateReplacement(
-                SourceRange(CtorArgs[0]->getBeginLoc(),
-                            CtorArgs[1]->getEndLoc()),
+                SourceRange(MutexArg->getBeginLoc(), 
AdoptLockArg->getEndLoc()),
                 (llvm::Twine(AdoptLockSourceText) + ", " + MutexSourceText)
                     .str());
     return;
@@ -215,7 +214,7 @@ void UseScopedLockCheck::emitDiag(const VarDecl *LockGuard,
 void UseScopedLockCheck::emitDiag(
     const std::vector<std::vector<const VarDecl *>> &LockGuardGroups,
     const MatchFinder::MatchResult &Result) {
-  for (const auto &Group : LockGuardGroups) {
+  for (const std::vector<const VarDecl *> &Group : LockGuardGroups) {
     if (Group.size() == 1 && !WarnOnlyMultipleLocks) {
       emitDiag(Group[0], Result);
     } else {
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
index 6d46e43bc2be4..2def300cad22c 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
@@ -1,5 +1,5 @@
 // RUN: %check_clang_tidy -std=c++17-or-later %s modernize-use-scoped-lock %t 
-- \
-// RUN:   -config="{CheckOptions: 
{modernize-use-scoped-lock.WarnOnlyMultipleLocks: true}}"
+// RUN:   -config="{CheckOptions: 
{modernize-use-scoped-lock.WarnOnlyMultipleLocks: true}} -- -- 
-fno-delayed-template-parsing"
 
 namespace std {
 
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp
index dae0b72076d4b..d7193b999a483 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy -std=c++17-or-later %s modernize-use-scoped-lock %t
+// RUN: %check_clang_tidy -std=c++17-or-later %s modernize-use-scoped-lock %t 
-- -- -fno-delayed-template-parsing
 
 namespace std {
 

>From b4dcae8dab7e8ad282c7a8d89123f352208f9109 Mon Sep 17 00:00:00 2001
From: baranov-V-V <bar.victor.2...@gmail.com>
Date: Wed, 12 Feb 2025 02:59:09 +0300
Subject: [PATCH 4/7] [clang-tidy] added fno-delayed-template-parsing to fix
 WIN tests

---
 .../modernize/use-scoped-lock-only-warn-on-multiple.cpp        | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
index 2def300cad22c..2948aaed4f7c5 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
@@ -1,5 +1,6 @@
 // RUN: %check_clang_tidy -std=c++17-or-later %s modernize-use-scoped-lock %t 
-- \
-// RUN:   -config="{CheckOptions: 
{modernize-use-scoped-lock.WarnOnlyMultipleLocks: true}} -- -- 
-fno-delayed-template-parsing"
+// RUN:   -config="{CheckOptions: 
{modernize-use-scoped-lock.WarnOnlyMultipleLocks: true}}" \
+// RUN:   -- -fno-delayed-template-parsing
 
 namespace std {
 

>From e6b587ac00bd379df7ecae9b3df3f3673a73b426 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2...@gmail.com>
Date: Thu, 13 Feb 2025 01:33:48 +0300
Subject: [PATCH 5/7] [clang-tidy] fix pr comments and add
 WarnOnUsingAndTypedefs

---
 .../modernize/UseScopedLockCheck.cpp          | 193 +++++++++++++-----
 .../clang-tidy/modernize/UseScopedLockCheck.h |  16 +-
 clang-tools-extra/docs/ReleaseNotes.rst       |   4 +-
 .../checks/modernize/use-scoped-lock.rst      |  48 +++--
 ...e-lock-warn-on-using-and-typedef-false.cpp |  57 ++++++
 .../use-scoped-lock-only-warn-on-multiple.cpp |   2 +-
 .../checkers/modernize/use-scoped-lock.cpp    |  61 ++++++
 7 files changed, 305 insertions(+), 76 deletions(-)
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/modernize/use-scope-lock-warn-on-using-and-typedef-false.cpp

diff --git a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
index 5d8ece18865a2..ecde9f24d4d20 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
@@ -15,9 +15,9 @@
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Lex/Lexer.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/Twine.h"
 #include <iterator>
-#include <optional>
 
 using namespace clang::ast_matchers;
 
@@ -28,7 +28,7 @@ namespace {
 bool isLockGuard(const QualType &Type) {
   if (const auto *Record = Type->getAs<RecordType>()) {
     if (const RecordDecl *Decl = Record->getDecl()) {
-      return Decl->getQualifiedNameAsString() == "std::lock_guard";
+      return Decl->getName() == "lock_guard" && Decl->isInStdNamespace();
     }
   }
 
@@ -36,15 +36,15 @@ bool isLockGuard(const QualType &Type) {
           Type->getAs<TemplateSpecializationType>()) {
     if (const TemplateDecl *Decl =
             TemplateSpecType->getTemplateName().getAsTemplateDecl()) {
-      return Decl->getQualifiedNameAsString() == "std::lock_guard";
+      return Decl->getName() == "lock_guard" && Decl->isInStdNamespace();
     }
   }
 
   return false;
 }
 
-std::vector<const VarDecl *> getLockGuardsFromDecl(const DeclStmt *DS) {
-  std::vector<const VarDecl *> LockGuards;
+llvm::SmallVector<const VarDecl *> getLockGuardsFromDecl(const DeclStmt *DS) {
+  llvm::SmallVector<const VarDecl *> LockGuards;
 
   for (const Decl *Decl : DS->decls()) {
     if (const auto *VD = dyn_cast<VarDecl>(Decl)) {
@@ -60,12 +60,12 @@ std::vector<const VarDecl *> getLockGuardsFromDecl(const 
DeclStmt *DS) {
 
 // Scans through the statements in a block and groups consecutive
 // 'std::lock_guard' variable declarations together.
-std::vector<std::vector<const VarDecl *>>
+llvm::SmallVector<llvm::SmallVector<const VarDecl *>>
 findLocksInCompoundStmt(const CompoundStmt *Block,
                         const ast_matchers::MatchFinder::MatchResult &Result) {
   // store groups of consecutive 'std::lock_guard' declarations
-  std::vector<std::vector<const VarDecl *>> LockGuardGroups;
-  std::vector<const VarDecl *> CurrentLockGuardGroup;
+  llvm::SmallVector<llvm::SmallVector<const VarDecl *>> LockGuardGroups;
+  llvm::SmallVector<const VarDecl *> CurrentLockGuardGroup;
 
   auto AddAndClearCurrentGroup = [&]() {
     if (!CurrentLockGuardGroup.empty()) {
@@ -76,21 +76,17 @@ findLocksInCompoundStmt(const CompoundStmt *Block,
 
   for (const Stmt *Stmt : Block->body()) {
     if (const auto *DS = dyn_cast<DeclStmt>(Stmt)) {
-      std::vector<const VarDecl *> LockGuards = getLockGuardsFromDecl(DS);
+      llvm::SmallVector<const VarDecl *> LockGuards = 
getLockGuardsFromDecl(DS);
 
       if (!LockGuards.empty()) {
         CurrentLockGuardGroup.insert(
             CurrentLockGuardGroup.end(),
             std::make_move_iterator(LockGuards.begin()),
             std::make_move_iterator(LockGuards.end()));
+        continue;
       }
-
-      if (LockGuards.empty()) {
-        AddAndClearCurrentGroup();
-      }
-    } else {
-      AddAndClearCurrentGroup();
     }
+    AddAndClearCurrentGroup();
   }
 
   AddAndClearCurrentGroup();
@@ -98,43 +94,65 @@ findLocksInCompoundStmt(const CompoundStmt *Block,
   return LockGuardGroups;
 }
 
-// Find the exact source range of the 'lock_guard<...>' token
-std::optional<SourceRange> getLockGuardRange(const VarDecl *LockGuard,
-                                             SourceManager &SM) {
-  const TypeSourceInfo *SourceInfo = LockGuard->getTypeSourceInfo();
+TemplateSpecializationTypeLoc
+getTemplateSpecializationTypeLoc(const TypeSourceInfo *SourceInfo) {
   const TypeLoc Loc = SourceInfo->getTypeLoc();
 
   const auto ElaboratedLoc = Loc.getAs<ElaboratedTypeLoc>();
   if (!ElaboratedLoc)
-    return std::nullopt;
+    return {};
+
+  return 
ElaboratedLoc.getNamedTypeLoc().getAs<TemplateSpecializationTypeLoc>();
+}
 
-  const auto TemplateLoc =
-      ElaboratedLoc.getNamedTypeLoc().getAs<TemplateSpecializationTypeLoc>();
+// Find the exact source range of the 'lock_guard<...>' token
+SourceRange getLockGuardTemplateRange(const TypeSourceInfo *SourceInfo) {
+  const TemplateSpecializationTypeLoc TemplateLoc =
+      getTemplateSpecializationTypeLoc(SourceInfo);
   if (!TemplateLoc)
-    return std::nullopt;
+    return {};
 
-  const SourceLocation LockGuardBeginLoc = TemplateLoc.getTemplateNameLoc();
-  const SourceLocation LockGuardRAngleLoc = TemplateLoc.getRAngleLoc();
+  return SourceRange(TemplateLoc.getTemplateNameLoc(),
+                     TemplateLoc.getRAngleLoc());
+}
 
-  return SourceRange(LockGuardBeginLoc, LockGuardRAngleLoc);
+SourceRange getLockGuardRange(const TypeSourceInfo *SourceInfo) {
+  const TemplateSpecializationTypeLoc TemplateLoc =
+      getTemplateSpecializationTypeLoc(SourceInfo);
+  if (!TemplateLoc)
+    return {};
+
+  return SourceRange(TemplateLoc.getTemplateNameLoc(),
+                     TemplateLoc.getLAngleLoc().getLocWithOffset(-1));
 }
 
+const StringRef UseScopedLockMessage =
+    "use 'std::scoped_lock' instead of 'std::lock_guard'";
+
 } // namespace
 
+UseScopedLockCheck::UseScopedLockCheck(StringRef Name,
+                                       ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      WarnOnlyOnMultipleLocks(Options.get("WarnOnlyOnMultipleLocks", false)),
+      WarnOnUsingAndTypedef(Options.get("WarnOnUsingAndTypedef", true)) {}
+
 void UseScopedLockCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
-  Options.store(Opts, "WarnOnlyMultipleLocks", WarnOnlyMultipleLocks);
+  Options.store(Opts, "WarnOnlyMultipleLocks", WarnOnlyOnMultipleLocks);
 }
 
 void UseScopedLockCheck::registerMatchers(MatchFinder *Finder) {
-  auto LockGuardType = qualType(hasDeclaration(namedDecl(
-      hasName("::std::lock_guard"),
-      anyOf(classTemplateDecl(), classTemplateSpecializationDecl()))));
+  auto LockGuardClassDecl =
+      namedDecl(anyOf(classTemplateDecl(), classTemplateSpecializationDecl()),
+                hasName("::std::lock_guard"));
+  auto LockGuardType = qualType(hasDeclaration(LockGuardClassDecl));
   auto LockVarDecl = varDecl(hasType(LockGuardType));
 
   // Match CompoundStmt with only one 'std::lock_guard'
-  if (!WarnOnlyMultipleLocks) {
+  if (!WarnOnlyOnMultipleLocks) {
     Finder->addMatcher(
-        compoundStmt(has(declStmt(has(LockVarDecl.bind("lock-decl-single")))),
+        compoundStmt(unless(isExpansionInSystemHeader()),
+                     has(declStmt(has(LockVarDecl.bind("lock-decl-single")))),
                      unless(hasDescendant(declStmt(has(varDecl(
                          hasType(LockGuardType),
                          unless(equalsBoundNode("lock-decl-single")))))))),
@@ -143,50 +161,94 @@ void UseScopedLockCheck::registerMatchers(MatchFinder 
*Finder) {
 
   // Match CompoundStmt with multiple 'std::lock_guard'
   Finder->addMatcher(
-      compoundStmt(has(declStmt(has(LockVarDecl.bind("lock-decl-multiple")))),
+      compoundStmt(unless(isExpansionInSystemHeader()),
+                   has(declStmt(has(LockVarDecl.bind("lock-decl-multiple")))),
                    hasDescendant(declStmt(has(varDecl(
                        hasType(LockGuardType),
                        unless(equalsBoundNode("lock-decl-multiple")))))))
           .bind("block-multiple"),
       this);
+
+  if (WarnOnUsingAndTypedef) {
+    // Match 'typedef std::lock_guard<std::mutex> Lock'
+    Finder->addMatcher(typedefDecl(unless(isExpansionInSystemHeader()),
+                                   hasUnderlyingType(LockGuardType))
+                           .bind("lock-guard-typedef"),
+                       this);
+
+    // Match 'using Lock = std::lock_guard<std::mutex>'
+    Finder->addMatcher(
+        typeAliasDecl(
+            unless(isExpansionInSystemHeader()),
+            hasType(elaboratedType(namesType(templateSpecializationType(
+                hasDeclaration(LockGuardClassDecl))))))
+            .bind("lock-guard-using-alias"),
+        this);
+
+    // Match 'using std::lock_guard'
+    Finder->addMatcher(
+        usingDecl(unless(isExpansionInSystemHeader()),
+                  hasAnyUsingShadowDecl(hasTargetDecl(
+                      namedDecl(hasName("lock_guard"), isInStdNamespace()))))
+            .bind("lock-guard-using-decl"),
+        this);
+  }
 }
 
 void UseScopedLockCheck::check(const MatchFinder::MatchResult &Result) {
   if (const auto *Decl = Result.Nodes.getNodeAs<VarDecl>("lock-decl-single")) {
     emitDiag(Decl, Result);
+    return;
   }
 
   if (const auto *Compound =
           Result.Nodes.getNodeAs<CompoundStmt>("block-multiple")) {
     emitDiag(findLocksInCompoundStmt(Compound, Result), Result);
+    return;
+  }
+
+  if (const auto *Typedef =
+          Result.Nodes.getNodeAs<TypedefDecl>("lock-guard-typedef")) {
+    emitDiag(Typedef->getTypeSourceInfo(), Result);
+    return;
+  }
+
+  if (const auto *UsingAlias =
+          Result.Nodes.getNodeAs<TypeAliasDecl>("lock-guard-using-alias")) {
+    emitDiag(UsingAlias->getTypeSourceInfo(), Result);
+    return;
+  }
+
+  if (const auto *Using =
+          Result.Nodes.getNodeAs<UsingDecl>("lock-guard-using-decl")) {
+    emitDiag(Using, Result);
   }
 }
 
 void UseScopedLockCheck::emitDiag(const VarDecl *LockGuard,
                                   const MatchFinder::MatchResult &Result) {
-  auto Diag = diag(LockGuard->getBeginLoc(),
-                   "use 'std::scoped_lock' instead of 'std::lock_guard'");
+  auto Diag = diag(LockGuard->getBeginLoc(), UseScopedLockMessage);
 
-  const std::optional<SourceRange> LockGuardTypeRange =
-      getLockGuardRange(LockGuard, *Result.SourceManager);
+  const SourceRange LockGuardTypeRange =
+      getLockGuardTemplateRange(LockGuard->getTypeSourceInfo());
 
-  if (!LockGuardTypeRange) {
+  if (LockGuardTypeRange.isInvalid()) {
     return;
   }
 
-  // Create Fix-its only if we can find the constructor call to handle
-  // 'std::lock_guard l(m, std::adopt_lock)' case
+  // Create Fix-its only if we can find the constructor call to properly handle
+  // 'std::lock_guard l(m, std::adopt_lock)' case. Otherwise create fix-notes.
   const auto *CtorCall = dyn_cast<CXXConstructExpr>(LockGuard->getInit());
   if (!CtorCall) {
     return;
   }
 
-  switch (CtorCall->getNumArgs()) {
-  case 1:
-    Diag << FixItHint::CreateReplacement(LockGuardTypeRange.value(),
-                                         "scoped_lock");
+  if (CtorCall->getNumArgs() == 1) {
+    Diag << FixItHint::CreateReplacement(LockGuardTypeRange, "scoped_lock");
     return;
-  case 2:
+  }
+
+  if (CtorCall->getNumArgs() == 2) {
     const Expr *const *CtorArgs = CtorCall->getArgs();
 
     const Expr *MutexArg = CtorArgs[0];
@@ -199,8 +261,7 @@ void UseScopedLockCheck::emitDiag(const VarDecl *LockGuard,
         CharSourceRange::getTokenRange(AdoptLockArg->getSourceRange()),
         *Result.SourceManager, Result.Context->getLangOpts());
 
-    Diag << FixItHint::CreateReplacement(LockGuardTypeRange.value(),
-                                         "scoped_lock")
+    Diag << FixItHint::CreateReplacement(LockGuardTypeRange, "scoped_lock")
          << FixItHint::CreateReplacement(
                 SourceRange(MutexArg->getBeginLoc(), 
AdoptLockArg->getEndLoc()),
                 (llvm::Twine(AdoptLockSourceText) + ", " + MutexSourceText)
@@ -212,22 +273,46 @@ void UseScopedLockCheck::emitDiag(const VarDecl 
*LockGuard,
 }
 
 void UseScopedLockCheck::emitDiag(
-    const std::vector<std::vector<const VarDecl *>> &LockGuardGroups,
-    const MatchFinder::MatchResult &Result) {
-  for (const std::vector<const VarDecl *> &Group : LockGuardGroups) {
-    if (Group.size() == 1 && !WarnOnlyMultipleLocks) {
+    const llvm::SmallVector<llvm::SmallVector<const VarDecl *>> &LockGroups,
+    const ast_matchers::MatchFinder::MatchResult &Result) {
+  for (const llvm::SmallVector<const VarDecl *> &Group : LockGroups) {
+    if (Group.size() == 1 && !WarnOnlyOnMultipleLocks) {
       emitDiag(Group[0], Result);
     } else {
       diag(Group[0]->getBeginLoc(),
            "use single 'std::scoped_lock' instead of multiple "
            "'std::lock_guard'");
 
-      for (size_t I = 1; I < Group.size(); ++I) {
-        diag(Group[I]->getLocation(),
-             "additional 'std::lock_guard' declared here", 
DiagnosticIDs::Note);
+      for (const VarDecl *Lock : llvm::drop_begin(Group)) {
+        diag(Lock->getLocation(), "additional 'std::lock_guard' declared here",
+             DiagnosticIDs::Note);
       }
     }
   }
 }
 
+void UseScopedLockCheck::emitDiag(
+    const TypeSourceInfo *LockGuardSourceInfo,
+    const ast_matchers::MatchFinder::MatchResult &Result) {
+  const TypeLoc TL = LockGuardSourceInfo->getTypeLoc();
+
+  if (const auto ElaboratedTL = TL.getAs<ElaboratedTypeLoc>()) {
+    auto Diag = diag(ElaboratedTL.getBeginLoc(), UseScopedLockMessage);
+
+    const SourceRange LockGuardRange = getLockGuardRange(LockGuardSourceInfo);
+    if (LockGuardRange.isInvalid()) {
+      return;
+    }
+
+    Diag << FixItHint::CreateReplacement(LockGuardRange, "scoped_lock");
+  }
+}
+
+void UseScopedLockCheck::emitDiag(
+    const UsingDecl *UsingDecl,
+    const ast_matchers::MatchFinder::MatchResult &Result) {
+  diag(UsingDecl->getLocation(), UseScopedLockMessage)
+      << FixItHint::CreateReplacement(UsingDecl->getLocation(), "scoped_lock");
+}
+
 } // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.h 
b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.h
index 0e1fd8067ddd1..0091939eaef3a 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.h
+++ b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.h
@@ -17,15 +17,13 @@
 namespace clang::tidy::modernize {
 
 /// Finds uses of ``std::lock_guard`` and suggests replacing them with C++17's
-/// more flexible and safer alternative ``std::scoped_lock``.
+/// alternative ``std::scoped_lock``.
 ///
 /// For the user-facing documentation see:
 /// 
http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-scoped-lock.html
 class UseScopedLockCheck : public ClangTidyCheck {
 public:
-  UseScopedLockCheck(StringRef Name, ClangTidyContext *Context)
-      : ClangTidyCheck(Name, Context),
-        WarnOnlyMultipleLocks(Options.get("WarnOnlyMultipleLocks", false)) {}
+  UseScopedLockCheck(StringRef Name, ClangTidyContext *Context);
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
@@ -39,10 +37,16 @@ class UseScopedLockCheck : public ClangTidyCheck {
 private:
   void emitDiag(const VarDecl *LockGuard,
                 const ast_matchers::MatchFinder::MatchResult &Result);
-  void emitDiag(const std::vector<std::vector<const VarDecl *>> &LockGroups,
+  void emitDiag(
+      const llvm::SmallVector<llvm::SmallVector<const VarDecl *>> &LockGroups,
+      const ast_matchers::MatchFinder::MatchResult &Result);
+  void emitDiag(const TypeSourceInfo *LockGuardSourceInfo,
+                const ast_matchers::MatchFinder::MatchResult &Result);
+  void emitDiag(const UsingDecl *UsingDecl,
                 const ast_matchers::MatchFinder::MatchResult &Result);
 
-  const bool WarnOnlyMultipleLocks;
+  const bool WarnOnlyOnMultipleLocks;
+  const bool WarnOnUsingAndTypedef;
 };
 
 } // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 6aefbc4737276..192d185fb9677 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -91,11 +91,11 @@ Improvements to clang-tidy
 New checks
 ^^^^^^^^^^
 
-- New :doc:`use-scoped-lock
+- New :doc:`modernize-use-scoped-lock
   <clang-tidy/checks/modernize/use-scoped-lock>` check.
 
   Finds uses of ``std::lock_guard`` and suggests replacing them with C++17's
-  more flexible and safer alternative ``std::scoped_lock``.
+  alternative ``std::scoped_lock``.
 
 New check aliases
 ^^^^^^^^^^^^^^^^^
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-scoped-lock.rst 
b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-scoped-lock.rst
index 04b35d0081b3c..cb0a0737a7f02 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-scoped-lock.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-scoped-lock.rst
@@ -3,11 +3,13 @@
 modernize-use-scoped-lock
 =========================
 
-Finds uses of ``std::lock_guard`` and suggests replacing them with C++17's more
-flexible and safer alternative ``std::scoped_lock``. The check will
-automatically transform only single declarations of ``std::lock_guard`` and
-emit warnings for multiple declarations of ``std::lock_guard`` that can be
-replaced with a single declaration of ``std::scoped_lock``.
+Finds uses of ``std::lock_guard`` and suggests replacing them with C++17's
+alternative ``std::scoped_lock``. ``std::scoped_lock`` is a superior version
+of ``std::lock_guard`` that can lock multiple mutexes at once with
+deadlock-avoidance algorithm. The check will automatically transform only
+single declarations of ``std::lock_guard`` and emit warnings for multiple
+declarations of ``std::lock_guard`` that can be replaced with a single
+declaration of ``std::scoped_lock``.
 
 Examples
 --------
@@ -24,7 +26,7 @@ Transforms to:
 
 .. code-block:: c++
 
-  std::mutex m;
+  std::mutex M;
   std::scoped_lock L(M);
 
 Single ``std::lock_guard`` declaration with ``std::adopt_lock``:
@@ -58,24 +60,44 @@ Limitations
 -----------
 
 The check will not emit warnings if ``std::lock_guard`` is used implicitly via
-``using``, ``typedef`` or ``template``.
+``using``, ``typedef`` or ``template``:
 
-.. code-block:: c
+.. code-block:: c++
 
   template <template <typename> typename Lock>
   void TemplatedLock() {
-    std::mutex m;
-    Lock<std::mutex> l(m); // no warning
+    std::mutex M;
+    Lock<std::mutex> L(M); // no warning
   }
 
   void UsingLock() {
     using Lock = std::lock_guard<std::mutex>;
-    std::mutex m;
-    Lock l(m); // no warning
+    std::mutex M;
+    Lock L(M); // no warning
   }
 
-.. option:: WarnOnlyMultipleLocks
+
+Options
+-------
+
+.. option:: WarnOnlyOnMultipleLocks
 
   When `true`, the check will only emit warnings if the there are multiple
   consecutive ``std::lock_guard`` declarations that can be replaced with a
   single ``std::scoped_lock`` declaration. Default is `false`.
+
+.. option:: WarnOnUsingAndTypedef
+
+  When `true`, the check will emit warnings if ``std::lock_guard`` is used
+  in ``using`` or ``typedef`` declarations. Default is `true`.
+
+  .. code-block:: c++
+
+    template <typename T>
+    using Lock = std::lock_guard<T>; // warning
+    
+    using LockMutex = std::lock_guard<std::mutex>; // warning
+    
+    typedef std::lock_guard<std::mutex> LockDef; // warning
+
+    using std::lock_guard; // warning
\ No newline at end of file
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scope-lock-warn-on-using-and-typedef-false.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scope-lock-warn-on-using-and-typedef-false.cpp
new file mode 100644
index 0000000000000..ffa9445ffc580
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scope-lock-warn-on-using-and-typedef-false.cpp
@@ -0,0 +1,57 @@
+// RUN: %check_clang_tidy -std=c++17-or-later %s modernize-use-scoped-lock %t 
-- \
+// RUN:   -config="{CheckOptions: 
{modernize-use-scoped-lock.WarnOnUsingAndTypedef: false}}" \
+// RUN:   -- -fno-delayed-template-parsing
+
+namespace std {
+
+struct mutex {
+  void lock() {}
+  void unlock() {}
+};
+
+template<class Lockable1, class Lockable2, class... LockableN >
+void lock(Lockable1& lock1, Lockable2& lock2, LockableN&... lockn );
+
+struct adopt_lock_t { };
+std::adopt_lock_t adopt_lock {};
+
+template <typename Mutex>
+struct lock_guard {
+  lock_guard(Mutex &m) { }
+  lock_guard(Mutex &m, std::adopt_lock_t t) {}
+  lock_guard( const lock_guard& ) = delete;
+};
+
+template <typename... MutexTypes>
+struct scoped_lock {
+  scoped_lock(MutexTypes&... m) {}
+  scoped_lock(std::adopt_lock_t t, MutexTypes&... m) {}
+};
+
+} // namespace std
+
+template <typename T>
+using Lock = std::lock_guard<T>;
+
+using LockM = std::lock_guard<std::mutex>;
+
+typedef std::lock_guard<std::mutex> LockDef;
+
+void PositiveUsingDecl() {
+  using std::lock_guard;
+
+  using LockMFun = std::lock_guard<std::mutex>;
+  
+  typedef std::lock_guard<std::mutex> LockDefFun;
+}
+
+template <typename T>
+void PositiveUsingDeclTemplate() {
+  using std::lock_guard;
+
+  using LockFunT = std::lock_guard<T>;
+
+  using LockMFunT = std::lock_guard<std::mutex>;
+
+  typedef std::lock_guard<std::mutex> LockDefFunT;
+}
\ No newline at end of file
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
index 2948aaed4f7c5..bf92d4498b28e 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp
@@ -1,5 +1,5 @@
 // RUN: %check_clang_tidy -std=c++17-or-later %s modernize-use-scoped-lock %t 
-- \
-// RUN:   -config="{CheckOptions: 
{modernize-use-scoped-lock.WarnOnlyMultipleLocks: true}}" \
+// RUN:   -config="{CheckOptions: 
{modernize-use-scoped-lock.WarnOnlyOnMultipleLocks: true}}" \
 // RUN:   -- -fno-delayed-template-parsing
 
 namespace std {
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp
index d7193b999a483..32305f64c97d0 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp
@@ -313,8 +313,50 @@ struct PositiveTemplatedClass {
 
 template <typename T>
 using Lock = std::lock_guard<T>;
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use 'std::scoped_lock' instead of 
'std::lock_guard'
+// CHECK-FIXES: using Lock = std::scoped_lock<T>;
+
 using LockM = std::lock_guard<std::mutex>;
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use 'std::scoped_lock' instead of 
'std::lock_guard'
+// CHECK-FIXES: using LockM = std::scoped_lock<std::mutex>;
+
 typedef std::lock_guard<std::mutex> LockDef;
+// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use 'std::scoped_lock' instead of 
'std::lock_guard'
+// CHECK-FIXES: typedef std::scoped_lock<std::mutex> LockDef;
+
+
+void PositiveUsingDecl() {
+  using std::lock_guard;
+  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+  // CHECK-FIXES: using std::scoped_lock;
+
+  using LockMFun = std::lock_guard<std::mutex>;
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+  // CHECK-FIXES: using LockMFun = std::scoped_lock<std::mutex>;
+
+  typedef std::lock_guard<std::mutex> LockDefFun;
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+  // CHECK-FIXES: typedef std::scoped_lock<std::mutex> LockDefFun;
+}
+
+template <typename T>
+void PositiveUsingDeclTemplate() {
+  using std::lock_guard;
+  // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+  // CHECK-FIXES: using std::scoped_lock;
+
+  using LockFunT = std::lock_guard<T>;
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+  // CHECK-FIXES: using LockFunT = std::scoped_lock<T>;
+
+  using LockMFunT = std::lock_guard<std::mutex>;
+  // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+  // CHECK-FIXES: using LockMFunT = std::scoped_lock<std::mutex>;
+
+  typedef std::lock_guard<std::mutex> LockDefFunT;
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use 'std::scoped_lock' instead 
of 'std::lock_guard'
+  // CHECK-FIXES: typedef std::scoped_lock<std::mutex> LockDefFunT;
+}
 
 void NegativeUsingTypedefs() {
   std::mutex m;
@@ -331,3 +373,22 @@ void NegativeUsingTypedefs() {
     LockDef l(m);
   }
 }
+
+// Non-standard lock_guard.
+template <typename Mutex>
+struct lock_guard {
+  lock_guard(Mutex &m) { }
+  lock_guard(const lock_guard& ) = delete;
+};
+
+void NegativeNonStdLockGuard() {
+  std::mutex m;
+  {
+    lock_guard<std::mutex> l(m);
+  }
+
+  {
+    lock_guard<std::mutex> l1(m);
+    lock_guard<std::mutex> l2(m);
+  }
+}
\ No newline at end of file

>From a09f14b5d598d85833e6379249b1556da13a1091 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2...@gmail.com>
Date: Thu, 13 Feb 2025 01:39:38 +0300
Subject: [PATCH 6/7] [clang-tidy] small fixes to use-scoped-lock.rst

---
 .../docs/clang-tidy/checks/modernize/use-scoped-lock.rst      | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-scoped-lock.rst 
b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-scoped-lock.rst
index cb0a0737a7f02..0563d18e54d04 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-scoped-lock.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-scoped-lock.rst
@@ -4,9 +4,7 @@ modernize-use-scoped-lock
 =========================
 
 Finds uses of ``std::lock_guard`` and suggests replacing them with C++17's
-alternative ``std::scoped_lock``. ``std::scoped_lock`` is a superior version
-of ``std::lock_guard`` that can lock multiple mutexes at once with
-deadlock-avoidance algorithm. The check will automatically transform only
+alternative ``std::scoped_lock``. The check will automatically transform only
 single declarations of ``std::lock_guard`` and emit warnings for multiple
 declarations of ``std::lock_guard`` that can be replaced with a single
 declaration of ``std::scoped_lock``.

>From a4413911665143fcbea9c7c401dcb909a3c983c9 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2...@gmail.com>
Date: Fri, 14 Feb 2025 10:38:33 +0300
Subject: [PATCH 7/7] [clang-tidy] small improvements

---
 .../clang-tidy/modernize/UseScopedLockCheck.cpp      | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
index ecde9f24d4d20..f69db50be0439 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
@@ -95,7 +95,7 @@ findLocksInCompoundStmt(const CompoundStmt *Block,
 }
 
 TemplateSpecializationTypeLoc
-getTemplateSpecializationTypeLoc(const TypeSourceInfo *SourceInfo) {
+getTemplateLockGuardTypeLoc(const TypeSourceInfo *SourceInfo) {
   const TypeLoc Loc = SourceInfo->getTypeLoc();
 
   const auto ElaboratedLoc = Loc.getAs<ElaboratedTypeLoc>();
@@ -108,7 +108,7 @@ getTemplateSpecializationTypeLoc(const TypeSourceInfo 
*SourceInfo) {
 // Find the exact source range of the 'lock_guard<...>' token
 SourceRange getLockGuardTemplateRange(const TypeSourceInfo *SourceInfo) {
   const TemplateSpecializationTypeLoc TemplateLoc =
-      getTemplateSpecializationTypeLoc(SourceInfo);
+      getTemplateLockGuardTypeLoc(SourceInfo);
   if (!TemplateLoc)
     return {};
 
@@ -116,9 +116,10 @@ SourceRange getLockGuardTemplateRange(const TypeSourceInfo 
*SourceInfo) {
                      TemplateLoc.getRAngleLoc());
 }
 
+// Find the exact source range of the 'lock_guard' token
 SourceRange getLockGuardRange(const TypeSourceInfo *SourceInfo) {
   const TemplateSpecializationTypeLoc TemplateLoc =
-      getTemplateSpecializationTypeLoc(SourceInfo);
+      getTemplateLockGuardTypeLoc(SourceInfo);
   if (!TemplateLoc)
     return {};
 
@@ -144,7 +145,7 @@ void 
UseScopedLockCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
 void UseScopedLockCheck::registerMatchers(MatchFinder *Finder) {
   auto LockGuardClassDecl =
       namedDecl(anyOf(classTemplateDecl(), classTemplateSpecializationDecl()),
-                hasName("::std::lock_guard"));
+                hasName("lock_guard"), isInStdNamespace());
   auto LockGuardType = qualType(hasDeclaration(LockGuardClassDecl));
   auto LockVarDecl = varDecl(hasType(LockGuardType));
 
@@ -188,8 +189,7 @@ void UseScopedLockCheck::registerMatchers(MatchFinder 
*Finder) {
     // Match 'using std::lock_guard'
     Finder->addMatcher(
         usingDecl(unless(isExpansionInSystemHeader()),
-                  hasAnyUsingShadowDecl(hasTargetDecl(
-                      namedDecl(hasName("lock_guard"), isInStdNamespace()))))
+                  hasAnyUsingShadowDecl(hasTargetDecl(LockGuardClassDecl)))
             .bind("lock-guard-using-decl"),
         this);
   }

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

Reply via email to