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 <rn...@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
 
+@protocol OS_dispatch_queue
+@end
+
+typedef NSObject<OS_dispatch_queue> *dispatch_queue_t;
+
+@protocol OS_dispatch_queue_attr
+@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@-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@-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@-1{{Call argument is unretained and unsafe}}
     consume_cf(provide_cf());
     // expected-warning@-1{{Call argument is unretained and unsafe}}
+    consume_dispatch(provide_dispatch());
+    // expected-warning@-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@-1{{Call argument for parameter 'foo' is unretained 
and unsafe}}
     // expected-warning@-2{{Call argument for parameter 'bar' is unretained 
and unsafe}}
+    // expected-warning@-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@-1{{Call argument for parameter 'foo' is unretained 
and unsafe}}
     // expected-warning@-2{{Call argument is unretained and unsafe}}
+    // expected-warning@-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@-1{{Call argument for parameter 'ptr' is unretained 
and unsafe}}
     c.consume_cf(provide_cf());
     // expected-warning@-1{{Call argument for parameter 'ref' is unretained 
and unsafe}}
+    c.consume_dispatch(provide_dispatch());
+    // expected-warning@-1{{Call argument for parameter 'ptr' is unretained 
and unsafe}}
   }
 
   void foo2() {
@@ -88,6 +96,12 @@ void something() {
         consume_cf(provide_cf());
         // expected-warning@-1{{Call argument is unretained and unsafe}}
       }
+
+      void consume_dispatch(dispatch_queue_t) { some_function(); }
+      void anything() {
+        consume_dispatch(provide_dispatch());
+        // expected-warning@-1{{Call argument is unretained and unsafe}}
+      }
     };
   }
 
@@ -104,6 +118,12 @@ void something() {
         this->consume_cf(provide_cf());
         // expected-warning@-1{{Call argument is unretained and unsafe}}
       }
+
+      void consume_dispatch(dispatch_queue_t) { some_function(); }
+      void anything() {
+        this->consume_dispatch(provide_dispatch());
+        // expected-warning@-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@-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@-1{{Call argument for parameter 'param' is unretained 
and unsafe}}
 
+  void function_with_default_arg3(dispatch_queue_t param = global_dispatch);
+  // expected-warning@-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@-1{{Call argument for parameter 'bad' is unretained 
and unsafe}}
     f(global);
     // expected-warning@-1{{Call argument for parameter 'bad' is unretained 
and unsafe}}
+    f << global_dispatch;
+    // expected-warning@-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@-1{{Call argument for parameter 'bad' is unretained 
and unsafe}}
     bar_cf(v ? provideProtectedCF().get() : provide_cf());
     // expected-warning@-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@-1{{Call argument is unretained and unsafe}}
+    bar_dispatch(v ? provideProtectedDispatch().get() : provide_dispatch());
+    // expected-warning@-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@-1{{Call argument for parameter 'str' is unretained and 
unsafe}}
   // expected-warning@-2{{Call argument for parameter 'dict' is unretained and 
unsafe}}
+  // expected-warning@-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@-1{{Call argument is unretained and unsafe}}
   // expected-warning@-2{{Call argument is unretained and unsafe}}
-  [self doWork:@"hello", RetainPtr<SomeObj> { provide() }.get(), 
RetainPtr<CFMutableArrayRef> { provide_cf() }.get()];
+  // expected-warning@-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@-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@-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@-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@-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@-1{{Implicitly captured reference 'cf' to unretained 
type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
   };
 
+  auto os = make_os();
+  auto baz1 = [os](){
+    // expected-warning@-1{{Captured reference 'os' to unretained type is 
unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
+    dispatch_queue_get_label(os);
+  };
+  auto baz2 = [&os](){
+    // expected-warning@-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@-1{{Implicitly captured reference 'os' to unretained 
type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
+    os = nullptr;
+  };
+  auto baz4 = [=](){
+    dispatch_queue_get_label(os);
+    // expected-warning@-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@-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@-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@-1{{Implicitly captured raw-pointer 'obj' to 
unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
     CFArrayAppendValue(cf, nullptr);
     // expected-warning@-1{{Implicitly captured reference 'cf' to unretained 
type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
+    dispatch_queue_get_label(os);
+    // expected-warning@-1{{Implicitly captured reference 'os' to unretained 
type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
   });
   callFunctionOpaque([&]() {
     [obj doWork];
     // expected-warning@-1{{Implicitly captured raw-pointer 'obj' to 
unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
     CFArrayAppendValue(cf, nullptr);
     // expected-warning@-1{{Implicitly captured reference 'cf' to unretained 
type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}
+    dispatch_queue_get_label(os);
+    // expected-warning@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-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@-1{{Local variable 'str' is unretained and unsafe 
[alpha.webkit.UnretainedLocalVarsChecker]}}
   CFDictionaryRef dict = provide_dict();
   // expected-warning@-1{{Local variable 'dict' is unretained and unsafe 
