[clang-tools-extra] [clang-tidy] Flag consecutive scoped_locks in use-scoped-lock (PR #209272)
Baranov Victor via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 13 22:26:21 PDT 2026
https://github.com/vbvictor updated https://github.com/llvm/llvm-project/pull/209272
>From adba5005e2e45e4daf70a3dcc788db8bc002b6f9 Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Mon, 13 Jul 2026 22:07:01 +0300
Subject: [PATCH 1/2] [clang-tidy] Flag consecutive scoped_locks in
use-scoped-lock
---
.../modernize/UseScopedLockCheck.cpp | 73 ++++++++---
clang-tools-extra/docs/ReleaseNotes.rst | 6 +
.../checks/modernize/use-scoped-lock.rst | 10 +-
...scoped-lock-warn-on-single-locks-false.cpp | 25 ++--
.../checkers/modernize/use-scoped-lock.cpp | 119 +++++++++++++++---
5 files changed, 184 insertions(+), 49 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
index 74f15a68d6326..a63113f362d2f 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
@@ -27,19 +27,39 @@ static bool isLockGuardDecl(const NamedDecl *Decl) {
Decl->getName() == "lock_guard" && Decl->isInStdNamespace();
}
-static bool isLockGuard(const QualType &Type) {
+static bool isScopedLockDecl(const NamedDecl *Decl) {
+ return Decl->getDeclName().isIdentifier() &&
+ Decl->getName() == "scoped_lock" && Decl->isInStdNamespace();
+}
+
+static const NamedDecl *getLockClassDecl(const QualType &Type) {
if (const auto *Record = Type->getAsCanonical<RecordType>())
- if (const RecordDecl *Decl = Record->getDecl())
- return isLockGuardDecl(Decl);
+ return Record->getDecl();
if (const auto *TemplateSpecType = Type->getAs<TemplateSpecializationType>())
- if (const TemplateDecl *Decl =
- TemplateSpecType->getTemplateName().getAsTemplateDecl())
- return isLockGuardDecl(Decl);
+ return TemplateSpecType->getTemplateName().getAsTemplateDecl();
+ return nullptr;
+}
+
+static bool isLockGuard(const QualType &Type) {
+ if (const NamedDecl *LockDecl = getLockClassDecl(Type))
+ return isLockGuardDecl(LockDecl);
return false;
}
+static bool isScopedLock(const QualType &Type) {
+ if (const NamedDecl *LockDecl = getLockClassDecl(Type))
+ return isScopedLockDecl(LockDecl);
+ return false;
+}
+
+static StringRef getLockClassName(const QualType &Type) {
+ if (const NamedDecl *LockDecl = getLockClassDecl(Type))
+ return LockDecl->getName();
+ return "";
+}
+
static SmallVector<const VarDecl *> getLockGuardsFromDecl(const DeclStmt *DS) {
SmallVector<const VarDecl *> LockGuards;
@@ -47,7 +67,7 @@ static SmallVector<const VarDecl *> getLockGuardsFromDecl(const DeclStmt *DS) {
if (const auto *VD = dyn_cast<VarDecl>(Decl)) {
const QualType Type =
VD->getType().getCanonicalType().getUnqualifiedType();
- if (isLockGuard(Type))
+ if (isLockGuard(Type) || isScopedLock(Type))
LockGuards.push_back(VD);
}
}
@@ -123,6 +143,9 @@ void UseScopedLockCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
void UseScopedLockCheck::registerMatchers(MatchFinder *Finder) {
const auto LockGuardClassDecl =
namedDecl(hasName("lock_guard"), isInStdNamespace());
+ const auto ScopedLockClassDecl =
+ namedDecl(hasName("scoped_lock"), isInStdNamespace());
+ const auto LockClassDecl = anyOf(LockGuardClassDecl, ScopedLockClassDecl);
const auto LockGuardType =
qualType(anyOf(hasUnqualifiedDesugaredType(
@@ -130,12 +153,18 @@ void UseScopedLockCheck::registerMatchers(MatchFinder *Finder) {
hasUnqualifiedDesugaredType(templateSpecializationType(
hasDeclaration(LockGuardClassDecl)))));
- const auto LockVarDecl = varDecl(hasType(LockGuardType));
+ const auto LockType = qualType(anyOf(
+ hasUnqualifiedDesugaredType(recordType(hasDeclaration(LockClassDecl))),
+ hasUnqualifiedDesugaredType(
+ templateSpecializationType(hasDeclaration(LockClassDecl)))));
+
+ const auto LockGuardVarDecl = varDecl(hasType(LockGuardType));
+ const auto LockVarDecl = varDecl(hasType(LockType));
if (WarnOnSingleLocks) {
Finder->addMatcher(
compoundStmt(
- has(declStmt(has(LockVarDecl)).bind("lock-decl-single")),
+ has(declStmt(has(LockGuardVarDecl)).bind("lock-decl-single")),
unless(has(declStmt(unless(equalsBoundNode("lock-decl-single")),
has(LockVarDecl))))),
this);
@@ -251,16 +280,24 @@ void UseScopedLockCheck::diagOnMultipleLocks(
const ast_matchers::MatchFinder::MatchResult &Result) {
for (const SmallVector<const VarDecl *> &Group : LockGroups) {
if (Group.size() == 1) {
- if (WarnOnSingleLocks)
+ if (WarnOnSingleLocks &&
+ isLockGuard(
+ Group[0]->getType().getCanonicalType().getUnqualifiedType()))
diagOnSingleLock(Group[0], Result);
- } else {
- diag(Group[0]->getBeginLoc(),
- "use single 'std::scoped_lock' instead of multiple "
- "'std::lock_guard'");
-
- for (const VarDecl *Lock : llvm::drop_begin(Group))
- diag(Lock->getLocation(), "additional 'std::lock_guard' declared here",
- DiagnosticIDs::Note);
+ continue;
+ }
+
+ diag(Group[0]->getBeginLoc(),
+ "use single 'std::scoped_lock' instead of multiple locks");
+
+ for (const VarDecl *Lock : llvm::drop_begin(Group)) {
+ const QualType Type =
+ Lock->getType().getCanonicalType().getUnqualifiedType();
+ diag(Lock->getLocation(),
+ (llvm::Twine("additional 'std::") + getLockClassName(Type) +
+ "' declared here")
+ .str(),
+ DiagnosticIDs::Note);
}
}
}
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 2581a9d3c5657..92445ee26bf51 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -690,6 +690,12 @@ Changes in existing checks
``std::remove_if``, ``std::partition``, ``std::stable_partition``, and
``std::rotate`` calls with their ``std::ranges`` counterparts.
+- Improved :doc:`modernize-use-scoped-lock
+ <clang-tidy/checks/modernize/use-scoped-lock>` check by fixing a false
+ negative where multiple ``std::scoped_lock`` declarations, or a mix of
+ ``std::scoped_lock`` and ``std::lock_guard`` declarations, in the same scope
+ were not flagged.
+
- Improved :doc:`modernize-use-std-format
<clang-tidy/checks/modernize/use-std-format>` check:
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 9235d4246782e..03da2da0d4d3c 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
@@ -7,8 +7,8 @@ Finds uses of ``std::lock_guard`` and suggests replacing them with C++17's
alternative ``std::scoped_lock``.
Fix-its are provided for single declarations of ``std::lock_guard`` and warning
-is emitted for multiple declarations of ``std::lock_guard`` that can be
-replaced with a single declaration of ``std::scoped_lock``.
+is emitted for multiple declarations of ``std::lock_guard`` or ``std::scoped_lock``
+that can be replaced with a single declaration of ``std::scoped_lock``.
Examples
--------
@@ -45,14 +45,14 @@ Transforms to:
std::lock(M);
std::scoped_lock L(std::adopt_lock, M);
-Multiple ``std::lock_guard`` declarations only emit warnings:
+Multiple consecutive lock declarations only emit warnings:
.. code-block:: c++
std::mutex M1, M2;
std::lock(M1, M2);
- std::lock_guard Lock1(M1, std::adopt_lock); // warning: use single 'std::scoped_lock' instead of multiple 'std::lock_guard'
- std::lock_guard Lock2(M2, std::adopt_lock); // note: additional 'std::lock_guard' declared here
+ std::lock_guard Lock1(M1, std::adopt_lock); // warning: use single 'std::scoped_lock' instead of multiple locks
+ std::scoped_lock<std::mutex> Lock2(M2, std::adopt_lock); // note: additional 'std::scoped_lock' declared here
Limitations
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-warn-on-single-locks-false.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-warn-on-single-locks-false.cpp
index 503ebe1ebc7b2..2dc0f6d9a8c53 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-warn-on-single-locks-false.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-warn-on-single-locks-false.cpp
@@ -10,14 +10,14 @@ void Positive() {
{
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]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
// 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-2]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
// 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
@@ -27,7 +27,7 @@ void Positive() {
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]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:33: note: additional 'std::lock_guard' declared here
}
}
@@ -42,17 +42,28 @@ void Negative() {
std::lock_guard<std::mutex> l(m, std::adopt_lock);
}
- {
+ {
std::lock_guard<std::mutex> l3(m);
int a = 0;
std::lock_guard<std::mutex> l4(m, std::adopt_lock);
}
}
+void NegativeSingleScopedLock() {
+ std::mutex m1, m2;
+ {
+ std::scoped_lock<std::mutex> l(m1);
+ }
+
+ {
+ std::scoped_lock<std::mutex, std::mutex> l(m1, m2);
+ }
+}
+
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]]:3: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:31: note: additional 'std::lock_guard' declared here
}
@@ -67,7 +78,7 @@ void PositiveTemplated() {
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]]:3: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:31: note: additional 'std::lock_guard' declared here
}
@@ -83,7 +94,7 @@ void PositiveTemplatedMutex() {
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]]:3: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:26: note: additional 'std::lock_guard' declared here
}
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 e09c28f73a5df..4ef8298536054 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
@@ -19,20 +19,20 @@ void Positive() {
{
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]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:33: note: additional 'std::lock_guard' declared here
}
{
std::lock_guard<std::mutex> l1(m), l2(m);
- // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use single 'std::scoped_lock' instead of multiple 'std::lock_guard'
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:40: 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-2]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
// 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
@@ -42,7 +42,7 @@ void Positive() {
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]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:33: note: additional 'std::lock_guard' declared here
int a = 0;
std::lock_guard<std::mutex> l3(m);
@@ -77,7 +77,7 @@ void PositiveNested() {
{
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]]:9: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:37: note: additional 'std::lock_guard' declared here
}
{
@@ -96,7 +96,7 @@ void PositiveNested() {
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]]:3: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:31: note: additional 'std::lock_guard' declared here
int a = 0;
std::lock_guard<std::mutex> l3(m3);
@@ -143,12 +143,12 @@ void PositiveLambda() {
std::lock_guard<std::mutex> l3(m);
std::lock_guard<std::mutex> l4(m);
- // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use single 'std::scoped_lock' instead of multiple 'std::lock_guard'
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:31: note: additional 'std::lock_guard' declared here
auto lamda2 = [&]() {
std::lock_guard<std::mutex> 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-2]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:33: note: additional 'std::lock_guard' declared here
};
@@ -156,7 +156,7 @@ void PositiveLambda() {
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]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:33: note: additional 'std::lock_guard' declared here
int a = 0;
std::lock_guard<std::mutex> l3(m);
@@ -191,7 +191,7 @@ void PositiveTemplated() {
{
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]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:33: note: additional 'std::lock_guard' declared here
}
@@ -199,7 +199,7 @@ void PositiveTemplated() {
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]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:33: note: additional 'std::lock_guard' declared here
int a = 0;
std::lock_guard<std::mutex> l3(m3);
@@ -220,7 +220,7 @@ void PositiveTemplatedMutex() {
{
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]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:28: note: additional 'std::lock_guard' declared here
}
@@ -228,7 +228,7 @@ void PositiveTemplatedMutex() {
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]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:28: note: additional 'std::lock_guard' declared here
int a = 0;
std::lock_guard<Mutex> l3(m3);
@@ -266,7 +266,7 @@ struct PositiveClass {
{
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]]:7: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:35: note: additional 'std::lock_guard' declared here
}
@@ -274,7 +274,7 @@ struct PositiveClass {
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]]:7: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:35: note: additional 'std::lock_guard' declared here
int a = 0;
std::lock_guard<std::mutex> l3(m3);
@@ -302,7 +302,7 @@ struct PositiveTemplatedClass {
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]]:7: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:35: note: additional 'std::lock_guard' declared here
int a = 0;
std::lock_guard<std::mutex> l3(m3);
@@ -323,7 +323,7 @@ struct PositiveTemplatedClass {
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]]:7: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-2]]:35: note: additional 'std::lock_guard' declared here
int a = 0;
std::lock_guard<std::mutex> l3(m3);
@@ -416,7 +416,7 @@ void PositiveInUsingTypedefs() {
Lock<std::mutex> l1(m, std::adopt_lock);
LockM l2(m, std::adopt_lock);
LockDef l3(m), l4(m);
- // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use single 'std::scoped_lock' instead of multiple 'std::lock_guard'
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-3]]:11: note: additional 'std::lock_guard' declared here
// CHECK-MESSAGES: :[[@LINE-3]]:13: note: additional 'std::lock_guard' declared here
// CHECK-MESSAGES: :[[@LINE-4]]:20: note: additional 'std::lock_guard' declared here
@@ -441,7 +441,7 @@ void PositiveInUsingTypedefsTemplated() {
Lock<Mutex> l1(m, std::adopt_lock);
LockM l2(m, std::adopt_lock);
LockDef l3(m), l4(m);
- // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use single 'std::scoped_lock' instead of multiple 'std::lock_guard'
+ // CHECK-MESSAGES: :[[@LINE-3]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
// CHECK-MESSAGES: :[[@LINE-3]]:11: note: additional 'std::lock_guard' declared here
// CHECK-MESSAGES: :[[@LINE-3]]:13: note: additional 'std::lock_guard' declared here
// CHECK-MESSAGES: :[[@LINE-4]]:20: note: additional 'std::lock_guard' declared here
@@ -469,3 +469,84 @@ void NegativeNonStdLockGuard() {
lock_guard<std::mutex> l2(m);
}
}
+
+void PositiveMultipleScopedLocks() {
+ std::mutex m1, m2;
+ {
+ std::scoped_lock<std::mutex> l1(m1);
+ std::scoped_lock<std::mutex> l2(m2);
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
+ // CHECK-MESSAGES: :[[@LINE-2]]:34: note: additional 'std::scoped_lock' declared here
+ }
+
+ {
+ std::scoped_lock<std::mutex> l1(m1), l2(m2);
+ std::scoped_lock<std::mutex> l3(m1);
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
+ // CHECK-MESSAGES: :[[@LINE-3]]:42: note: additional 'std::scoped_lock' declared here
+ // CHECK-MESSAGES: :[[@LINE-3]]:34: note: additional 'std::scoped_lock' declared here
+ }
+}
+
+void PositiveMixedLockGuardAndScopedLock() {
+ std::mutex m1, m2;
+ {
+ std::lock_guard<std::mutex> l1(m1);
+ std::scoped_lock<std::mutex> l2(m2);
+ // CHECK-MESSAGES: :[[@LINE-2]]:5: warning: use single 'std::scoped_lock' instead of multiple locks
+ // CHECK-MESSAGES: :[[@LINE-2]]:34: note: additional 'std::scoped_lock' declared here
+ }
+
+ {
+ std::scoped_lock<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 locks
+ // CHECK-MESSAGES: :[[@LINE-2]]:33: note: additional 'std::lock_guard' declared here
+ }
+}
+
+void NegativeMultiMutexScopedLock() {
+ std::mutex m1, m2;
+ std::scoped_lock<std::mutex, std::mutex> l(m1, m2);
+}
+
+void PositiveMultipleMultiMutexLocks() {
+ std::mutex m1, m2, m3, m4;
+ std::scoped_lock<std::mutex, std::mutex> l1(m1, m2);
+ std::scoped_lock<std::mutex, std::mutex> l2(m3, m4);
+ // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use single 'std::scoped_lock' instead of multiple locks
+ // CHECK-MESSAGES: :[[@LINE-2]]:44: note: additional 'std::scoped_lock' declared here
+}
+
+void PositiveOneTwoOneLocks() {
+ std::mutex m1, m2, m3, m4;
+ std::scoped_lock<std::mutex> l1(m1);
+ std::scoped_lock<std::mutex, std::mutex> l2(m2, m3);
+ std::lock_guard<std::mutex> l3(m4);
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use single 'std::scoped_lock' instead of multiple locks
+ // CHECK-MESSAGES: :[[@LINE-3]]:44: note: additional 'std::scoped_lock' declared here
+ // CHECK-MESSAGES: :[[@LINE-3]]:31: note: additional 'std::lock_guard' declared here
+}
+
+void PositiveOneOneTwoLocks() {
+ std::mutex m1, m2, m3, m4;
+ std::scoped_lock<std::mutex> l1(m1);
+ std::lock_guard<std::mutex> l2(m2);
+ std::scoped_lock<std::mutex, std::mutex> l3(m3, m4);
+ // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use single 'std::scoped_lock' instead of multiple locks
+ // CHECK-MESSAGES: :[[@LINE-3]]:31: note: additional 'std::lock_guard' declared here
+ // CHECK-MESSAGES: :[[@LINE-3]]:44: note: additional 'std::scoped_lock' declared here
+}
+
+void NegativeSingleScopedLock() {
+ std::mutex m1, m2;
+ {
+ std::scoped_lock<std::mutex> l(m1);
+ }
+
+ {
+ std::scoped_lock<std::mutex> l1(m1);
+ int a = 0;
+ std::scoped_lock<std::mutex> l2(m2);
+ }
+}
>From 1f742de4a652f1b28c5ed9276ce58d70cf43237a Mon Sep 17 00:00:00 2001
From: Victor Baranov <bar.victor.2002 at gmail.com>
Date: Tue, 14 Jul 2026 08:26:01 +0300
Subject: [PATCH 2/2] fix
---
.../modernize/UseScopedLockCheck.cpp | 21 ++++++++-----------
1 file changed, 9 insertions(+), 12 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
index a63113f362d2f..dabb3ffeb7c2b 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp
@@ -55,9 +55,9 @@ static bool isScopedLock(const QualType &Type) {
}
static StringRef getLockClassName(const QualType &Type) {
- if (const NamedDecl *LockDecl = getLockClassDecl(Type))
- return LockDecl->getName();
- return "";
+ const NamedDecl *LockDecl = getLockClassDecl(Type);
+ assert(LockDecl);
+ return LockDecl->getName();
}
static SmallVector<const VarDecl *> getLockGuardsFromDecl(const DeclStmt *DS) {
@@ -147,16 +147,13 @@ void UseScopedLockCheck::registerMatchers(MatchFinder *Finder) {
namedDecl(hasName("scoped_lock"), isInStdNamespace());
const auto LockClassDecl = anyOf(LockGuardClassDecl, ScopedLockClassDecl);
- const auto LockGuardType =
- qualType(anyOf(hasUnqualifiedDesugaredType(
- recordType(hasDeclaration(LockGuardClassDecl))),
- hasUnqualifiedDesugaredType(templateSpecializationType(
- hasDeclaration(LockGuardClassDecl)))));
+ const auto LockGuardType = qualType(hasUnqualifiedDesugaredType(
+ mapAnyOf(recordType, templateSpecializationType)
+ .with(hasDeclaration(LockGuardClassDecl))));
- const auto LockType = qualType(anyOf(
- hasUnqualifiedDesugaredType(recordType(hasDeclaration(LockClassDecl))),
- hasUnqualifiedDesugaredType(
- templateSpecializationType(hasDeclaration(LockClassDecl)))));
+ const auto LockType = qualType(hasUnqualifiedDesugaredType(
+ mapAnyOf(recordType, templateSpecializationType)
+ .with(hasDeclaration(LockClassDecl))));
const auto LockGuardVarDecl = varDecl(hasType(LockGuardType));
const auto LockVarDecl = varDecl(hasType(LockType));
More information about the cfe-commits
mailing list