https://github.com/rniwa updated 
https://github.com/llvm/llvm-project/pull/132316

>From 642057c409b1c3b98ee4ecb16e95b5fb5be47a01 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rn...@webkit.org>
Date: Thu, 20 Mar 2025 17:54:22 -0700
Subject: [PATCH 1/3] [alpha.webkit.RetainPtrCtorAdoptChecker] Support
 adopt(cast(copy(~))

This PR adds the support for recognizing calling adoptCF/adoptNS on the result 
of a cast
operation on the return value of a function which creates NS or CF types. It 
also fixes
a bug that we weren't reporting memory leaks when CF types are created without 
ever
calling RetainPtr's constructor, adoptCF, or adoptNS.

To do this, this PR adds a new mechanism to report a memory leak whenever 
create or copy
CF functions are invoked unless this CallExpr has already been visited while 
validating
a call to adoptCF. Also added an early exit when isOwned returns 
IsOwnedResult::Skip due
to an unresolved template argument.
---
 .../WebKit/RetainPtrCtorAdoptChecker.cpp      | 70 ++++++++++++++----
 .../Checkers/WebKit/objc-mock-types.h         | 72 ++++++++++++++++++-
 .../WebKit/retain-ptr-ctor-adopt-use-arc.mm   |  9 ++-
 .../WebKit/retain-ptr-ctor-adopt-use.mm       |  9 ++-
 4 files changed, 140 insertions(+), 20 deletions(-)

diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
index 4ce3262e90e13..2d9620cc8ee5e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
@@ -34,6 +34,7 @@ class RetainPtrCtorAdoptChecker
   mutable BugReporter *BR;
   mutable std::unique_ptr<RetainSummaryManager> Summaries;
   mutable llvm::DenseSet<const ValueDecl *> CreateOrCopyOutArguments;
+  mutable llvm::DenseSet<const Expr *> CreateOrCopyFnCall;
   mutable RetainTypeChecker RTC;
 
 public:
@@ -119,7 +120,7 @@ class RetainPtrCtorAdoptChecker
       return;
 
     if (!isAdoptFn(F) || !CE->getNumArgs()) {
-      rememberOutArguments(CE, F);
+      checkCreateOrCopyFunction(CE, F, DeclWithIssue);
       return;
     }
 
@@ -128,24 +129,30 @@ class RetainPtrCtorAdoptChecker
     auto Name = safeGetName(F);
     if (Result == IsOwnedResult::Unknown)
       Result = IsOwnedResult::NotOwned;
-    if (Result == IsOwnedResult::NotOwned && !isAllocInit(Arg) &&
-        !isCreateOrCopy(Arg)) {
-      if (auto *DRE = dyn_cast<DeclRefExpr>(Arg)) {
-        if (CreateOrCopyOutArguments.contains(DRE->getDecl()))
-          return;
-      }
-      if (RTC.isARCEnabled() && isAdoptNS(F))
-        reportUseAfterFree(Name, CE, DeclWithIssue, "when ARC is disabled");
-      else
-        reportUseAfterFree(Name, CE, DeclWithIssue);
+    if (isAllocInit(Arg) || isCreateOrCopy(Arg)) {
+      CreateOrCopyFnCall.insert(Arg); // Avoid double reporting.
+      return;
+    }
+    if (Result == IsOwnedResult::Owned || Result == IsOwnedResult::Skip)
+      return;
+
+    if (auto *DRE = dyn_cast<DeclRefExpr>(Arg)) {
+      if (CreateOrCopyOutArguments.contains(DRE->getDecl()))
+        return;
     }
+    if (RTC.isARCEnabled() && isAdoptNS(F))
+      reportUseAfterFree(Name, CE, DeclWithIssue, "when ARC is disabled");
+    else
+      reportUseAfterFree(Name, CE, DeclWithIssue);
   }
 
-  void rememberOutArguments(const CallExpr *CE,
-                            const FunctionDecl *Callee) const {
+  void checkCreateOrCopyFunction(const CallExpr *CE,
+                                 const FunctionDecl *Callee,
+                                 const Decl *DeclWithIssue) const {
     if (!isCreateOrCopyFunction(Callee))
       return;
 
+    bool hasOutArgument = false;
     unsigned ArgCount = CE->getNumArgs();
     for (unsigned ArgIndex = 0; ArgIndex < ArgCount; ++ArgIndex) {
       auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();
@@ -164,7 +171,10 @@ class RetainPtrCtorAdoptChecker
       if (!Decl)
         continue;
       CreateOrCopyOutArguments.insert(Decl);
+      hasOutArgument = true;
     }
+    if (!hasOutArgument && !CreateOrCopyFnCall.contains(CE))
+      reportLeak(CE, DeclWithIssue);
   }
 
   void visitConstructExpr(const CXXConstructExpr *CE,
@@ -190,6 +200,13 @@ class RetainPtrCtorAdoptChecker
     std::string Name = "RetainPtr constructor";
     auto *Arg = CE->getArg(0)->IgnoreParenCasts();
     auto Result = isOwned(Arg);
+
+    if (isCreateOrCopy(Arg))
+      CreateOrCopyFnCall.insert(Arg); // Avoid double reporting.
+    
+    if (Result == IsOwnedResult::Skip)
+      return;
+
     if (Result == IsOwnedResult::Unknown)
       Result = IsOwnedResult::NotOwned;
     if (Result == IsOwnedResult::Owned)
@@ -303,11 +320,22 @@ class RetainPtrCtorAdoptChecker
         if (auto *Callee = CE->getDirectCallee()) {
           if (isAdoptFn(Callee))
             return IsOwnedResult::NotOwned;
-          if (safeGetName(Callee) == "__builtin___CFStringMakeConstantString")
+          auto Name = safeGetName(Callee);
+          if (Name == "__builtin___CFStringMakeConstantString")
             return IsOwnedResult::NotOwned;
+          if ((Name == "checked_cf_cast" || Name == "dynamic_cf_cast" ||
+               Name == "checked_objc_cast" || Name == "dynamic_objc_cast") &&
+              CE->getNumArgs() == 1) {
+            E = CE->getArg(0)->IgnoreParenCasts();
+            continue;
+          }
           auto RetType = Callee->getReturnType();
           if (isRetainPtrType(RetType))
             return IsOwnedResult::NotOwned;
+          if (isCreateOrCopyFunction(Callee)) {
+            CreateOrCopyFnCall.insert(CE);
+            return IsOwnedResult::Owned;
+          }
         } else if (auto *CalleeExpr = CE->getCallee()) {
           if (isa<CXXDependentScopeMemberExpr>(CalleeExpr))
             return IsOwnedResult::Skip; // Wait for instantiation.
@@ -371,6 +399,20 @@ class RetainPtrCtorAdoptChecker
     Report->setDeclWithIssue(DeclWithIssue);
     BR->emitReport(std::move(Report));
   }
+
+  void reportLeak(const CallExpr *CE, const Decl *DeclWithIssue) const {
+    SmallString<100> Buf;
+    llvm::raw_svector_ostream Os(Buf);
+
+    Os << "The return value is +1 and results in a memory leak.";
+
+    PathDiagnosticLocation BSLoc(CE->getSourceRange().getBegin(),
+                                 BR->getSourceManager());
+    auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
+    Report->addRange(CE->getSourceRange());
+    Report->setDeclWithIssue(DeclWithIssue);
+    BR->emitReport(std::move(Report));
+  }
 };
 } // namespace
 
diff --git a/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h 
b/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
index 5bd265596a0b4..ab5e820b2c636 100644
--- a/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
+++ b/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
@@ -21,6 +21,11 @@ typedef struct CF_BRIDGED_MUTABLE_TYPE(CFRunLoopRef) 
__CFRunLoop * CFRunLoopRef;
 
 extern const CFAllocatorRef kCFAllocatorDefault;
 typedef struct _NSZone NSZone;
+typedef unsigned long CFTypeID;
+
+CFTypeID CFGetTypeID(CFTypeRef cf);
+
+CFTypeID CFArrayGetTypeID(void);
 CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex 
capacity);
 extern void CFArrayAppendValue(CFMutableArrayRef theArray, const void *value);
 CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, 
