objc_invalidation.m revision 6503255e4fa0689f427b3b798180fceac29c98c2
1// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -fobjc-default-synthesize-properties -verify %s 2extern void __assert_fail (__const char *__assertion, __const char *__file, 3 unsigned int __line, __const char *__function) 4 __attribute__ ((__noreturn__)); 5 6#define assert(expr) \ 7 ((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__)) 8 9@protocol NSObject 10@end 11@interface NSObject <NSObject> {} 12+(id)alloc; 13+(id)new; 14-(id)init; 15-(id)autorelease; 16-(id)copy; 17- (Class)class; 18-(id)retain; 19-(id)description; 20@end 21@class NSString; 22 23extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); 24 25@protocol Invalidation1 <NSObject> 26- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); 27@end 28 29@protocol Invalidation2 <NSObject> 30- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); 31@end 32 33@protocol Invalidation3 <NSObject> 34- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); 35- (void) invalidate2 __attribute__((annotate("objc_instance_variable_invalidator"))); 36@end 37 38@interface Invalidation2Class <Invalidation2> 39@end 40 41@interface Invalidation1Class <Invalidation1> 42@end 43 44@interface SomeInvalidationImplementingObject: NSObject <Invalidation3, Invalidation2> { 45 SomeInvalidationImplementingObject *ObjA; // invalidation in the parent 46} 47@end 48 49@implementation SomeInvalidationImplementingObject 50- (void)invalidate{ 51 ObjA = 0; 52} 53- (void)invalidate2 { 54 [self invalidate]; 55} 56@end 57 58@interface SomeSubclassInvalidatableObject : SomeInvalidationImplementingObject { 59 SomeInvalidationImplementingObject *Ivar1; // regular ivar 60 SomeInvalidationImplementingObject *Ivar2; // regular ivar, sending invalidate message 61 SomeInvalidationImplementingObject *_Ivar3; // no property, call -description 62 SomeInvalidationImplementingObject *_Ivar4; // no property, provide as argument to NSLog() 63 64 SomeInvalidationImplementingObject *_Prop1; // partially implemented property, set to 0 with dot syntax 65 SomeInvalidationImplementingObject *_Prop2; // fully implemented prop, set to 0 with dot syntax 66 SomeInvalidationImplementingObject *_propIvar; // property with custom named ivar, set to 0 via setter 67 Invalidation1Class *MultipleProtocols; // regular ivar belonging to a different class 68 Invalidation2Class *MultInheritance; // regular ivar belonging to a different class 69 SomeInvalidationImplementingObject *_Prop3; // property, invalidate via sending a message to a getter method 70 SomeInvalidationImplementingObject *_Prop4; // property with @synthesize, invalidate via property 71 SomeInvalidationImplementingObject *_Prop5; // property with @synthesize, invalidate via getter method 72 SomeInvalidationImplementingObject *_Prop8; 73 74 // No warnings on these as they are not invalidatable. 75 NSObject *NIvar1; 76 NSObject *NObj2; 77 NSObject *_NProp1; 78 NSObject *_NpropIvar; 79} 80 81@property (assign) SomeInvalidationImplementingObject* Prop0; 82@property (nonatomic, assign) SomeInvalidationImplementingObject* Prop1; 83@property (assign) SomeInvalidationImplementingObject* Prop2; 84@property (assign) SomeInvalidationImplementingObject* Prop3; 85@property (assign) SomeInvalidationImplementingObject *Prop5; 86@property (assign) SomeInvalidationImplementingObject *Prop4; 87 88@property (assign) SomeInvalidationImplementingObject* Prop6; // automatically synthesized prop 89@property (assign) SomeInvalidationImplementingObject* Prop7; // automatically synthesized prop 90@property (assign) SomeInvalidationImplementingObject *SynthIvarProp; 91 92@property (assign) NSObject* NProp0; 93@property (nonatomic, assign) NSObject* NProp1; 94@property (assign) NSObject* NProp2; 95 96-(void)setProp1: (SomeInvalidationImplementingObject*) InO; 97-(void)setNProp1: (NSObject*) InO; 98 99-(void)invalidate; 100 101@end 102 103@interface SomeSubclassInvalidatableObject() 104@property (assign) SomeInvalidationImplementingObject* Prop8; 105@end 106 107@implementation SomeSubclassInvalidatableObject{ 108 @private 109 SomeInvalidationImplementingObject *Ivar5; 110} 111 112@synthesize Prop7 = _propIvar; 113@synthesize Prop3 = _Prop3; 114@synthesize Prop5 = _Prop5; 115@synthesize Prop4 = _Prop4; 116@synthesize Prop8 = _Prop8; 117 118 119- (void) setProp1: (SomeInvalidationImplementingObject*) InObj { 120 _Prop1 = InObj; 121} 122 123- (void) setProp2: (SomeInvalidationImplementingObject*) InObj { 124 _Prop2 = InObj; 125} 126- (SomeInvalidationImplementingObject*) Prop2 { 127 return _Prop2; 128} 129 130@synthesize NProp2 = _NpropIvar; 131 132- (void) setNProp1: (NSObject*) InObj { 133 _NProp1 = InObj; 134} 135 136- (void) invalidate { 137 [Ivar2 invalidate]; 138 self.Prop0 = 0; 139 self.Prop1 = 0; 140 [self setProp2:0]; 141 [self setProp3:0]; 142 [[self Prop5] invalidate2]; 143 [self.Prop4 invalidate]; 144 [self.Prop8 invalidate]; 145 self.Prop6 = 0; 146 [[self Prop7] invalidate]; 147 148 [_Ivar3 description]; 149 NSLog(@"%@", _Ivar4); 150 [super invalidate]; 151} 152// expected-warning@-1 {{Instance variable Ivar1 needs to be invalidated}} 153 // expected-warning@-2 {{Instance variable MultipleProtocols needs to be invalidated}} 154 // expected-warning@-3 {{Instance variable MultInheritance needs to be invalidated}} 155 // expected-warning@-4 {{Property SynthIvarProp needs to be invalidated or set to nil}} 156 // expected-warning@-5 {{Instance variable _Ivar3 needs to be invalidated}} 157 // expected-warning@-6 {{Instance variable _Ivar4 needs to be invalidated}} 158 // expected-warning@-7 {{Instance variable Ivar5 needs to be invalidated or set to nil}} 159@end 160 161// Example, where the same property is inherited through 162// the parent and directly through a protocol. If a property backing ivar is 163// synthesized in the parent, let the parent invalidate it. 164 165@protocol IDEBuildable <NSObject> 166@property (readonly, strong) id <Invalidation2> ObjB; 167@end 168 169@interface Parent : NSObject <IDEBuildable, Invalidation2> { 170 Invalidation2Class *_ObjB; // Invalidation of ObjB happens in the parent. 171} 172@end 173 174@interface Child: Parent <Invalidation2, IDEBuildable> 175@end 176 177@implementation Parent{ 178 @private 179 Invalidation2Class *Ivar10; 180 Invalidation2Class *Ivar11; 181 Invalidation2Class *Ivar12; 182} 183 184@synthesize ObjB = _ObjB; 185- (void)invalidate{ 186 _ObjB = ((void*)0); 187 188 assert(Ivar10 == 0); 189 190 if (__builtin_expect(!(Ivar11 == ((void*)0)), 0)) 191 assert(0); 192 193 assert(0 == Ivar12); 194 195} 196@end 197 198@implementation Child 199- (void)invalidate{ 200 // no-warning 201} 202@end 203 204@protocol Invalidation <NSObject> 205- (void)invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); 206@end 207 208@interface Foo : NSObject <Invalidation> 209@end 210 211@class FooBar; 212@protocol FooBar_Protocol <NSObject> 213@end 214 215@interface MissingInvalidationMethod : Foo <FooBar_Protocol> 216@property (assign) MissingInvalidationMethod *foobar15_warn; // expected-warning {{No invalidation method defined in the @implementation for MissingInvalidationMethod; Property foobar15_warn needs to be invalidated}} 217@end 218@implementation MissingInvalidationMethod 219@end 220 221@interface MissingInvalidationMethod2 : Foo <FooBar_Protocol> { 222 Foo *Ivar1;// expected-warning {{No invalidation method defined in the @implementation for MissingInvalidationMethod2; Instance variable Ivar1 needs to be invalidated}} 223} 224@end 225@implementation MissingInvalidationMethod2 226@end 227 228@interface MissingInvalidationMethodDecl : NSObject { 229 Foo *Ivar1;// expected-warning {{No invalidation method declared in the @interface for MissingInvalidationMethodDecl; Instance variable Ivar1 needs to be invalidated}} 230} 231@end 232@implementation MissingInvalidationMethodDecl 233@end 234 235@interface MissingInvalidationMethodDecl2 : NSObject { 236@private 237 Foo *_foo1; // expected-warning {{No invalidation method declared in the @interface for MissingInvalidationMethodDecl2; Instance variable _foo1 needs to be invalidated}} 238} 239@property (strong) Foo *bar1; 240@end 241@implementation MissingInvalidationMethodDecl2 242@end 243