[clang] [webkit.UncountedLambdaCapturesChecker] Fix a regression that [[noescape]] on a member function no longer works. (PR #126016)

Ryosuke Niwa via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 6 15:08:10 PST 2025


https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/126016

>From b4c9048f3f28bd0522338ef7e4498926b66db571 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Wed, 5 Feb 2025 22:48:30 -0800
Subject: [PATCH 1/2] [webkit.UncountedLambdaCapturesChecker] Fix a regression
 that [[noescape]] on a member function no longer works.

We should skip the first argument for CXXOperatorCallExpr, not other kinds of calls.
---
 .../WebKit/UncountedLambdaCapturesChecker.cpp |  4 +---
 .../WebKit/uncounted-lambda-captures.cpp      | 23 +++++++++++++++++++
 2 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
index 53ef423bd82e7e2..a56f48c83c660a9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
@@ -109,9 +109,7 @@ class UncountedLambdaCapturesChecker
       bool VisitCallExpr(CallExpr *CE) override {
         checkCalleeLambda(CE);
         if (auto *Callee = CE->getDirectCallee()) {
-          unsigned ArgIndex = 0;
-          if (auto *CXXCallee = dyn_cast<CXXMethodDecl>(Callee))
-            ArgIndex = CXXCallee->isInstance();
+          unsigned ArgIndex = isa<CXXOperatorCallExpr>(CE);
           bool TreatAllArgsAsNoEscape = shouldTreatAllArgAsNoEscape(Callee);
           for (auto *Param : Callee->parameters()) {
             if (ArgIndex >= CE->getNumArgs())
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
index 2a1a164557cdbe7..b6e84769fdf7247 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
@@ -63,6 +63,18 @@ template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::Callab
     return Function<Out(In...)>(impl, Function<Out(In...)>::Adopt);
 }
 
+template <typename KeyType, typename ValueType>
+class HashMap {
+public:
+  HashMap();
+  HashMap([[clang::noescape]] const Function<ValueType()>&);
+  void ensure(const KeyType&, [[clang::noescape]] const Function<ValueType()>&);
+  bool operator+([[clang::noescape]] const Function<ValueType()>&) const;
+
+private:
+  ValueType* m_table { nullptr };
+};
+
 } // namespace WTF
 
 struct A {
@@ -268,6 +280,17 @@ struct RefCountableWithLambdaCapturingThis {
       nonTrivial();
     });
   }
+
+  void method_captures_this_in_template_method() {
+    RefCountable* obj = make_obj();
+    WTF::HashMap<int, RefPtr<RefCountable>> nextMap;
+    nextMap.ensure(3, [&] {
+      return obj->next();
+    });
+    nextMap+[&] {
+      return obj->next();
+    };
+  }
 };
 
 struct NonRefCountableWithLambdaCapturingThis {

>From 2988246096b23979c565b10c500518413f6dfd8d Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Thu, 6 Feb 2025 15:06:50 -0800
Subject: [PATCH 2/2] Add more test cases for passing a lambda to a static
 member function and a non-member function.

---
 .../Checkers/WebKit/uncounted-lambda-captures.cpp         | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
index b6e84769fdf7247..4f4a96028225303 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
@@ -70,6 +70,7 @@ class HashMap {
   HashMap([[clang::noescape]] const Function<ValueType()>&);
   void ensure(const KeyType&, [[clang::noescape]] const Function<ValueType()>&);
   bool operator+([[clang::noescape]] const Function<ValueType()>&) const;
+  static void ifAny(HashMap, [[clang::noescape]] const Function<bool(ValueType)>&);
 
 private:
   ValueType* m_table { nullptr };
@@ -281,6 +282,7 @@ struct RefCountableWithLambdaCapturingThis {
     });
   }
 
+  static void callLambda([[clang::noescape]] const WTF::Function<RefPtr<RefCountable>()>&);
   void method_captures_this_in_template_method() {
     RefCountable* obj = make_obj();
     WTF::HashMap<int, RefPtr<RefCountable>> nextMap;
@@ -290,6 +292,12 @@ struct RefCountableWithLambdaCapturingThis {
     nextMap+[&] {
       return obj->next();
     };
+    WTF::HashMap<int, RefPtr<RefCountable>>::ifAny(nextMap, [&](auto& item) -> bool {
+      return item->next() && obj->next();
+    });
+    callLambda([&]() -> RefPtr<RefCountable> {
+      return obj->next();
+    });
   }
 };
 



More information about the cfe-commits mailing list