Files
RedBear-OS/local/recipes/dev/libclc/source/clang/test/Analysis/properties.m
T
vasilito cb424d7448 build: static patch-sanity linter (shift-left the malformed-patch class)
verify-patch-sanity.py validates every active recipe .patch has internally-
consistent hunk line counts — catching the 'malformed patch at line N' failure
at commit/CI/preflight time instead of hours into a cook. This cycle hit that
class three times (qtwaylandscanner, sddm, xwayland), each only discovered when
cookbook tried to apply the patch.

Running it across the repo found 29 latent malformed patches (validated against
GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22').
They were harmless only because they sit in vendored recipes (baked, not re-
applied) — but would fail on any version-bump re-derivation. --fix recounts the
hunk headers (body untouched) and repaired all 29.

Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test
(test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats
(empty placeholders, bare-@@ git hunks).
2026-08-01 05:13:02 +03:00

1088 lines
29 KiB
Objective-C

// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.Dealloc,debug.ExprInspection -verify -Wno-objc-root-class -analyzer-config eagerly-assume=false %s
// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.Dealloc,debug.ExprInspection -verify -Wno-objc-root-class -fobjc-arc -analyzer-config eagerly-assume=false %s
void clang_analyzer_eval(int);
#define nil ((id)0)
typedef const void * CFTypeRef;
extern CFTypeRef CFRetain(CFTypeRef cf);
void CFRelease(CFTypeRef cf);
typedef signed char BOOL;
typedef unsigned int NSUInteger;
typedef struct _NSZone NSZone;
@class NSInvocation, NSMethodSignature, NSCoder, NSString, NSEnumerator;
@protocol NSObject - (BOOL)isEqual:(id)object; @end
@protocol NSCopying - (id)copyWithZone:(NSZone *)zone; @end
@protocol NSCoding - (void)encodeWithCoder:(NSCoder *)aCoder; @end
@protocol NSMutableCopying - (id)mutableCopyWithZone:(NSZone *)zone; @end
@interface NSObject <NSObject> {}
+(id)alloc;
-(id)init;
-(id)autorelease;
-(id)copy;
-(id)retain;
-(oneway void)release;
-(void)dealloc;
@end
@interface NSString : NSObject <NSCopying, NSMutableCopying, NSCoding>
- (NSUInteger)length;
-(id)initWithFormat:(NSString *)f,...;
-(BOOL)isEqualToString:(NSString *)s;
+ (id)string;
@end
@interface NSNumber : NSObject {}
+(id)alloc;
-(id)initWithInteger:(int)i;
@end
@interface Test1 : NSObject {
NSString *text;
}
-(id)myMethod;
@property (nonatomic, assign) NSString *text;
@end
#if !__has_feature(objc_arc)
@implementation Test1
@synthesize text;
-(id)myMethod {
Test1 *cell = [[[Test1 alloc] init] autorelease];
NSString *string1 = [[NSString alloc] initWithFormat:@"test %f", 0.0]; // expected-warning {{Potential leak}}
cell.text = string1;
return cell;
}
@end
@interface MyNumber : NSObject
{
NSNumber* _myNumber;
}
- (id)initWithNumber:(NSNumber *)number;
@property (nonatomic, readonly) NSNumber* myNumber;
@property (nonatomic, readonly) NSNumber* newMyNumber;
@end
@implementation MyNumber
@synthesize myNumber=_myNumber;
- (id)initWithNumber:(NSNumber *)number
{
self = [super init];
if ( self )
{
_myNumber = [number copy];
}
return self;
}
- (NSNumber*)newMyNumber
{
if ( _myNumber )
return [_myNumber retain];
return [[NSNumber alloc] initWithInteger:1];
}
- (id)valueForUndefinedKey:(NSString*)key
{
id value = 0;
if ([key isEqualToString:@"MyIvarNumberAsPropertyOverReleased"])
value = self.myNumber; // _myNumber will be over released, since the value returned from self.myNumber is not retained.
else if ([key isEqualToString:@"MyIvarNumberAsPropertyOk"])
value = [self.myNumber retain]; // this line fixes the over release
else if ([key isEqualToString:@"MyIvarNumberAsNewMyNumber"])
value = self.newMyNumber; // this one is ok, since value is returned retained
else
value = [[NSNumber alloc] initWithInteger:0];
return [value autorelease]; // expected-warning {{Object autoreleased too many times}}
}
@end
NSNumber* numberFromMyNumberProperty(MyNumber* aMyNumber)
{
NSNumber* result = aMyNumber.myNumber;
return [result autorelease]; // expected-warning {{Object autoreleased too many times}}
}
#endif
@interface Person : NSObject {
NSString *_name;
}
@property (retain) NSString * name;
@property (assign) id friend;
@end
@implementation Person
@synthesize name = _name;
-(void)dealloc {
#if !__has_feature(objc_arc)
self.name = [[NSString alloc] init]; // expected-warning {{leak}}
[super dealloc]; // expected-warning {{The '_name' ivar in 'Person' was retained by a synthesized property but not released before '[super dealloc]}}
#endif
}
@end
#if !__has_feature(objc_arc)
void rdar6611873(void) {
Person *p = [[[Person alloc] init] autorelease];
p.name = [[NSString string] retain]; // expected-warning {{leak}}
p.name = [[NSString alloc] init]; // expected-warning {{leak}}
p.friend = [[Person alloc] init]; // expected-warning {{leak}}
}
#endif
@interface SubPerson : Person
-(NSString *)foo;
@end
@implementation SubPerson
-(NSString *)foo {
return super.name;
}
@end
#if !__has_feature(objc_arc)
// Static analyzer doesn't detect uninitialized variable issues for property accesses
@interface RDar9241180
@property (readwrite,assign) id x;
-(id)testAnalyzer1:(int) y;
-(void)testAnalyzer2;
@end
@implementation RDar9241180
@synthesize x;
-(id)testAnalyzer1:(int)y {
RDar9241180 *o;
if (y && o.x) // expected-warning {{Property access on an uninitialized object pointer}}
return o;
return o; // expected-warning {{Undefined or garbage value returned to caller}}
}
-(void)testAnalyzer2 {
id y;
self.x = y; // expected-warning {{Argument for property setter is an uninitialized value}}
}
@end
#endif
//------
// Property accessor synthesis
//------
extern void doSomethingWithPerson(Person *p);
extern void doSomethingWithName(NSString *name);
void testConsistencyRetain(Person *p) {
clang_analyzer_eval(p.name == p.name); // expected-warning{{TRUE}}
id origName = p.name;
clang_analyzer_eval(p.name == origName); // expected-warning{{TRUE}}
doSomethingWithPerson(p);
clang_analyzer_eval(p.name == origName); // expected-warning{{UNKNOWN}}
}
void testConsistencyAssign(Person *p) {
clang_analyzer_eval(p.friend == p.friend); // expected-warning{{TRUE}}
id origFriend = p.friend;
clang_analyzer_eval(p.friend == origFriend); // expected-warning{{TRUE}}
doSomethingWithPerson(p);
clang_analyzer_eval(p.friend == origFriend); // expected-warning{{UNKNOWN}}
}
@interface ClassWithShadowedReadWriteProperty {
int _f;
}
@property (readonly) int someProp;
@end
@interface ClassWithShadowedReadWriteProperty ()
@property (readwrite) int someProp;
@end
@implementation ClassWithShadowedReadWriteProperty
- (void)testSynthesisForShadowedReadWriteProperties; {
clang_analyzer_eval(self.someProp == self.someProp); // expected-warning{{TRUE}}
_f = 1;
// Read of shadowed property should not invalidate receiver.
(void)self.someProp;
clang_analyzer_eval(_f == 1); // expected-warning{{TRUE}}
_f = 2;
// Call to getter of shadowed property should not invalidate receiver.
(void)[self someProp];
clang_analyzer_eval(_f == 2); // expected-warning{{TRUE}}
}
@end
// Tests for the analyzer fix that works around a Sema bug
// where multiple methods are created for properties in class extensions that
// are redeclared in a category method.
@interface ClassWithRedeclaredPropertyInExtensionFollowedByCategory
@end
@interface ClassWithRedeclaredPropertyInExtensionFollowedByCategory ()
@end
@interface ClassWithRedeclaredPropertyInExtensionFollowedByCategory ()
@property (readwrite) int someProp;
@property (readonly) int otherProp;
@end
@interface ClassWithRedeclaredPropertyInExtensionFollowedByCategory (MyCat)
@property (readonly) int someProp;
@property (readonly) int otherProp;
@end
@implementation ClassWithRedeclaredPropertyInExtensionFollowedByCategory
- (void)testSynthesisForRedeclaredProperties; {
clang_analyzer_eval(self.someProp == self.someProp); // expected-warning{{TRUE}}
clang_analyzer_eval([self someProp] == self.someProp); // expected-warning{{TRUE}}
clang_analyzer_eval(self.otherProp == self.otherProp); // expected-warning{{TRUE}}
clang_analyzer_eval([self otherProp] == self.otherProp); // expected-warning{{TRUE}}
}
@end
// The relative order of the extension and the category matter, so test both.
@interface ClassWithRedeclaredPropertyInCategoryFollowedByExtension
@end
@interface ClassWithRedeclaredPropertyInCategoryFollowedByExtension ()
@property (readwrite) int someProp;
@end
@interface ClassWithRedeclaredPropertyInCategoryFollowedByExtension (MyCat)
@property (readonly) int someProp;
@end
@implementation ClassWithRedeclaredPropertyInCategoryFollowedByExtension
- (void)testSynthesisForRedeclaredProperties; {
clang_analyzer_eval(self.someProp == self.someProp); // expected-warning{{TRUE}}
clang_analyzer_eval([self someProp] == self.someProp); // expected-warning{{TRUE}}
}
@end
@interface ClassWithSynthesizedPropertyAndGetter
@property (readonly) int someProp;
@end
@implementation ClassWithSynthesizedPropertyAndGetter
@synthesize someProp;
// Make sure that the actual getter is inlined and not a getter created
// by BodyFarm
- (void)testBodyFarmGetterNotUsed {
int i = self.someProp;
clang_analyzer_eval(i == 22); // expected-warning {{TRUE}}
}
-(int)someProp {
return 22;
}
@end
__attribute__((objc_root_class))
@interface ClassWithPrivatePropertyInClassExtensionWithProtocolShadowingCategory
@end
@protocol HasStuff
@property (nonatomic, readonly) int stuffProperty;
@end
@interface ClassWithPrivatePropertyInClassExtensionWithProtocolShadowingCategory (Private)
@property (nonatomic, readonly) int stuffProperty;
@end
@interface ClassWithPrivatePropertyInClassExtensionWithProtocolShadowingCategory (Internal) <HasStuff>
@end
@interface ClassWithPrivatePropertyInClassExtensionWithProtocolShadowingCategory() <HasStuff>
@end
@implementation ClassWithPrivatePropertyInClassExtensionWithProtocolShadowingCategory
@synthesize stuffProperty = _stuffProperty;
-(void)foo {
(void)self.stuffProperty;
}
@end
//------
// Setter ivar invalidation.
//------
@interface ClassWithSetters
// Note: These properties have implicit @synthesize implementations to be
// backed with ivars.
@property (assign) int propWithIvar1;
@property (assign) int propWithIvar2;
@property (retain) NSNumber *retainedProperty;
@end
@interface ClassWithSetters (InOtherTranslationUnit)
// The implementation of this property is in another translation unit.
// We don't know whether it is backed by an ivar or not.
@property (assign) int propInOther;
@end
@implementation ClassWithSetters
- (void) testSettingPropWithIvarInvalidatesExactlyThatIvar; {
_propWithIvar1 = 1;
_propWithIvar2 = 2;
self.propWithIvar1 = 66;
// Calling the setter of a property backed by the instance variable
// should invalidate the storage for the instance variable but not
// the rest of the receiver. Ideally we would model the setter completely
// but doing so would cause the new value to escape when it is bound
// to the ivar. This would cause bad false negatives in the retain count
// checker. (There is a test for this scenario in
// testWriteRetainedValueToRetainedProperty below).
clang_analyzer_eval(_propWithIvar1 == 66); // expected-warning{{UNKNOWN}}
clang_analyzer_eval(_propWithIvar2 == 2); // expected-warning{{TRUE}}
_propWithIvar1 = 1;
[self setPropWithIvar1:66];
clang_analyzer_eval(_propWithIvar1 == 66); // expected-warning{{UNKNOWN}}
clang_analyzer_eval(_propWithIvar2 == 2); // expected-warning{{TRUE}}
}
- (void) testSettingPropWithoutIvarInvalidatesEntireInstance; {
_propWithIvar1 = 1;
_propWithIvar2 = 2;
self.propInOther = 66;
clang_analyzer_eval(_propWithIvar1 == 66); // expected-warning{{UNKNOWN}}
clang_analyzer_eval(_propWithIvar2 == 2); // expected-warning{{UNKNOWN}}
_propWithIvar1 = 1;
_propWithIvar2 = 2;
[self setPropInOther:66];
clang_analyzer_eval(_propWithIvar1 == 66); // expected-warning{{UNKNOWN}}
clang_analyzer_eval(_propWithIvar2 == 2); // expected-warning{{UNKNOWN}}
}
#if !__has_feature(objc_arc)
- (void) testWriteRetainedValueToRetainedProperty; {
NSNumber *number = [[NSNumber alloc] initWithInteger:5]; // expected-warning {{Potential leak of an object stored into 'number'}}
// Make sure we catch this leak.
self.retainedProperty = number;
}
#endif
@end
//------
// class properties
//------
int gBackingForReadWriteClassProp = 0;
@interface ClassWithClassProperties
@property(class, readonly) int readOnlyClassProp;
@property(class) int readWriteClassProp;
// Make sure we handle when a class and instance property have the same
// name. Test both when instance comes first and when class comes first.
@property(readonly) int classAndInstancePropWithSameNameOrderInstanceFirst;
@property(class, readonly) int classAndInstancePropWithSameNameOrderInstanceFirst;
@property(class, readonly) int classAndInstancePropWithSameNameOrderClassFirst;
@property(readonly) int classAndInstancePropWithSameNameOrderClassFirst;
@property(class, readonly) int dynamicClassProp;
@end
@interface ClassWithClassProperties (OtherTranslationUnit)
@property(class, assign) id propInOtherTranslationUnit;
@end
@implementation ClassWithClassProperties
@dynamic dynamicClassProp;
+ (int)readOnlyClassProp {
return 1;
}
+ (int)readWriteClassProp {
return gBackingForReadWriteClassProp;
}
+ (void)setReadWriteClassProp:(int)val {
gBackingForReadWriteClassProp = val;
}
- (int)classAndInstancePropWithSameNameOrderInstanceFirst {
return 12;
}
+ (int)classAndInstancePropWithSameNameOrderInstanceFirst {
return 13;
}
+ (int)classAndInstancePropWithSameNameOrderClassFirst {
return 14;
}
- (int)classAndInstancePropWithSameNameOrderClassFirst {
return 15;
}
- (void)testInlineClassProp {
clang_analyzer_eval(ClassWithClassProperties.readOnlyClassProp == 1); // expected-warning{{TRUE}}
ClassWithClassProperties.readWriteClassProp = 7;
clang_analyzer_eval(ClassWithClassProperties.readWriteClassProp == 7); // expected-warning{{TRUE}}
ClassWithClassProperties.readWriteClassProp = 8;
clang_analyzer_eval(ClassWithClassProperties.readWriteClassProp == 8); // expected-warning{{TRUE}}
}
- (void)testUnknownClassProp {
clang_analyzer_eval(ClassWithClassProperties.propInOtherTranslationUnit == ClassWithClassProperties.propInOtherTranslationUnit); // expected-warning{{UNKNOWN}}
}
- (void)testEscapeGlobalOnUnknownProp {
gBackingForReadWriteClassProp = 33;
ClassWithClassProperties.propInOtherTranslationUnit = 0;
clang_analyzer_eval(gBackingForReadWriteClassProp == 33); // expected-warning{{UNKNOWN}}
}
- (void)testClassAndInstancePropertyWithSameName {
clang_analyzer_eval(self.classAndInstancePropWithSameNameOrderInstanceFirst == 12); // expected-warning{{TRUE}}
clang_analyzer_eval(ClassWithClassProperties.classAndInstancePropWithSameNameOrderInstanceFirst == 13); // expected-warning{{TRUE}}
clang_analyzer_eval(ClassWithClassProperties.classAndInstancePropWithSameNameOrderClassFirst == 14); // expected-warning{{TRUE}}
clang_analyzer_eval(self.classAndInstancePropWithSameNameOrderClassFirst == 15); // expected-warning{{TRUE}}
}
- (void)testDynamicClassProp {
clang_analyzer_eval(ClassWithClassProperties.dynamicClassProp == 16); // expected-warning{{UNKNOWN}}
}
@end
@interface SubclassOfClassWithClassProperties : ClassWithClassProperties
@end
@implementation SubclassOfClassWithClassProperties
+ (int)dynamicClassProp; {
return 16;
}
- (void)testDynamicClassProp {
clang_analyzer_eval(SubclassOfClassWithClassProperties.dynamicClassProp == 16); // expected-warning{{TRUE}}
}
@end
#if !__has_feature(objc_arc)
void testOverrelease(Person *p, int coin) {
switch (coin) {
case 0:
[p.name release]; // expected-warning{{not owned}}
break;
case 1:
[p.friend release]; // expected-warning{{not owned}}
break;
case 2: {
id friend = p.friend;
doSomethingWithPerson(p);
[friend release]; // expected-warning{{not owned}}
}
}
}
@implementation Person (Rdar16333368)
- (void)testDeliberateRelease:(Person *)other {
doSomethingWithName(self.name);
[_name release]; // no-warning
self->_name = 0;
doSomethingWithName(other->_name);
[other.name release]; // no-warning
}
- (void)deliberateReleaseFalseNegative {
// This is arguably a false negative because the result of p.friend shouldn't
// be released, even though we are manipulating the ivar in between the two
// actions.
id name = self.name;
_name = 0;
[name release];
}
- (void)testRetainAndRelease {
[self.name retain];
[self.name release];
[self.name release]; // expected-warning{{not owned}}
}
- (void)testRetainAndReleaseIVar {
[self.name retain];
[_name release];
[_name release];
}
@end
#endif
@interface IntWrapper
@property int value;
@end
@implementation IntWrapper
@synthesize value;
@end
void testConsistencyInt(IntWrapper *w) {
clang_analyzer_eval(w.value == w.value); // expected-warning{{TRUE}}
int origValue = w.value;
if (origValue != 42)
return;
clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
}
void testConsistencyInt2(IntWrapper *w) {
if (w.value != 42)
return;
clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
}
@interface IntWrapperAuto
@property int value;
@end
@implementation IntWrapperAuto
@end
void testConsistencyIntAuto(IntWrapperAuto *w) {
clang_analyzer_eval(w.value == w.value); // expected-warning{{TRUE}}
int origValue = w.value;
if (origValue != 42)
return;
clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
}
void testConsistencyIntAuto2(IntWrapperAuto *w) {
if (w.value != 42)
return;
clang_analyzer_eval(w.value == 42); // expected-warning{{TRUE}}
}
typedef struct {
int value;
} IntWrapperStruct;
@interface StructWrapper
@property IntWrapperStruct inner;
@end
@implementation StructWrapper
@synthesize inner;
@end
void testConsistencyStruct(StructWrapper *w) {
clang_analyzer_eval(w.inner.value == w.inner.value); // expected-warning{{TRUE}}
int origValue = w.inner.value;
if (origValue != 42)
return;
clang_analyzer_eval(w.inner.value == 42); // expected-warning{{TRUE}}
}
@interface OpaqueIntWrapper
@property int value;
@end
// For now, don't assume a property is implemented using an ivar unless we can
// actually see that it is.
void testOpaqueConsistency(OpaqueIntWrapper *w) {
clang_analyzer_eval(w.value == w.value); // expected-warning{{UNKNOWN}}
}
#if !__has_feature(objc_arc)
// Test quite a few cases of retain/release issues.
@interface RetainCountTesting
@property (strong) id ownedProp;
@property (unsafe_unretained) id unownedProp;
@property (nonatomic, strong) id manualProp;
@property (readonly) id readonlyProp;
@property (nonatomic, readwrite/*, assign */) id implicitManualProp; // expected-warning {{'assign' is assumed}} expected-warning {{'assign' not appropriate}}
@property (nonatomic, readwrite/*, assign */) id implicitSynthProp; // expected-warning {{'assign' is assumed}} expected-warning {{'assign' not appropriate}}
@property CFTypeRef cfProp;
@end
@implementation RetainCountTesting {
id _ivarOnly;
}
- (id)manualProp {
return _manualProp;
}
- (void)setImplicitManualProp:(id)newValue {}
- (void)testOverreleaseOwnedIvar {
[_ownedProp retain];
[_ownedProp release];
[_ownedProp release];
[_ownedProp release]; // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseUnownedIvar {
[_unownedProp retain];
[_unownedProp release];
[_unownedProp release]; // FIXME-warning{{not owned at this point by the caller}}
}
- (void)testOverreleaseIvarOnly {
[_ivarOnly retain];
[_ivarOnly release];
[_ivarOnly release];
[_ivarOnly release]; // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseReadonlyIvar {
[_readonlyProp retain];
[_readonlyProp release];
[_readonlyProp release];
[_readonlyProp release]; // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseImplicitManualIvar {
[_implicitManualProp retain];
[_implicitManualProp release];
[_implicitManualProp release];
[_implicitManualProp release]; // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseImplicitSynthIvar {
[_implicitSynthProp retain];
[_implicitSynthProp release];
[_implicitSynthProp release]; // FIXME-warning{{not owned at this point by the caller}}
}
- (void)testOverreleaseCF {
CFRetain(_cfProp);
CFRelease(_cfProp);
CFRelease(_cfProp);
CFRelease(_cfProp); // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseOwnedIvarUse {
[_ownedProp retain];
[_ownedProp release];
[_ownedProp release];
[_ownedProp myMethod]; // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseIvarOnlyUse {
[_ivarOnly retain];
[_ivarOnly release];
[_ivarOnly release];
[_ivarOnly myMethod]; // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseCFUse {
CFRetain(_cfProp);
CFRelease(_cfProp);
CFRelease(_cfProp);
extern void CFUse(CFTypeRef);
CFUse(_cfProp); // FIXME-warning{{used after it is released}}
}
- (void)testOverreleaseOwnedIvarAutoreleaseOkay {
[_ownedProp retain];
[_ownedProp release];
[_ownedProp autorelease];
} // no-warning
- (void)testOverreleaseIvarOnlyAutoreleaseOkay {
[_ivarOnly retain];
[_ivarOnly release];
[_ivarOnly autorelease];
} // no-warning
- (void)testOverreleaseOwnedIvarAutorelease {
[_ownedProp retain];
[_ownedProp release];
[_ownedProp autorelease];
[_ownedProp autorelease];
} // FIXME-warning{{Object autoreleased too many times}}
- (void)testOverreleaseIvarOnlyAutorelease {
[_ivarOnly retain];
[_ivarOnly release];
[_ivarOnly autorelease];
[_ivarOnly autorelease];
} // FIXME-warning{{Object autoreleased too many times}}
- (void)testPropertyAccessThenReleaseOwned {
id owned = [self.ownedProp retain];
[owned release];
[_ownedProp release];
clang_analyzer_eval(owned == _ownedProp); // expected-warning{{TRUE}}
}
- (void)testPropertyAccessThenReleaseOwned2 {
id fromIvar = _ownedProp;
id owned = [self.ownedProp retain];
[owned release];
[fromIvar release];
clang_analyzer_eval(owned == fromIvar); // expected-warning{{TRUE}}
}
- (void)testPropertyAccessThenReleaseUnowned {
id unowned = [self.unownedProp retain];
[unowned release];
[_unownedProp release]; // FIXME-warning{{not owned}}
}
- (void)testPropertyAccessThenReleaseUnowned2 {
id fromIvar = _unownedProp;
id unowned = [self.unownedProp retain];
[unowned release];
clang_analyzer_eval(unowned == fromIvar); // expected-warning{{TRUE}}
[fromIvar release]; // FIXME-warning{{not owned}}
}
- (void)testPropertyAccessThenReleaseManual {
id prop = [self.manualProp retain];
[prop release];
[_manualProp release]; // no-warning
}
- (void)testPropertyAccessThenReleaseManual2 {
id fromIvar = _manualProp;
id prop = [self.manualProp retain];
[prop release];
clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}}
[fromIvar release]; // no-warning
}
- (void)testPropertyAccessThenReleaseCF {
CFTypeRef owned = CFRetain(self.cfProp);
CFRelease(owned);
CFRelease(_cfProp); // no-warning
clang_analyzer_eval(owned == _cfProp); // expected-warning{{TRUE}}
}
- (void)testPropertyAccessThenReleaseCF2 {
CFTypeRef fromIvar = _cfProp;
CFTypeRef owned = CFRetain(self.cfProp);
CFRelease(owned);
CFRelease(fromIvar);
clang_analyzer_eval(owned == fromIvar); // expected-warning{{TRUE}}
}
- (void)testPropertyAccessThenReleaseReadonly {
id prop = [self.readonlyProp retain];
[prop release];
[_readonlyProp release]; // no-warning
}
- (void)testPropertyAccessThenReleaseReadonly2 {
id fromIvar = _readonlyProp;
id prop = [self.readonlyProp retain];
[prop release];
clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}}
[fromIvar release]; // no-warning
}
- (void)testPropertyAccessThenReleaseImplicitManual {
id prop = [self.implicitManualProp retain];
[prop release];
[_implicitManualProp release]; // no-warning
}
- (void)testPropertyAccessThenReleaseImplicitManual2 {
id fromIvar = _implicitManualProp;
id prop = [self.implicitManualProp retain];
[prop release];
clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}}
[fromIvar release]; // no-warning
}
- (void)testPropertyAccessThenReleaseImplicitSynth {
id prop = [self.implicitSynthProp retain];
[prop release];
[_implicitSynthProp release]; // FIXME-warning{{not owned}}
}
- (void)testPropertyAccessThenReleaseImplicitSynth2 {
id fromIvar = _implicitSynthProp;
id prop = [self.implicitSynthProp retain];
[prop release];
clang_analyzer_eval(prop == fromIvar); // expected-warning{{TRUE}}
[fromIvar release]; // FIXME-warning{{not owned}}
}
- (id)getUnownedFromProperty {
[_ownedProp retain];
[_ownedProp autorelease];
return _ownedProp; // no-warning
}
- (id)transferUnownedFromProperty {
[_ownedProp retain];
[_ownedProp autorelease];
return [_ownedProp autorelease]; // no-warning
}
- (id)transferOwnedFromProperty __attribute__((ns_returns_retained)) {
[_ownedProp retain];
[_ownedProp autorelease];
return _ownedProp; // no-warning
}
- (void)testAssignOwned:(id)newValue {
_ownedProp = newValue;
[_ownedProp release]; // FIXME: no-warning{{not owned}}
}
- (void)testAssignUnowned:(id)newValue {
_unownedProp = newValue;
[_unownedProp release]; // FIXME: no-warning{{not owned}}
}
- (void)testAssignIvarOnly:(id)newValue {
_ivarOnly = newValue;
[_ivarOnly release]; // FIXME: no-warning{{not owned}}
}
- (void)testAssignCF:(CFTypeRef)newValue {
_cfProp = newValue;
CFRelease(_cfProp); // FIXME: no-warning{{not owned}}
}
- (void)testAssignReadonly:(id)newValue {
_readonlyProp = newValue;
[_readonlyProp release]; // FIXME: no-warning{{not owned}}
}
- (void)testAssignImplicitManual:(id)newValue {
_implicitManualProp = newValue;
[_implicitManualProp release]; // FIXME: no-warning{{not owned}}
}
- (void)testAssignImplicitSynth:(id)newValue {
_implicitSynthProp = newValue;
[_implicitSynthProp release]; // FIXME: no-warning{{not owned}}
}
- (void)testAssignOwnedOkay:(id)newValue {
_ownedProp = [newValue retain];
[_ownedProp release]; // no-warning
}
- (void)testAssignUnownedOkay:(id)newValue {
_unownedProp = [newValue retain];
[_unownedProp release]; // no-warning
}
- (void)testAssignIvarOnlyOkay:(id)newValue {
_ivarOnly = [newValue retain];
[_ivarOnly release]; // no-warning
}
- (void)testAssignCFOkay:(CFTypeRef)newValue {
_cfProp = CFRetain(newValue);
CFRelease(_cfProp); // no-warning
}
- (void)testAssignReadonlyOkay:(id)newValue {
_readonlyProp = [newValue retain];
[_readonlyProp release]; // FIXME: no-warning{{not owned}}
}
- (void)testAssignImplicitManualOkay:(id)newValue {
_implicitManualProp = [newValue retain];
[_implicitManualProp release]; // FIXME: no-warning{{not owned}}
}
- (void)testAssignImplicitSynthOkay:(id)newValue {
_implicitSynthProp = [newValue retain];
[_implicitSynthProp release]; // FIXME: no-warning{{not owned}}
}
- (void)establishIvarIsNilDuringLoops {
extern id getRandomObject(void);
int i = 4; // Must be at least 4 to trigger the bug.
while (--i) {
id x = 0;
if (getRandomObject())
x = _ivarOnly;
if (!x)
x = getRandomObject();
[x myMethod];
}
}
- (void)retainIvarAndInvalidateSelf {
extern void invalidate(id);
[_unownedProp retain];
invalidate(self);
[_unownedProp release]; // no-warning
}
@end
@interface Wrapper
@property(nonatomic, readonly) int value;
@end
@implementation Wrapper
@synthesize value;
@end
void testNoCrashWhenAccessPropertyAndThereAreNoDirectBindingsAtAll(void) {
union {
Wrapper *wrapper;
} u = { 0 };
[u.wrapper value];
}
#endif // non-ARC
@interface ExplicitAccessorInCategory : NSObject
@property(readonly) int normal;
- (int)normal;
@property(readonly) int no_custom_accessor;
@end
@interface ExplicitAccessorInCategory ()
@property(readonly) int in_category;
@property(readonly) int still_no_custom_accessor;
// This is an ordinary method, not a getter.
- (int)still_no_custom_accessor;
@end
@interface ExplicitAccessorInCategory ()
- (int)in_category;
// This is an ordinary method, not a getter.
- (int)no_custom_accessor;
@end
@implementation ExplicitAccessorInCategory
- (void)foo {
// Make sure we don't farm bodies for explicit accessors: in particular,
// we're not sure that the accessor always returns the same value.
clang_analyzer_eval(self.normal == self.normal); // expected-warning{{UNKNOWN}}
// Also this used to crash.
clang_analyzer_eval(self.in_category == self.in_category); // expected-warning{{UNKNOWN}}
// When there is no explicit accessor defined (even if it looks like there is),
// farm the getter body and see if it does actually always yield the same value.
clang_analyzer_eval(self.no_custom_accessor == self.no_custom_accessor); // expected-warning{{TRUE}}
clang_analyzer_eval(self.still_no_custom_accessor == self.still_no_custom_accessor); // expected-warning{{TRUE}}
}
@end
@interface Shadowed
@property (assign) NSObject *o;
- (NSObject *)getShadowedIvar;
- (void)clearShadowedIvar;
- (NSObject *)getShadowedProp;
- (void)clearShadowedProp;
@property (assign) NSObject *o2;
@end
@implementation Shadowed
- (NSObject *)getShadowedIvar {
return self->_o;
}
- (void)clearShadowedIvar {
self->_o = nil;
}
- (NSObject *)getShadowedProp {
return self.o;
}
- (void)clearShadowedProp {
self.o = nil;
}
@end
@interface Shadowing : Shadowed
@end
@implementation Shadowing
// Property 'o' is declared in the superclass but synthesized here.
// This creates a separate ivar that shadows the superclass's ivar,
// but the old ivar is still accessible from the methods of the superclass.
// The old property, however, is not accessible with the property syntax
// even from the superclass methods.
@synthesize o;
-(void)testPropertyShadowing {
NSObject *oo = self.o; // no-crash
clang_analyzer_eval(self.o == oo); // expected-warning{{TRUE}}
clang_analyzer_eval([self getShadowedIvar] == oo); // expected-warning{{UNKNOWN}}
[self clearShadowedIvar];
clang_analyzer_eval(self.o == oo); // expected-warning{{TRUE}}
clang_analyzer_eval([self getShadowedIvar] == oo); // expected-warning{{UNKNOWN}}
clang_analyzer_eval([self getShadowedIvar] == nil); // expected-warning{{TRUE}}
}
@synthesize o2 = ooo2;
-(void)testPropertyShadowingWithExplicitIvar {
NSObject *oo2 = self.o2; // no-crash
}
@end