lewmpk updated this revision to Diff 189078.
lewmpk marked an inline comment as done.
lewmpk added a comment.

added example in docs and explicitly specified types for some variables


Repository:
  rCTE Clang Tools Extra

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D58818/new/

https://reviews.llvm.org/D58818

Files:
  clang-tidy/cppcoreguidelines/CMakeLists.txt
  clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
  clang-tidy/cppcoreguidelines/UseRaiiLocksCheck.cpp
  clang-tidy/cppcoreguidelines/UseRaiiLocksCheck.h
  docs/ReleaseNotes.rst
  docs/clang-tidy/checks/cppcoreguidelines-use-raii-locks.rst
  docs/clang-tidy/checks/list.rst
  test/clang-tidy/cppcoreguidelines-use-raii-locks.cpp

Index: test/clang-tidy/cppcoreguidelines-use-raii-locks.cpp
===================================================================
--- /dev/null
+++ test/clang-tidy/cppcoreguidelines-use-raii-locks.cpp
@@ -0,0 +1,194 @@
+// RUN: %check_clang_tidy %s cppcoreguidelines-use-raii-locks %t
+
+// Mock implementation of std::mutex
+namespace std {
+struct mutex {
+  void lock();
+  void try_lock();
+  void unlock();
+};
+typedef mutex recursive_mutex;
+} // namespace std
+
+void warn_me1_simple() {
+  std::mutex m;
+  m.lock();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use RAII
+  m.unlock();
+}
+
+void warn_me2_nested() {
+  std::mutex m;
+  m.lock();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use RAII
+  {
+    std::mutex m;
+    m.lock();
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use RAII
+    m.unlock();
+  }
+  m.unlock();
+}
+
+void warn_me3_nested_extra() {
+  std::mutex m1;
+  std::mutex m2;
+  {
+    m1.lock();
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use RAII
+    {
+      m2.lock();
+      // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use RAII
+      m2.unlock();
+    }
+    m1.unlock();
+  }
+}
+
+void warn_me4_multi_mutex() {
+  std::mutex m1;
+  std::mutex m2;
+
+  m1.lock();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use RAII
+  m1.unlock();
+  m2.lock();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use RAII
+  m2.unlock();
+}
+
+void warn_me5_multi_mutex_extra() {
+  std::mutex m1;
+  std::mutex m2;
+
+  m1.lock();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use RAII
+  m2.lock();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use RAII
+  m1.unlock();
+  m2.unlock();
+}
+
+void warn_me6() {
+  std::mutex m;
+  m.lock();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use RAII
+  m.unlock();
+  m.lock();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use RAII
+  m.unlock();
+  m.try_lock();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use RAII
+  m.lock();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use RAII
+  m.unlock();
+}
+
+void warn_me7_loop() {
+  std::mutex m;
+  for (auto i = 0; i < 3; i++) {
+    m.lock();
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use RAII
+    m.unlock();
+  }
+}
+
+template <typename M>
+void attempt(M m) {
+  m.lock();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use RAII
+  m.unlock();
+}
+
+void warn_me8_template_func() {
+  std::mutex m;
+  attempt(m);
+}
+
+// clang-format off
+#define ATTEMPT(m) {\ 
+            m.lock();\ 
+            m.unlock();\ 
+          }
+// clang-format on
+
+void warn_me9_macro() {
+  std::mutex m;
+  ATTEMPT(m);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use RAII
+}
+
+void warn_me10_inline() {
+  std::mutex m;
+  // clang-format off
+  m.lock(); m.unlock();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use RAII
+  // clang-format on
+}
+
+void warn_me11_recursive_mutex() {
+  std::recursive_mutex m;
+  m.lock();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: use RAII
+  m.unlock();
+}
+
+void ignore_me1_rev_order() {
+  std::mutex m;
+  m.unlock();
+  m.lock();
+  // CHECK-MESSAGES-NOT: warning:
+}
+
+void ignore_me2_diff_mtx() {
+  std::mutex m1;
+  std::mutex m2;
+  m1.lock();
+  // CHECK-MESSAGES-NOT: warning:
+  m2.unlock();
+}
+
+void ignore_me3() {
+  std::recursive_mutex m1;
+  std::recursive_mutex m2;
+  m1.lock();
+  // CHECK-MESSAGES-NOT: warning:
+  m2.unlock();
+}
+
+void ignore_me4() {
+  std::mutex m;
+  m.unlock();
+  m.lock();
+  m.lock();
+  // CHECK-MESSAGES-NOT: warning:
+}
+
+void ignore_me5_inline() {
+  std::mutex m;
+  m.unlock();
+  m.lock();
+  // CHECK-MESSAGES-NOT: warning:
+}
+
+void ignore_me6_seperate_scopes() {
+  std::mutex m;
+  {
+    m.lock();
+    // CHECK-MESSAGES-NOT: warning:
+  }
+  {
+    m.unlock();
+  }
+}
+
+void ignore_me7_seperate_scopes_nested() {
+  std::mutex m;
+  {
+    m.lock();
+    // CHECK-MESSAGES-NOT: warning:
+    {
+      m.unlock();
+    }
+  }
+}
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -118,6 +118,7 @@
    cppcoreguidelines-pro-type-vararg
    cppcoreguidelines-slicing
    cppcoreguidelines-special-member-functions
