Author: Baranov Victor Date: 2025-06-29T22:34:32+03:00 New Revision: a3a60e03e2bf7b79683517584a9a7b3e4c8cd297
URL: https://github.com/llvm/llvm-project/commit/a3a60e03e2bf7b79683517584a9a7b3e4c8cd297 DIFF: https://github.com/llvm/llvm-project/commit/a3a60e03e2bf7b79683517584a9a7b3e4c8cd297.diff LOG: [clang-tidy] add new check: modernize-use-scoped-lock (#126434) Add new clang-tidy check 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' } ``` This PR closes https://github.com/llvm/llvm-project/issues/107839. Added: clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.h clang-tools-extra/docs/clang-tidy/checks/modernize/use-scoped-lock.rst clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/mutex clang-tools-extra/test/clang-tidy/checkers/modernize/use-scope-lock-warn-on-using-and-typedef-false.cpp clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-warn-on-single-locks-false.cpp clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp Modified: clang-tools-extra/clang-tidy/modernize/CMakeLists.txt clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/list.rst Removed: ################################################################################ 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 0cf59b6e0216a..fdf38bc4b6308 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..9c2fc9e06fb45 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.cpp @@ -0,0 +1,311 @@ +//===--- 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/SmallVector.h" +#include "llvm/ADT/Twine.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +static bool isLockGuardDecl(const NamedDecl *Decl) { + return Decl->getDeclName().isIdentifier() && + Decl->getName() == "lock_guard" && Decl->isInStdNamespace(); +} + +static bool isLockGuard(const QualType &Type) { + if (const auto *Record = Type->getAs<RecordType>()) + if (const RecordDecl *Decl = Record->getDecl()) + return isLockGuardDecl(Decl); + + if (const auto *TemplateSpecType = Type->getAs<TemplateSpecializationType>()) + if (const TemplateDecl *Decl = + TemplateSpecType->getTemplateName().getAsTemplateDecl()) + return isLockGuardDecl(Decl); + + return false; +} + +static 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)) { + const QualType Type = + VD->getType().getCanonicalType().getUnqualifiedType(); + 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. +static llvm::SmallVector<llvm::SmallVector<const VarDecl *>> +findLocksInCompoundStmt(const CompoundStmt *Block, + const ast_matchers::MatchFinder::MatchResult &Result) { + // store groups of consecutive 'std::lock_guard' declarations + llvm::SmallVector<llvm::SmallVector<const VarDecl *>> LockGuardGroups; + llvm::SmallVector<const VarDecl *> CurrentLockGuardGroup; + + auto AddAndClearCurrentGroup = [&]() { + if (!CurrentLockGuardGroup.empty()) { + LockGuardGroups.push_back(CurrentLockGuardGroup); + CurrentLockGuardGroup.clear(); + } + }; + + for (const Stmt *Stmt : Block->body()) { + if (const auto *DS = dyn_cast<DeclStmt>(Stmt)) { + llvm::SmallVector<const VarDecl *> LockGuards = getLockGuardsFromDecl(DS); + + if (!LockGuards.empty()) { + CurrentLockGuardGroup.append(LockGuards); + continue; + } + } + AddAndClearCurrentGroup(); + } + + AddAndClearCurrentGroup(); + + return LockGuardGroups; +} + +static TemplateSpecializationTypeLoc +getTemplateLockGuardTypeLoc(const TypeSourceInfo *SourceInfo) { + const TypeLoc Loc = SourceInfo->getTypeLoc(); + + const auto ElaboratedLoc = Loc.getAs<ElaboratedTypeLoc>(); + if (!ElaboratedLoc) + return {}; + + return ElaboratedLoc.getNamedTypeLoc().getAs<TemplateSpecializationTypeLoc>(); +} + +// Find the exact source range of the 'lock_guard' token +static SourceRange getLockGuardRange(const TypeSourceInfo *SourceInfo) { + const TypeLoc LockGuardTypeLoc = SourceInfo->getTypeLoc(); + + return SourceRange(LockGuardTypeLoc.getBeginLoc(), + LockGuardTypeLoc.getEndLoc()); +} + +// Find the exact source range of the 'lock_guard' name token +static SourceRange getLockGuardNameRange(const TypeSourceInfo *SourceInfo) { + const TemplateSpecializationTypeLoc TemplateLoc = + getTemplateLockGuardTypeLoc(SourceInfo); + if (!TemplateLoc) + return {}; + + return SourceRange(TemplateLoc.getTemplateNameLoc(), + TemplateLoc.getLAngleLoc().getLocWithOffset(-1)); +} + +const static StringRef UseScopedLockMessage = + "use 'std::scoped_lock' instead of 'std::lock_guard'"; + +UseScopedLockCheck::UseScopedLockCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + WarnOnSingleLocks(Options.get("WarnOnSingleLocks", true)), + WarnOnUsingAndTypedef(Options.get("WarnOnUsingAndTypedef", true)) {} + +void UseScopedLockCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "WarnOnSingleLocks", WarnOnSingleLocks); + Options.store(Opts, "WarnOnUsingAndTypedef", WarnOnUsingAndTypedef); +} + +void UseScopedLockCheck::registerMatchers(MatchFinder *Finder) { + const auto LockGuardClassDecl = + namedDecl(hasName("lock_guard"), isInStdNamespace()); + + const auto LockGuardType = qualType(anyOf( + hasUnqualifiedDesugaredType( + recordType(hasDeclaration(LockGuardClassDecl))), + elaboratedType(namesType(hasUnqualifiedDesugaredType( + templateSpecializationType(hasDeclaration(LockGuardClassDecl))))))); + + const auto LockVarDecl = varDecl(hasType(LockGuardType)); + + if (WarnOnSingleLocks) { + Finder->addMatcher( + compoundStmt( + unless(isExpansionInSystemHeader()), + has(declStmt(has(LockVarDecl)).bind("lock-decl-single")), + unless(has(declStmt(unless(equalsBoundNode("lock-decl-single")), + has(LockVarDecl))))), + this); + } + + Finder->addMatcher( + compoundStmt(unless(isExpansionInSystemHeader()), + has(declStmt(has(LockVarDecl)).bind("lock-decl-multiple")), + has(declStmt(unless(equalsBoundNode("lock-decl-multiple")), + has(LockVarDecl)))) + .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(LockGuardClassDecl))) + .bind("lock-guard-using-decl"), + this); + } +} + +void UseScopedLockCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *DS = Result.Nodes.getNodeAs<DeclStmt>("lock-decl-single")) { + llvm::SmallVector<const VarDecl *> Decls = getLockGuardsFromDecl(DS); + diagOnMultipleLocks({Decls}, Result); + return; + } + + if (const auto *Compound = + Result.Nodes.getNodeAs<CompoundStmt>("block-multiple")) { + diagOnMultipleLocks(findLocksInCompoundStmt(Compound, Result), Result); + return; + } + + if (const auto *Typedef = + Result.Nodes.getNodeAs<TypedefDecl>("lock-guard-typedef")) { + diagOnSourceInfo(Typedef->getTypeSourceInfo(), Result); + return; + } + + if (const auto *UsingAlias = + Result.Nodes.getNodeAs<TypeAliasDecl>("lock-guard-using-alias")) { + diagOnSourceInfo(UsingAlias->getTypeSourceInfo(), Result); + return; + } + + if (const auto *Using = + Result.Nodes.getNodeAs<UsingDecl>("lock-guard-using-decl")) { + diagOnUsingDecl(Using, Result); + } +} + +void UseScopedLockCheck::diagOnSingleLock( + const VarDecl *LockGuard, const MatchFinder::MatchResult &Result) { + auto Diag = diag(LockGuard->getBeginLoc(), UseScopedLockMessage); + + const SourceRange LockGuardTypeRange = + getLockGuardRange(LockGuard->getTypeSourceInfo()); + + if (LockGuardTypeRange.isInvalid()) + return; + + // Create Fix-its only if we can find the constructor call to properly handle + // 'std::lock_guard l(m, std::adopt_lock)' case. + const auto *CtorCall = dyn_cast<CXXConstructExpr>(LockGuard->getInit()); + if (!CtorCall) + return; + + if (CtorCall->getNumArgs() == 1) { + Diag << FixItHint::CreateReplacement(LockGuardTypeRange, + "std::scoped_lock"); + return; + } + + if (CtorCall->getNumArgs() == 2) { + const Expr *const *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, "std::scoped_lock") + << FixItHint::CreateReplacement( + SourceRange(MutexArg->getBeginLoc(), AdoptLockArg->getEndLoc()), + (llvm::Twine(AdoptLockSourceText) + ", " + MutexSourceText) + .str()); + return; + } + + llvm_unreachable("Invalid argument number of std::lock_guard constructor"); +} + +void UseScopedLockCheck::diagOnMultipleLocks( + 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) { + if (WarnOnSingleLocks) + 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); + } + } +} + +void UseScopedLockCheck::diagOnSourceInfo( + 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 = + getLockGuardNameRange(LockGuardSourceInfo); + if (LockGuardRange.isInvalid()) + return; + + Diag << FixItHint::CreateReplacement(LockGuardRange, "scoped_lock"); + } +} + +void UseScopedLockCheck::diagOnUsingDecl( + 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 new file mode 100644 index 0000000000000..a5697805c15ca --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/UseScopedLockCheck.h @@ -0,0 +1,54 @@ +//===--- 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 +/// 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); + 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 diagOnSingleLock(const VarDecl *LockGuard, + const ast_matchers::MatchFinder::MatchResult &Result); + void diagOnMultipleLocks( + const llvm::SmallVector<llvm::SmallVector<const VarDecl *>> &LockGroups, + const ast_matchers::MatchFinder::MatchResult &Result); + void diagOnSourceInfo(const TypeSourceInfo *LockGuardSourceInfo, + const ast_matchers::MatchFinder::MatchResult &Result); + void diagOnUsingDecl(const UsingDecl *UsingDecl, + const ast_matchers::MatchFinder::MatchResult &Result); + + const bool WarnOnSingleLocks; + const bool WarnOnUsingAndTypedef; +}; + +} // 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 ccd6aa239c1cf..e50d40b76e8c4 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -142,6 +142,12 @@ New checks Finds unscoped (non-class) ``enum`` declarations and suggests using ``enum class`` instead. +- 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 + alternative ``std::scoped_lock``. + - New :doc:`portability-avoid-pragma-once <clang-tidy/checks/portability/avoid-pragma-once>` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index ccb78ee45e9c4..5098582d0c42b 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -312,6 +312,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..d184f1aefd806 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-scoped-lock.rst @@ -0,0 +1,101 @@ +.. 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 +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``. + +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 +``template`` parameter: + +.. code-block:: c++ + + template <template <typename> typename Lock> + void TemplatedLock() { + std::mutex M; + Lock<std::mutex> L(M); // no warning + } + + void instantiate() { + TemplatedLock<std::lock_guard>(); + } + + +Options +------- + +.. option:: WarnOnSingleLocks + + When `true`, the check will warn on single ``std::lock_guard`` declarations. + Set this option to `false` if you want to get warnings only on multiple + ``std::lock_guard`` declarations that can be replaced with a single + ``std::scoped_lock``. Default is `true`. + +.. option:: WarnOnUsingAndTypedef + + When `true`, the check will emit warnings if ``std::lock_guard`` is used + in ``using`` or ``typedef`` context. Default is `true`. + + .. code-block:: c++ + + template <typename T> + using Lock = std::lock_guard<T>; // warning: use 'std::scoped_lock' instead of 'std::lock_guard' + + using LockMutex = std::lock_guard<std::mutex>; // warning: use 'std::scoped_lock' instead of 'std::lock_guard' + + typedef std::lock_guard<std::mutex> LockDef; // warning: use 'std::scoped_lock' instead of 'std::lock_guard' + + using std::lock_guard; // warning: use 'std::scoped_lock' instead of 'std::lock_guard' \ No newline at end of file diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/mutex b/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/mutex new file mode 100644 index 0000000000000..a0030a2b9da0a --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/mutex @@ -0,0 +1,33 @@ +#ifndef _MUTEX_ +#define _MUTEX_ + +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) {} + scoped_lock(const scoped_lock&) = delete; +}; + +} // namespace std + +#endif // _MUTEX_ 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..77df845756530 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scope-lock-warn-on-using-and-typedef-false.cpp @@ -0,0 +1,31 @@ +// 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: -- -isystem %clang_tidy_headers -fno-delayed-template-parsing + +#include <mutex> + +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; +} 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 new file mode 100644 index 0000000000000..7b30cdd75c801 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock-warn-on-single-locks-false.cpp @@ -0,0 +1,102 @@ +// RUN: %check_clang_tidy -std=c++17-or-later %s modernize-use-scoped-lock %t -- \ +// RUN: -config="{CheckOptions: {modernize-use-scoped-lock.WarnOnSingleLocks: false}}" \ +// RUN: -- -isystem %clang_tidy_headers -fno-delayed-template-parsing + +#include <mutex> + +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); + } + + { + std::lock_guard<std::mutex> l3(m); + int a = 0; + std::lock_guard<std::mutex> l4(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..45eabdbece68c --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-scoped-lock.cpp @@ -0,0 +1,471 @@ +// RUN: %check_clang_tidy -std=c++17-or-later %s modernize-use-scoped-lock %t -- -- -isystem %clang_tidy_headers -fno-delayed-template-parsing + +#include <mutex> + +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); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use single 'std::scoped_lock' instead of multiple 'std::lock_guard' + // 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-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); + } +} + + +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); +} + + +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); + } +} + +void PositiveLambda() { + std::mutex m; + std::lock_guard<std::mutex> l1(m); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::scoped_lock' instead of 'std::lock_guard' + // CHECK-FIXES: std::scoped_lock l1(m); + auto lambda1 = [&]() { + std::lock_guard<std::mutex> l1(m); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead of 'std::lock_guard' + // CHECK-FIXES: std::scoped_lock l1(m); + }; + + 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]]: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]]:33: note: additional 'std::lock_guard' declared here + }; + + auto lamda3 = [&]() { + 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); + }; + + auto lamda4 = [&]() { + std::lock_guard<std::mutex> l1(m); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead of 'std::lock_guard' + // CHECK-FIXES: std::scoped_lock l1(m); + int a = 0; + std::lock_guard<std::mutex> l2(m); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead of 'std::lock_guard' + // CHECK-FIXES: std::scoped_lock l2(m); + }; +} + +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>; +// 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; + + std::mutex m; + lock_guard<std::mutex> l(m); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'std::scoped_lock' instead of 'std::lock_guard' + // CHECK-FIXES: std::scoped_lock l(m); + + 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 PositiveInUsingTypedefs() { + std::mutex m; + + { + Lock<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); + } + + { + LockM l(m); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead of 'std::lock_guard' + // CHECK-FIXES: std::scoped_lock l(m); + } + + { + LockDef 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(m, m); + 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]]: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 + int a = 0; + LockDef l5(m); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead of 'std::lock_guard' + // CHECK-FIXES: std::scoped_lock l5(m); + } +} + +template <typename Mutex> +void PositiveInUsingTypedefsTemplated() { + Mutex m; + + { + Lock<Mutex> l(m); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead of 'std::lock_guard' + } + + { + std::lock(m, m); + 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]]: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 + int a = 0; + LockDef l5(m); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'std::scoped_lock' instead of 'std::lock_guard' + } +} + +// Non-STD 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); + } +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits