abelkocsis updated this revision to Diff 245113.
abelkocsis added a comment.

Test cases adding, checker modifying to pass new cases.


Repository:
  rCTE Clang Tools Extra

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

https://reviews.llvm.org/D70876

Files:
  clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
  clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
  clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.cpp
  clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.h
  clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  
clang-tools-extra/docs/clang-tidy/checks/bugprone-spuriously-wake-up-functions.rst
  clang-tools-extra/docs/clang-tidy/checks/cert-con36-c.rst
  clang-tools-extra/docs/clang-tidy/checks/cert-con54-cpp.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/test/clang-tidy/bugprone-spuriously-wake-up-functions.c
  clang-tools-extra/test/clang-tidy/bugprone-spuriously-wake-up-functions.cpp

Index: clang-tools-extra/test/clang-tidy/bugprone-spuriously-wake-up-functions.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/bugprone-spuriously-wake-up-functions.cpp
@@ -0,0 +1,191 @@
+// RUN: %check_clang_tidy %s bugprone-spuriously-wake-up-functions %t -- --
+#define NULL 0
+
+namespace std {
+using intmax_t = int;
+
+template <intmax_t N, intmax_t D = 1>
+class ratio {
+public:
+  static constexpr intmax_t num = 0;
+  static constexpr intmax_t den = 0;
+  typedef ratio<num, den> type;
+};
+typedef ratio<1, 1000> milli;
+namespace chrono {
+
+template <class Rep, class Period = ratio<1>>
+class duration {
+public:
+  using rep = Rep;
+  using period = Period;
+
+public:
+  constexpr duration() = default;
+  template <class Rep2>
+  constexpr explicit duration(const Rep2 &r);
+  template <class Rep2, class Period2>
+  constexpr duration(const duration<Rep2, Period2> &d);
+  ~duration() = default;
+  duration(const duration &) = default;
+};
+
+template <class Clock, class Duration = typename Clock::duration>
+class time_point {
+public:
+  using clock = Clock;
+  using duration = Duration;
+
+public:
+  constexpr time_point();
+  constexpr explicit time_point(const duration &d);
+  template <class Duration2>
+  constexpr time_point(const time_point<clock, Duration2> &t);
+};
+
+using milliseconds = duration<int, milli>;
+
+class system_clock {
+public:
+  typedef milliseconds duration;
+  typedef duration::rep rep;
+  typedef duration::period period;
+  typedef chrono::time_point<system_clock> time_point;
+
+  static time_point now() noexcept;
+};
+} // namespace chrono
+
+class mutex;
+template <class Mutex>
+class unique_lock {
+public:
+  typedef Mutex mutex_type;
+
+  unique_lock() noexcept;
+  explicit unique_lock(mutex_type &m);
+};
+
+class mutex {
+public:
+  constexpr mutex() noexcept;
+  ~mutex();
+  mutex(const mutex &) = delete;
+  mutex &operator=(const mutex &) = delete;
+};
+
+enum class cv_status {
+  no_timeout,
+  timeout
+};
+
+class condition_variable {
+public:
+  condition_variable();
+  ~condition_variable();
+  condition_variable(const condition_variable &) = delete;
+
+  void wait(unique_lock<mutex> &lock);
+  template <class Predicate>
+  void wait(unique_lock<mutex> &lock, Predicate pred);
+  template <class Clock, class Duration>
+  cv_status wait_until(unique_lock<mutex> &lock,
+                       const chrono::time_point<Clock, Duration> &abs_time){};
+  template <class Clock, class Duration, class Predicate>
+  bool wait_until(unique_lock<mutex> &lock,
+                  const chrono::time_point<Clock, Duration> &abs_time,
+                  Predicate pred){};
+  template <class Rep, class Period>
+  cv_status wait_for(unique_lock<mutex> &lock,
+                     const chrono::duration<Rep, Period> &rel_time){};
+  template <class Rep, class Period, class Predicate>
+  bool wait_for(unique_lock<mutex> &lock,
+                const chrono::duration<Rep, Period> &rel_time,
+                Predicate pred){};
+};
+
+} // namespace std
+
+struct Node1 {
+  void *Node1;
+  struct Node1 *next;
+};
+
+static Node1 list;
+static std::mutex m;
+static std::condition_variable condition;
+
+void consume_list_element(std::condition_variable &condition) {
+  std::unique_lock<std::mutex> lk(m);
+
+  if (list.next == nullptr) {
+    condition.wait(lk);
+    // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 'wait' should be placed inside a while statement or used with a conditional parameter [bugprone-spuriously-wake-up-functions]
+  }
+
+  while (list.next == nullptr) {
+    condition.wait(lk);
+  }
+
+  do {
+    condition.wait(lk);
+  } while (list.next == nullptr);
+
+  for (;; list.next == nullptr) {
+    condition.wait(lk);
+  }
+
+  if (list.next == nullptr) {
+    while (list.next == nullptr) {
+      condition.wait(lk);
+    }
+  }
+
+  if (list.next == nullptr) {
+    do {
+      condition.wait(lk);
+    } while (list.next == nullptr);
+  }
+
+  if (list.next == nullptr) {
+    for (;; list.next == nullptr) {
+      condition.wait(lk);
+    }
+  }
+  using durtype = std::chrono::duration<int, std::milli>;
+  durtype dur = std::chrono::duration<int, std::milli>();
+  if (list.next == nullptr) {
+    condition.wait_for(lk, dur);
+    // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 'wait_for' should be placed inside a while statement or used with a conditional parameter [bugprone-spuriously-wake-up-functions]
+  }
+  if (list.next == nullptr) {
+    condition.wait_for(lk, dur, [] { return 1; });
+  }
+  while (list.next == nullptr) {
+    condition.wait_for(lk, dur);
+  }
+  do {
+    condition.wait_for(lk, dur);
+  } while (list.next == nullptr);
+  for (;; list.next == nullptr) {
+    condition.wait_for(lk, dur);
+  }
+
+  auto now = std::chrono::system_clock::now();
+  if (list.next == nullptr) {
+    condition.wait_until(lk, now);
+    // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 'wait_until' should be placed inside a while statement or used with a conditional parameter [bugprone-spuriously-wake-up-functions]
+  }
+  if (list.next == nullptr) {
+    condition.wait_until(lk, now, [] { return 1; });
+  }
+  while (list.next == nullptr) {
+    condition.wait_until(lk, now);
+  }
+  do {
+    condition.wait_until(lk, now);
+  } while (list.next == nullptr);
+  for (;; list.next == nullptr) {
+    condition.wait_until(lk, now);
+  }
+}
Index: clang-tools-extra/test/clang-tidy/bugprone-spuriously-wake-up-functions.c
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/bugprone-spuriously-wake-up-functions.c
@@ -0,0 +1,164 @@
+// RUN: %check_clang_tidy %s bugprone-spuriously-wake-up-functions %t -- --
+#define NULL 0
+
+struct Node1 {
+  void *Node1;
+  struct Node1 *next;
+};
+
+typedef struct mtx_t {
+} mtx_t;
+typedef struct cnd_t {
+} cnd_t;
+struct timespec {};
+
+int cnd_wait(cnd_t *cond, mtx_t *mutex){};
+int cnd_timedwait(cnd_t *cond, mtx_t *mutex,
+                  const struct timespec *time_point){};
+
+struct Node1 list_c;
+static mtx_t lock;
+static cnd_t condition_c;
+struct timespec ts;
+
+void consume_list_element(void) {
+
+  if (list_c.next == NULL) {
+    if (0 != cnd_wait(&condition_c, &lock)) {
+      // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 'cnd_wait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
+    }
+  }
+  if (list_c.next == NULL)
+    if (0 != cnd_wait(&condition_c, &lock))
+      // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 'cnd_wait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
+      ;
+  if (list_c.next == NULL && 0 != cnd_wait(&condition_c, &lock))
+    // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: 'cnd_wait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
+    ;
+  while (list_c.next == NULL) {
+    if (0 != cnd_wait(&condition_c, &lock)) {
+    }
+  }
+  while (list_c.next == NULL)
+    if (0 != cnd_wait(&condition_c, &lock)) {
+    }
+  while (list_c.next == NULL)
+    if (0 != cnd_wait(&condition_c, &lock))
+      ;
+  if (list_c.next == NULL) {
+    cnd_wait(&condition_c, &lock);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'cnd_wait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
+  }
+  if (list_c.next == NULL)
+    cnd_wait(&condition_c, &lock);
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'cnd_wait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
+  while (list_c.next == NULL) {
+    cnd_wait(&condition_c, &lock);
+  }
+  while (list_c.next == NULL)
+    cnd_wait(&condition_c, &lock);
+
+  do {
+    if (0 != cnd_wait(&condition_c, &lock)) {
+    }
+  } while (list_c.next == NULL);
+  do
+    if (0 != cnd_wait(&condition_c, &lock)) {
+    }
+  while (list_c.next == NULL);
+  do
+    if (0 != cnd_wait(&condition_c, &lock))
+      ;
+  while (list_c.next == NULL);
+  do {
+    cnd_wait(&condition_c, &lock);
+  } while (list_c.next == NULL);
+  do
+    cnd_wait(&condition_c, &lock);
+  while (list_c.next == NULL);
+  for (;; list_c.next == NULL) {
+    if (0 != cnd_wait(&condition_c, &lock)) {
+    }
+  }
+  for (;; list_c.next == NULL)
+    if (0 != cnd_wait(&condition_c, &lock)) {
+    }
+  for (;; list_c.next == NULL)
+    if (0 != cnd_wait(&condition_c, &lock))
+      ;
+  for (;; list_c.next == NULL) {
+    cnd_wait(&condition_c, &lock);
+  }
+  for (;; list_c.next == NULL)
+    cnd_wait(&condition_c, &lock);
+
+  if (list_c.next == NULL) {
+    if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
+      // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 'cnd_timedwait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
+    }
+  }
+  if (list_c.next == NULL)
+    if (0 != cnd_timedwait(&condition_c, &lock, &ts))
+      // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 'cnd_timedwait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
+      ;
+  if (list_c.next == NULL && 0 != cnd_timedwait(&condition_c, &lock, &ts))
+    // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: 'cnd_timedwait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
+    ;
+  while (list_c.next == NULL) {
+    if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
+    }
+  }
+  while (list_c.next == NULL)
+    if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
+    }
+  while (list_c.next == NULL)
+    if (0 != cnd_timedwait(&condition_c, &lock, &ts))
+      ;
+  if (list_c.next == NULL) {
+    cnd_timedwait(&condition_c, &lock, &ts);
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'cnd_timedwait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
+  }
+  if (list_c.next == NULL)
+    cnd_timedwait(&condition_c, &lock, &ts);
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'cnd_timedwait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
+  while (list_c.next == NULL) {
+    cnd_timedwait(&condition_c, &lock, &ts);
+  }
+  while (list_c.next == NULL)
+    cnd_timedwait(&condition_c, &lock, &ts);
+
+  do {
+    if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
+    }
+  } while (list_c.next == NULL);
+  do
+    if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
+    }
+  while (list_c.next == NULL);
+  do
+    if (0 != cnd_timedwait(&condition_c, &lock, &ts))
+      ;
+  while (list_c.next == NULL);
+  do {
+    cnd_timedwait(&condition_c, &lock, &ts);
+  } while (list_c.next == NULL);
+  do
+    cnd_timedwait(&condition_c, &lock, &ts);
+  while (list_c.next == NULL);
+  for (;; list_c.next == NULL) {
+    if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
+    }
+  }
+  for (;; list_c.next == NULL)
+    if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
+    }
+  for (;; list_c.next == NULL)
+    if (0 != cnd_timedwait(&condition_c, &lock, &ts))
+      ;
+  for (;; list_c.next == NULL) {
+    cnd_timedwait(&condition_c, &lock, &ts);
+  }
+  for (;; list_c.next == NULL)
+    cnd_timedwait(&condition_c, &lock, &ts);
+}
+int main() { return 0; }
\ No newline at end of file
Index: clang-tools-extra/docs/clang-tidy/checks/list.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -75,6 +75,7 @@
    `bugprone-signed-char-misuse <bugprone-signed-char-misuse.html>`_,
    `bugprone-sizeof-container <bugprone-sizeof-container.html>`_,
    `bugprone-sizeof-expression <bugprone-sizeof-expression.html>`_,