+   cppcoreguidelines-use-raii-locks
    fuchsia-default-arguments
    fuchsia-header-anon-namespaces (redirects to google-build-namespaces) <fuchsia-header-anon-namespaces>
    fuchsia-multiple-inheritance
Index: docs/clang-tidy/checks/cppcoreguidelines-use-raii-locks.rst
===================================================================
--- /dev/null
+++ docs/clang-tidy/checks/cppcoreguidelines-use-raii-locks.rst
@@ -0,0 +1,33 @@
+.. title:: clang-tidy - cppcoreguidelines-use-raii-locks
+
+cppcoreguidelines-use-raii-locks
+================================
+
+Checks for explicit usage of ``std::mutex`` functions ``lock()``, 
+``try_lock()`` and ``unlock()`` which is error-prone and should be avoided.
+It's recommended to use RAII-style locking mechanisms such as 
+``std::lock_guard`` or ``std::unique_lock``.
+See `C++ Core Guidelines <https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rconc-raii>`_.
+
+.. code-block:: c++
+
+  std::mutex m;
+  // Warns the following lock() call
+  m.lock()
+
+  m.unlock()
+
+Options
+-------
+
+.. option:: LockableTypes
+
+   Semicolon-separated list of fully qualified names of types that support 
+   locking and unlocking a mutex.
+   Defaults to: 
+        `::std::mutex;::std::recursive_mutex;::std::timed_mutex;
+         ::std::recursive_timed_mutex;std::shared_mutex;
+         ::std::unique_lock;::std::shared_lock;
+         ::boost::mutex;::boost::recursive_mutex;::boost::timed_mutex;
+         ::boost::recursive_timed_mutex;::boost::shared_mutex;
+         ::boost::unique_lock;::boost::shared_lock`.
Index: docs/ReleaseNotes.rst
===================================================================
--- docs/ReleaseNotes.rst
+++ docs/ReleaseNotes.rst
@@ -91,6 +91,12 @@
   Finds and fixes ``absl::Time`` subtraction expressions to do subtraction
   in the Time domain instead of the numeric domain.
 
+- New :doc:`cppcoreguidelines-use-raii-locks
+  <clang-tidy/checks/cppcoreguidelines-use-raii-locks>` check.
+
+  Checks for explicit usage of ``std::mutex`` functions ``lock()``, 
+  ``try_lock()`` and ``unlock()`` which is error-prone and should be avoided.
+
 - New :doc:`google-readability-avoid-underscore-in-googletest-name
   <clang-tidy/checks/google-readability-avoid-underscore-in-googletest-name>`
   check.
