[clang] [WebKit checkers] Add the support for OSObjectPtr (PR #159484)
Ryosuke Niwa via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 17 17:01:54 PDT 2025
https://github.com/rniwa created https://github.com/llvm/llvm-project/pull/159484
Add the support for OSObjectPtr, which behaves like RetainPtr.
>From 126317069f2e9332849985bcfced95aba280e1fa Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Wed, 17 Sep 2025 16:55:50 -0700
Subject: [PATCH] [WebKit checkers] Add the support for OSObjectPtr
Add the support for OSObjectPtr, which behaves like RetainPtr.
---
.../Checkers/WebKit/PtrTypesSemantics.cpp | 6 +-
.../WebKit/RawPtrRefMemberChecker.cpp | 11 +-
.../WebKit/RetainPtrCtorAdoptChecker.cpp | 3 +-
.../Checkers/WebKit/call-args-checked.cpp | 14 --
.../Analysis/Checkers/WebKit/mock-types.h | 10 ++
.../Checkers/WebKit/objc-mock-types.h | 156 ++++++++++++++++++
.../Checkers/WebKit/uncounted-obj-arg.cpp | 3 -
.../WebKit/unretained-call-args-arc.mm | 15 +-
.../Checkers/WebKit/unretained-call-args.mm | 95 +++++++++--
.../WebKit/unretained-lambda-captures-arc.mm | 49 +++++-
.../WebKit/unretained-lambda-captures.mm | 67 +++++++-
.../WebKit/unretained-local-vars-arc.mm | 19 ++-
.../Checkers/WebKit/unretained-local-vars.mm | 128 +++++++++++++-
.../Checkers/WebKit/unretained-members-arc.mm | 24 ++-
.../Checkers/WebKit/unretained-members.mm | 48 ++++--
15 files changed, 570 insertions(+), 78 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 90b2343b4be77..44a0cc52662d8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -130,7 +130,8 @@ bool isRefType(const std::string &Name) {
}
bool isRetainPtr(const std::string &Name) {
- return Name == "RetainPtr" || Name == "RetainPtrArc";
+ return Name == "RetainPtr" || Name == "RetainPtrArc" ||
+ Name == "OSObjectPtr" || Name == "OSObjectPtrArc";
}
bool isCheckedPtr(const std::string &Name) {
@@ -170,7 +171,8 @@ bool isCtorOfRetainPtr(const clang::FunctionDecl *F) {
const std::string &FunctionName = safeGetName(F);
return FunctionName == "RetainPtr" || FunctionName == "adoptNS" ||
FunctionName == "adoptCF" || FunctionName == "retainPtr" ||
- FunctionName == "RetainPtrArc" || FunctionName == "adoptNSArc";
+ FunctionName == "RetainPtrArc" || FunctionName == "adoptNSArc" ||
+ FunctionName == "adoptOSObject" || FunctionName == "adoptOSObjectArc";
}
bool isCtorOfSafePtr(const clang::FunctionDecl *F) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
index 8faf6a219450a..a776aa575fc94 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
@@ -119,10 +119,11 @@ class RawPtrRefMemberChecker
auto *Desugared = PointeeType->getUnqualifiedDesugaredType();
if (!Desugared)
return nullptr;
- auto *ObjCType = dyn_cast<ObjCInterfaceType>(Desugared);
- if (!ObjCType)
- return nullptr;
- return ObjCType->getDecl();
+ if (auto *ObjCType = dyn_cast<ObjCInterfaceType>(Desugared))
+ return ObjCType->getDecl();
+ if (auto* ObjCType = dyn_cast<ObjCObjectType>(Desugared))
+ return ObjCType->getInterface();
+ return nullptr;
}
void visitObjCDecl(const ObjCContainerDecl *CD) const {
@@ -369,7 +370,7 @@ class NoUnretainedMemberChecker final : public RawPtrRefMemberChecker {
const char *typeName() const final { return "retainable type"; }
const char *invariant() const final {
- return "member variables must be a RetainPtr";
+ return "member variables must be a RetainPtr or OSObjectPtr";
}
PrintDeclKind printPointer(llvm::raw_svector_ostream &Os,
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
index 5c1b2d7cce45d..572cbc6bb40a9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
@@ -121,7 +121,8 @@ class RetainPtrCtorAdoptChecker
}
bool isAdoptFnName(const std::string &Name) const {
- return isAdoptNS(Name) || Name == "adoptCF" || Name == "adoptCFArc";
+ return isAdoptNS(Name) || Name == "adoptCF" || Name == "adoptCFArc" ||
+ Name == "adoptOSObject" || Name == "adoptOSObjectArc";
}
bool isAdoptNS(const std::string &Name) const {
diff --git a/clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp b/clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp
index b2fb042e7deff..e9f01c8ed7540 100644
--- a/clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp
@@ -2,20 +2,6 @@
#include "mock-types.h"
-namespace std {
-
-template <typename T> struct remove_reference {
- typedef T type;
-};
-
-template <typename T> struct remove_reference<T&> {
- typedef T type;
-};
-
-template<typename T> typename remove_reference<T>::type&& move(T&& t);
-
-} // namespace std
-
RefCountableAndCheckable* makeObj();
CheckedRef<RefCountableAndCheckable> makeObjChecked();
void someFunction(RefCountableAndCheckable*);
diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h
index a03d31870ee0d..08b8ad0675946 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h
@@ -3,6 +3,16 @@
namespace std {
+template <typename T> struct remove_reference {
+typedef T type;
+};
+
+template <typename T> struct remove_reference<T&> {
+typedef T type;
+};
+
+template<typename T> typename remove_reference<T>::type&& move(T&& t);
+
template <typename T>
class unique_ptr {
private:
diff --git a/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h b/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
index 09b303961fd6a..5bdd14c6afd1f 100644
--- a/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
@@ -157,6 +157,49 @@ __attribute__((objc_root_class))
- (void)doMoreWork:(OtherObj *)other;
@end
+ at protocol OS_dispatch_queue
+ at end
+
+typedef NSObject<OS_dispatch_queue> *dispatch_queue_t;
+
+ at protocol OS_dispatch_queue_attr
+ at end
+
+typedef NSObject<OS_dispatch_queue_attr> *dispatch_queue_attr_t;
+
+NS_RETURNS_RETAINED dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
+const char *dispatch_queue_get_label(dispatch_queue_t queue);
+
+namespace std {
+
+template <typename T> struct remove_reference {
+typedef T type;
+};
+
+template <typename T> struct remove_reference<T&> {
+typedef T type;
+};
+
+template<typename T> typename remove_reference<T>::type&& move(T&& t);
+
+template <typename StorageType>
+void swap(StorageType& a, StorageType& b)
+{
+ StorageType temp = static_cast<StorageType&&>(a);
+ a = static_cast<StorageType&&>(b);
+ b = static_cast<StorageType&&>(temp);
+}
+
+template <typename StorageType, typename ValueType>
+StorageType exchange(StorageType& obj, ValueType& value)
+{
+ StorageType returnValue = static_cast<StorageType&&>(obj);
+ obj = static_cast<StorageType&&>(value);
+ return returnValue;
+}
+
+}
+
namespace WTF {
void WTFCrash(void);
@@ -293,6 +336,117 @@ template<typename T> inline RetainPtr<T> retainPtr(T* ptr)
return ptr;
}
+template<typename> class OSObjectPtr;
+template<typename T> OSObjectPtr<T> adoptOSObject(T);
+
+template<typename T> static inline void retainOSObject(T ptr)
+{
+#if !__has_feature(objc_arc)
+ [ptr retain];
+#endif
+}
+
+template<typename T> static inline void releaseOSObject(T ptr)
+{
+#if !__has_feature(objc_arc)
+ [ptr release];
+#endif
+}
+
+template<typename T> class OSObjectPtr {
+public:
+ OSObjectPtr()
+ : m_ptr(nullptr)
+ {
+ }
+
+ ~OSObjectPtr()
+ {
+ if (m_ptr)
+ releaseOSObject(m_ptr);
+ }
+
+ T get() const { return m_ptr; }
+
+ explicit operator bool() const { return m_ptr; }
+ bool operator!() const { return !m_ptr; }
+
+ OSObjectPtr(const OSObjectPtr& other)
+ : m_ptr(other.m_ptr)
+ {
+ if (m_ptr)
+ retainOSObject(m_ptr);
+ }
+
+ OSObjectPtr(OSObjectPtr&& other)
+ : m_ptr(std::move(other.m_ptr))
+ {
+ other.m_ptr = nullptr;
+ }
+
+ OSObjectPtr(T ptr)
+ : m_ptr(std::move(ptr))
+ {
+ if (m_ptr)
+ retainOSObject(m_ptr);
+ }
+
+ OSObjectPtr& operator=(const OSObjectPtr& other)
+ {
+ OSObjectPtr ptr = other;
+ swap(ptr);
+ return *this;
+ }
+
+ OSObjectPtr& operator=(OSObjectPtr&& other)
+ {
+ OSObjectPtr ptr = std::move(other);
+ swap(ptr);
+ return *this;
+ }
+
+ OSObjectPtr& operator=(decltype(nullptr))
+ {
+ if (m_ptr)
+ releaseOSObject(m_ptr);
+ m_ptr = nullptr;
+ return *this;
+ }
+
+ OSObjectPtr& operator=(T other)
+ {
+ OSObjectPtr ptr = std::move(other);
+ swap(ptr);
+ return *this;
+ }
+
+ void swap(OSObjectPtr& other)
+ {
+ std::swap(m_ptr, other.m_ptr);
+ }
+
+ T leakRef()
+ {
+ return std::exchange(m_ptr, nullptr);
+ }
+
+ friend OSObjectPtr adoptOSObject<T>(T);
+
+private:
+ struct AdoptOSObject { };
+ OSObjectPtr(AdoptOSObject, T ptr)
+ : m_ptr(std::move(ptr))
+ {
+ }
+
+ T m_ptr;
+};
+
+template<typename T> inline OSObjectPtr<T> adoptOSObject(T ptr)
+{
+ return OSObjectPtr<T> { typename OSObjectPtr<T>::AdoptOSObject { }, std::move(ptr) };
+}
+
inline NSObject *bridge_cast(CFTypeRef object)
{
return (__bridge NSObject *)object;
@@ -455,6 +609,8 @@ using WTF::RetainPtr;
using WTF::adoptNS;
using WTF::adoptCF;
using WTF::retainPtr;
+using WTF::OSObjectPtr;
+using WTF::adoptOSObject;
using WTF::downcast;
using WTF::bridge_cast;
using WTF::bridge_id_cast;
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
index 2c6ccb55e2ce8..a9cd77c066f6f 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
@@ -74,9 +74,6 @@ T* addressof(T& arg);
template<typename T>
T&& forward(T& arg);
-template<typename T>
-T&& move( T&& t );
-
template<typename ToType, typename FromType>
ToType bit_cast(FromType from);
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-call-args-arc.mm b/clang/test/Analysis/Checkers/WebKit/unretained-call-args-arc.mm
index fa866258a2f6d..2763d8a188d8a 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-call-args-arc.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-call-args-arc.mm
@@ -4,6 +4,7 @@
SomeObj *provide();
CFMutableArrayRef provide_cf();
+dispatch_queue_t provide_os();
void someFunction();
CGImageRef provideImage();
NSString *stringForImage(CGImageRef);
@@ -14,6 +15,7 @@ void foo() {
[provide() doWork];
CFArrayAppendValue(provide_cf(), nullptr);
// expected-warning at -1{{Call argument for parameter 'theArray' is unretained and unsafe [alpha.webkit.UnretainedCallArgsChecker]}}
+ dispatch_queue_get_label(provide_os());
}
} // namespace raw_ptr
@@ -22,15 +24,17 @@ void foo() {
extern NSString * const SomeConstant;
extern CFDictionaryRef const SomeDictionary;
-void doWork(NSString *str, CFDictionaryRef dict);
+extern dispatch_queue_t const SomeDispatch;
+void doWork(NSString *str, CFDictionaryRef dict, dispatch_queue_t dispatch);
void use_const_global() {
- doWork(SomeConstant, SomeDictionary);
+ doWork(SomeConstant, SomeDictionary, SomeDispatch);
}
NSString *provide_str();
CFDictionaryRef provide_dict();
+dispatch_queue_t provide_dispatch();
void use_const_local() {
- doWork(provide_str(), provide_dict());
+ doWork(provide_str(), provide_dict(), provide_dispatch());
// expected-warning at -1{{Call argument for parameter 'dict' is unretained and unsafe}}
}
@@ -65,4 +69,9 @@ - (NSString *)convertImage {
RetainPtr<CGImageRef> image = [self createImage];
return stringForImage(image.get());
}
+
+- (const char *)dispatchLabel {
+ OSObjectPtr obj = provide_os();
+ return dispatch_queue_get_label(obj.get());
+}
@end
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm b/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm
index 75eead070fdf9..343e37d30e054 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm
@@ -9,6 +9,9 @@
CFMutableArrayRef provide_cf();
void consume_cf(CFMutableArrayRef);
+dispatch_queue_t provide_dispatch();
+void consume_dispatch(dispatch_queue_t);
+
CGImageRef provideImage();
NSString *stringForImage(CGImageRef);
@@ -20,6 +23,8 @@ void foo() {
// expected-warning at -1{{Call argument is unretained and unsafe}}
consume_cf(provide_cf());
// expected-warning at -1{{Call argument is unretained and unsafe}}
+ consume_dispatch(provide_dispatch());
+ // expected-warning at -1{{Call argument is unretained and unsafe}}
}
// Test that the checker works with [[clang::suppress]].
@@ -31,32 +36,32 @@ void foo_suppressed() {
}
namespace multi_arg {
- void consume_retainable(int, SomeObj* foo, CFMutableArrayRef bar, bool);
+ void consume_retainable(int, SomeObj* foo, CFMutableArrayRef bar, dispatch_queue_t baz, bool);
void foo() {
- consume_retainable(42, provide(), provide_cf(), true);
+ consume_retainable(42, provide(), provide_cf(), provide_dispatch(), true);
// expected-warning at -1{{Call argument for parameter 'foo' is unretained and unsafe}}
// expected-warning at -2{{Call argument for parameter 'bar' is unretained and unsafe}}
+ // expected-warning at -3{{Call argument for parameter 'baz' is unretained and unsafe}}
}
void consume_retainable(SomeObj* foo, ...);
void bar() {
- consume_retainable(provide(), 1, provide_cf(), RetainPtr<CFMutableArrayRef> { provide_cf() }.get());
+ consume_retainable(provide(), 1, provide_cf(), RetainPtr<CFMutableArrayRef> { provide_cf() }.get(), provide_dispatch());
// expected-warning at -1{{Call argument for parameter 'foo' is unretained and unsafe}}
// expected-warning at -2{{Call argument is unretained and unsafe}}
+ // expected-warning at -3{{Call argument is unretained and unsafe}}
consume_retainable(RetainPtr<SomeObj> { provide() }.get(), 1, RetainPtr<CFMutableArrayRef> { provide_cf() }.get());
}
}
namespace retained {
- RetainPtr<SomeObj> provide_obj() { return RetainPtr<SomeObj>{}; }
- void consume_obj(RetainPtr<SomeObj>) {}
-
- RetainPtr<CFMutableArrayRef> provide_cf() { return CFMutableArrayRef{}; }
- void consume_cf(RetainPtr<CFMutableArrayRef>) {}
-
+ RetainPtr<SomeObj> provide_obj();
+ RetainPtr<CFMutableArrayRef> provide_cf();
+ OSObjectPtr<dispatch_queue_t> provide_dispatch();
void foo() {
consume_obj(provide_obj().get()); // no warning
consume_cf(provide_cf().get()); // no warning
+ consume_dispatch(provide_dispatch().get()); // no warning
}
}
@@ -64,6 +69,7 @@ void foo() {
struct Consumer {
void consume_obj(SomeObj* ptr);
void consume_cf(CFMutableArrayRef ref);
+ void consume_dispatch(dispatch_queue_t ptr);
};
void foo() {
@@ -73,6 +79,8 @@ void foo() {
// expected-warning at -1{{Call argument for parameter 'ptr' is unretained and unsafe}}
c.consume_cf(provide_cf());
// expected-warning at -1{{Call argument for parameter 'ref' is unretained and unsafe}}
+ c.consume_dispatch(provide_dispatch());
+ // expected-warning at -1{{Call argument for parameter 'ptr' is unretained and unsafe}}
}
void foo2() {
@@ -88,6 +96,12 @@ void something() {
consume_cf(provide_cf());
// expected-warning at -1{{Call argument is unretained and unsafe}}
}
+
+ void consume_dispatch(dispatch_queue_t) { some_function(); }
+ void anything() {
+ consume_dispatch(provide_dispatch());
+ // expected-warning at -1{{Call argument is unretained and unsafe}}
+ }
};
}
@@ -104,6 +118,12 @@ void something() {
this->consume_cf(provide_cf());
// expected-warning at -1{{Call argument is unretained and unsafe}}
}
+
+ void consume_dispatch(dispatch_queue_t) { some_function(); }
+ void anything() {
+ this->consume_dispatch(provide_dispatch());
+ // expected-warning at -1{{Call argument is unretained and unsafe}}
+ }
};
}
@@ -131,6 +151,8 @@ void foo_ref() {
consume_obj(0);
consume_cf(nullptr);
consume_cf(0);
+ consume_dispatch(nullptr);
+ consume_dispatch(0);
}
}
@@ -161,6 +183,7 @@ void bar() {
namespace param_formarding_function {
void consume_more_obj(OtherObj*);
void consume_more_cf(CFMutableArrayRef);
+ void consume_more_dispatch(dispatch_queue_t);
namespace objc {
void foo(SomeObj* param) {
@@ -178,6 +201,7 @@ void foo(CFMutableArrayRef param) {
namespace param_formarding_lambda {
auto consume_more_obj = [](OtherObj*) { some_function(); };
auto consume_more_cf = [](CFMutableArrayRef) { some_function(); };
+ auto consume_more_dispatch = [](dispatch_queue_t) { some_function(); };
namespace objc {
void foo(SomeObj* param) {
@@ -190,6 +214,12 @@ void foo(CFMutableArrayRef param) {
consume_more_cf(param);
}
}
+
+ namespace os_obj {
+ void foo(dispatch_queue_t param) {
+ consume_more_dispatch(param);
+ }
+ }
}
namespace param_forwarding_method {
@@ -198,6 +228,8 @@ void foo(CFMutableArrayRef param) {
static void consume_obj_s(SomeObj*);
void consume_cf(CFMutableArrayRef);
static void consume_cf_s(CFMutableArrayRef);
+ void consume_dispatch(dispatch_queue_t);
+ static void consume_dispatch_s(dispatch_queue_t);
};
void bar(Consumer* consumer, SomeObj* param) {
@@ -212,12 +244,18 @@ void baz(Consumer* consumer, CFMutableArrayRef param) {
consumer->consume_cf(param);
Consumer::consume_cf_s(param);
}
+
+ void baz(Consumer* consumer, dispatch_queue_t param) {
+ consumer->consume_dispatch(param);
+ Consumer::consume_dispatch_s(param);
+ }
}
namespace default_arg {
SomeObj* global;
CFMutableArrayRef global_cf;
+ dispatch_queue_t global_dispatch;
void function_with_default_arg1(SomeObj* param = global);
// expected-warning at -1{{Call argument for parameter 'param' is unretained and unsafe}}
@@ -225,9 +263,13 @@ void baz(Consumer* consumer, CFMutableArrayRef param) {
void function_with_default_arg2(CFMutableArrayRef param = global_cf);
// expected-warning at -1{{Call argument for parameter 'param' is unretained and unsafe}}
+ void function_with_default_arg3(dispatch_queue_t param = global_dispatch);
+ // expected-warning at -1{{Call argument for parameter 'param' is unretained and unsafe}}
+
void foo() {
function_with_default_arg1();
function_with_default_arg2();
+ function_with_default_arg3();
}
}
@@ -259,9 +301,11 @@ void bar() {
Foo& operator+(SomeObj* bad);
friend Foo& operator-(Foo& lhs, SomeObj* bad);
void operator()(SomeObj* bad);
+ Foo& operator<<(dispatch_queue_t bad);
};
SomeObj* global;
+ dispatch_queue_t global_dispatch;
void foo() {
Foo f;
@@ -271,6 +315,8 @@ void foo() {
// expected-warning at -1{{Call argument for parameter 'bad' is unretained and unsafe}}
f(global);
// expected-warning at -1{{Call argument for parameter 'bad' is unretained and unsafe}}
+ f << global_dispatch;
+ // expected-warning at -1{{Call argument for parameter 'bad' is unretained and unsafe}}
}
}
@@ -280,6 +326,8 @@ void foo() {
void foo() {
RetainPtr<SomeObj> ptr;
ptr = provide();
+ OSObjectPtr<dispatch_queue_t> objPtr;
+ objPtr = provide_dispatch();
}
}
@@ -287,8 +335,10 @@ void foo() {
namespace call_with_ptr_on_ref {
RetainPtr<SomeObj> provideProtected();
RetainPtr<CFMutableArrayRef> provideProtectedCF();
+ OSObjectPtr<dispatch_queue_t> provideProtectedDispatch();
void bar(SomeObj* bad);
void bar_cf(CFMutableArrayRef bad);
+ void bar_dispatch(dispatch_queue_t);
bool baz();
void foo(bool v) {
bar(v ? nullptr : provideProtected().get());
@@ -304,6 +354,13 @@ void foo(bool v) {
// expected-warning at -1{{Call argument for parameter 'bad' is unretained and unsafe}}
bar_cf(v ? provideProtectedCF().get() : provide_cf());
// expected-warning at -1{{Call argument for parameter 'bad' is unretained and unsafe}}
+
+ bar_dispatch(v ? nullptr : provideProtectedDispatch().get());
+ bar_dispatch(baz() ? provideProtectedDispatch().get() : nullptr);
+ bar_dispatch(v ? provide_dispatch() : provideProtectedDispatch().get());
+ // expected-warning at -1{{Call argument is unretained and unsafe}}
+ bar_dispatch(v ? provideProtectedDispatch().get() : provide_dispatch());
+ // expected-warning at -1{{Call argument is unretained and unsafe}}
}
}
@@ -320,12 +377,16 @@ void bar() {
void baz() {
bar<int>();
}
+ void os_ptr() {
+ consume_dispatch(OSObjectPtr { provide_dispatch() }.get());
+ }
}
namespace call_with_adopt_ref {
void foo() {
[adoptNS(provide()).get() doWork];
CFArrayAppendValue(adoptCF(provide_cf()).get(), nullptr);
+ consume_dispatch(adoptOSObject(provide_dispatch()).get());
}
}
@@ -423,17 +484,19 @@ void idcf(CFTypeRef obj) {
extern NSString * const SomeConstant;
extern CFDictionaryRef const SomeDictionary;
-void doWork(NSString *str, CFDictionaryRef dict);
+extern dispatch_queue_t const SomeDispatch;
+void doWork(NSString *str, CFDictionaryRef dict, dispatch_queue_t dispatch);
void use_const_global() {
- doWork(SomeConstant, SomeDictionary);
+ doWork(SomeConstant, SomeDictionary, SomeDispatch);
}
NSString *provide_str();
CFDictionaryRef provide_dict();
void use_const_local() {
- doWork(provide_str(), provide_dict());
+ doWork(provide_str(), provide_dict(), provide_dispatch());
// expected-warning at -1{{Call argument for parameter 'str' is unretained and unsafe}}
// expected-warning at -2{{Call argument for parameter 'dict' is unretained and unsafe}}
+ // expected-warning at -3{{Call argument for parameter 'dispatch' is unretained and unsafe}}
}
} // namespace const_global
@@ -470,12 +533,15 @@ bool baz(NSObject *obj) {
NSString *provideNS() NS_RETURNS_RETAINED;
CFDictionaryRef provideCF() CF_RETURNS_RETAINED;
+dispatch_queue_t provideDispatch() NS_RETURNS_RETAINED;
void consumeNS(NSString *);
void consumeCF(CFDictionaryRef);
+void consumeDispatch(dispatch_queue_t);
void foo() {
consumeNS(provideNS());
consumeCF(provideCF());
+ consumeDispatch(provideDispatch());
}
struct Base {
@@ -506,10 +572,11 @@ - (void)doWork:(NSString *)msg, ... {
- (void)doWorkOnSelf {
[self doWork:nil];
- [self doWork:@"hello", provide(), provide_cf()];
+ [self doWork:@"hello", provide(), provide_cf(), provide_dispatch()];
// expected-warning at -1{{Call argument is unretained and unsafe}}
// expected-warning at -2{{Call argument is unretained and unsafe}}
- [self doWork:@"hello", RetainPtr<SomeObj> { provide() }.get(), RetainPtr<CFMutableArrayRef> { provide_cf() }.get()];
+ // expected-warning at -3{{Call argument is unretained and unsafe}}
+ [self doWork:@"hello", RetainPtr<SomeObj> { provide() }.get(), RetainPtr<CFMutableArrayRef> { provide_cf() }.get(), OSObjectPtr { provide_dispatch() }.get()];
[self doWork:__null];
[self doWork:nil];
}
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures-arc.mm b/clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures-arc.mm
index 63526a5047157..4e024dea7037a 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures-arc.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures-arc.mm
@@ -112,6 +112,7 @@ explicit CallableWrapper(CallableType& callable)
SomeObj* make_obj();
CFMutableArrayRef make_cf();
+dispatch_queue_t make_os();
void someFunction();
template <typename Callback> void call(Callback callback) {
@@ -125,8 +126,6 @@ void raw_ptr() {
auto foo1 = [obj](){
[obj doWork];
};
- call(foo1);
-
auto foo2 = [&obj](){
[obj doWork];
};
@@ -157,6 +156,21 @@ void raw_ptr() {
// expected-warning at -1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
};
+ auto os = make_os();
+ auto baz1 = [os](){
+ dispatch_queue_get_label(os);
+ };
+ auto baz2 = [&os](){
+ dispatch_queue_get_label(os);
+ };
+ auto baz3 = [&](){
+ dispatch_queue_get_label(os);
+ os = nullptr;
+ };
+ auto baz4 = [=](){
+ dispatch_queue_get_label(os);
+ };
+
call(foo1);
call(foo2);
call(foo3);
@@ -166,6 +180,11 @@ void raw_ptr() {
call(bar2);
call(bar3);
call(bar4);
+
+ call(baz1);
+ call(baz2);
+ call(baz3);
+ call(baz4);
}
void quiet() {
@@ -208,6 +227,14 @@ void get_count_cf(CFArrayRef array, [[clang::noescape]] Callback1&& callback1, C
callback2(count);
}
+template <typename Callback1, typename Callback2>
+void get_count_os(dispatch_queue_t queue, [[clang::noescape]] Callback1&& callback1, Callback2&& callback2)
+{
+ auto* label = dispatch_queue_get_label(queue);
+ callback1(label);
+ callback2(label);
+}
+
void noescape_lambda() {
SomeObj* someObj = make_obj();
SomeObj* otherObj = make_obj();
@@ -230,6 +257,13 @@ void noescape_lambda() {
CFArrayAppendValue(someCF, nullptr);
// expected-warning at -1{{Implicitly captured reference 'someCF' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
});
+
+ dispatch_queue_t someOS = make_os();
+ get_count_os(make_os(), [&](const char* label) {
+ dispatch_queue_get_label(someOS);
+ }, [&](const char* label) {
+ dispatch_queue_get_label(someOS);
+ });
}
void callFunctionOpaque(WTF::Function<void()>&&);
@@ -238,22 +272,25 @@ void callFunction(WTF::Function<void()>&& function) {
function();
}
-void lambda_converted_to_function(SomeObj* obj, CFMutableArrayRef cf)
+void lambda_converted_to_function(SomeObj* obj, CFMutableArrayRef cf, dispatch_queue_t os)
{
callFunction([&]() {
[obj doWork];
CFArrayAppendValue(cf, nullptr);
// expected-warning at -1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
+ dispatch_queue_get_label(os);
});
callFunctionOpaque([&]() {
[obj doWork];
CFArrayAppendValue(cf, nullptr);
// expected-warning at -1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
+ dispatch_queue_get_label(os);
});
}
@interface ObjWithSelf : NSObject {
RetainPtr<id> delegate;
+ OSObjectPtr<dispatch_queue_t> queue;
}
-(void)doWork;
-(void)doMoreWork;
@@ -274,9 +311,15 @@ -(void)doWork {
someFunction();
[delegate doWork];
};
+ auto* queuePtr = queue.get();
+ auto doAdditionalWork = [&] {
+ someFunction();
+ dispatch_queue_get_label(queuePtr);
+ };
callFunctionOpaque(doWork);
callFunctionOpaque(doMoreWork);
callFunctionOpaque(doExtraWork);
+ callFunctionOpaque(doAdditionalWork);
}
-(void)doMoreWork {
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures.mm b/clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures.mm
index dcc6672261d8c..76a1da7707a2a 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures.mm
@@ -112,6 +112,7 @@ explicit CallableWrapper(CallableType& callable)
SomeObj* make_obj();
CFMutableArrayRef make_cf();
+dispatch_queue_t make_os();
void someFunction();
template <typename Callback> void call(Callback callback) {
@@ -161,6 +162,25 @@ void raw_ptr() {
// expected-warning at -1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
};
+ auto os = make_os();
+ auto baz1 = [os](){
+ // expected-warning at -1{{Captured reference 'os' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
+ dispatch_queue_get_label(os);
+ };
+ auto baz2 = [&os](){
+ // expected-warning at -1{{Captured reference 'os' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
+ dispatch_queue_get_label(os);
+ };
+ auto baz3 = [&](){
+ dispatch_queue_get_label(os);
+ // expected-warning at -1{{Implicitly captured reference 'os' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
+ os = nullptr;
+ };
+ auto baz4 = [=](){
+ dispatch_queue_get_label(os);
+ // expected-warning at -1{{Implicitly captured reference 'os' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
+ };
+
call(foo1);
call(foo2);
call(foo3);
@@ -171,8 +191,13 @@ void raw_ptr() {
call(bar3);
call(bar4);
+ call(baz1);
+ call(baz2);
+ call(baz3);
+ call(baz4);
+
// Confirm that the checker respects [[clang::suppress]].
- SomeObj* suppressed_obj = nullptr;
+ SomeObj* suppressed_obj = make_obj();
[[clang::suppress]] auto foo5 = [suppressed_obj](){
[suppressed_obj doWork];
};
@@ -180,12 +205,20 @@ void raw_ptr() {
call(foo5);
// Confirm that the checker respects [[clang::suppress]].
- CFMutableArrayRef suppressed_cf = nullptr;
+ CFMutableArrayRef suppressed_cf = make_cf();
[[clang::suppress]] auto bar5 = [suppressed_cf](){
CFArrayAppendValue(suppressed_cf, nullptr);
};
// no warning.
call(bar5);
+
+ // Confirm that the checker respects [[clang::suppress]].
+ dispatch_queue_t suppressed_os = make_os();
+ [[clang::suppress]] auto baz5 = [suppressed_os](){
+ dispatch_queue_get_label(suppressed_os);
+ };
+ // no warning.
+ call(baz5);
}
void quiet() {
@@ -228,6 +261,14 @@ void get_count_cf(CFArrayRef array, [[clang::noescape]] Callback1&& callback1, C
callback2(count);
}
+template <typename Callback1, typename Callback2>
+void get_count_os(dispatch_queue_t queue, [[clang::noescape]] Callback1&& callback1, Callback2&& callback2)
+{
+ auto* label = dispatch_queue_get_label(queue);
+ callback1(label);
+ callback2(label);
+}
+
void noescape_lambda() {
SomeObj* someObj = make_obj();
SomeObj* otherObj = make_obj();
@@ -251,6 +292,14 @@ void noescape_lambda() {
CFArrayAppendValue(someCF, nullptr);
// expected-warning at -1{{Implicitly captured reference 'someCF' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
});
+
+ dispatch_queue_t someOS = make_os();
+ get_count_os(make_os(), [&](const char* label) {
+ dispatch_queue_get_label(someOS);
+ }, [&](const char* label) {
+ dispatch_queue_get_label(someOS);
+ // expected-warning at -1{{Implicitly captured reference 'someOS' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
+ });
}
void callFunctionOpaque(WTF::Function<void()>&&);
@@ -259,24 +308,29 @@ void callFunction(WTF::Function<void()>&& function) {
function();
}
-void lambda_converted_to_function(SomeObj* obj, CFMutableArrayRef cf)
+void lambda_converted_to_function(SomeObj* obj, CFMutableArrayRef cf, dispatch_queue_t os)
{
callFunction([&]() {
[obj doWork];
// expected-warning at -1{{Implicitly captured raw-pointer 'obj' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
CFArrayAppendValue(cf, nullptr);
// expected-warning at -1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
+ dispatch_queue_get_label(os);
+ // expected-warning at -1{{Implicitly captured reference 'os' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
});
callFunctionOpaque([&]() {
[obj doWork];
// expected-warning at -1{{Implicitly captured raw-pointer 'obj' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
CFArrayAppendValue(cf, nullptr);
// expected-warning at -1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
+ dispatch_queue_get_label(os);
+ // expected-warning at -1{{Implicitly captured reference 'os' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
});
}
@interface ObjWithSelf : NSObject {
RetainPtr<id> delegate;
+ OSObjectPtr<dispatch_queue_t> queue;
}
-(void)doWork;
-(void)doMoreWork;
@@ -299,9 +353,16 @@ -(void)doWork {
someFunction();
[delegate doWork];
};
+ auto* queuePtr = queue.get();
+ auto doAdditionalWork = [&] {
+ someFunction();
+ dispatch_queue_get_label(queuePtr);
+ // expected-warning at -1{{Implicitly captured raw-pointer 'queuePtr' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
+ };
callFunctionOpaque(doWork);
callFunctionOpaque(doMoreWork);
callFunctionOpaque(doExtraWork);
+ callFunctionOpaque(doAdditionalWork);
}
-(void)doMoreWork {
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-local-vars-arc.mm b/clang/test/Analysis/Checkers/WebKit/unretained-local-vars-arc.mm
index a84bee8529645..3d256f1599f04 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-local-vars-arc.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-local-vars-arc.mm
@@ -23,24 +23,32 @@ void bar() {
CFArrayAppendValue(array, nullptr);
}
+void baz() {
+ auto queue = dispatch_queue_create("some queue", nullptr);
+ dispatch_queue_get_label(queue);
+}
+
} // namespace raw_ptr
namespace const_global {
extern NSString * const SomeConstant;
extern CFDictionaryRef const SomeDictionary;
-void doWork(NSString *, CFDictionaryRef);
+extern dispatch_queue_t const SomeDispatch;
+void doWork(NSString *, CFDictionaryRef, dispatch_queue_t);
void use_const_global() {
- doWork(SomeConstant, SomeDictionary);
+ doWork(SomeConstant, SomeDictionary, SomeDispatch);
}
NSString *provide_str();
CFDictionaryRef provide_dict();
+dispatch_queue_t provide_dispatch();
void use_const_local() {
NSString * const str = provide_str();
CFDictionaryRef dict = provide_dict();
// expected-warning at -1{{Local variable 'dict' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}
- doWork(str, dict);
+ auto dispatch = provide_dispatch();
+ doWork(str, dict, dispatch);
}
} // namespace const_global
@@ -63,4 +71,9 @@ - (void)bar {
// expected-warning at -1{{Local variable 'array' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}
CFArrayAppendValue(array, nullptr);
}
+
+- (void)baz {
+ auto queue = dispatch_queue_create("some queue", nullptr);
+ dispatch_queue_get_label(queue);
+}
@end
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-local-vars.mm b/clang/test/Analysis/Checkers/WebKit/unretained-local-vars.mm
index 0ad8f707e254c..307a4d03fe101 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-local-vars.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-local-vars.mm
@@ -30,18 +30,27 @@ void cf_ptr() {
// expected-warning at -1{{Local variable 'array' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}
CFArrayAppendValue(array, nullptr);
}
+
+dispatch_queue_t provide_os();
+void os_ptr() {
+ auto queue = provide_os();
+ // expected-warning at -1{{Local variable 'queue' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}
+ dispatch_queue_get_label(queue);
+}
+
} // namespace pointer
namespace guardian_scopes {
+SomeObj *provide();
void foo1() {
- RetainPtr<SomeObj> foo;
+ RetainPtr<SomeObj> foo = provide();
{
SomeObj *bar = foo.get();
}
}
void foo2() {
- RetainPtr<SomeObj> foo;
+ RetainPtr<SomeObj> foo = provide();
// missing embedded scope here
SomeObj *bar = foo.get();
// expected-warning at -1{{Local variable 'bar' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}
@@ -49,7 +58,7 @@ void foo2() {
}
void foo3() {
- RetainPtr<SomeObj> foo;
+ RetainPtr<SomeObj> foo = provide();
{
{ SomeObj *bar = foo.get(); }
}
@@ -57,11 +66,35 @@ void foo3() {
void foo4() {
{
- RetainPtr<SomeObj> foo;
+ RetainPtr<SomeObj> foo = provide();
{ SomeObj *bar = foo.get(); }
}
}
+CFMutableArrayRef provide_cf();
+void foo5() {
+ RetainPtr<CFMutableArrayRef> foo = provide_cf();
+ {
+ CFMutableArrayRef bar = foo.get();
+ CFArrayAppendValue(bar, nullptr);
+ }
+ CFMutableArrayRef baz = foo.get();
+ // expected-warning at -1{{Local variable 'baz' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}
+ CFArrayAppendValue(baz, nullptr);
+}
+
+dispatch_queue_t provide_os();
+void foo6() {
+ OSObjectPtr<dispatch_queue_t> queue = provide_os();
+ {
+ dispatch_queue_t bar = queue.get();
+ dispatch_queue_get_label(bar);
+ }
+ dispatch_queue_t baz = queue.get();
+ // expected-warning at -1{{Local variable 'baz' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}
+ dispatch_queue_get_label(baz);
+}
+
struct SelfReferencingStruct {
SelfReferencingStruct* ptr;
SomeObj* obj { nullptr };
@@ -171,13 +204,35 @@ void foo10() {
}
}
+bool trivialFunction(dispatch_queue_t queue) { return !!queue; }
+void foo11() {
+ OSObjectPtr<dispatch_queue_t> queue = adoptOSObject(dispatch_queue_create("some queue", nullptr));
+ {
+ dispatch_queue_t queuePtr = queue.get();
+ dispatch_queue_get_label(queuePtr);
+ }
+ {
+ dispatch_queue_t queuePtr = queue.get();
+ // expected-warning at -1{{Local variable 'queuePtr' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}
+ queue = nullptr;
+ dispatch_queue_get_label(queuePtr);
+ }
+ {
+ dispatch_queue_t queuePtr = queue.get();
+ if (trivialFunction(queuePtr))
+ queuePtr = nullptr;
+ }
+}
+
} // namespace guardian_scopes
namespace auto_keyword {
class Foo {
SomeObj *provide_obj();
CFMutableArrayRef provide_cf_array();
+ dispatch_queue_t provide_queue();
void doWork(CFMutableArrayRef);
+ void doWork(dispatch_queue_t);
void evil_func() {
SomeObj *bar = provide_obj();
@@ -204,6 +259,14 @@ void bar() {
doWork(baz);
}
+ void baz() {
+ auto value1 = provide_queue();
+ // expected-warning at -1{{Local variable 'value1' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}
+ doWork(value1);
+ [[clang::suppress]] auto value2 = provide_queue(); // no-warning
+ doWork(value2);
+ }
+
};
} // namespace auto_keyword
@@ -223,6 +286,14 @@ void foo2() {
someFunction();
}
}
+
+void foo3() {
+ OSObjectPtr<dispatch_queue_t> foo;
+ {
+ dispatch_queue_t bar = foo.get();
+ someFunction();
+ }
+}
} // namespace guardian_casts
namespace conditional_op {
@@ -292,6 +363,15 @@ void bar(CFMutableArrayRef a) {
doWork(a);
}
+dispatch_queue_t provide_queue();
+void doWork(dispatch_queue_t);
+
+void baz(dispatch_queue_t a) {
+ a = provide_queue();
+ // expected-warning at -1{{Assignment to an unretained parameter 'a' is unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}
+ doWork(a);
+}
+
} // namespace local_assignment_to_parameter
namespace local_assignment_to_static_local {
@@ -317,6 +397,16 @@ void bar() {
doWork(a);
}
+dispatch_queue_t provide_queue();
+void doWork(dispatch_queue_t);
+
+void baz() {
+ static dispatch_queue_t a = nullptr;
+ // expected-warning at -1{{Static local variable 'a' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}
+ a = provide_queue();
+ doWork(a);
+}
+
} // namespace local_assignment_to_static_local
namespace local_assignment_to_global {
@@ -344,6 +434,16 @@ void bar() {
doWork(g_b);
}
+dispatch_queue_t provide_queue();
+void doWork(dispatch_queue_t);
+dispatch_queue_t g_c = nullptr;
+// expected-warning at -1{{Global variable 'local_assignment_to_global::g_c' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}
+
+void baz() {
+ g_c = provide_queue();
+ doWork(g_c);
+}
+
} // namespace local_assignment_to_global
namespace local_var_for_singleton {
@@ -358,6 +458,11 @@ void foo() {
void bar() {
CFMutableArrayRef cf = cfSingleton();
}
+
+ dispatch_queue_t osSingleton();
+ void baz() {
+ dispatch_queue_t os = osSingleton();
+ }
}
namespace ptr_conversion {
@@ -391,19 +496,23 @@ unsigned ccf(CFTypeRef obj) {
extern NSString * const SomeConstant;
extern CFDictionaryRef const SomeDictionary;
-void doWork(NSString *, CFDictionaryRef);
+extern dispatch_queue_t const SomeQueue;
+void doWork(NSString *, CFDictionaryRef, dispatch_queue_t);
void use_const_global() {
- doWork(SomeConstant, SomeDictionary);
+ doWork(SomeConstant, SomeDictionary, SomeQueue);
}
NSString *provide_str();
CFDictionaryRef provide_dict();
+dispatch_queue_t provide_queue();
void use_const_local() {
NSString * const str = provide_str();
// expected-warning at -1{{Local variable 'str' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}
CFDictionaryRef dict = provide_dict();
// expected-warning at -1{{Local variable 'dict' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}
- doWork(str, dict);
+ dispatch_queue_t queue = provide_queue();
+ // expected-warning at -1{{Local variable 'queue' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}}
+ doWork(str, dict, queue);
}
} // namespace const_global
@@ -412,13 +521,16 @@ void use_const_local() {
NSString *provideNS() NS_RETURNS_RETAINED;
CFDictionaryRef provideCF() CF_RETURNS_RETAINED;
+dispatch_queue_t provideOS() CF_RETURNS_RETAINED;
void consumeNS(NSString *);
void consumeCF(CFDictionaryRef);
+int consumeOS(dispatch_queue_t);
unsigned foo() {
auto *string = provideNS();
auto *dictionary = provideCF();
- return string.length + CFDictionaryGetCount(dictionary);
+ auto* queue = provideOS();
+ return string.length + CFDictionaryGetCount(dictionary) + consumeOS(queue);
}
} // namespace ns_retained_return_value
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm b/clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm
index 00e6e6ec1dcfa..19c54c4dc07ba 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm
@@ -20,22 +20,26 @@
CFMutableArrayRef e = nullptr;
// expected-warning at -1{{Member variable 'e' in 'members::Foo' is a retainable type 'CFMutableArrayRef'}}
+
+ dispatch_queue_t f = nullptr;
};
union FooUnion {
SomeObj* a;
CFMutableArrayRef b;
// expected-warning at -1{{Member variable 'b' in 'members::FooUnion' is a retainable type 'CFMutableArrayRef'}}
+ dispatch_queue_t c;
};
- template<class T, class S>
+ template<class T, class S, class R>
struct FooTmpl {
T* x;
S y;
-// expected-warning at -1{{Member variable 'y' in 'members::FooTmpl<SomeObj, __CFArray *>' is a raw pointer to retainable type}}
+// expected-warning at -1{{Member variable 'y' in 'members::FooTmpl<SomeObj, __CFArray *, NSObject<OS_dispatch_queue> *>' is a raw pointer to retainable type}}
+ R z;
};
- void forceTmplToInstantiate(FooTmpl<SomeObj, CFMutableArrayRef>) {}
+ void forceTmplToInstantiate(FooTmpl<SomeObj, CFMutableArrayRef, dispatch_queue_t>) {}
struct [[clang::suppress]] FooSuppressed {
private:
@@ -51,16 +55,19 @@ void forceTmplToInstantiate(FooTmpl<SomeObj, CFMutableArrayRef>) {}
// expected-warning at -1{{Member variable 'elements2' in 'ptr_to_ptr_to_retained::List' contains a retainable type 'CFMutableArrayRef'}}
};
- template <typename T, typename S>
+ template <typename T, typename S, typename R>
struct TemplateList {
+ T* elements1;
S* elements2;
- // expected-warning at -1{{Member variable 'elements2' in 'ptr_to_ptr_to_retained::TemplateList<SomeObj, __CFArray *>' contains a raw pointer to retainable type '__CFArray'}}
+ // expected-warning at -1{{Member variable 'elements2' in 'ptr_to_ptr_to_retained::TemplateList<SomeObj, __CFArray *, NSObject<OS_dispatch_queue> *>' contains a raw pointer to retainable type '__CFArray'}}
+ R* elements3;
};
- TemplateList<SomeObj, CFMutableArrayRef> list;
+ TemplateList<SomeObj, CFMutableArrayRef, dispatch_queue_t> list;
struct SafeList {
RetainPtr<SomeObj>* elements1;
RetainPtr<CFMutableArrayRef>* elements2;
+ OSObjectPtr<dispatch_queue_t> elements3;
};
} // namespace ptr_to_ptr_to_retained
@@ -69,6 +76,7 @@ @interface AnotherObject : NSObject {
NSString *ns_string;
CFStringRef cf_string;
// expected-warning at -1{{Instance variable 'cf_string' in 'AnotherObject' is a retainable type 'CFStringRef'; member variables must be a RetainPtr}}
+ dispatch_queue_t queue;
}
@property(nonatomic, strong) NSString *prop_string1;
@property(nonatomic, assign) NSString *prop_string2;
@@ -76,6 +84,7 @@ @interface AnotherObject : NSObject {
@property(nonatomic, unsafe_unretained) NSString *prop_string3;
// expected-warning at -1{{Property 'prop_string3' in 'AnotherObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
@property(nonatomic, readonly) NSString *prop_string4;
+ at property(nonatomic, readonly) dispatch_queue_t prop_string5;
@end
NS_REQUIRES_PROPERTY_DEFINITIONS
@@ -90,6 +99,8 @@ @interface NoSynthObject : NSObject {
// expected-warning at -1{{Property 'prop_string3' in 'NoSynthObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
@property(nonatomic, unsafe_unretained) NSString *prop_string4;
// expected-warning at -1{{Property 'prop_string4' in 'NoSynthObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
+ at property(nonatomic, unsafe_unretained) dispatch_queue_t prop_string5;
+// expected-warning at -1{{Property 'prop_string5' in 'NoSynthObject' is a retainable type 'dispatch_queue_t'}}
@end
@implementation NoSynthObject
@@ -99,4 +110,5 @@ - (NSString *)prop_string1 {
@synthesize prop_string2;
@synthesize prop_string3;
@synthesize prop_string4;
+ at synthesize prop_string5;
@end
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-members.mm b/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
index 46f65dfa603ad..155848f9834af 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
@@ -11,6 +11,8 @@
private:
SomeObj* a = nullptr;
// expected-warning at -1{{Member variable 'a' in 'members::Foo' is a raw pointer to retainable type}}
+ dispatch_queue_t a2 = nullptr;
+// expected-warning at -1{{Member variable 'a2' in 'members::Foo' is a retainable type 'dispatch_queue_t'}}
[[clang::suppress]]
SomeObj* a_suppressed = nullptr;
@@ -19,25 +21,31 @@
protected:
RetainPtr<SomeObj> b;
// No warning.
+ OSObjectPtr<dispatch_queue_t> b2;
+// No warning.
public:
SomeObj* c = nullptr;
// expected-warning at -1{{Member variable 'c' in 'members::Foo' is a raw pointer to retainable type}}
RetainPtr<SomeObj> d;
+ OSObjectPtr<dispatch_queue_t> d2;
CFMutableArrayRef e = nullptr;
// expected-warning at -1{{Member variable 'e' in 'members::Foo' is a retainable type 'CFMutableArrayRef'}}
+
};
- template<class T, class S>
+ template<class T, class S, class R>
struct FooTmpl {
T* a;
-// expected-warning at -1{{Member variable 'a' in 'members::FooTmpl<SomeObj, __CFArray *>' is a raw pointer to retainable type}}
+// expected-warning at -1{{Member variable 'a' in 'members::FooTmpl<SomeObj, __CFArray *, NSObject<OS_dispatch_queue> *>' is a raw pointer to retainable type}}
S b;
-// expected-warning at -1{{Member variable 'b' in 'members::FooTmpl<SomeObj, __CFArray *>' is a raw pointer to retainable type}}
+// expected-warning at -1{{Member variable 'b' in 'members::FooTmpl<SomeObj, __CFArray *, NSObject<OS_dispatch_queue> *>' is a raw pointer to retainable type}}
+ R c;
+// expected-warning at -1{{Member variable 'c' in 'members::FooTmpl<SomeObj, __CFArray *, NSObject<OS_dispatch_queue> *>' is a raw pointer to retainable type}}
};
- void forceTmplToInstantiate(FooTmpl<SomeObj, CFMutableArrayRef>) {}
+ void forceTmplToInstantiate(FooTmpl<SomeObj, CFMutableArrayRef, dispatch_queue_t>) {}
struct [[clang::suppress]] FooSuppressed {
private:
@@ -54,6 +62,8 @@ void forceTmplToInstantiate(FooTmpl<SomeObj, CFMutableArrayRef>) {}
RetainPtr<SomeObj> b;
CFMutableArrayRef c;
// expected-warning at -1{{Member variable 'c' in 'unions::Foo' is a retainable type 'CFMutableArrayRef'}}
+ dispatch_queue_t d;
+ // expected-warning at -1{{Member variable 'd' in 'unions::Foo' is a retainable type 'dispatch_queue_t'}}
};
template<class T>
@@ -72,16 +82,20 @@ void forceTmplToInstantiate(FooTempl<SomeObj>) {}
// expected-warning at -1{{Member variable 'elements1' in 'ptr_to_ptr_to_retained::List' contains a raw pointer to retainable type 'SomeObj'}}
CFMutableArrayRef* elements2;
// expected-warning at -1{{Member variable 'elements2' in 'ptr_to_ptr_to_retained::List' contains a retainable type 'CFMutableArrayRef'}}
+ dispatch_queue_t* elements3;
+ // expected-warning at -1{{Member variable 'elements3' in 'ptr_to_ptr_to_retained::List' contains a retainable type 'dispatch_queue_t'}}
};
- template <typename T, typename S>
+ template <typename T, typename S, typename R>
struct TemplateList {
T** elements1;
- // expected-warning at -1{{Member variable 'elements1' in 'ptr_to_ptr_to_retained::TemplateList<SomeObj, __CFArray *>' contains a raw pointer to retainable type 'SomeObj'}}
+ // expected-warning at -1{{Member variable 'elements1' in 'ptr_to_ptr_to_retained::TemplateList<SomeObj, __CFArray *, NSObject<OS_dispatch_queue> *>' contains a raw pointer to retainable type 'SomeObj'}}
S* elements2;
- // expected-warning at -1{{Member variable 'elements2' in 'ptr_to_ptr_to_retained::TemplateList<SomeObj, __CFArray *>' contains a raw pointer to retainable type '__CFArray'}}
+ // expected-warning at -1{{Member variable 'elements2' in 'ptr_to_ptr_to_retained::TemplateList<SomeObj, __CFArray *, NSObject<OS_dispatch_queue> *>' contains a raw pointer to retainable type '__CFArray'}}
+ R* elements3;
+ // expected-warning at -1{{Member variable 'elements3' in 'ptr_to_ptr_to_retained::TemplateList<SomeObj, __CFArray *, NSObject<OS_dispatch_queue> *>' contains a raw pointer to retainable type 'NSObject'}}
};
- TemplateList<SomeObj, CFMutableArrayRef> list;
+ TemplateList<SomeObj, CFMutableArrayRef, dispatch_queue_t> list;
struct SafeList {
RetainPtr<SomeObj>* elements1;
@@ -92,20 +106,24 @@ void forceTmplToInstantiate(FooTempl<SomeObj>) {}
@interface AnotherObject : NSObject {
NSString *ns_string;
- // expected-warning at -1{{Instance variable 'ns_string' in 'AnotherObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
+ // expected-warning at -1{{Instance variable 'ns_string' in 'AnotherObject' is a raw pointer to retainable type 'NSString'}}
CFStringRef cf_string;
- // expected-warning at -1{{Instance variable 'cf_string' in 'AnotherObject' is a retainable type 'CFStringRef'; member variables must be a RetainPtr}}
+ // expected-warning at -1{{Instance variable 'cf_string' in 'AnotherObject' is a retainable type 'CFStringRef'}}
+ dispatch_queue_t dispatch;
+ // expected-warning at -1{{Instance variable 'dispatch' in 'AnotherObject' is a retainable type 'dispatch_queue_t'}}
}
@property(nonatomic, strong) NSString *prop_string;
-// expected-warning at -1{{Property 'prop_string' in 'AnotherObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
+// expected-warning at -1{{Property 'prop_string' in 'AnotherObject' is a raw pointer to retainable type 'NSString'}}
@end
NS_REQUIRES_PROPERTY_DEFINITIONS
@interface NoSynthObject : NSObject {
NSString *ns_string;
- // expected-warning at -1{{Instance variable 'ns_string' in 'NoSynthObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
+ // expected-warning at -1{{Instance variable 'ns_string' in 'NoSynthObject' is a raw pointer to retainable type 'NSString'}}
CFStringRef cf_string;
- // expected-warning at -1{{Instance variable 'cf_string' in 'NoSynthObject' is a retainable type 'CFStringRef'; member variables must be a RetainPtr}}
+ // expected-warning at -1{{Instance variable 'cf_string' in 'NoSynthObject' is a retainable type 'CFStringRef'}}
+ dispatch_queue_t dispatch;
+ // expected-warning at -1{{Instance variable 'dispatch' in 'NoSynthObject' is a retainable type 'dispatch_queue_t'}}
}
@property(nonatomic, readonly, strong) NSString *prop_string1;
@property(nonatomic, readonly, strong) NSString *prop_string2;
@@ -114,6 +132,7 @@ @interface NoSynthObject : NSObject {
// expected-warning at -1{{Property 'prop_string3' in 'NoSynthObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
@property(nonatomic, unsafe_unretained) NSString *prop_string4;
// expected-warning at -1{{Property 'prop_string4' in 'NoSynthObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
+ at property(nonatomic, readonly, strong) NSString *dispatch;
@end
@implementation NoSynthObject
@@ -123,4 +142,7 @@ - (NSString *)prop_string1 {
@synthesize prop_string2;
@synthesize prop_string3;
@synthesize prop_string4;
+- (dispatch_queue_t)dispatch {
+ return nil;
+}
@end
More information about the cfe-commits
mailing list