CFIndex numValues);
@@ -29,6 +34,7 @@ CFIndex CFArrayGetCount(CFArrayRef theArray);
 typedef const struct CF_BRIDGED_TYPE(NSDictionary) __CFDictionary * 
CFDictionaryRef;
 typedef struct CF_BRIDGED_MUTABLE_TYPE(NSMutableDictionary) __CFDictionary * 
CFMutableDictionaryRef;
 
+CFTypeID CFDictionaryGetTypeID(void);
 CFDictionaryRef CFDictionaryCreate(CFAllocatorRef allocator, const void 
**keys, const void **values, CFIndex numValues);
 CFDictionaryRef CFDictionaryCreateCopy(CFAllocatorRef allocator, 
CFDictionaryRef theDict);
 CFDictionaryRef CFDictionaryCreateMutableCopy(CFAllocatorRef allocator, 
CFIndex capacity, CFDictionaryRef theDict);
@@ -135,6 +141,8 @@ __attribute__((objc_root_class))
 
 namespace WTF {
 
+void WTFCrash(void);
+
 template<typename T> class RetainPtr;
 template<typename T> RetainPtr<T> adoptNS(T*);
 template<typename T> RetainPtr<T> adoptCF(T);
@@ -265,19 +273,79 @@ template<typename T> inline RetainPtr<T> retainPtr(T* ptr)
 
 inline NSObject *bridge_cast(CFTypeRef object)
 {
-    return (__bridge NSObject *)object;
+  return (__bridge NSObject *)object;
 }
 
 inline CFTypeRef bridge_cast(NSObject *object)
 {
-    return (__bridge CFTypeRef)object;
+  return (__bridge CFTypeRef)object;
+}
+
+template <typename> struct CFTypeTrait;
+
+// Use dynamic_cf_cast<> instead of checked_cf_cast<> when actively checking 
CF types,
+// similar to dynamic_cast<> in C++. Be sure to include a nullptr check.
+
+template<typename T> T dynamic_cf_cast(CFTypeRef object)
+{
+  if (!object)
+    return nullptr;
+
+  if (CFGetTypeID(object) != CFTypeTrait<T>::typeID())
+    return nullptr;
+
+  return static_cast<T>(const_cast<CF_BRIDGED_TYPE(id) void*>(object));
+}
+
+template<typename T, typename U> RetainPtr<T> dynamic_cf_cast(RetainPtr<U>&& 
object)
+{
+  if (!object)
+    return nullptr;
+
+  if (CFGetTypeID(object.get()) != CFTypeTrait<T>::typeID())
+    return nullptr;
+
+  return adoptCF(static_cast<T>(const_cast<CF_BRIDGED_TYPE(id) 
void*>(object.leakRef())));
 }
 
+// Use checked_cf_cast<> instead of dynamic_cf_cast<> when a specific CF type 
is required.
+
+template<typename T> T checked_cf_cast(CFTypeRef object)
+{
+  if (!object)
+    return nullptr;
+
+  if (CFGetTypeID(object) != CFTypeTrait<T>::typeID())
+    WTFCrash();
+
+  return static_cast<T>(const_cast<CF_BRIDGED_TYPE(id) void*>(object));
 }
 
+} // namespace WTF
+
+#define WTF_DECLARE_CF_TYPE_TRAIT(ClassName) \
+template <> \
+struct WTF::CFTypeTrait<ClassName##Ref> { \
+    static inline CFTypeID typeID(void) { return ClassName##GetTypeID(); } \
+};
+
+WTF_DECLARE_CF_TYPE_TRAIT(CFArray);
+WTF_DECLARE_CF_TYPE_TRAIT(CFDictionary);
+
+#define WTF_DECLARE_CF_MUTABLE_TYPE_TRAIT(ClassName, MutableClassName) \
+template <> \
+struct WTF::CFTypeTrait<MutableClassName##Ref> { \
+    static inline CFTypeID typeID(void) { return ClassName##GetTypeID(); } \
+};
+
+WTF_DECLARE_CF_MUTABLE_TYPE_TRAIT(CFArray, CFMutableArray);
+WTF_DECLARE_CF_MUTABLE_TYPE_TRAIT(CFDictionary, CFMutableDictionary);
+
 using WTF::RetainPtr;
 using WTF::adoptNS;
 using WTF::adoptCF;
 using WTF::retainPtr;
 using WTF::downcast;
 using WTF::bridge_cast;
