1// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -DRUN_IVAR_INVALIDATION -verify %s 2// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.osx.cocoa.MissingInvalidationMethod -DRUN_MISSING_INVALIDATION_METHOD -verify %s 3extern void __assert_fail (__const char *__assertion, __const char *__file, 4 unsigned int __line, __const char *__function) 5 __attribute__ ((__noreturn__)); 6 7#define assert(expr) \ 8 ((expr) ? (void)(0) : __assert_fail (#expr, __FILE__, __LINE__, __func__)) 9 10@protocol NSObject 11@end 12@interface NSObject <NSObject> {} 13+(id)alloc; 14+(id)new; 15-(id)init; 16-(id)autorelease; 17-(id)copy; 18- (Class)class; 19-(id)retain; 20-(id)description; 21@end 22@class NSString; 23 24extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); 25 26@protocol Invalidation1 <NSObject> 27- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); 28@end 29 30@protocol Invalidation2 <NSObject> 31- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); 32@end 33 34@protocol Invalidation3 <NSObject> 35- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); 36- (void) invalidate2 __attribute__((annotate("objc_instance_variable_invalidator"))); 37@end 38 39@protocol Invalidation3; 40@protocol Invalidation2; 41 42@interface Invalidation2Class <Invalidation2> 43@end 44 45@interface Invalidation1Class <Invalidation1> 46@end 47 48@interface ClassWithInvalidationMethodInCategory <NSObject> 49@end 50 51@interface ClassWithInvalidationMethodInCategory () 52- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); 53@end 54 55@interface SomeInvalidationImplementingObject: NSObject <Invalidation3, Invalidation2> { 56 SomeInvalidationImplementingObject *ObjA; // invalidation in the parent 57} 58@end 59 60@implementation SomeInvalidationImplementingObject 61- (void)invalidate{ 62 ObjA = 0; 63} 64- (void)invalidate2 { 65 [self invalidate]; 66} 67@end 68 69@interface SomeSubclassInvalidatableObject : SomeInvalidationImplementingObject { 70 SomeInvalidationImplementingObject *Ivar1; // regular ivar 71 SomeInvalidationImplementingObject *Ivar2; // regular ivar, sending invalidate message 72 SomeInvalidationImplementingObject *_Ivar3; // no property, call -description 73 SomeInvalidationImplementingObject *_Ivar4; // no property, provide as argument to NSLog() 74 75 SomeInvalidationImplementingObject *_Prop1; // partially implemented property, set to 0 with dot syntax 76 SomeInvalidationImplementingObject *_Prop2; // fully implemented prop, set to 0 with dot syntax 77 SomeInvalidationImplementingObject *_propIvar; // property with custom named ivar, set to 0 via setter 78 Invalidation1Class *MultipleProtocols; // regular ivar belonging to a different class 79 Invalidation2Class *MultInheritance; // regular ivar belonging to a different class 80 SomeInvalidationImplementingObject *_Prop3; // property, invalidate via sending a message to a getter method 81 SomeInvalidationImplementingObject *_Prop4; // property with @synthesize, invalidate via property 82 SomeInvalidationImplementingObject *_Prop5; // property with @synthesize, invalidate via getter method 83 SomeInvalidationImplementingObject *_Prop8; 84 85 // Ivars invalidated by the partial invalidator. 86 SomeInvalidationImplementingObject *Ivar9; 87 SomeInvalidationImplementingObject *_Prop10; 88 SomeInvalidationImplementingObject *Ivar11; 89 90 // No warnings on these as they are not invalidatable. 91 NSObject *NIvar1; 92 NSObject *NObj2; 93 NSObject *_NProp1; 94 NSObject *_NpropIvar; 95} 96 97@property (assign) SomeInvalidationImplementingObject* Prop0; 98@property (nonatomic, assign) SomeInvalidationImplementingObject* Prop1; 99@property (assign) SomeInvalidationImplementingObject* Prop2; 100@property (assign) SomeInvalidationImplementingObject* Prop3; 101@property (assign) SomeInvalidationImplementingObject *Prop5; 102@property (assign) SomeInvalidationImplementingObject *Prop4; 103 104@property (assign) SomeInvalidationImplementingObject* Prop6; // automatically synthesized prop 105@property (assign) SomeInvalidationImplementingObject* Prop7; // automatically synthesized prop 106@property (assign) SomeInvalidationImplementingObject *SynthIvarProp; 107 108@property (assign) NSObject* NProp0; 109@property (nonatomic, assign) NSObject* NProp1; 110@property (assign) NSObject* NProp2; 111 112-(void)setProp1: (SomeInvalidationImplementingObject*) InO; 113-(void)setNProp1: (NSObject*) InO; 114 115-(void)invalidate; 116 117// Partial invalidators invalidate only some ivars. They are guaranteed to be 118// called before the invalidation methods. 119-(void)partialInvalidator1 __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 120-(void)partialInvalidator2 __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 121@end 122 123@interface SomeSubclassInvalidatableObject() 124@property (assign) SomeInvalidationImplementingObject* Prop8; 125@property (assign) SomeInvalidationImplementingObject* Prop10; 126@end 127 128@implementation SomeSubclassInvalidatableObject{ 129 @private 130 SomeInvalidationImplementingObject *Ivar5; 131 ClassWithInvalidationMethodInCategory *Ivar13; 132} 133 134@synthesize Prop7 = _propIvar; 135@synthesize Prop3 = _Prop3; 136@synthesize Prop5 = _Prop5; 137@synthesize Prop4 = _Prop4; 138@synthesize Prop8 = _Prop8; 139@synthesize Prop10 = _Prop10; 140 141 142- (void) setProp1: (SomeInvalidationImplementingObject*) InObj { 143 _Prop1 = InObj; 144} 145 146- (void) setProp2: (SomeInvalidationImplementingObject*) InObj { 147 _Prop2 = InObj; 148} 149- (SomeInvalidationImplementingObject*) Prop2 { 150 return _Prop2; 151} 152 153@synthesize NProp2 = _NpropIvar; 154 155- (void) setNProp1: (NSObject*) InObj { 156 _NProp1 = InObj; 157} 158 159- (void) invalidate { 160 [Ivar2 invalidate]; 161 self.Prop0 = 0; 162 self.Prop1 = 0; 163 [self setProp2:0]; 164 [self setProp3:0]; 165 [[self Prop5] invalidate2]; 166 [self.Prop4 invalidate]; 167 [self.Prop8 invalidate]; 168 self.Prop6 = 0; 169 [[self Prop7] invalidate]; 170 171 [_Ivar3 description]; 172 NSLog(@"%@", _Ivar4); 173 [super invalidate]; 174} 175#if RUN_IVAR_INVALIDATION 176// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated}} 177// expected-warning@-3 {{Instance variable MultipleProtocols needs to be invalidated}} 178// expected-warning@-4 {{Instance variable MultInheritance needs to be invalidated}} 179// expected-warning@-5 {{Property SynthIvarProp needs to be invalidated or set to nil}} 180// expected-warning@-6 {{Instance variable _Ivar3 needs to be invalidated}} 181// expected-warning@-7 {{Instance variable _Ivar4 needs to be invalidated}} 182// expected-warning@-8 {{Instance variable Ivar5 needs to be invalidated or set to nil}} 183// expected-warning@-9 {{Instance variable Ivar13 needs to be invalidated or set to nil}} 184#endif 185 186-(void)partialInvalidator1 { 187 [Ivar9 invalidate]; 188 [_Prop10 invalidate]; 189} 190 191-(void)partialInvalidator2 { 192 [Ivar11 invalidate]; 193} 194 195@end 196 197// Example, where the same property is inherited through 198// the parent and directly through a protocol. If a property backing ivar is 199// synthesized in the parent, let the parent invalidate it. 200 201@protocol IDEBuildable <NSObject> 202@property (readonly, strong) id <Invalidation2> ObjB; 203@end 204 205@interface Parent : NSObject <IDEBuildable, Invalidation2> { 206 Invalidation2Class *_ObjB; // Invalidation of ObjB happens in the parent. 207} 208@end 209 210@interface Child: Parent <Invalidation2, IDEBuildable> 211@end 212 213@implementation Parent{ 214 @private 215 Invalidation2Class *Ivar10; 216 Invalidation2Class *Ivar11; 217 Invalidation2Class *Ivar12; 218} 219 220@synthesize ObjB = _ObjB; 221- (void)invalidate{ 222 _ObjB = ((void*)0); 223 224 assert(Ivar10 == 0); 225 226 if (__builtin_expect(!(Ivar11 == ((void*)0)), 0)) 227 assert(0); 228 229 assert(0 == Ivar12); 230 231} 232@end 233 234@implementation Child 235- (void)invalidate{ 236 // no-warning 237} 238@end 239 240@protocol Invalidation <NSObject> 241- (void)invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); 242@end 243 244@interface Foo : NSObject <Invalidation> 245@end 246 247@class FooBar; 248@protocol FooBar_Protocol <NSObject> 249@end 250 251@interface MissingInvalidationMethod : Foo <FooBar_Protocol> 252@property (assign) MissingInvalidationMethod *foobar15_warn; 253#if RUN_IVAR_INVALIDATION 254// expected-warning@-2 {{Property foobar15_warn needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod}} 255#endif 256@end 257@implementation MissingInvalidationMethod 258@end 259 260@interface MissingInvalidationMethod2 : Foo <FooBar_Protocol> { 261 Foo *Ivar1; 262#if RUN_IVAR_INVALIDATION 263// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod2}} 264#endif 265} 266@end 267@implementation MissingInvalidationMethod2 268@end 269 270@interface MissingInvalidationMethodDecl : NSObject { 271 Foo *Ivar1; 272#if RUN_MISSING_INVALIDATION_METHOD 273// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl}} 274#endif 275} 276@end 277@implementation MissingInvalidationMethodDecl 278@end 279 280@interface MissingInvalidationMethodDecl2 : NSObject { 281@private 282 Foo *_foo1; 283#if RUN_MISSING_INVALIDATION_METHOD 284// expected-warning@-2 {{Instance variable _foo1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl2}} 285#endif 286} 287@property (strong) Foo *bar1; 288@end 289@implementation MissingInvalidationMethodDecl2 290@end 291 292@interface InvalidatedInPartial : SomeInvalidationImplementingObject { 293 SomeInvalidationImplementingObject *Ivar1; 294 SomeInvalidationImplementingObject *Ivar2; 295} 296-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 297@end 298@implementation InvalidatedInPartial 299-(void)partialInvalidator { 300 [Ivar1 invalidate]; 301 Ivar2 = 0; 302} 303@end 304 305@interface NotInvalidatedInPartial : SomeInvalidationImplementingObject { 306 SomeInvalidationImplementingObject *Ivar1; 307} 308-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 309-(void)partialInvalidatorCallsPartial __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 310@end 311@implementation NotInvalidatedInPartial 312-(void)partialInvalidator { 313} 314-(void)partialInvalidatorCallsPartial { 315 [self partialInvalidator]; 316} 317 318-(void)invalidate { 319} 320#if RUN_IVAR_INVALIDATION 321// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated or set to nil}} 322#endif 323@end 324 325@interface SomeNotInvalidatedInPartial : SomeInvalidationImplementingObject { 326 SomeInvalidationImplementingObject *Ivar1; 327 SomeInvalidationImplementingObject *Ivar2; 328#if RUN_IVAR_INVALIDATION 329 // expected-warning@-2 {{Instance variable Ivar2 needs to be invalidated or set to nil}} 330#endif 331} 332-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 333-(void)partialInvalidatorCallsPartial __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 334@end 335@implementation SomeNotInvalidatedInPartial { 336 SomeInvalidationImplementingObject *Ivar3; 337#if RUN_IVAR_INVALIDATION 338 // expected-warning@-2 {{Instance variable Ivar3 needs to be invalidated or set to nil}} 339#endif 340} 341-(void)partialInvalidator { 342 Ivar1 = 0; 343} 344-(void)partialInvalidatorCallsPartial { 345 [self partialInvalidator]; 346} 347@end 348 349@interface OnlyPartialDeclsBase : NSObject 350-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 351@end 352@implementation OnlyPartialDeclsBase 353-(void)partialInvalidator {} 354@end 355 356@interface OnlyPartialDecls : OnlyPartialDeclsBase { 357 SomeInvalidationImplementingObject *Ivar1; 358#if RUN_IVAR_INVALIDATION 359 // expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for OnlyPartialDecls}} 360#endif 361} 362@end 363@implementation OnlyPartialDecls 364@end 365 366// False negative. 367@interface PartialCallsFull : SomeInvalidationImplementingObject { 368 SomeInvalidationImplementingObject *Ivar1; 369} 370-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 371@end 372@implementation PartialCallsFull 373-(void)partialInvalidator { 374 [self invalidate]; 375} // TODO: It would be nice to check that the full invalidation method actually invalidates the ivar. 376@end 377 378