Index: clang-tidy/cppcoreguidelines/UseRaiiLocksCheck.h
===================================================================
--- /dev/null
+++ clang-tidy/cppcoreguidelines/UseRaiiLocksCheck.h
@@ -0,0 +1,48 @@
+//===--- UseRaiiLocksCheck.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_CPPCOREGUIDELINES_USERAIILOCKSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_USERAIILOCKSCHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// Check for instances of explicit std::mutex lock() and unlock() calls
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-use-raii-locks.html
+class UseRaiiLocksCheck : public ClangTidyCheck {
+public:
+  UseRaiiLocksCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context),
+        // clang-format off
+        LockableTypes(Options.get(
+            "LockableTypes",
+            "::std::mutex;::std::recursive_mutex;::std::timed_mutex;"
+            "::std::recursive_timed_mutex;std::shared_mutex;"
+            "::std::unique_lock;::std::shared_lock;"
+            "::boost::mutex;::boost::recursive_mutex;::boost::timed_mutex;"
+            "::boost::recursive_timed_mutex;::boost::shared_mutex;"
+            "::boost::unique_lock;::boost::shared_lock")) {}
+        // clang-format on
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+  const std::string LockableTypes;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_USERAIILOCKSCHECK_H
Index: clang-tidy/cppcoreguidelines/UseRaiiLocksCheck.cpp
===================================================================
--- /dev/null
+++ clang-tidy/cppcoreguidelines/UseRaiiLocksCheck.cpp
@@ -0,0 +1,105 @@
+//===--- UseRaiiLocksCheck.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 "UseRaiiLocksCheck.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+using namespace clang::ast_matchers::internal;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+static Matcher<RecordDecl> hasAnyListedName(const std::string &TypeNames) {
+  std::vector<std::string> NameList =
+      utils::options::parseStringList(TypeNames);
+  return hasAnyName(std::vector<StringRef>(NameList.begin(), NameList.end()));
+}
+
+static DeclRefExpr *findDeclRefExpr(const CXXMemberCallExpr *MemberCallExpr) {
+  Expr *ObjectExpr = MemberCallExpr->getImplicitObjectArgument();
+  if (auto *ObjectCast = dyn_cast<ImplicitCastExpr>(ObjectExpr)) {
+    ObjectExpr = ObjectCast->getSubExpr();
+  }
+  return dyn_cast<DeclRefExpr>(ObjectExpr);
+}
+
+void UseRaiiLocksCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "LockableTypes", LockableTypes);
+}
+
+void UseRaiiLocksCheck::registerMatchers(MatchFinder *Finder) {
+  if (!getLangOpts().CPlusPlus)
+    return;
+
+  auto MutexType = type(hasUnqualifiedDesugaredType(recordType(
+      hasDeclaration(cxxRecordDecl(hasAnyListedName(LockableTypes))))));
+  // Match expressions of type mutex or mutex pointer.
+  auto MutexExpr =
+      expr(anyOf(hasType(MutexType), hasType(qualType(pointsTo(MutexType)))));
+
+  // Match a call to mutex lock() or try_lock().
+  auto MutexLockCallExpr =
+      cxxMemberCallExpr(on(MutexExpr), callee(memberExpr()),
+                        callee(cxxMethodDecl(hasAnyName("lock", "try_lock"))));
+
+  // Match a call to mutex unlock().
+  auto MutexUnlockCallExpr =
+      cxxMemberCallExpr(on(MutexExpr), callee(memberExpr()),
+                        callee(cxxMethodDecl(hasAnyName("unlock"))));
+
+  // Match a scope with a calls to both lock() and unlock().
+  auto ScopedProblem =
+      compoundStmt(forEach(MutexLockCallExpr.bind("lock")),
+                   forEach(MutexUnlockCallExpr.bind("unlock")));
+  Finder->addMatcher(ScopedProblem, this);
+}
+
+void UseRaiiLocksCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *LockCallExpr = Result.Nodes.getNodeAs<CXXMemberCallExpr>("lock");
+  const auto *UnlockCallExpr =
+      Result.Nodes.getNodeAs<CXXMemberCallExpr>("unlock");
+
+  const auto *LockDeclRef = findDeclRefExpr(LockCallExpr);
+  const auto *UnlockDeclRef = findDeclRefExpr(UnlockCallExpr);
+
+  assert(LockDeclRef && UnlockDeclRef);
+
+  StringRef LockObjectName = LockDeclRef->getFoundDecl()->getName();
+  StringRef UnlockObjectName = UnlockDeclRef->getFoundDecl()->getName();
+
+  // Ignore m.lock(); m2.unlock().
+  if (LockObjectName != UnlockObjectName)
+    return;
+
+  auto LockLocation =
+      Result.SourceManager->getPresumedLoc(LockCallExpr->getBeginLoc());
+  auto UnlockLocation =
+      Result.SourceManager->getPresumedLoc(UnlockCallExpr->getBeginLoc());
+
+  // Ignore unlock() before lock().
+  if (UnlockLocation.getLine() < LockLocation.getLine() ||
+      (UnlockLocation.getLine() == LockLocation.getLine() &&
+       UnlockLocation.getColumn() < LockLocation.getColumn()))
+    return;
+
+  diag(LockCallExpr->getBeginLoc(),
+       "use RAII-style locking mechanisms such as %0.")
+      << (getLangOpts().CPlusPlus11
+              ? "'std::lock_guard' "
+                "or 'std::unique_lock'"
+              : "'boost:lock_guard' or 'boost::unique_lock'");
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
===================================================================
--- clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
+++ clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
@@ -32,6 +32,7 @@
 #include "ProTypeVarargCheck.h"
 #include "SlicingCheck.h"
 #include "SpecialMemberFunctionsCheck.h"
+#include "UseRaiiLocksCheck.h"
 
 namespace clang {
 namespace tidy {
@@ -83,6 +84,8 @@
     CheckFactories.registerCheck<SpecialMemberFunctionsCheck>(
         "cppcoreguidelines-special-member-functions");
     CheckFactories.registerCheck<SlicingCheck>("cppcoreguidelines-slicing");
+    CheckFactories.registerCheck<UseRaiiLocksCheck>(
+        "cppcoreguidelines-use-raii-locks");
     CheckFactories.registerCheck<misc::UnconventionalAssignOperatorCheck>(
         "cppcoreguidelines-c-copy-assignment-signature");
   }
Index: clang-tidy/cppcoreguidelines/CMakeLists.txt
===================================================================
--- clang-tidy/cppcoreguidelines/CMakeLists.txt
+++ clang-tidy/cppcoreguidelines/CMakeLists.txt
@@ -20,6 +20,7 @@
   ProTypeVarargCheck.cpp
   SlicingCheck.cpp
   SpecialMemberFunctionsCheck.cpp
+  UseRaiiLocksCheck.cpp
 
   LINK_LIBS
   clangAST
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to