+   `bugprone-spuriously-wake-up-functions <bugprone-spuriously-wake-up-functions.html>`_,
    `bugprone-string-constructor <bugprone-string-constructor.html>`_, "Yes"
    `bugprone-string-integer-assignment <bugprone-string-integer-assignment.html>`_, "Yes"
    `bugprone-string-literal-with-embedded-nul <bugprone-string-literal-with-embedded-nul.html>`_,
@@ -296,6 +297,8 @@
 .. csv-table:: Aliases..
    :header: "Name", "Redirect", "Offers fixes"
 
+   `cert-con36-c <cert-con36-c.html>`_, `bugprone-spuriously-wake-up-functions <bugprone-spuriously-wake-up-functions.html>`_,
+   `cert-con54-cpp <cert-con54-cpp.html>`_, `bugprone-spuriously-wake-up-functions <bugprone-spuriously-wake-up-functions.html>`_,
    `cert-dcl03-c <cert-dcl03-c.html>`_, `misc-static-assert <misc-static-assert.html>`_, "Yes"
    `cert-dcl16-c <cert-dcl16-c.html>`_, `readability-uppercase-literal-suffix <readability-uppercase-literal-suffix.html>`_, "Yes"
    `cert-dcl54-cpp <cert-dcl54-cpp.html>`_, `misc-new-delete-overloads <misc-new-delete-overloads.html>`_,
