Author: Ryosuke Niwa
Date: 2025-12-09T12:28:22-08:00
New Revision: f9326ffb7ede55229a81907cc03aaa8c523520ab

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

LOG: [WebKit checkers] Treat a weak property / variable as safe (#163689)

Treat a weak Objective-C property, ivar, member variable, and local
variable as safe.

Added: 
    clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures-weak-arc.mm
    clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures-weak.mm
    clang/test/Analysis/Checkers/WebKit/unretained-local-vars-weak-arc.mm
    clang/test/Analysis/Checkers/WebKit/unretained-local-vars-weak.mm
    clang/test/Analysis/Checkers/WebKit/unretained-members-weak-arc.mm
    clang/test/Analysis/Checkers/WebKit/unretained-members-weak.mm

Modified: 
    clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
    clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
    clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp

Removed: 
    


################################################################################
diff  --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
index f60d1936b7584..f3fadeaefc491 100644
--- 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
+++ 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLambdaCapturesChecker.cpp
@@ -587,6 +587,8 @@ class UnretainedLambdaCapturesChecker : public 
RawPtrRefLambdaCapturesChecker {
   }
 
   std::optional<bool> isUnsafePtr(QualType QT) const final {
+    if (QT.hasStrongOrWeakObjCLifetime())
+      return false;
     return RTC->isUnretained(QT);
   }
 

diff  --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
index c13df47920f72..f2235e7c25ab2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefLocalVarsChecker.cpp
@@ -433,6 +433,8 @@ class UnretainedLocalVarsChecker final : public 
RawPtrRefLocalVarsChecker {
     RTC = RetainTypeChecker();
   }
   std::optional<bool> isUnsafePtr(const QualType T) const final {
+    if (T.hasStrongOrWeakObjCLifetime())
+      return false;
     return RTC->isUnretained(T);
   }
   bool isSafePtr(const CXXRecordDecl *Record) const final {

diff  --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
index ace639ce7ab18..0e23ae34ea212 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
@@ -231,8 +231,11 @@ class RawPtrRefMemberChecker
     // "assign" property doesn't retain even under ARC so treat it as unsafe.
     bool ignoreARC =
         !PD->isReadOnly() && PD->getSetterKind() == ObjCPropertyDecl::Assign;
+    bool IsWeak =
+        PD->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak;
+    bool HasSafeAttr = PD->isRetaining() || IsWeak;
     auto IsUnsafePtr = isUnsafePtr(QT, ignoreARC);
-    return {IsUnsafePtr && *IsUnsafePtr && !PD->isRetaining(), PropType};
+    return {IsUnsafePtr && *IsUnsafePtr && !HasSafeAttr, PropType};
   }
 
   bool shouldSkipDecl(const RecordDecl *RD) const {
@@ -363,6 +366,8 @@ class NoUnretainedMemberChecker final : public 
RawPtrRefMemberChecker {
   }
 
   std::optional<bool> isUnsafePtr(QualType QT, bool ignoreARC) const final {
+    if (QT.hasStrongOrWeakObjCLifetime())
+      return false;
     return RTC->isUnretained(QT, ignoreARC);
   }
 

diff  --git 
a/clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures-weak-arc.mm 
b/clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures-weak-arc.mm
new file mode 100644
index 0000000000000..a52bc7c9a5572
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures-weak-arc.mm
@@ -0,0 +1,22 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.UnretainedLambdaCapturesChecker 
-fobjc-runtime-has-weak -fobjc-weak -fobjc-arc -verify %s
+// expected-no-diagnostics
+
+#include "objc-mock-types.h"
+
+void someFunction();
+template <typename Callback> void call(Callback callback) {
+  someFunction();
+  callback();
+}
+
+NSString *provideStr();
+SomeObj *provideSomeObj();
+
+void foo() {
+  __weak NSString *weakStr = provideStr();
+  __weak SomeObj *weakObj = provideSomeObj();
+  auto lambda = [weakStr, weakObj]() {
+    return [weakStr length] + [weakObj value];
+  };
+  call(lambda);
+}

diff  --git 
a/clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures-weak.mm 
b/clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures-weak.mm
new file mode 100644
index 0000000000000..7439d7f8bb93b
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-lambda-captures-weak.mm
@@ -0,0 +1,22 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.UnretainedLambdaCapturesChecker 
-fobjc-runtime-has-weak -fobjc-weak -verify %s
+// expected-no-diagnostics
+
+#include "objc-mock-types.h"
+
+void someFunction();
+template <typename Callback> void call(Callback callback) {
+  someFunction();
+  callback();
+}
+
+NSString *provideStr();
+SomeObj *provideSomeObj();
+
+void foo() {
+  __weak NSString *weakStr = provideStr();
+  __weak SomeObj *weakObj = provideSomeObj();
+  auto lambda = [weakStr, weakObj]() {
+    return [weakStr length] + [weakObj value];
+  };
+  call(lambda);
+}

diff  --git 
a/clang/test/Analysis/Checkers/WebKit/unretained-local-vars-weak-arc.mm 
b/clang/test/Analysis/Checkers/WebKit/unretained-local-vars-weak-arc.mm
new file mode 100644
index 0000000000000..8c709b5921227
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-local-vars-weak-arc.mm
@@ -0,0 +1,13 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.UnretainedLocalVarsChecker 
-fobjc-runtime-has-weak -fobjc-weak -fobjc-arc -verify %s
+// expected-no-diagnostics
+
+#include "objc-mock-types.h"
+
+NSString *provideStr();
+SomeObj *provideSomeObj();
+
+int foo() {
+  __weak NSString *weakStr = provideStr();
+  __weak SomeObj *weakObj = provideSomeObj();
+  return [weakStr length] + [weakObj value];
+}

diff  --git a/clang/test/Analysis/Checkers/WebKit/unretained-local-vars-weak.mm 
b/clang/test/Analysis/Checkers/WebKit/unretained-local-vars-weak.mm
new file mode 100644
index 0000000000000..3ac4ff9d1e4cb
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-local-vars-weak.mm
@@ -0,0 +1,13 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.UnretainedLocalVarsChecker 
-fobjc-runtime-has-weak -fobjc-weak -verify %s
+// expected-no-diagnostics
+
+#include "objc-mock-types.h"
+
+NSString *provideStr();
+SomeObj *provideSomeObj();
+
+int foo() {
+  __weak NSString *weakStr = provideStr();
+  __weak SomeObj *weakObj = provideSomeObj();
+  return [weakStr length] + [weakObj value];
+}

diff  --git 
a/clang/test/Analysis/Checkers/WebKit/unretained-members-weak-arc.mm 
b/clang/test/Analysis/Checkers/WebKit/unretained-members-weak-arc.mm
new file mode 100644
index 0000000000000..c0aaac09e68d8
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-members-weak-arc.mm
@@ -0,0 +1,29 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.NoUnretainedMemberChecker 
-fobjc-runtime-has-weak -fobjc-weak -fobjc-arc -verify %s
+// expected-no-diagnostics
+
+#include "objc-mock-types.h"
+
+struct Foo {
+  __weak NSString *weakPtr = nullptr;
+  Foo();
+  ~Foo();
+  void bar();
+};
+
+@interface ObjectWithWeakProperty : NSObject
+@property(nonatomic, weak) NSString *weak_prop;
+@end
+
+@implementation ObjectWithWeakProperty
+@end
+
+NS_REQUIRES_PROPERTY_DEFINITIONS
+@interface NoSynthesisObjectWithWeakProperty : NSObject
+@property(nonatomic, readonly, weak) NSString *weak_prop;
+@end
+
+@implementation NoSynthesisObjectWithWeakProperty
+- (NSString *)weak_prop {
+  return nil;
+}
+@end

diff  --git a/clang/test/Analysis/Checkers/WebKit/unretained-members-weak.mm 
b/clang/test/Analysis/Checkers/WebKit/unretained-members-weak.mm
new file mode 100644
index 0000000000000..422cf6189446d
--- /dev/null
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-members-weak.mm
@@ -0,0 +1,31 @@
+// RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.NoUnretainedMemberChecker 
-fobjc-runtime-has-weak -fobjc-weak -verify %s
+// expected-no-diagnostics
+
+#include "objc-mock-types.h"
+
+struct Foo {
+  __weak NSString *weakPtr = nullptr;
+  Foo();
+  ~Foo();
+  void bar();
+};
+
+@interface ObjectWithWeakProperty : NSObject
+@property(nonatomic, weak) NSString *weak_prop;
+@end
+
+@implementation ObjectWithWeakProperty
+@end
+
+NS_REQUIRES_PROPERTY_DEFINITIONS
+@interface NoSynthesisObjectWithWeakProperty : NSObject
+@property(nonatomic, readonly, weak) NSString *weak_prop;
+@end
+
+@implementation NoSynthesisObjectWithWeakProperty {
+  __weak NSNumber *weak_ivar;
+}
+- (NSString *)weak_prop {
+  return nil;
+}
+@end


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to