[clang] [alpha.webkit.NoUnretainedMemberChecker] Only check @property when @implementation is seen (PR #159947)
Ryosuke Niwa via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 24 19:03:18 PDT 2025
https://github.com/rniwa updated https://github.com/llvm/llvm-project/pull/159947
>From e369e9c9c390191bb8ac0fb5cc80ebe4e22e290a Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Sat, 20 Sep 2025 14:07:19 -0700
Subject: [PATCH 1/3] [alpha.webkit.NoUnretainedMemberChecker] Only check
@property when @implementation is seen
A @interface declaration with a raw pointer @property does not necessarily mean it synthesizes
ivar of that type. To determine whether such a synthesis happens or not, we must wait for
@implementation to appear. So this PR makes the checker only validate @property then.
---
.../WebKit/RawPtrRefMemberChecker.cpp | 19 +++++++++----------
.../Checkers/WebKit/unretained-members-arc.mm | 15 +++++++++++++++
.../Checkers/WebKit/unretained-members.mm | 15 +++++++++++++++
3 files changed, 39 insertions(+), 10 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
index 8faf6a219450a..baafc1bc61c15 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
@@ -129,17 +129,16 @@ class RawPtrRefMemberChecker
if (BR->getSourceManager().isInSystemHeader(CD->getLocation()))
return;
- ObjCContainerDecl::PropertyMap map;
- CD->collectPropertiesToImplement(map);
- for (auto it : map)
- visitObjCPropertyDecl(CD, it.second);
-
- if (auto *ID = dyn_cast<ObjCInterfaceDecl>(CD)) {
- for (auto *Ivar : ID->ivars())
- visitIvarDecl(CD, Ivar);
- return;
- }
if (auto *ID = dyn_cast<ObjCImplementationDecl>(CD)) {
+ ObjCContainerDecl::PropertyMap map;
+ CD->collectPropertiesToImplement(map);
+ for (auto it : map)
+ visitObjCPropertyDecl(CD, it.second);
+
+ if (auto *Interface = ID->getClassInterface()) {
+ for (auto *Ivar : Interface->ivars())
+ visitIvarDecl(CD, Ivar);
+ }
for (auto *PropImpl : ID->property_impls())
visitPropImpl(CD, PropImpl);
for (auto *Ivar : ID->ivars())
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm b/clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm
index 00e6e6ec1dcfa..daa0c222251d9 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm
@@ -76,6 +76,21 @@ @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) NSString *prop_safe;
+ at end
+
+ at implementation AnotherObject
+- (NSString *)prop_safe {
+ return nil;
+}
+ at end
+
+// No warnings for @interface declaration itself.
+ at interface InterfaceOnlyObject : NSObject
+ at property(nonatomic, strong) NSString *prop_string1;
+ at property(nonatomic, assign) NSString *prop_string2;
+ at property(nonatomic, unsafe_unretained) NSString *prop_string3;
+ at property(nonatomic, readonly) NSString *prop_string4;
@end
NS_REQUIRES_PROPERTY_DEFINITIONS
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-members.mm b/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
index 46f65dfa603ad..800d882f79696 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
@@ -98,6 +98,21 @@ @interface AnotherObject : NSObject {
}
@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}}
+ at property(nonatomic, readonly) NSString *prop_safe;
+ at end
+
+ at implementation AnotherObject
+- (NSString *)prop_safe {
+ return nil;
+}
+ at end
+
+// No warnings for @interface declaration itself.
+ at interface InterfaceOnlyObject : NSObject
+ at property(nonatomic, strong) NSString *prop_string1;
+ at property(nonatomic, assign) NSString *prop_string2;
+ at property(nonatomic, unsafe_unretained) NSString *prop_string3;
+ at property(nonatomic, readonly) NSString *prop_string4;
@end
NS_REQUIRES_PROPERTY_DEFINITIONS
>From 6d70f15b25b2b61d3bb0cf41a0b8a8ba2914315c Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Tue, 23 Sep 2025 23:29:43 -0700
Subject: [PATCH 2/3] Add test cases for inherited interfaces
---
.../Checkers/WebKit/unretained-members.mm | 22 +++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-members.mm b/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
index 56fae675c3e96..7b66aa9332a85 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
@@ -112,7 +112,7 @@ @interface AnotherObject : NSObject {
dispatch_queue_t dispatch;
// expected-warning at -1{{Instance variable 'dispatch' in 'AnotherObject' is a retainable type 'dispatch_queue_t'}}
}
- at property(nonatomic, strong) NSString *prop_string;
+ at property(nonatomic, readonly, 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}}
@property(nonatomic, readonly) NSString *prop_safe;
@end
@@ -123,13 +123,31 @@ - (NSString *)prop_safe {
}
@end
+ at interface DerivedObject : AnotherObject {
+ NSNumber *ns_number;
+ // expected-warning at -1{{Instance variable 'ns_number' in 'DerivedObject' is a raw pointer to retainable type 'NSNumber'}}
+ CGImageRef cg_image;
+ // expected-warning at -1{{Instance variable 'cg_image' in 'DerivedObject' is a retainable type 'CGImageRef'}}
+ dispatch_queue_t os_dispatch;
+ // expected-warning at -1{{Instance variable 'os_dispatch' in 'DerivedObject' is a retainable type 'dispatch_queue_t'}}
+}
+ at property(nonatomic, strong) NSNumber *prop_number;
+// expected-warning at -1{{Property 'prop_number' in 'DerivedObject' is a raw pointer to retainable type 'NSNumber'; member variables must be a RetainPtr}}
+ at property(nonatomic, readonly) NSString *prop_string;
+ at end
+
+ at implementation DerivedObject
+- (NSString *)prop_string {
+ return nil;
+}
+ at end
+
// No warnings for @interface declaration itself.
@interface InterfaceOnlyObject : NSObject
@property(nonatomic, strong) NSString *prop_string1;
@property(nonatomic, assign) NSString *prop_string2;
@property(nonatomic, unsafe_unretained) NSString *prop_string3;
@property(nonatomic, readonly) NSString *prop_string4;
-
@end
NS_REQUIRES_PROPERTY_DEFINITIONS
>From c4bd06b68299cf142a4750ed0667179754ab0a7f Mon Sep 17 00:00:00 2001
From: Ryosuke Niwa <rniwa at webkit.org>
Date: Wed, 24 Sep 2025 19:03:03 -0700
Subject: [PATCH 3/3] Add a test case for a subclass interface with
implementation
---
.../Checkers/WebKit/unretained-members.mm | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-members.mm b/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
index 7b66aa9332a85..adf1d8aef9d7d 100644
--- a/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
+++ b/clang/test/Analysis/Checkers/WebKit/unretained-members.mm
@@ -150,6 +150,23 @@ @interface InterfaceOnlyObject : NSObject
@property(nonatomic, readonly) NSString *prop_string4;
@end
+ at interface InterfaceOnlyObject2 : NSObject
+ at property(nonatomic, strong) NSString *prop_string1;
+ at property(nonatomic, assign) NSString *prop_string2;
+ at property(nonatomic, unsafe_unretained) NSString *prop_string3;
+// expected-warning at -1{{Property 'prop_string3' in 'DerivedObject2' is a raw pointer to retainable type 'NSString'}}
+ at property(nonatomic, readonly) NSString *prop_string4;
+ at end
+
+ at interface DerivedObject2 : InterfaceOnlyObject2
+ at property(nonatomic, readonly) NSString *prop_string5;
+// expected-warning at -1{{Property 'prop_string5' in 'DerivedObject2' is a raw pointer to retainable type 'NSString'}}
+ at end
+
+ at implementation DerivedObject2
+ at synthesize prop_string3;
+ at end
+
NS_REQUIRES_PROPERTY_DEFINITIONS
@interface NoSynthObject : NSObject {
NSString *ns_string;
More information about the cfe-commits
mailing list