+using WTF::dynamic_cf_cast;
+using WTF::checked_cf_cast;
\ No newline at end of file
diff --git 
a/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm 
b/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm
index dd7208a534ea1..c2a93358b4cdd 100644
--- a/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm
+++ b/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use-arc.mm
@@ -3,6 +3,8 @@
 
 #include "objc-mock-types.h"
 
+CFTypeRef CFCopyArray(CFArrayRef);
+
 void basic_correct() {
   auto ns1 = adoptNS([SomeObj alloc]);
   auto ns2 = adoptNS([[SomeObj alloc] init]);
@@ -12,6 +14,7 @@ void basic_correct() {
   auto ns6 = retainPtr([ns3 next]);
   CFMutableArrayRef cf1 = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, 
10));
   auto cf2 = adoptCF(SecTaskCreateFromSelf(kCFAllocatorDefault));
+  auto cf3 = adoptCF(checked_cf_cast<CFArrayRef>(CFCopyArray(cf1)));
 }
 
 CFMutableArrayRef provide_cf();
@@ -27,6 +30,8 @@ void basic_wrong() {
   // expected-warning@-1{{Incorrect use of adoptCF. The argument is +0 and 
results in an use-after-free [alpha.webkit.RetainPtrCtorAdoptChecker]}}
   RetainPtr<CFTypeRef> cf3 = SecTaskCreateFromSelf(kCFAllocatorDefault);
   // expected-warning@-1{{Incorrect use of RetainPtr constructor. The argument 
