[clang] 9d933c7 - [WebKit checkers] Add the support for OSObjectPtr (#159484)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 18 21:46:26 PDT 2025


Author: Ryosuke Niwa
Date: 2025-09-18T21:46:22-07:00
New Revision: 9d933c794af32362dbbbefe53825054b533d7b2c

URL: https://github.com/llvm/llvm-project/commit/9d933c794af32362dbbbefe53825054b533d7b2c
DIFF: https://github.com/llvm/llvm-project/commit/9d933c794af32362dbbbefe53825054b533d7b2c.diff

LOG: [WebKit checkers] Add the support for OSObjectPtr (#159484)

Add the support for OSObjectPtr, which behaves like RetainPtr.

Added: 
    

Modified: 
    clang/docs/analyzer/checkers.rst
    clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
    clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
    clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp
    clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
    clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
    clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
    clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
    clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
    clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
    clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
    clang/test/Analysis/Checkers/WebKit/call-args-checked.cpp
    clang/test/Analysis/Checkers/WebKit/forward-decl-checker.mm
    clang/test/Analysis/Checkers/WebKit/mock-types.h
    clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
    clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp
    clang/test/Analysis/Checkers/WebKit/unretained-call-args-arc.mm
    clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm
    clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures-arc.mm
    clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures.mm
    clang/test/Analysis/Checkers/WebKit/unretained-local-vars-arc.mm
    clang/test/Analysis/Checkers/WebKit/unretained-local-vars.mm
    clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm
    clang/test/Analysis/Checkers/WebKit/unretained-members.mm

Removed: 
    


################################################################################
diff  --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index 15d7557ae6af9..d942578dd7596 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -3633,12 +3633,13 @@ See `WebKit Guidelines for Safer C++ Programming <https://github.com/WebKit/WebK
 
 alpha.webkit.NoUnretainedMemberChecker
 """"""""""""""""""""""""""""""""""""""""
-Raw pointers and references to a NS or CF object can't be used as class members or ivars. Only RetainPtr is allowed for CF types regardless of whether ARC is enabled or disabled. Only RetainPtr is allowed for NS types when ARC is disabled.
+Raw pointers and references to a NS or CF object can't be used as class members or ivars. Only RetainPtr is allowed for CF types regardless of whether ARC is enabled or disabled. Only RetainPtr or OSObjectPtr is allowed for NS types when ARC is disabled.
 
 .. code-block:: cpp
 
  struct Foo {
    NSObject *ptr; // warn
+   dispatch_queue_t queue; // warn
    // ...
  };
 
@@ -3646,13 +3647,14 @@ See `WebKit Guidelines for Safer C++ Programming <https://github.com/WebKit/WebK
 
 alpha.webkit.UnretainedLambdaCapturesChecker
 """"""""""""""""""""""""""""""""""""""""""""
-Raw pointers and references to NS or CF types can't be captured in lambdas. Only RetainPtr is allowed for CF types regardless of whether ARC is enabled or disabled, and only RetainPtr is allowed for NS types when ARC is disabled.
+Raw pointers and references to NS or CF types can't be captured in lambdas. Only RetainPtr is allowed for CF types regardless of whether ARC is enabled or disabled, and only RetainPtr or OSObjectPtr is allowed for NS types when ARC is disabled.
 
 .. code-block:: cpp
 
- void foo(NSObject *a, NSObject *b) {
+ void foo(NSObject *a, NSObject *b, dispatch_queue_t c) {
    [&, a](){ // warn about 'a'
      do_something(b); // warn about 'b'
+     dispatch_queue_get_specific(c, "some"); // warn about 'c'
    };
  };
 
@@ -3755,7 +3757,7 @@ alpha.webkit.UnretainedCallArgsChecker
 """"""""""""""""""""""""""""""""""""""
 The goal of this rule is to make sure that lifetime of any dynamically allocated NS or CF objects passed as a call argument keeps its memory region past the end of the call. This applies to call to any function, method, lambda, function pointer or functor. NS or CF objects aren't supposed to be allocated on stack so we check arguments for parameters of raw pointers and references to unretained types.
 
-The rules of when to use and not to use RetainPtr are same as alpha.webkit.UncountedCallArgsChecker for ref-counted objects.
+The rules of when to use and not to use RetainPtr or OSObjectPtr are same as alpha.webkit.UncountedCallArgsChecker for ref-counted objects.
 
 alpha.webkit.UncountedLocalVarsChecker
 """"""""""""""""""""""""""""""""""""""
@@ -3845,9 +3847,9 @@ Here are some examples of situations that we warn about as they *might* be poten
 
 alpha.webkit.UnretainedLocalVarsChecker
 """""""""""""""""""""""""""""""""""""""
-The goal of this rule is to make sure that any NS or CF local variable is backed by a RetainPtr with lifetime that is strictly larger than the scope of the unretained local variable. To be on the safe side we require the scope of an unretained variable to be embedded in the scope of Retainptr object that backs it.
+The goal of this rule is to make sure that any NS or CF local variable is backed by a RetainPtr or OSObjectPtr with lifetime that is strictly larger than the scope of the unretained local variable. To be on the safe side we require the scope of an unretained variable to be embedded in the scope of RetainPtr or OSObjectPtr object that backs it.
 
-The rules of when to use and not to use RetainPtr are same as alpha.webkit.UncountedCallArgsChecker for ref-counted objects.
+The rules of when to use and not to use RetainPtr or OSObjectPtr are same as alpha.webkit.UncountedCallArgsChecker for ref-counted objects.
 
 These are examples of cases that we consider safe:
 
@@ -3890,8 +3892,8 @@ Here are some examples of situations that we warn about as they *might* be poten
 
 webkit.RetainPtrCtorAdoptChecker
 """"""""""""""""""""""""""""""""
-The goal of this rule is to make sure the constructor of RetainPtr as well as adoptNS and adoptCF are used correctly.
-When creating a RetainPtr with +1 semantics, adoptNS or adoptCF should be used, and in +0 semantics, RetainPtr constructor should be used.
+The goal of this rule is to make sure the constructors of RetainPtr and OSObjectPtr as well as adoptNS, adoptCF, and adoptOSObject are used correctly.
+When creating a RetainPtr or OSObjectPtr with +1 semantics, adoptNS, adoptCF, or adoptOSObject should be used, and in +0 semantics, RetainPtr or OSObjectPtr constructor should be used.
 Warn otherwise.
 
 These are examples of cases that we consider correct:
@@ -3900,6 +3902,7 @@ These are examples of cases that we consider correct:
 
     RetainPtr ptr = adoptNS([[NSObject alloc] init]); // ok
     RetainPtr ptr = CGImageGetColorSpace(image); // ok
+    OSObjectPtr ptr = adoptOSObject(dispatch_queue_create("some queue", nullptr)); // ok
 
 Here are some examples of cases that we consider incorrect use of RetainPtr constructor and adoptCF
 
@@ -3907,6 +3910,7 @@ Here are some examples of cases that we consider incorrect use of RetainPtr cons
 
     RetainPtr ptr = [[NSObject alloc] init]; // warn
     auto ptr = adoptCF(CGImageGetColorSpace(image)); // warn
+    OSObjectPtr ptr = dispatch_queue_create("some queue", nullptr); // warn
 
 Debug Checkers
 ---------------

diff  --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index a1f5bdfb9edf1..4473c54d8d6e3 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -1726,7 +1726,7 @@ def UnretainedLocalVarsChecker : Checker<"UnretainedLocalVarsChecker">,
   Documentation<HasDocumentation>;
 
 def RetainPtrCtorAdoptChecker : Checker<"RetainPtrCtorAdoptChecker">,
-  HelpText<"Check for correct use of RetainPtr constructor, adoptNS, and adoptCF">,
+  HelpText<"Check for correct use of RetainPtr/OSObjectPtr constructor, adoptNS, adoptCF, and adoptOSObject">,
   Documentation<HasDocumentation>;
 
 } // end alpha.webkit

diff  --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
index b629de3254ed3..00a1b8b6e7e89 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
@@ -115,7 +115,7 @@ bool tryToFindPtrOrigin(
         if (auto *Callee = operatorCall->getDirectCallee()) {
           auto ClsName = safeGetName(Callee->getParent());
           if (isRefType(ClsName) || isCheckedPtr(ClsName) ||
-              isRetainPtr(ClsName) || ClsName == "unique_ptr" ||
+              isRetainPtrOrOSPtr(ClsName) || ClsName == "unique_ptr" ||
               ClsName == "UniqueRef" || ClsName == "WeakPtr" ||
               ClsName == "WeakRef") {
             if (operatorCall->getNumArgs() == 1) {

diff  --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp
index 9deb1845a2f1a..d8539eaaac49f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ForwardDeclChecker.cpp
@@ -162,7 +162,7 @@ class ForwardDeclChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
     // Ref-counted smartpointers actually have raw-pointer to uncounted type as
     // a member but we trust them to handle it correctly.
     auto R = llvm::dyn_cast_or_null<CXXRecordDecl>(RD);
-    if (!R || isRefCounted(R) || isCheckedPtr(R) || isRetainPtr(R))
+    if (!R || isRefCounted(R) || isCheckedPtr(R) || isRetainPtrOrOSPtr(R))
       return;
 
     for (auto *Member : RD->fields()) {

diff  --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 90b2343b4be77..e5c74bbaf3d6b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -129,8 +129,9 @@ bool isRefType(const std::string &Name) {
          Name == "RefPtr" || Name == "RefPtrAllowingPartiallyDestroyed";
 }
 
-bool isRetainPtr(const std::string &Name) {
-  return Name == "RetainPtr" || Name == "RetainPtrArc";
+bool isRetainPtrOrOSPtr(const std::string &Name) {
+  return Name == "RetainPtr" || Name == "RetainPtrArc" ||
+         Name == "OSObjectPtr" || Name == "OSObjectPtrArc";
 }
 
 bool isCheckedPtr(const std::string &Name) {
@@ -138,7 +139,7 @@ bool isCheckedPtr(const std::string &Name) {
 }
 
 bool isSmartPtrClass(const std::string &Name) {
-  return isRefType(Name) || isCheckedPtr(Name) || isRetainPtr(Name) ||
+  return isRefType(Name) || isCheckedPtr(Name) || isRetainPtrOrOSPtr(Name) ||
          Name == "WeakPtr" || Name == "WeakPtrFactory" ||
          Name == "WeakPtrFactoryWithBitField" || Name == "WeakPtrImplBase" ||
          Name == "WeakPtrImplBaseSingleThread" || Name == "ThreadSafeWeakPtr" ||
@@ -166,15 +167,17 @@ bool isCtorOfCheckedPtr(const clang::FunctionDecl *F) {
   return isCheckedPtr(safeGetName(F));
 }
 
-bool isCtorOfRetainPtr(const clang::FunctionDecl *F) {
+bool isCtorOfRetainPtrOrOSPtr(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) {
-  return isCtorOfRefCounted(F) || isCtorOfCheckedPtr(F) || isCtorOfRetainPtr(F);
+  return isCtorOfRefCounted(F) || isCtorOfCheckedPtr(F) ||
+         isCtorOfRetainPtrOrOSPtr(F);
 }
 
 template <typename Predicate>
@@ -198,8 +201,8 @@ bool isRefOrCheckedPtrType(const clang::QualType T) {
       T, [](auto Name) { return isRefType(Name) || isCheckedPtr(Name); });
 }
 
-bool isRetainPtrType(const clang::QualType T) {
-  return isPtrOfType(T, [](auto Name) { return isRetainPtr(Name); });
+bool isRetainPtrOrOSPtrType(const clang::QualType T) {
+  return isPtrOfType(T, [](auto Name) { return isRetainPtrOrOSPtr(Name); });
 }
 
 bool isOwnerPtrType(const clang::QualType T) {
@@ -273,7 +276,7 @@ bool RetainTypeChecker::isUnretained(const QualType QT, bool ignoreARC) {
 std::optional<bool> isUnretained(const QualType T, bool IsARCEnabled) {
   if (auto *Subst = dyn_cast<SubstTemplateTypeParmType>(T)) {
     if (auto *Decl = Subst->getAssociatedDecl()) {
-      if (isRetainPtr(safeGetName(Decl)))
+      if (isRetainPtrOrOSPtr(safeGetName(Decl)))
         return false;
     }
   }
@@ -373,7 +376,7 @@ std::optional<bool> isGetterOfSafePtr(const CXXMethodDecl *M) {
          method == "impl"))
       return true;
 
-    if (isRetainPtr(className) && method == "get")
+    if (isRetainPtrOrOSPtr(className) && method == "get")
       return true;
 
     // Ref<T> -> T conversion
@@ -394,7 +397,7 @@ std::optional<bool> isGetterOfSafePtr(const CXXMethodDecl *M) {
       }
     }
 
-    if (isRetainPtr(className)) {
+    if (isRetainPtrOrOSPtr(className)) {
       if (auto *maybeRefToRawOperator = dyn_cast<CXXConversionDecl>(M)) {
         auto QT = maybeRefToRawOperator->getConversionType();
         auto *T = QT.getTypePtrOrNull();
@@ -425,10 +428,10 @@ bool isCheckedPtr(const CXXRecordDecl *R) {
   return false;
 }
 
-bool isRetainPtr(const CXXRecordDecl *R) {
+bool isRetainPtrOrOSPtr(const CXXRecordDecl *R) {
   assert(R);
   if (auto *TmplR = R->getTemplateInstantiationPattern())
-    return isRetainPtr(safeGetName(TmplR));
+    return isRetainPtrOrOSPtr(safeGetName(TmplR));
   return false;
 }
 

diff  --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index d2095d07e1434..8300a6c051f3e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -57,7 +57,7 @@ bool isRefCounted(const clang::CXXRecordDecl *Class);
 bool isCheckedPtr(const clang::CXXRecordDecl *Class);
 
 /// \returns true if \p Class is a RetainPtr, false if not.
-bool isRetainPtr(const clang::CXXRecordDecl *Class);
+bool isRetainPtrOrOSPtr(const clang::CXXRecordDecl *Class);
 
 /// \returns true if \p Class is a smart pointer (RefPtr, WeakPtr, etc...),
 /// false if not.
@@ -116,7 +116,7 @@ std::optional<bool> isUnsafePtr(const QualType T, bool IsArcEnabled);
 bool isRefOrCheckedPtrType(const clang::QualType T);
 
 /// \returns true if \p T is a RetainPtr, false if not.
-bool isRetainPtrType(const clang::QualType T);
+bool isRetainPtrOrOSPtrType(const clang::QualType T);
 
 /// \returns true if \p T is a RefPtr, Ref, CheckedPtr, CheckedRef, or
 /// unique_ptr, false if not.
@@ -141,7 +141,7 @@ bool isRefType(const std::string &Name);
 bool isCheckedPtr(const std::string &Name);
 
 /// \returns true if \p Name is RetainPtr or its variant, false if not.
-bool isRetainPtr(const std::string &Name);
+bool isRetainPtrOrOSPtr(const std::string &Name);
 
 /// \returns true if \p Name is a smart pointer type name, false if not.
 bool isSmartPtrClass(const std::string &Name);

diff  --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
index e80f1749d595b..b841caf8c74b1 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
@@ -465,11 +465,11 @@ class UnretainedCallArgsChecker final : public RawPtrRefCallArgsChecker {
   }
 
   bool isSafePtr(const CXXRecordDecl *Record) const final {
-    return isRetainPtr(Record);
+    return isRetainPtrOrOSPtr(Record);
   }
 
   bool isSafePtrType(const QualType type) const final {
-    return isRetainPtrType(type);
+    return isRetainPtrOrOSPtrType(type);
   }
 
   bool isSafeExpr(const Expr *E) const final {

diff  --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
index 63f0ed4a54fb5..033eb8cc299b0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
@@ -500,7 +500,7 @@ class UnretainedLambdaCapturesChecker : public RawPtrRefLambdaCapturesChecker {
   }
 
   virtual bool isPtrType(const std::string &Name) const final {
-    return isRetainPtr(Name);
+    return isRetainPtrOrOSPtr(Name);
   }
 
   const char *ptrKind(QualType QT) const final { return "unretained"; }

diff  --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
index f4f6e28c97ea1..dd9701fbbb017 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
@@ -434,10 +434,10 @@ class UnretainedLocalVarsChecker final : public RawPtrRefLocalVarsChecker {
     return RTC->isUnretained(T);
   }
   bool isSafePtr(const CXXRecordDecl *Record) const final {
-    return isRetainPtr(Record);
+    return isRetainPtrOrOSPtr(Record);
   }
   bool isSafePtrType(const QualType type) const final {
-    return isRetainPtrType(type);
+    return isRetainPtrOrOSPtrType(type);
   }
   bool isSafeExpr(const Expr *E) const final {
     return ento::cocoa::isCocoaObjectRef(E->getType()) &&

diff  --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
index 8faf6a219450a..a97a37f85e96c 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..e1f9a77f5a5ca 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
@@ -67,7 +67,7 @@ class RetainPtrCtorAdoptChecker
       }
 
       bool TraverseClassTemplateDecl(ClassTemplateDecl *CTD) {
-        if (isRetainPtr(safeGetName(CTD)))
+        if (isRetainPtrOrOSPtr(safeGetName(CTD)))
           return true; // Skip the contents of RetainPtr.
         return Base::TraverseClassTemplateDecl(CTD);
       }
@@ -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 {
@@ -304,7 +305,7 @@ class RetainPtrCtorAdoptChecker
     if (!Cls)
       return;
 
-    if (!isRetainPtr(safeGetName(Cls)) || !CE->getNumArgs())
+    if (!isRetainPtrOrOSPtr(safeGetName(Cls)) || !CE->getNumArgs())
       return;
 
     // Ignore RetainPtr construction inside adoptNS, adoptCF, and retainPtr.
@@ -491,7 +492,7 @@ class RetainPtrCtorAdoptChecker
         return IsOwnedResult::NotOwned;
       if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
         auto QT = DRE->getType();
-        if (isRetainPtrType(QT))
+        if (isRetainPtrOrOSPtrType(QT))
           return IsOwnedResult::NotOwned;
         QT = QT.getCanonicalType();
         if (RTC.isUnretained(QT, true /* ignoreARC */))
@@ -530,12 +531,13 @@ class RetainPtrCtorAdoptChecker
           if (auto *CD = dyn_cast<CXXConversionDecl>(MD)) {
             auto QT = CD->getConversionType().getCanonicalType();
             auto *ResultType = QT.getTypePtrOrNull();
-            if (isRetainPtr(safeGetName(Cls)) && ResultType &&
+            if (isRetainPtrOrOSPtr(safeGetName(Cls)) && ResultType &&
                 (ResultType->isPointerType() || ResultType->isReferenceType() ||
                  ResultType->isObjCObjectPointerType()))
               return IsOwnedResult::NotOwned;
           }
-          if (safeGetName(MD) == "leakRef" && isRetainPtr(safeGetName(Cls)))
+          if (safeGetName(MD) == "leakRef" &&
+              isRetainPtrOrOSPtr(safeGetName(Cls)))
             return IsOwnedResult::Owned;
         }
       }
@@ -553,7 +555,7 @@ class RetainPtrCtorAdoptChecker
             continue;
           }
           auto RetType = Callee->getReturnType();
-          if (isRetainPtrType(RetType))
+          if (isRetainPtrOrOSPtrType(RetType))
             return IsOwnedResult::NotOwned;
           if (isCreateOrCopyFunction(Callee)) {
             CreateOrCopyFnCall.insert(CE);

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/forward-decl-checker.mm b/clang/test/Analysis/Checkers/WebKit/forward-decl-checker.mm
index 084b47322d7f9..104b555c1c41d 100644
--- a/clang/test/Analysis/Checkers/WebKit/forward-decl-checker.mm
+++ b/clang/test/Analysis/Checkers/WebKit/forward-decl-checker.mm
@@ -4,20 +4,6 @@
 #include "objc-mock-types.h"
 #include "mock-system-header.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
-
 typedef struct OpaqueJSString * JSStringRef;
 
 class Obj;

diff  --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h
index a03d31870ee0d..a49faa1d25336 100644
--- a/clang/test/Analysis/Checkers/WebKit/mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h
@@ -1,3 +1,22 @@
+#ifndef std_move
+#define std_move
+
+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);
+
+}
+
+#endif
+
 #ifndef mock_types_1103988513531
 #define mock_types_1103988513531
 

diff  --git a/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h b/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
index 09b303961fd6a..854742b82a2d4 100644
--- a/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
@@ -1,3 +1,22 @@
+#ifndef std_move
+#define std_move
+
+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);
+
+}
+
+#endif
+
 @class NSString;
 @class NSArray;
 @class NSMutableArray;
@@ -157,6 +176,39 @@ __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 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 +345,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 +618,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