Index: clang-tools-extra/docs/clang-tidy/checks/cert-con54-cpp.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/cert-con54-cpp.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - cert-con54-cpp
+.. meta::
+:http-equiv=refresh: 5;URL=bugprone-spuriously-wake-up-functions.html
+	
+cert-con54-cpp
+==============
+
+The cert-con54-cpp check is an alias, please see
+`bugprone-spuriously-wake-up-functions <bugprone-spuriously-wake-up-functions.html>`_ 
+for more information.
Index: clang-tools-extra/docs/clang-tidy/checks/cert-con36-c.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/cert-con36-c.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - cert-con36-c
+.. meta::
+:http-equiv=refresh: 5;URL=bugprone-spuriously-wake-up-functions.html
+	
+cert-con36-c
+============
+
+The cert-con36-c check is an alias, please see
+`bugprone-spuriously-wake-up-functions <bugprone-spuriously-wake-up-functions.html>`_ 
+for more information.
Index: clang-tools-extra/docs/clang-tidy/checks/bugprone-spuriously-wake-up-functions.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/bugprone-spuriously-wake-up-functions.rst
@@ -0,0 +1,29 @@
+.. title:: clang-tidy - bugprone-spuriously-wake-up-functions
+
+bugprone-spuriously-wake-up-functions
+=====================================
+
+Finds ``cnd_wait``, ``cnd_timedwait``, ``wait``, ``wait_for``, or 
+``wait_until`` function calls when the function is not invoked from a loop
+that checks whether a condition predicate holds or the function has a 
+condition parameter.
+
+.. code-block: c++
+
+    if (condition_predicate) {
+        condition.wait(lk);
+    }
+
+.. code-block: c
+
+    if (condition_predicate) {
+        if (thrd_success != cnd_wait(&condition, &lock)) {
+        }
+    }
+
+This check corresponds to the CERT C++ Coding Standard rule
+`CON54-CPP. Wrap functions that can spuriously wake up in a loop
+<https://wiki.sei.cmu.edu/confluence/display/cplusplus/CON54-CPP.+Wrap+functions+that+can+spuriously+wake+up+in+a+loop>`_.
+and CERT C Coding Standard rule
+`CON36-C. Wrap functions that can spuriously wake up in a loop
+<https://wiki.sei.cmu.edu/confluence/display/c/CON36-C.+Wrap+functions+that+can+spuriously+wake+up+in+a+loop>`_.
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -77,6 +77,14 @@
   result of a memory allocation function (``malloc()``, ``calloc()``,
   ``realloc()``, ``alloca()``) instead of its argument.
 
