|  | // RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.Dealloc,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class %s | 
|  | // RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.RetainCount,osx.cocoa.Dealloc,debug.ExprInspection -analyzer-store=region -verify -Wno-objc-root-class -fobjc-arc %s | 
|  |  | 
|  | void clang_analyzer_eval(int); | 
|  |  | 
|  | 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 | 
|  |  | 
|  | // rdar://6946338 | 
|  |  | 
|  | @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 | 
|  |  | 
|  |  | 
|  | // rdar://8824416 | 
|  |  | 
|  | @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 | 
|  |  | 
|  |  | 
|  | // rdar://6611873 | 
|  |  | 
|  | @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() { | 
|  | 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) | 
|  | // <rdar://problem/9241180> 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. | 
|  | // The Sema bug is tracked as <rdar://problem/25481164>. | 
|  | @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}} | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // <rdar://problem/16333368> | 
|  | @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}} | 
|  | } | 
|  |  | 
|  | // rdar://problem/19862648 | 
|  | - (void)establishIvarIsNilDuringLoops { | 
|  | extern id getRandomObject(); | 
|  |  | 
|  | 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]; | 
|  | } | 
|  | } | 
|  |  | 
|  | // rdar://problem/20335433 | 
|  | - (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() { | 
|  | union { | 
|  | Wrapper *wrapper; | 
|  | } u = { 0 }; | 
|  | [u.wrapper value]; | 
|  | } | 
|  |  | 
|  | #endif // non-ARC | 
|  |  |