https://github.com/rniwa created 
https://github.com/llvm/llvm-project/pull/170820

This PR adds support for treating WTF::move like std::move in various WebKit 
checkers.

>From f7951e6a535a92e6e551242d6f352b9f00e45935 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <[email protected]>
Date: Fri, 5 Dec 2025 01:03:17 -0800
Subject: [PATCH] Add the support for recognizing WTF::move like std::move

This PR adds support for treating WTF::move like std::move in various WebKit 
checkers.
---
 clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp  | 10 +++++-----
 .../Checkers/WebKit/ForwardDeclChecker.cpp             |  3 +--
 .../Checkers/WebKit/PtrTypesSemantics.cpp              |  9 +++++++++
 .../StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h |  3 +++
 .../Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp |  7 ++-----
 .../Analysis/Checkers/WebKit/call-args-checked.cpp     |  1 +
 .../Analysis/Checkers/WebKit/forward-decl-checker.mm   |  3 +++
 clang/test/Analysis/Checkers/WebKit/mock-types.h       |  6 ++++++
 clang/test/Analysis/Checkers/WebKit/objc-mock-types.h  | 10 ++++++++--
 .../Checkers/WebKit/uncounted-lambda-captures.cpp      |  8 ++++++++
 .../Analysis/Checkers/WebKit/uncounted-obj-arg.cpp     |  1 +
 11 files changed, 47 insertions(+), 14 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
index 84adbf318e9f8..8f104feffa66b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
@@ -132,11 +132,6 @@ bool tryToFindPtrOrigin(
         }
       }
 