[alpha.webkit.UnretainedLocalVarsChecker]}}
-  doWork(str, dict);
+  dispatch_queue_t queue = provide_queue();
+  // expected-warning@-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@-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@-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@-1{{Member variable 'y' in 'members::FooTmpl<SomeObj, 
__CFArray *>' is a raw pointer to retainable type}}
+// expected-warning@-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@-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@-1{{Member variable 'elements2' in 
'ptr_to_ptr_to_retained::TemplateList<SomeObj, __CFArray *>' contains a raw 
pointer to retainable type '__CFArray'}}
+    // expected-warning@-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@-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@-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;
+@property(nonatomic, readonly) dispatch_queue_t prop_string5;
 @end
 
 NS_REQUIRES_PROPERTY_DEFINITIONS
@@ -90,6 +99,8 @@ @interface NoSynthObject : NSObject {
 // expected-warning@-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@-1{{Property 'prop_string4' in 'NoSynthObject' is a raw 
pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
+@property(nonatomic, unsafe_unretained) dispatch_queue_t prop_string5;
+// expected-warning@-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;
+@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@-1{{Member variable 'a' in 'members::Foo' is a raw pointer 
to retainable type}}
+    dispatch_queue_t a2 = nullptr;
+// expected-warning@-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@-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@-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@-1{{Member variable 'a' in 'members::FooTmpl<SomeObj, 
__CFArray *>' is a raw pointer to retainable type}}
+// expected-warning@-1{{Member variable 'a' in 'members::FooTmpl<SomeObj, 
__CFArray *, NSObject<OS_dispatch_queue> *>' is a raw pointer to retainable 
type}}
     S b;
-// expected-warning@-1{{Member variable 'b' in 'members::FooTmpl<SomeObj, 
__CFArray *>' is a raw pointer to retainable type}}
+// expected-warning@-1{{Member variable 'b' in 'members::FooTmpl<SomeObj, 
__CFArray *, NSObject<OS_dispatch_queue> *>' is a raw pointer to retainable 
type}}
+    R c;
+// expected-warning@-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@-1{{Member variable 'c' in 'unions::Foo' is a 
retainable type 'CFMutableArrayRef'}}
+    dispatch_queue_t d;
+    // expected-warning@-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@-1{{Member variable 'elements1' in 
'ptr_to_ptr_to_retained::List' contains a raw pointer to retainable type 
'SomeObj'}}
     CFMutableArrayRef* elements2;
     // expected-warning@-1{{Member variable 'elements2' in 
'ptr_to_ptr_to_retained::List' contains a retainable type 'CFMutableArrayRef'}}
+    dispatch_queue_t* elements3;
+    // expected-warning@-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@-1{{Member variable 'elements1' in 
'ptr_to_ptr_to_retained::TemplateList<SomeObj, __CFArray *>' contains a raw 
pointer to retainable type 'SomeObj'}}
+    // expected-warning@-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@-1{{Member variable 'elements2' in 
'ptr_to_ptr_to_retained::TemplateList<SomeObj, __CFArray *>' contains a raw 
pointer to retainable type '__CFArray'}}
+    // expected-warning@-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@-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@-1{{Instance variable 'ns_string' in 'AnotherObject' is 
a raw pointer to retainable type 'NSString'; member variables must be a 
RetainPtr}}
+  // expected-warning@-1{{Instance variable 'ns_string' in 'AnotherObject' is 
a raw pointer to retainable type 'NSString'}}
   CFStringRef cf_string;
-  // expected-warning@-1{{Instance variable 'cf_string' in 'AnotherObject' is 
a retainable type 'CFStringRef'; member variables must be a RetainPtr}}
+  // expected-warning@-1{{Instance variable 'cf_string' in 'AnotherObject' is 
a retainable type 'CFStringRef'}}
+  dispatch_queue_t dispatch;
+  // expected-warning@-1{{Instance variable 'dispatch' in 'AnotherObject' is a 
retainable type 'dispatch_queue_t'}}
 }
 @property(nonatomic, strong) NSString *prop_string;
-// expected-warning@-1{{Property 'prop_string' in 'AnotherObject' is a raw 
pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
+// expected-warning@-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@-1{{Instance variable 'ns_string' in 'NoSynthObject' is 
a raw pointer to retainable type 'NSString'; member variables must be a 
RetainPtr}}
+  // expected-warning@-1{{Instance variable 'ns_string' in 'NoSynthObject' is 
a raw pointer to retainable type 'NSString'}}
   CFStringRef cf_string;
-  // expected-warning@-1{{Instance variable 'cf_string' in 'NoSynthObject' is 
a retainable type 'CFStringRef'; member variables must be a RetainPtr}}
+  // expected-warning@-1{{Instance variable 'cf_string' in 'NoSynthObject' is 
a retainable type 'CFStringRef'}}
+  dispatch_queue_t dispatch;
+  // expected-warning@-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@-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@-1{{Property 'prop_string4' in 'NoSynthObject' is a raw 
pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
+@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

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to