objc_invalidation.m revision 26db7dbf67b1532b2d617b3a85428699a1ffc997
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@protocol Invalidation3; 39@protocol Invalidation2; 40 41@interface Invalidation2Class <Invalidation2> 42@end 43 44@interface Invalidation1Class <Invalidation1> 45@end 46 47@interface ClassWithInvalidationMethodInCategory <NSObject> 48@end 49 50@interface ClassWithInvalidationMethodInCategory () 51- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); 52@end 53 54@interface SomeInvalidationImplementingObject: NSObject <Invalidation3, Invalidation2> { 55 SomeInvalidationImplementingObject *ObjA; // invalidation in the parent 56} 57@end 58 59@implementation SomeInvalidationImplementingObject 60- (void)invalidate{ 61 ObjA = 0; 62} 63- (void)invalidate2 { 64 [self invalidate]; 65} 66@end 67 68@interface SomeSubclassInvalidatableObject : SomeInvalidationImplementingObject { 69 SomeInvalidationImplementingObject *Ivar1; // regular ivar 70 SomeInvalidationImplementingObject *Ivar2; // regular ivar, sending invalidate message 71 SomeInvalidationImplementingObject *_Ivar3; // no property, call -description 72 SomeInvalidationImplementingObject *_Ivar4; // no property, provide as argument to NSLog() 73 74 SomeInvalidationImplementingObject *_Prop1; // partially implemented property, set to 0 with dot syntax 75 SomeInvalidationImplementingObject *_Prop2; // fully implemented prop, set to 0 with dot syntax 76 SomeInvalidationImplementingObject *_propIvar; // property with custom named ivar, set to 0 via setter 77 Invalidation1Class *MultipleProtocols; // regular ivar belonging to a different class 78 Invalidation2Class *MultInheritance; // regular ivar belonging to a different class 79 SomeInvalidationImplementingObject *_Prop3; // property, invalidate via sending a message to a getter method 80 SomeInvalidationImplementingObject *_Prop4; // property with @synthesize, invalidate via property 81 SomeInvalidationImplementingObject *_Prop5; // property with @synthesize, invalidate via getter method 82 SomeInvalidationImplementingObject *_Prop8; 83 84 // Ivars invalidated by the partial invalidator. 85 SomeInvalidationImplementingObject *Ivar9; 86 SomeInvalidationImplementingObject *_Prop10; 87 SomeInvalidationImplementingObject *Ivar11; 88 89 // No warnings on these as they are not invalidatable. 90 NSObject *NIvar1; 91 NSObject *NObj2; 92 NSObject *_NProp1; 93 NSObject *_NpropIvar; 94} 95 96@property (assign) SomeInvalidationImplementingObject* Prop0; 97@property (nonatomic, assign) SomeInvalidationImplementingObject* Prop1; 98@property (assign) SomeInvalidationImplementingObject* Prop2; 99@property (assign) SomeInvalidationImplementingObject* Prop3; 100@property (assign) SomeInvalidationImplementingObject *Prop5; 101@property (assign) SomeInvalidationImplementingObject *Prop4; 102 103@property (assign) SomeInvalidationImplementingObject* Prop6; // automatically synthesized prop 104@property (assign) SomeInvalidationImplementingObject* Prop7; // automatically synthesized prop 105@property (assign) SomeInvalidationImplementingObject *SynthIvarProp; 106 107@property (assign) NSObject* NProp0; 108@property (nonatomic, assign) NSObject* NProp1; 109@property (assign) NSObject* NProp2; 110 111-(void)setProp1: (SomeInvalidationImplementingObject*) InO; 112-(void)setNProp1: (NSObject*) InO; 113 114-(void)invalidate; 115 116// Partial invalidators invalidate only some ivars. They are guaranteed to be 117// called before the invalidation methods. 118-(void)partialInvalidator1 __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 119-(void)partialInvalidator2 __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 120@end 121 122@interface SomeSubclassInvalidatableObject() 123@property (assign) SomeInvalidationImplementingObject* Prop8; 124@property (assign) SomeInvalidationImplementingObject* Prop10; 125@end 126 127@implementation SomeSubclassInvalidatableObject{ 128 @private 129 SomeInvalidationImplementingObject *Ivar5; 130 ClassWithInvalidationMethodInCategory *Ivar13; 131} 132 133@synthesize Prop7 = _propIvar; 134@synthesize Prop3 = _Prop3; 135@synthesize Prop5 = _Prop5; 136@synthesize Prop4 = _Prop4; 137@synthesize Prop8 = _Prop8; 138@synthesize Prop10 = _Prop10; 139 140 141- (void) setProp1: (SomeInvalidationImplementingObject*) InObj { 142 _Prop1 = InObj; 143} 144 145- (void) setProp2: (SomeInvalidationImplementingObject*) InObj { 146 _Prop2 = InObj; 147} 148- (SomeInvalidationImplementingObject*) Prop2 { 149 return _Prop2; 150} 151 152@synthesize NProp2 = _NpropIvar; 153 154- (void) setNProp1: (NSObject*) InObj { 155 _NProp1 = InObj; 156} 157 158- (void) invalidate { 159 [Ivar2 invalidate]; 160 self.Prop0 = 0; 161 self.Prop1 = 0; 162 [self setProp2:0]; 163 [self setProp3:0]; 164 [[self Prop5] invalidate2]; 165 [self.Prop4 invalidate]; 166 [self.Prop8 invalidate]; 167 self.Prop6 = 0; 168 [[self Prop7] invalidate]; 169 170 [_Ivar3 description]; 171 NSLog(@"%@", _Ivar4); 172 [super invalidate]; 173} 174// expected-warning@-1 {{Instance variable Ivar1 needs to be invalidated}} 175// expected-warning@-2 {{Instance variable MultipleProtocols needs to be invalidated}} 176// expected-warning@-3 {{Instance variable MultInheritance needs to be invalidated}} 177// expected-warning@-4 {{Property SynthIvarProp needs to be invalidated or set to nil}} 178// expected-warning@-5 {{Instance variable _Ivar3 needs to be invalidated}} 179// expected-warning@-6 {{Instance variable _Ivar4 needs to be invalidated}} 180// expected-warning@-7 {{Instance variable Ivar5 needs to be invalidated or set to nil}} 181// expected-warning@-8 {{Instance variable Ivar13 needs to be invalidated or set to nil}} 182 183 184-(void)partialInvalidator1 { 185 [Ivar9 invalidate]; 186 [_Prop10 invalidate]; 187} 188 189-(void)partialInvalidator2 { 190 [Ivar11 invalidate]; 191} 192 193@end 194 195// Example, where the same property is inherited through 196// the parent and directly through a protocol. If a property backing ivar is 197// synthesized in the parent, let the parent invalidate it. 198 199@protocol IDEBuildable <NSObject> 200@property (readonly, strong) id <Invalidation2> ObjB; 201@end 202 203@interface Parent : NSObject <IDEBuildable, Invalidation2> { 204 Invalidation2Class *_ObjB; // Invalidation of ObjB happens in the parent. 205} 206@end 207 208@interface Child: Parent <Invalidation2, IDEBuildable> 209@end 210 211@implementation Parent{ 212 @private 213 Invalidation2Class *Ivar10; 214 Invalidation2Class *Ivar11; 215 Invalidation2Class *Ivar12; 216} 217 218@synthesize ObjB = _ObjB; 219- (void)invalidate{ 220 _ObjB = ((void*)0); 221 222 assert(Ivar10 == 0); 223 224 if (__builtin_expect(!(Ivar11 == ((void*)0)), 0)) 225 assert(0); 226 227 assert(0 == Ivar12); 228 229} 230@end 231 232@implementation Child 233- (void)invalidate{ 234 // no-warning 235} 236@end 237 238@protocol Invalidation <NSObject> 239- (void)invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); 240@end 241 242@interface Foo : NSObject <Invalidation> 243@end 244 245@class FooBar; 246@protocol FooBar_Protocol <NSObject> 247@end 248 249@interface MissingInvalidationMethod : Foo <FooBar_Protocol> 250@property (assign) MissingInvalidationMethod *foobar15_warn; // expected-warning {{Property foobar15_warn needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod}} 251@end 252@implementation MissingInvalidationMethod 253@end 254 255@interface MissingInvalidationMethod2 : Foo <FooBar_Protocol> { 256 Foo *Ivar1;// expected-warning {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod2}} 257} 258@end 259@implementation MissingInvalidationMethod2 260@end 261 262@interface MissingInvalidationMethodDecl : NSObject { 263 Foo *Ivar1;// expected-warning {{Instance variable Ivar1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl}} 264} 265@end 266@implementation MissingInvalidationMethodDecl 267@end 268 269@interface MissingInvalidationMethodDecl2 : NSObject { 270@private 271 Foo *_foo1; // expected-warning {{Instance variable _foo1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl2}} 272} 273@property (strong) Foo *bar1; 274@end 275@implementation MissingInvalidationMethodDecl2 276@end 277 278@interface InvalidatedInPartial : SomeInvalidationImplementingObject { 279 SomeInvalidationImplementingObject *Ivar1; 280 SomeInvalidationImplementingObject *Ivar2; 281} 282-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 283@end 284@implementation InvalidatedInPartial 285-(void)partialInvalidator { 286 [Ivar1 invalidate]; 287 Ivar2 = 0; 288} 289@end 290 291@interface NotInvalidatedInPartial : SomeInvalidationImplementingObject { 292 SomeInvalidationImplementingObject *Ivar1; 293} 294-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 295-(void)partialInvalidatorCallsPartial __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 296@end 297@implementation NotInvalidatedInPartial 298-(void)partialInvalidator { 299} 300-(void)partialInvalidatorCallsPartial { 301 [self partialInvalidator]; 302} 303 304-(void)invalidate { 305} // expected-warning {{Instance variable Ivar1 needs to be invalidated or set to nil}} 306 307@end 308 309// False negative. 310@interface PartialCallsFull : SomeInvalidationImplementingObject { 311 SomeInvalidationImplementingObject *Ivar1; 312} 313-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 314@end 315@implementation PartialCallsFull 316-(void)partialInvalidator { 317 [self invalidate]; 318} // TODO: It would be nice to check that the full invalidation method actually invalidates the ivar. 319@end 320 321