is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
+  CFCopyArray(cf1);
+  // expected-warning@-1{{The return value is +1 and results in a memory leak 
[alpha.webkit.RetainPtrCtorAdoptChecker]}}
 }
 
 RetainPtr<CVPixelBufferRef> cf_out_argument() {
@@ -68,7 +73,7 @@ void adopt_retainptr() {
 
 class MemberInit {
 public:
-  MemberInit(CFMutableArrayRef array, NSString *str, CFRunLoopRef runLoop)
+  MemberInit(RetainPtr<CFMutableArrayRef>&& array, NSString *str, CFRunLoopRef 
runLoop)
     : m_array(array)
     , m_str(str)
     , m_runLoop(runLoop)
@@ -80,7 +85,7 @@ void adopt_retainptr() {
   RetainPtr<CFRunLoopRef> m_runLoop;
 };
 void create_member_init() {
-  MemberInit init { CFArrayCreateMutable(kCFAllocatorDefault, 10), @"hello", 
CFRunLoopGetCurrent() };
+  MemberInit init { adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, 10)), 
@"hello", CFRunLoopGetCurrent() };
 }
 
 RetainPtr<CFStringRef> cfstr() {
diff --git a/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm 
b/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm
index 79e0bdb7c577b..c6d2c1fddb9e8 100644
--- a/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm
+++ b/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm
@@ -3,6 +3,8 @@
 
 #include "objc-mock-types.h"
 
+CFTypeRef CFCopyArray(CFArrayRef);
+
 void basic_correct() {
   auto ns1 = adoptNS([SomeObj alloc]);
   auto ns2 = adoptNS([[SomeObj alloc] init]);
@@ -12,6 +14,7 @@ void basic_correct() {
   auto ns6 = retainPtr([ns3 next]);
   CFMutableArrayRef cf1 = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, 
10));
   auto cf2 = adoptCF(SecTaskCreateFromSelf(kCFAllocatorDefault));
+  auto cf3 = adoptCF(checked_cf_cast<CFArrayRef>(CFCopyArray(cf1)));
 }
 
 CFMutableArrayRef provide_cf();
@@ -27,6 +30,8 @@ void basic_wrong() {
   // expected-warning@-1{{Incorrect use of adoptCF. The argument is +0 and 
results in an use-after-free [alpha.webkit.RetainPtrCtorAdoptChecker]}}
   RetainPtr<CFTypeRef> cf3 = SecTaskCreateFromSelf(kCFAllocatorDefault);
   // expected-warning@-1{{Incorrect use of RetainPtr constructor. The argument 
