[clang-tools-extra] [clang-tidy] add new modernize-use-scoped-lock check (PR #126434)

via cfe-commits cfe-commits at lists.llvm.org
Sun Feb 9 11:59:09 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-tools-extra

Author: Baranov Victor (vbvictor)

<details>
<summary>Changes</summary>

Add new clang-tidy that finds uses of `std::lock_guard` and suggests replacing them with C++17's more flexible and safer alternative `std::scoped_lock`.

Here is a small description of how it works for better understanding of the code:
Two separate AST matchers are registered:

- The first one matches declarations of `std::lock_guard` that are single in their scope (only one `std::lock_guard` in `CompoundStmt`). It's an easy case, we can emit warning right away.

- The second one matches `CompoundStmt`'s that have multiple `std::lock_guard` declarations, which means that we may have consecutive declarations of `std::lock_guard` that can be replaced by a single `std::scoped_lock`. In order to ensure that declarations are consecutive, we need to loop over `Stmt`'s in `CompoundStmt`. Here is a small example:
```cpp
{
  std::mutex m1, m2;
  std::lock(m1, m2);
  std::lock_guard<std::mutex> l1(m, std::adopt_lock); // first declaration of 'std::lock_guard'
  std::lock_guard<std::mutex> l2(m, std::adopt_lock); // second declaration of 'std::lock_guard' that can be merged with first using 'scoped_lock'
}
```

If there is an easier way to find consecutive declarations of `std::lock_guard` in AST matchers, I'm happy to learn and adjust my code.

This PR closes https://github.com/llvm/llvm-project/issues/107839.

---

Patch is 29.95 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/126434.diff


9 Files Affected:

- (modified) clang-tools-extra/clang-tidy/modernize/CMakeLists.txt (+1) 
- (modified) clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp (+3) 
- (added) clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp (+234) 
- (added) clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.h (+50) 
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+6) 
- (modified) clang-tools-extra/docs/clang-tidy/checks/list.rst (+1) 
- (added) clang-tools-extra/docs/clang-tidy/checks/modernize/use-scoped-lock.rst (+81) 
- (added) clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-only-warn-on-multiple.cpp (+122) 
- (added) clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp (+290) 


``````````diff
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index bab1167fb15ff20..619a27b2f9bb6b2 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 fc46c72982fdce8..b2d4ddd6675022a 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 000000000000000..af2fea5ad310e6d
--- /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 000000000000000..0e1fd8067ddd1e5
--- /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 3bddeeda06e06b9..6aefbc473727634 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 7b9b905ef76715e..b21633459a95cd7 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 000000000000000..04b35d0081b3c55
--- /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 000000000000000..6d46e43bc2be477
--- /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...
[truncated]

``````````

</details>


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


More information about the cfe-commits mailing list