Author: Noah Watkins
Date: 2023-03-10T14:06:50Z
New Revision: 54178fc6161a5856bea608dce0d726787a3b71c3

URL: 
https://github.com/llvm/llvm-project/commit/54178fc6161a5856bea608dce0d726787a3b71c3
DIFF: 
https://github.com/llvm/llvm-project/commit/54178fc6161a5856bea608dce0d726787a3b71c3.diff

LOG: [clang-tidy] add check for capturing lambda coroutines

Signed-off-by: Noah Watkins <n...@redpanda.com>

Reviewed By: ChuanqiXu

Differential Revision: https://reviews.llvm.org/D137514

Added: 
    
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.cpp
    
clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.h
    
clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines.rst
    
clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-capturing-lambda-coroutines.cpp

Modified: 
    clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
    
clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.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/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.cpp
 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.cpp
new file mode 100644
index 0000000000000..de9c9eaa7f407
--- /dev/null
+++ 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.cpp
@@ -0,0 +1,45 @@
+//===--- AvoidCapturingLambdaCoroutinesCheck.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 "AvoidCapturingLambdaCoroutinesCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+void AvoidCapturingLambdaCoroutinesCheck::registerMatchers(
+    MatchFinder *Finder) {
+  Finder->addMatcher(lambdaExpr().bind("lambda"), this);
+}
+
+void AvoidCapturingLambdaCoroutinesCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
+  if (!Lambda) {
+    return;
+  }
+
+  const auto *Body = dyn_cast<CoroutineBodyStmt>(Lambda->getBody());
+  if (!Body) {
+    return;
+  }
+
+  if (Lambda->captures().empty()) {
+    return;
+  }
+
+  diag(Lambda->getBeginLoc(), "found capturing coroutine lambda");
+}
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang

diff  --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.h
 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.h
new file mode 100644
index 0000000000000..63895f3354414
--- /dev/null
+++ 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidCapturingLambdaCoroutinesCheck.h
@@ -0,0 +1,36 @@
+//===--- AvoidCapturingLambdaCoroutinesCheck.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_AVOIDCAPTURINGLAMBDACOROUTINESCHECK_H
+#define 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDCAPTURINGLAMBDACOROUTINESCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace cppcoreguidelines {
+
+/// The normal usage of captures in lambdas are problematic when the lambda is 
a
+/// coroutine because the captures are destroyed after the first suspension
+/// point. Using the captures after this point is a use-after-free issue.
+///
+/// For the user-facing documentation see:
+/// 
http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-avoid-capturing-lambda-coroutines.html
+class AvoidCapturingLambdaCoroutinesCheck : public ClangTidyCheck {
+public:
+  AvoidCapturingLambdaCoroutinesCheck(StringRef Name, ClangTidyContext 
*Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace cppcoreguidelines
+} // namespace tidy
+} // namespace clang
+
+#endif // 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CPPCOREGUIDELINES_AVOIDCAPTURINGLAMBDACOROUTINESCHECK_H

