Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ std::optional<bool> isUnchecked(const QualType T) {
void RetainTypeChecker::visitTranslationUnitDecl(
const TranslationUnitDecl *TUD) {
IsARCEnabled = TUD->getLangOpts().ObjCAutoRefCount;
DefaultSynthProperties = TUD->getLangOpts().ObjCDefaultSynthProperties;
}

void RetainTypeChecker::visitTypedef(const TypedefDecl *TD) {
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,14 @@ class RetainTypeChecker {
llvm::DenseSet<const RecordType *> CFPointees;
llvm::DenseSet<const Type *> RecordlessTypes;
bool IsARCEnabled{false};
bool DefaultSynthProperties{true};

public:
void visitTranslationUnitDecl(const TranslationUnitDecl *);
void visitTypedef(const TypedefDecl *);
bool isUnretained(const QualType, bool ignoreARC = false);
bool isARCEnabled() const { return IsARCEnabled; }
bool defaultSynthProperties() const { return DefaultSynthProperties; }
};

/// \returns true if \p Class is NS or CF objects AND not retained, false if
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ class RawPtrRefMemberChecker
RawPtrRefMemberChecker(const char *description)
: Bug(this, description, "WebKit coding guidelines") {}

virtual std::optional<bool> isUnsafePtr(QualType) const = 0;
virtual std::optional<bool> isUnsafePtr(QualType,
bool ignoreARC = false) const = 0;
virtual const char *typeName() const = 0;
virtual const char *invariant() const = 0;

Expand Down Expand Up @@ -174,7 +175,15 @@ class RawPtrRefMemberChecker
if (!PropType)
return;

auto IsUnsafePtr = isUnsafePtr(QT);
if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CD)) {
if (!RTC || !RTC->defaultSynthProperties() ||
ID->isObjCRequiresPropertyDefs())
return;
}

bool ignoreARC =
!PD->isReadOnly() && PD->getSetterKind() == ObjCPropertyDecl::Assign;
auto IsUnsafePtr = isUnsafePtr(QT, ignoreARC);
if (!IsUnsafePtr || !*IsUnsafePtr)
return;

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

std::optional<bool> isUnsafePtr(QualType QT) const final {
std::optional<bool> isUnsafePtr(QualType QT, bool) const final {
return isUncountedPtr(QT.getCanonicalType());
}

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

std::optional<bool> isUnsafePtr(QualType QT) const final {
std::optional<bool> isUnsafePtr(QualType QT, bool) const final {
return isUncheckedPtr(QT.getCanonicalType());
}

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

std::optional<bool> isUnsafePtr(QualType QT) const final {
return RTC->isUnretained(QT);
std::optional<bool> isUnsafePtr(QualType QT, bool ignoreARC) const final {
return RTC->isUnretained(QT, ignoreARC);
}

const char *typeName() const final { return "retainable type"; }
Expand Down
1 change: 1 addition & 0 deletions clang/test/Analysis/Checkers/WebKit/objc-mock-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ typedef struct CF_BRIDGED_TYPE(id) CGImage *CGImageRef;
#define NS_RETURNS_RETAINED __attribute__((ns_returns_retained))
#define CF_CONSUMED __attribute__((cf_consumed))
#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
#define NS_REQUIRES_PROPERTY_DEFINITIONS __attribute__((objc_requires_property_definitions))

extern const CFAllocatorRef kCFAllocatorDefault;
typedef struct _NSZone NSZone;
Expand Down
30 changes: 30 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,33 @@ void forceTmplToInstantiate(FooTmpl<SomeObj, CFMutableArrayRef>) {}
};

} // namespace ptr_to_ptr_to_retained

@interface AnotherObject : NSObject {
NSString *ns_string;
CFStringRef cf_string;
// expected-warning@-1{{Instance variable 'cf_string' in 'AnotherObject' is a retainable type 'CFStringRef'; member variables must be a RetainPtr}}
}
@property(nonatomic, strong) NSString *prop_string1;
@property(nonatomic, assign) NSString *prop_string2;
// expected-warning@-1{{Property 'prop_string2' in 'AnotherObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
@property(nonatomic, unsafe_unretained) NSString *prop_string3;
// expected-warning@-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;
@end

NS_REQUIRES_PROPERTY_DEFINITIONS
@interface NoSynthObject : NSObject {
NSString *ns_string;
CFStringRef cf_string;
// expected-warning@-1{{Instance variable 'cf_string' in 'NoSynthObject' is a retainable type 'CFStringRef'; member variables must be a RetainPtr}}
}
@property(nonatomic, readonly, strong) NSString *prop_string1;
@property(nonatomic, readonly, strong) NSString *prop_string2;
@end

@implementation NoSynthObject
- (NSString *)prop_string1 {
return nil;
}
@synthesize prop_string2;
@end
19 changes: 19 additions & 0 deletions clang/test/Analysis/Checkers/WebKit/unretained-members.mm
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,22 @@ @interface AnotherObject : NSObject {
@property(nonatomic, strong) NSString *prop_string;
// expected-warning@-1{{Property 'prop_string' in 'AnotherObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
@end

NS_REQUIRES_PROPERTY_DEFINITIONS
@interface NoSynthObject : NSObject {
NSString *ns_string;
// expected-warning@-1{{Instance variable 'ns_string' in 'NoSynthObject' is a raw pointer to retainable type 'NSString'; member variables must be a RetainPtr}}
CFStringRef cf_string;
// expected-warning@-1{{Instance variable 'cf_string' in 'NoSynthObject' is a retainable type 'CFStringRef'; member variables must be a RetainPtr}}
}
@property(nonatomic, readonly, strong) NSString *prop_string1;
@property(nonatomic, readonly, strong) NSString *prop_string2;
@end

@implementation NoSynthObject
- (NSString *)prop_string1 {
return nil;
}
@synthesize prop_string2;
// expected-warning@-1{{Instance variable 'prop_string2' in 'NoSynthObject' is a raw pointer to retainable type 'NSString'}}
@end