[clang] Add the support for recognizing WTF::move like std::move (PR #170820)
Ryosuke Niwa via cfe-commits
cfe-commits at lists.llvm.org
Tue Dec 9 13:52:18 PST 2025
https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/170820
>From 289c8175465f20bdd7d701432f923d624259b505 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Fri, 5 Dec 2025 01:03:17 -0800
Subject: [PATCH 1/3] 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 at -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 at -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 at -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;
>From 31e83304aa066336356b121f8b8b273463a0b38d Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Tue, 9 Dec 2025 13:46:27 -0800
Subject: [PATCH 2/3] Add a check that the parent of WTF/std is a
TranslationUnitDecl.
---
clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp | 3 +++
1 file changed, 3 insertions(+)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 3636b37dea632..379119549f186 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -190,6 +190,9 @@ bool isStdOrWTFMove(const clang::FunctionDecl *F) {
auto *Namespace = F->getParent();
if (!Namespace)
return false;
+ auto* TUDeck = Namespace->getParent();
+ if (!TUDeck || !isa<TranslationUnitDecl>(TUDeck))
+ return false;
auto NsName = safeGetName(Namespace);
return (NsName == "WTF" || NsName == "std") && FnName == "move";
}
>From f016d9e569a447a0101834ee1616bb3518dac18b Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Tue, 9 Dec 2025 13:52:02 -0800
Subject: [PATCH 3/3] Use isa_and_nonnull instead of manaully checking for
nullptr. Also fix the formatting.
---
.../lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 379119549f186..3c5d472720336 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -190,8 +190,8 @@ bool isStdOrWTFMove(const clang::FunctionDecl *F) {
auto *Namespace = F->getParent();
if (!Namespace)
return false;
- auto* TUDeck = Namespace->getParent();
- if (!TUDeck || !isa<TranslationUnitDecl>(TUDeck))
+ auto *TUDeck = Namespace->getParent();
+ if (!isa_and_nonnull<TranslationUnitDecl>(TUDeck))
return false;
auto NsName = safeGetName(Namespace);
return (NsName == "WTF" || NsName == "std") && FnName == "move";
More information about the cfe-commits
mailing list