is +1 and results in a memory leak [alpha.webkit.RetainPtrCtorAdoptChecker]}}
+  CFCopyArray(cf1);
+  // expected-warning@-1{{The return value is +1 and results in a memory leak 
[alpha.webkit.RetainPtrCtorAdoptChecker]}}
 }
 
 RetainPtr<CVPixelBufferRef> cf_out_argument() {
@@ -68,7 +73,7 @@ void adopt_retainptr() {
 
 class MemberInit {
 public:
-  MemberInit(CFMutableArrayRef array, NSString *str, CFRunLoopRef runLoop)
+  MemberInit(RetainPtr<CFMutableArrayRef>&& array, NSString *str, CFRunLoopRef 
runLoop)
     : m_array(array)
     , m_str(str)
     , m_runLoop(runLoop)
@@ -80,7 +85,7 @@ void adopt_retainptr() {
   RetainPtr<CFRunLoopRef> m_runLoop;
 };
 void create_member_init() {
-  MemberInit init { CFArrayCreateMutable(kCFAllocatorDefault, 10), @"hello", 
CFRunLoopGetCurrent() };
+  MemberInit init { adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, 10)), 
@"hello", CFRunLoopGetCurrent() };
 }
 
 RetainPtr<CFStringRef> cfstr() {

>From 9dde1db04ee04c005e9ee4476d861a07d3c34790 Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rn...@webkit.org>
Date: Thu, 20 Mar 2025 18:16:03 -0700
Subject: [PATCH 2/3] Fix formatting.

---
 .../Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp            | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
index 2d9620cc8ee5e..5f9d7b81f113b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
@@ -146,8 +146,7 @@ class RetainPtrCtorAdoptChecker
       reportUseAfterFree(Name, CE, DeclWithIssue);
   }
 
-  void checkCreateOrCopyFunction(const CallExpr *CE,
-                                 const FunctionDecl *Callee,
+  void checkCreateOrCopyFunction(const CallExpr *CE, const FunctionDecl 
*Callee,
                                  const Decl *DeclWithIssue) const {
     if (!isCreateOrCopyFunction(Callee))
       return;
@@ -203,7 +202,7 @@ class RetainPtrCtorAdoptChecker
 
     if (isCreateOrCopy(Arg))
       CreateOrCopyFnCall.insert(Arg); // Avoid double reporting.
-    
+
     if (Result == IsOwnedResult::Skip)
       return;
 

>From 763bb3a390168fa8e13339228a82f00f369590be Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rn...@webkit.org>
Date: Fri, 21 Mar 2025 20:23:25 -0700
Subject: [PATCH 3/3] Fix a regression that
 alpha.webkit.RetainPtrCtorAdoptChecker emits a warning for non-retained
 types.

This was caused by the checkCreateOrCopyFunction not checking RTC.isUnretained. 
Fixed this bug by
adding the check. This in turn revealed a bug that we weren't properly 
recognizing CFTypeRef as
the pointee type is "void" and therefore does not have a corresponding Record 
object. Added a new
dense set, RecordlessTypes, to discover these types. We only use as a fallback 
since looping over
ElaboratedType and checking its existence in the set is slower than just 
checking the presence of
the canonical type in the CFPointees set.

Finally, skip the analyses of smart pointer template classes in 
RawPtrRefCallArgsChecker and
RawPtrRefLocalVarsChecker now that we properly recognize CFTypeRef as a CF type 
and this type
is used internally inside the mock RetainPtr.
---
 .../Checkers/WebKit/PtrTypesSemantics.cpp     | 28 ++++++++++++++++++-
 .../Checkers/WebKit/PtrTypesSemantics.h       |  4 +++
 .../WebKit/RawPtrRefCallArgsChecker.cpp       |  2 +-
 .../WebKit/RawPtrRefLocalVarsChecker.cpp      |  6 ++++
 .../WebKit/RetainPtrCtorAdoptChecker.cpp      |  2 ++
 .../WebKit/retain-ptr-ctor-adopt-use.mm       |  2 ++
 6 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index b4d2353a03cd2..1e9959371d2a6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -125,6 +125,16 @@ bool isCheckedPtr(const std::string &Name) {
   return Name == "CheckedPtr" || Name == "CheckedRef";
 }
 
+bool isSmartPtrClass(const std::string &Name) {
+  return isRefType(Name) || isCheckedPtr(Name) || isRetainPtr(Name) ||
+         Name == "WeakPtr" || Name == "WeakPtr" || Name == "WeakPtrFactory" ||
+         Name == "WeakPtrFactoryWithBitField" || Name == "WeakPtrImplBase" ||
+         Name == "WeakPtrImplBaseSingleThread" || Name == "ThreadSafeWeakPtr" 
||
+         Name == "ThreadSafeWeakOrStrongPtr" ||
+         Name == "ThreadSafeWeakPtrControlBlock" ||
+         Name == "ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr";
+}
+
 bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
   assert(F);
   const std::string &FunctionName = safeGetName(F);
@@ -222,8 +232,13 @@ void RetainTypeChecker::visitTypedef(const TypedefDecl 
*TD) {
 
   auto PointeeQT = QT->getPointeeType();
   const RecordType *RT = PointeeQT->getAs<RecordType>();
-  if (!RT)
+  if (!RT) {
+    if (TD->hasAttr<ObjCBridgeAttr>() || TD->hasAttr<ObjCBridgeMutableAttr>()) 
{
+      if (auto *Type = TD->getTypeForDecl())
+        RecordlessTypes.insert(Type);
+    }
     return;
+  }
 
   for (auto *Redecl : RT->getDecl()->getMostRecentDecl()->redecls()) {
     if (Redecl->getAttr<ObjCBridgeAttr>() ||
@@ -240,6 +255,17 @@ bool RetainTypeChecker::isUnretained(const QualType QT, 
bool ignoreARC) {
   auto CanonicalType = QT.getCanonicalType();
   auto PointeeType = CanonicalType->getPointeeType();
   auto *RT = dyn_cast_or_null<RecordType>(PointeeType.getTypePtrOrNull());
+  if (!RT) {
+    auto *Type = QT.getTypePtrOrNull();
+    while (Type) {
+      if (RecordlessTypes.contains(Type))
+        return true;
+      auto *ET = dyn_cast_or_null<ElaboratedType>(Type);
+      if (!ET)
+        break;
+      Type = ET->desugar().getTypePtrOrNull();
+    }
+  }
   return RT && CFPointees.contains(RT);
 }
 
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 096675fb912f2..97c9d0510e67d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -70,6 +70,7 @@ std::optional<bool> isUnchecked(const clang::QualType T);
 /// underlying pointer type.
 class RetainTypeChecker {
   llvm::DenseSet<const RecordType *> CFPointees;
+  llvm::DenseSet<const Type *> RecordlessTypes;
   bool IsARCEnabled{false};
 
 public:
@@ -135,6 +136,9 @@ 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);
 
+/// \returns true if \p Name is a smart pointer type name, false if not.
+bool isSmartPtrClass(const std::string &Name);
+
 /// \returns true if \p M is getter of a ref-counted class, false if not.
 std::optional<bool> isGetterOfSafePtr(const clang::CXXMethodDecl *Method);
 
diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
index 39e9cd023d1f7..d21b2eedec8ac 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefCallArgsChecker.cpp
@@ -68,7 +68,7 @@ class RawPtrRefCallArgsChecker
       }
 
       bool TraverseClassTemplateDecl(ClassTemplateDecl *Decl) override {
-        if (isRefType(safeGetName(Decl)))
+        if (isSmartPtrClass(safeGetName(Decl)))
           return true;
         return DynamicRecursiveASTVisitor::TraverseClassTemplateDecl(Decl);
       }
diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
index d413e33a490c5..845a7013e6037 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
@@ -260,6 +260,12 @@ class RawPtrRefLocalVarsChecker
           return DynamicRecursiveASTVisitor::TraverseCompoundStmt(CS);
         return true;
       }
+
+      bool TraverseClassTemplateDecl(ClassTemplateDecl *Decl) override {
+        if (isSmartPtrClass(safeGetName(Decl)))
+          return true;
+        return DynamicRecursiveASTVisitor::TraverseClassTemplateDecl(Decl);
+      }
     };
 
     LocalVisitor visitor(this);
diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
index 5f9d7b81f113b..bc6a5798c1c63 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RetainPtrCtorAdoptChecker.cpp
@@ -172,6 +172,8 @@ class RetainPtrCtorAdoptChecker
       CreateOrCopyOutArguments.insert(Decl);
       hasOutArgument = true;
     }
+    if (!RTC.isUnretained(Callee->getReturnType()))
+      return;
     if (!hasOutArgument && !CreateOrCopyFnCall.contains(CE))
       reportLeak(CE, DeclWithIssue);
   }
diff --git a/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm 
b/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm
index c6d2c1fddb9e8..33cf98960f793 100644
--- a/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm
+++ b/clang/test/Analysis/Checkers/WebKit/retain-ptr-ctor-adopt-use.mm
@@ -4,6 +4,7 @@
 #include "objc-mock-types.h"
 
 CFTypeRef CFCopyArray(CFArrayRef);
+void* CreateCopy();
 
 void basic_correct() {
   auto ns1 = adoptNS([SomeObj alloc]);
@@ -15,6 +16,7 @@ void basic_correct() {
   CFMutableArrayRef cf1 = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, 
10));
   auto cf2 = adoptCF(SecTaskCreateFromSelf(kCFAllocatorDefault));
   auto cf3 = adoptCF(checked_cf_cast<CFArrayRef>(CFCopyArray(cf1)));
+  CreateCopy();
 }
 
 CFMutableArrayRef provide_cf();

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

Reply via email to