[clang] [WebKit checkers] Add the support for OSObjectPtr (PR #159484)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 17 17:02:23 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Ryosuke Niwa (rniwa)
<details>
<summary>Changes</summary>
Add the support for OSObjectPtr, which behaves like RetainPtr.
---
Patch is 51.33 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/159484.diff
15 Files Affected:
- (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp (+4-2)
- (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp (+6-5)
- (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp (+2-1)
- (modified) clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp (-14)
- (modified) clang/test/Analysis/Checkers/WebKit/mock-types.h (+10)
- (modified) clang/test/Analysis/Checkers/WebKit/objc-mock-types.h (+156)
- (modified) clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp (-3)
- (modified) clang/test/Analysis/Checkers/WebKit/unretained-call-args-arc.mm (+12-3)
- (modified) clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm (+81-14)
- (modified) clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures-arc.mm (+46-3)
- (modified) clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures.mm (+64-3)
- (modified) clang/test/Analysis/Checkers/WebKit/unretained-local-vars-arc.mm (+16-3)
- (modified) clang/test/Analysis/Checkers/WebKit/unretained-local-vars.mm (+120-8)
- (modified) clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm (+18-6)
- (modified) clang/test/Analysis/Checkers/WebKit/unretained-members.mm (+35-13)
``````````diff
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, CFDictiona...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/159484
More information about the cfe-commits
mailing list