diff  --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
index bd7a999a71743..4210c3ea03fc8 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/CMakeLists.txt
@@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_clang_library(clangTidyCppCoreGuidelinesModule
   AvoidCaptureDefaultWhenCapturingThisCheck.cpp
+  AvoidCapturingLambdaCoroutinesCheck.cpp
   AvoidConstOrRefDataMembersCheck.cpp
   AvoidDoWhileCheck.cpp
   AvoidGotoCheck.cpp

diff  --git 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
index ac70fc8eaa24c..ac4b8d7b01d7a 100644
--- 
a/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
+++ 
b/clang-tools-extra/clang-tidy/cppcoreguidelines/CppCoreGuidelinesTidyModule.cpp
@@ -15,6 +15,7 @@
 #include "../modernize/UseOverrideCheck.h"
 #include "../readability/MagicNumbersCheck.h"
 #include "AvoidCaptureDefaultWhenCapturingThisCheck.h"
+#include "AvoidCapturingLambdaCoroutinesCheck.h"
 #include "AvoidConstOrRefDataMembersCheck.h"
 #include "AvoidDoWhileCheck.h"
 #include "AvoidGotoCheck.h"
@@ -50,6 +51,8 @@ class CppCoreGuidelinesModule : public ClangTidyModule {
   void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
     CheckFactories.registerCheck<AvoidCaptureDefaultWhenCapturingThisCheck>(
         "cppcoreguidelines-avoid-capture-default-when-capturing-this");
+    CheckFactories.registerCheck<AvoidCapturingLambdaCoroutinesCheck>(
+        "cppcoreguidelines-avoid-capturing-lambda-coroutines");
     CheckFactories.registerCheck<modernize::AvoidCArraysCheck>(
         "cppcoreguidelines-avoid-c-arrays");
     CheckFactories.registerCheck<AvoidConstOrRefDataMembersCheck>(

diff  --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index e8a74f8402460..64908944913fc 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -120,6 +120,13 @@ New checks
   Checks that all implicit and explicit inline functions in header files are
   tagged with the ``LIBC_INLINE`` macro.
 
+- New :doc:`cppcoreguidelines-avoid-capturing-lambda-coroutines
+  <clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines>` 
check.
+
+  Adds check for cpp core guideline: "CP.51: Do not use capturing lambdas that
+  are coroutines."
+
+
 New check aliases
 ^^^^^^^^^^^^^^^^^
 

diff  --git 
a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines.rst
 
b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines.rst
new file mode 100644
index 0000000000000..c199152edeac3
--- /dev/null
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/avoid-capturing-lambda-coroutines.rst
@@ -0,0 +1,31 @@
+.. title:: clang-tidy - cppcoreguidelines-avoid-capturing-lambda-coroutines
+
+cppcoreguidelines-avoid-capturing-lambda-coroutines
+===================================================
+
+Warns if a capturing lambda is a coroutine. For example:
+
+.. code-block:: c++
+
+   int c;
+
+   [c] () -> task { co_return; };
+   [&] () -> task { int y = c; co_return; };
+   [=] () -> task { int y = c; co_return; };
+
+   struct s {
+       void m() {
+           [this] () -> task { co_return; };
+       }
+   };
+
+All of the cases above will trigger the warning. However, implicit captures
+do not trigger the warning unless the body of the lambda uses the capture.
+For example, the following do not trigger the warning.
+
+.. code-block:: c++
+
+   int c;
+
+   [&] () -> task { co_return; };
+   [=] () -> task { co_return; };

diff  --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst 
b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 5a2f9c877a961..0eb15a9d382e0 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -180,6 +180,7 @@ Clang-Tidy Checks
    `concurrency-mt-unsafe <concurrency/mt-unsafe.html>`_,
    `concurrency-thread-canceltype-asynchronous 
<concurrency/thread-canceltype-asynchronous.html>`_,
    `cppcoreguidelines-avoid-capture-default-when-capturing-this 
<cppcoreguidelines/avoid-capture-default-when-capturing-this.html>`_,
+   `cppcoreguidelines-avoid-capturing-lambda-coroutines 
<cppcoreguidelines/avoid-capturing-lambda-coroutines.html>`_, "Yes"
    `cppcoreguidelines-avoid-const-or-ref-data-members 
<cppcoreguidelines/avoid-const-or-ref-data-members.html>`_,
    `cppcoreguidelines-avoid-do-while <cppcoreguidelines/avoid-do-while.html>`_,
    `cppcoreguidelines-avoid-goto <cppcoreguidelines/avoid-goto.html>`_,

diff  --git 
a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-capturing-lambda-coroutines.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-capturing-lambda-coroutines.cpp
new file mode 100644
index 0000000000000..9a8a88e5d0283
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/avoid-capturing-lambda-coroutines.cpp
@@ -0,0 +1,35 @@
+// RUN: %check_clang_tidy -std=c++20-or-later %s 
cppcoreguidelines-avoid-capturing-lambda-coroutines %t -- -- \
+// RUN:   -isystem %S/../readability/Inputs/identifier-naming/system
+
+#include <coroutines.h>
+
+void Caught() {
+    int v;
+
+    [&] () -> task { int y = v; co_return; };
+    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: found capturing coroutine 
lambda [cppcoreguidelines-avoid-capturing-lambda-coroutines]
+    [=] () -> task { int y = v; co_return; };
+    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: found capturing coroutine 
lambda [cppcoreguidelines-avoid-capturing-lambda-coroutines]
+    [v] () -> task { co_return; };
+    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: found capturing coroutine 
lambda [cppcoreguidelines-avoid-capturing-lambda-coroutines]
+    [&v] () -> task { co_return; };
+    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: found capturing coroutine 
lambda [cppcoreguidelines-avoid-capturing-lambda-coroutines]
+    [y=v] () -> task { co_return; };
+    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: found capturing coroutine 
lambda [cppcoreguidelines-avoid-capturing-lambda-coroutines]
+    [y{v}] () -> task { co_return; };
+    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: found capturing coroutine 
lambda [cppcoreguidelines-avoid-capturing-lambda-coroutines]
+}
+
+struct S {
+    void m() {
+        [this] () -> task { co_return; };
+        // CHECK-MESSAGES: [[@LINE-1]]:9: warning: found capturing coroutine 
lambda [cppcoreguidelines-avoid-capturing-lambda-coroutines]
+    }
+};
+
+void Safe() {
+    int v;
+    [] () -> task { co_return; };
+    [&] () -> task { co_return; };
+    [=] () -> task { co_return; };
+}


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to