+- New :doc:`bugprone-spuriously-wake-up-functions
+  <clang-tidy/checks/bugprone-spuriously-wake-up-functions>` check.
+
+  Finds ``cnd_wait``, ``cnd_timedwait``, ``wait``, ``wait_for``, or
+  ``wait_until`` function calls when the function is not invoked from a loop
+  that checks whether a condition predicate holds or the function has a 
+  condition parameter.
+
 - New :doc:`bugprone-reserved-identifier
   <clang-tidy/checks/bugprone-reserved-identifier>` check.
 
@@ -96,6 +104,16 @@
 New check aliases
 ^^^^^^^^^^^^^^^^^
 
+- New alias :doc:`cert-con36-c
+  <clang-tidy/checks/cert-con36-c>` to
+  :doc:`bugprone-spuriously-wake-up-functions
+  <clang-tidy/checks/bugprone-spuriously-wake-up-functions>` was added.
+
+- New alias :doc:`cert-con54-cpp
+  <clang-tidy/checks/cert-con54-cpp>` to
+  :doc:`bugprone-spuriously-wake-up-functions
+  <clang-tidy/checks/bugprone-spuriously-wake-up-functions>` was added.
+
 - New alias :doc:`cert-dcl37-c
   <clang-tidy/checks/cert-dcl37-c>` to
   :doc:`bugprone-reserved-identifier
Index: clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
+++ clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
@@ -11,6 +11,7 @@
 #include "../ClangTidyModuleRegistry.h"
 #include "../bugprone/BadSignalToKillThreadCheck.h"
 #include "../bugprone/ReservedIdentifierCheck.h"
+#include "../bugprone/SpuriouslyWakeUpFunctionsCheck.h"
 #include "../bugprone/UnhandledSelfAssignmentCheck.h"
 #include "../google/UnnamedNamespaceInHeaderCheck.h"
 #include "../misc/NewDeleteOverloadsCheck.h"
@@ -42,6 +43,9 @@
 public:
   void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
     // C++ checkers
+    // CON
+    CheckFactories.registerCheck<bugprone::SpuriouslyWakeUpFunctionsCheck>(
+        "cert-con54-cpp");
     // DCL
     CheckFactories.registerCheck<PostfixOperatorCheck>(
         "cert-dcl21-cpp");
@@ -80,6 +84,9 @@
         "cert-oop58-cpp");
 
     // C checkers
+    // CON
+    CheckFactories.registerCheck<bugprone::SpuriouslyWakeUpFunctionsCheck>(
+        "cert-con36-c");
     // DCL
     CheckFactories.registerCheck<misc::StaticAssertCheck>("cert-dcl03-c");
     CheckFactories.registerCheck<readability::UppercaseLiteralSuffixCheck>(
Index: clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.h
@@ -0,0 +1,37 @@
+//===--- SpuriouslyWakeUpFunctionsCheck.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_BUGPRONE_SPURIOUSLYWAKEUPFUNCTIONSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPURIOUSLYWAKEUPFUNCTIONSCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds ``cnd_wait``, ``cnd_timedwait``, ``wait``, ``wait_for``, or 
+/// ``wait_until`` function calls when the function is not invoked from a loop 
+/// that checks whether a condition predicate holds or the function has a 
+/// condition parameter.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-spuriously-wake-up-functions.html
+class SpuriouslyWakeUpFunctionsCheck : public ClangTidyCheck {
+public:
+  SpuriouslyWakeUpFunctionsCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPURIOUSLYWAKEUPFUNCTIONSCHECK_H
Index: clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.cpp
@@ -0,0 +1,108 @@
+//===--- SpuriouslyWakeUpFunctionsCheck.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 "SpuriouslyWakeUpFunctionsCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+void SpuriouslyWakeUpFunctionsCheck::registerMatchers(MatchFinder *Finder) {
+
+  auto hasUniqueLock = hasDescendant(declRefExpr(
+      hasDeclaration(varDecl(hasType(recordDecl(classTemplateSpecializationDecl(
+          hasName("::std::unique_lock"),
+          hasTemplateArgument(
+              0, templateArgument(refersToType(qualType(hasDeclaration(
+                     cxxRecordDecl(hasName("::std::mutex"))))))))))))));
+
+  auto hasWaitDescendantCPP = hasDescendant(
+      cxxMemberCallExpr(
+          anyOf(
+              allOf(hasDescendant(memberExpr(hasDeclaration(functionDecl(
+                        allOf(hasName("::std::condition_variable::wait"),
+                              parameterCountIs(1)))))),
+                    onImplicitObjectArgument(
+                        declRefExpr(to(varDecl(hasType(references(recordDecl(
+                            hasName("::std::condition_variable")))))))),
+                    hasUniqueLock),
+              allOf(hasDescendant(memberExpr(hasDeclaration(functionDecl(
+                        allOf(hasName("::std::condition_variable::wait_for"),
+                              parameterCountIs(2)))))),
+                    onImplicitObjectArgument(
+                        declRefExpr(to(varDecl(hasType(references(recordDecl(
+                            hasName("::std::condition_variable")))))))),
+                    hasUniqueLock),
+              allOf(hasDescendant(memberExpr(hasDeclaration(functionDecl(
+                        allOf(hasName("::std::condition_variable::wait_until"),
+                              parameterCountIs(2)))))),
+                    onImplicitObjectArgument(
+                        declRefExpr(to(varDecl(hasType(references(recordDecl(
+                            hasName("::std::condition_variable")))))))),
+                    hasUniqueLock)
+
+                  ))
+          .bind("wait"));
+
+  auto hasWaitDescendantC = hasDescendant(
+      callExpr(callee(functionDecl(
+                   anyOf(hasName("cnd_wait"), hasName("cnd_timedwait")))))
+          .bind("wait"));
+  if (getLangOpts().CPlusPlus) {
+    // Check for `CON54-CPP`
+    Finder->addMatcher(
+        ifStmt(
+
+            allOf(hasWaitDescendantCPP,
+                  unless(anyOf(hasDescendant(ifStmt(hasWaitDescendantCPP)),
+                               hasDescendant(whileStmt(hasWaitDescendantCPP)),
+                               hasDescendant(forStmt(hasWaitDescendantCPP)),
+                               hasDescendant(doStmt(hasWaitDescendantCPP)))))
+
+                ),
+        this);
+  } else {
+    // Check for `CON36-C`
+    Finder->addMatcher(
+
+        ifStmt(
+            allOf(hasWaitDescendantC,
+                  unless(anyOf(hasDescendant(ifStmt(hasWaitDescendantC)),
+                               hasDescendant(whileStmt(hasWaitDescendantC)),
+                               hasDescendant(forStmt(hasWaitDescendantC)),
+                               hasDescendant(doStmt(hasWaitDescendantC)),
+                               hasParent(whileStmt()),
+                               hasParent(compoundStmt(hasParent(whileStmt()))),
+                               hasParent(forStmt()),
+                               hasParent(compoundStmt(hasParent(forStmt()))),
+                               hasParent(doStmt()),
+                               hasParent(compoundStmt(hasParent(doStmt())))))
+
+                      ))
+
+            ,
+        this);
+  }
+}
+
+void SpuriouslyWakeUpFunctionsCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *MatchedWait = Result.Nodes.getNodeAs<CallExpr>("wait");
+  StringRef WaitName = MatchedWait->getDirectCallee()->getName();
+  diag(MatchedWait->getExprLoc(),
+       "'%0' should be placed inside a while statement %select{|or used with a "
+       "conditional parameter}1")
+      << WaitName << (WaitName != "cnd_wait" && WaitName != "cnd_timedwait");
+}
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
Index: clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -33,6 +33,7 @@
   SignedCharMisuseCheck.cpp
   SizeofContainerCheck.cpp
   SizeofExpressionCheck.cpp
+  SpuriouslyWakeUpFunctionsCheck.cpp
   StringConstructorCheck.cpp
   StringIntegerAssignmentCheck.cpp
   StringLiteralWithEmbeddedNulCheck.cpp
Index: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -41,6 +41,7 @@
 #include "SignedCharMisuseCheck.h"
 #include "SizeofContainerCheck.h"
 #include "SizeofExpressionCheck.h"
+#include "SpuriouslyWakeUpFunctionsCheck.h"
 #include "StringConstructorCheck.h"
 #include "StringIntegerAssignmentCheck.h"
 #include "StringLiteralWithEmbeddedNulCheck.h"
@@ -132,6 +133,8 @@
         "bugprone-sizeof-container");
     CheckFactories.registerCheck<SizeofExpressionCheck>(
         "bugprone-sizeof-expression");
+    CheckFactories.registerCheck<SpuriouslyWakeUpFunctionsCheck>(
+        "bugprone-spuriously-wake-up-functions");
     CheckFactories.registerCheck<StringConstructorCheck>(
         "bugprone-string-constructor");
     CheckFactories.registerCheck<StringIntegerAssignmentCheck>(
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to