Skip to content

Commit bcee060

Browse files
committed
[alpha.webkit.NoUnretainedMemberChecker] Recognize NS_REQUIRES_PROPERTY_DEFINITIONS
Allow @Property of a raw pointer when NS_REQUIRES_PROPERTY_DEFINITIONS is specified on the interface since such an interface does not automatically synthesize raw pointer ivars. Also emit a warning for @Property(assign) and @Property(unsafe_unretained) under ARC.
1 parent 436504c commit bcee060

File tree

6 files changed

+68
-6
lines changed

6 files changed

+68
-6
lines changed

clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ std::optional<bool> isUnchecked(const QualType T) {
236236
void RetainTypeChecker::visitTranslationUnitDecl(
237237
const TranslationUnitDecl *TUD) {
238238
IsARCEnabled = TUD->getLangOpts().ObjCAutoRefCount;
239+
DefaultSynthProperties = TUD->getLangOpts().ObjCDefaultSynthProperties;
239240
}
240241

241242
void RetainTypeChecker::visitTypedef(const TypedefDecl *TD) {

clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,14 @@ class RetainTypeChecker {
7676
llvm::DenseSet<const RecordType *> CFPointees;
7777
llvm::DenseSet<const Type *> RecordlessTypes;
7878
bool IsARCEnabled{false};
79+
bool DefaultSynthProperties{true};
7980

8081
public:
8182
void visitTranslationUnitDecl(const TranslationUnitDecl *);
8283
void visitTypedef(const TypedefDecl *);
8384
bool isUnretained(const QualType, bool ignoreARC = false);
8485
bool isARCEnabled() const { return IsARCEnabled; }
86+
bool defaultSynthProperties() const { return DefaultSynthProperties; }
8587
};
8688

8789
/// \returns true if \p Class is NS or CF objects AND not retained, false if

clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ class RawPtrRefMemberChecker
3838
RawPtrRefMemberChecker(const char *description)
3939
: Bug(this, description, "WebKit coding guidelines") {}
4040

41-
virtual std::optional<bool> isUnsafePtr(QualType) const = 0;
41+
virtual std::optional<bool> isUnsafePtr(QualType,
42+
bool ignoreARC = false) const = 0;
4243
virtual const char *typeName() const = 0;
4344
virtual const char *invariant() const = 0;
4445

@@ -174,7 +175,15 @@ class RawPtrRefMemberChecker
174175
if (!PropType)
175176
return;
176177

177-
auto IsUnsafePtr = isUnsafePtr(QT);
178+
if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CD)) {
179+
if (!RTC || !RTC->defaultSynthProperties() ||
180+
ID->isObjCRequiresPropertyDefs())
181+
return;
182+
}
183+
184+
bool ignoreARC =
185+
!PD->isReadOnly() && PD->getSetterKind() == ObjCPropertyDecl::Assign;
186+
auto IsUnsafePtr = isUnsafePtr(QT, ignoreARC);
178187
if (!IsUnsafePtr || !*IsUnsafePtr)
179188
return;
180189