-      if (call->isCallToStdMove() && call->getNumArgs() == 1) {
-        E = call->getArg(0)->IgnoreParenCasts();
-        continue;
-      }
-
       if (auto *callee = call->getDirectCallee()) {
         if (isCtorOfSafePtr(callee)) {
           if (StopAtFirstRefCountedObj)
@@ -146,6 +141,11 @@ bool tryToFindPtrOrigin(
           continue;
         }
 
+        if (isStdOrWTFMove(callee) && call->getNumArgs() == 1) {
+          E = call->getArg(0)->IgnoreParenCasts();
+          continue;
+        }
+
         if (isSafePtrType(callee->getReturnType()))
           return callback(E, true);
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp
index 1d4e6dd572749..59336328a2823 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp
@@ -267,8 +267,7 @@ class ForwardDeclChecker : public 
Checker<check::ASTDecl<TranslationUnitDecl>> {
       ArgExpr = ArgExpr->IgnoreParenCasts();
       if (auto *InnerCE = dyn_cast<CallExpr>(ArgExpr)) {
         auto *InnerCallee = InnerCE->getDirectCallee();
-        if (InnerCallee && InnerCallee->isInStdNamespace() &&
-            safeGetName(InnerCallee) == "move" && InnerCE->getNumArgs() == 1) {
+        if (isStdOrWTFMove(InnerCallee) && InnerCE->getNumArgs() == 1) {
           ArgExpr = InnerCE->getArg(0);
           continue;
         }
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 5cd894af1fd65..3636b37dea632 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -185,6 +185,15 @@ bool isCtorOfSafePtr(const clang::FunctionDecl *F) {
          isCtorOfRetainPtrOrOSPtr(F);
 }
 
+bool isStdOrWTFMove(const clang::FunctionDecl *F) {
+  auto FnName = safeGetName(F);
+  auto *Namespace = F->getParent();
+  if (!Namespace)
+    return false;
+  auto NsName = safeGetName(Namespace);
+  return (NsName == "WTF" || NsName == "std") && FnName == "move";
+}
+
 template <typename Predicate>
 static bool isPtrOfType(const clang::QualType T, Predicate Pred) {
   QualType type = T;
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 12e2e2d75b75d..96250f7f851e9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -134,6 +134,9 @@ bool isCtorOfCheckedPtr(const clang::FunctionDecl *F);
 /// uncounted parameter, false if not.
 bool isCtorOfSafePtr(const clang::FunctionDecl *F);
 
+/// \returns true if \p F is std::move or WTF::move.
+bool isStdOrWTFMove(const clang::FunctionDecl *F);
+
 /// \returns true if \p Name is RefPtr, Ref, or its variant, false if not.
 bool isRefType(const std::string &Name);
 
diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
index f60d1936b7584..d9b5261612a36 100644
--- 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
+++ 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
@@ -416,12 +416,9 @@ class RawPtrRefLambdaCapturesChecker
             return false;
           }
           if (auto *CE = dyn_cast<CallExpr>(Arg)) {
-            if (CE->isCallToStdMove() && CE->getNumArgs() == 1) {
-              Arg = CE->getArg(0)->IgnoreParenCasts();
-              continue;
-            }
             if (auto *Callee = CE->getDirectCallee()) {
-              if (isCtorOfSafePtr(Callee) && CE->getNumArgs() == 1) {
+              if ((isStdOrWTFMove(Callee) || isCtorOfSafePtr(Callee)) &&
+                  CE->getNumArgs() == 1) {
                 Arg = CE->getArg(0)->IgnoreParenCasts();
                 continue;
               }
diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp 
b/clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp
index e9f01c8ed7540..b257d09236c07 100644
--- a/clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp
@@ -80,6 +80,7 @@ namespace call_with_std_move {
 void consume(CheckedObj&&);
 void foo(CheckedObj&& obj) {
   consume(std::move(obj));
+  consume(WTF::move(obj));
 }
 
 }
diff --git a/clang/test/Analysis/Checkers/WebKit/forward-decl-checker.mm 
b/clang/test/Analysis/Checkers/WebKit/forward-decl-checker.mm
index 8aad838b71b35..1f0a0281eaf7a 100644
--- a/clang/test/Analysis/Checkers/WebKit/forward-decl-checker.mm
+++ b/clang/test/Analysis/Checkers/WebKit/forward-decl-checker.mm
@@ -44,6 +44,7 @@ void opaque_call_arg(Obj* obj, Obj&& otherObj, const 
RefPtr<Obj>& safeObj, WeakP
   receive_obj_ref(*obj);
   receive_obj_ptr(&*obj);
   receive_obj_rref(std::move(otherObj));
+  receive_obj_rref(WTF::move(otherObj));
   receive_obj_ref(*safeObj.get());
   receive_obj_ptr(weakObj.get());
   // expected-warning@-1{{Call argument for parameter 'p' uses a forward 
declared type 'Obj *'}}
@@ -59,6 +60,7 @@ void rval(Obj&& arg) {
   auto &&obj = provide_obj_rval();
   // expected-warning@-1{{Local variable 'obj' uses a forward declared type 
'Obj &&'}}
   receive_obj_rval(std::move(arg));
+  receive_obj_rval(WTF::move(arg));
 }
 
 ObjCObj *provide_objcobj();
@@ -84,6 +86,7 @@ void construct_ptr(Obj&& arg) {
   WrapperObj wrapper2(provide_obj_ref());
   // expected-warning@-1{{Call argument for parameter 'obj' uses a forward 
declared type 'Obj &'}}
   WrapperObj wrapper3(std::move(arg));
+  WrapperObj wrapper4(WTF::move(arg));
 }
 
 JSStringRef provide_opaque_ptr();
diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h 
b/clang/test/Analysis/Checkers/WebKit/mock-types.h
index 7055a94753a37..8a24a3c64e0e4 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h
@@ -17,6 +17,12 @@ template<typename T> typename remove_reference<T>::type&& 
move(T&& t);
 
 #endif
 
+namespace WTF {
+
+template<typename T> typename std::remove_reference<T>::type&& move(T&& t);
+
+}
+
 #ifndef mock_types_1103988513531
 #define mock_types_1103988513531
 
diff --git a/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h 
b/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
index edf40115afa19..124821a8ded55 100644
--- a/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
@@ -17,6 +17,12 @@ template<typename T> typename remove_reference<T>::type&& 
move(T&& t);
 
 #endif
 
+namespace WTF {
+
+template<typename T> typename std::remove_reference<T>::type&& move(T&& t);
+
+}
+
 namespace std {
 
 template <bool, typename U = void> struct enable_if {
@@ -453,7 +459,7 @@ template<typename T> class OSObjectPtr {
     }
 
     OSObjectPtr(T ptr)
-        : m_ptr(std::move(ptr))
+        : m_ptr(WTF::move(ptr))
     {
         if (m_ptr)
             retainOSObject(m_ptr);
@@ -483,7 +489,7 @@ template<typename T> class OSObjectPtr {
 
     OSObjectPtr& operator=(T other)
     {
-        OSObjectPtr ptr = std::move(other);
+        OSObjectPtr ptr = WTF::move(other);
         swap(ptr);
         return *this;
     }
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp 
b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
index fd1eecdda64fd..8eb15f4f77973 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-lambda-captures.cpp
@@ -437,6 +437,14 @@ struct RefCountableWithLambdaCapturingThis {
       });
     });
   }
+
+  void method_nested_lambda4() {
+    callAsync([this, protectedThis = RefPtr { this }] {
+      callAsync([this, protectedThis = WTF::move(*protectedThis)] {
+        nonTrivial();
+      });
+    });
+  }
 };
 
 struct NonRefCountableWithLambdaCapturingThis {
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp 
b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
index a9cd77c066f6f..b83eaedf264e4 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
@@ -387,6 +387,7 @@ class RefCounted {
   unsigned trivial69() { return offsetof(OtherObj, children); }
   DerivedNumber* trivial70() { [[clang::suppress]] return 
static_cast<DerivedNumber*>(number); }
   unsigned trivial71() { return std::bit_cast<unsigned>(nullptr); }
+  unsigned trivial72() { Number n { 5 }; return WTF::move(n).value(); }
 
   static RefCounted& singleton() {
     static RefCounted s_RefCounted;

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to