@@ -274,7 +283,7 @@ class NoUncountedMemberChecker final : public RawPtrRefMemberChecker {
274283
: RawPtrRefMemberChecker("Member variable is a raw-pointer/reference to "
275284
"reference-countable type") {}
276285

277-
std::optional<bool> isUnsafePtr(QualType QT) const final {
286+
std::optional<bool> isUnsafePtr(QualType QT, bool) const final {
278287
return isUncountedPtr(QT.getCanonicalType());
279288
}
280289

@@ -291,7 +300,7 @@ class NoUncheckedPtrMemberChecker final : public RawPtrRefMemberChecker {
291300
: RawPtrRefMemberChecker("Member variable is a raw-pointer/reference to "
292301
"checked-pointer capable type") {}
293302

294-
std::optional<bool> isUnsafePtr(QualType QT) const final {
303+
std::optional<bool> isUnsafePtr(QualType QT, bool) const final {
295304
return isUncheckedPtr(QT.getCanonicalType());
296305
}
297306

@@ -311,8 +320,8 @@ class NoUnretainedMemberChecker final : public RawPtrRefMemberChecker {
311320
RTC = RetainTypeChecker();
312321
}
313322

314-
std::optional<bool> isUnsafePtr(QualType QT) const final {
315-
return RTC->isUnretained(QT);
323+
std::optional<bool> isUnsafePtr(QualType QT, bool ignoreARC) const final {
324+
return RTC->isUnretained(QT, ignoreARC);
316325
}
317326

318327
const char *typeName() const final { return "retainable type"; }

clang/test/Analysis/Checkers/WebKit/objc-mock-types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ typedef struct CF_BRIDGED_TYPE(id) CGImage *CGImageRef;
2222
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
2323
#define CF_CONSUMED __attribute__((cf_consumed))
2424
#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
25+
#define NS_REQUIRES_PROPERTY_DEFINITIONS __attribute__((objc_requires_property_definitions))
2526

2627
extern const CFAllocatorRef kCFAllocatorDefault;
2728
typedef struct _NSZone NSZone;

clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,33 @@ void forceTmplToInstantiate(FooTmpl<SomeObj, CFMutableArrayRef>) {}
6464
};
6565

6666
} // namespace ptr_to_ptr_to_retained
67+
68+
@interface AnotherObject : NSObject {
69+
NSString *ns_string;
70+
CFStringRef cf_string;
71+
// expected-warning@-1{{Instance variable 'cf_string' in 'AnotherObject' is a retainable type 'CFStringRef'; member variables must be a RetainPtr}}
72+
}
73+
@property(nonatomic, strong) NSString *prop_string1;
74+
@property(nonatomic, assign) NSString *prop_string2;
75+
// expected-warning@-1{{Property 'prop_string2' in 'AnotherObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
76+
@property(nonatomic, unsafe_unretained) NSString *prop_string3;
77+
// expected-warning@-1{{Property 'prop_string3' in 'AnotherObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
78+
@property(nonatomic, readonly) NSString *prop_string4;
79+
@end
80+
81+
NS_REQUIRES_PROPERTY_DEFINITIONS
82+
@interface NoSynthObject : NSObject {
83+
NSString *ns_string;
84+
CFStringRef cf_string;
85+
// expected-warning@-1{{Instance variable 'cf_string' in 'NoSynthObject' is a retainable type 'CFStringRef'; member variables must be a RetainPtr}}
86+
}
87+
@property(nonatomic, readonly, strong) NSString *prop_string1;
88+
@property(nonatomic, readonly, strong) NSString *prop_string2;
89+
@end
90+
91+
@implementation NoSynthObject
92+
- (NSString *)prop_string1 {
93+
return nil;
94+
}
95+
@synthesize prop_string2;
96+
@end

clang/test/Analysis/Checkers/WebKit/unretained-members.mm

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,22 @@ @interface AnotherObject : NSObject {
9999
@property(nonatomic, strong) NSString *prop_string;
100100
// expected-warning@-1{{Property 'prop_string' in 'AnotherObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
101101
@end
102+
103+
NS_REQUIRES_PROPERTY_DEFINITIONS
104+
@interface NoSynthObject : NSObject {
105+
NSString *ns_string;
106+
// expected-warning@-1{{Instance variable 'ns_string' in 'NoSynthObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
107+
CFStringRef cf_string;
108+
// expected-warning@-1{{Instance variable 'cf_string' in 'NoSynthObject' is a retainable type 'CFStringRef'; member variables must be a RetainPtr}}
109+
}
110+
@property(nonatomic, readonly, strong) NSString *prop_string1;
111+
@property(nonatomic, readonly, strong) NSString *prop_string2;
112+
@end
113+
114+
@implementation NoSynthObject
115+
- (NSString *)prop_string1 {
116+
return nil;
117+
}
118+
@synthesize prop_string2;
119+
// expected-warning@-1{{Instance variable 'prop_string2' in 'NoSynthObject' is a raw pointer to retainable type 'NSString'}}
120+
@end

0 commit comments

Comments
 (0)