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 SuppressedMissingInvalidationMethod : Foo <FooBar_Protocol> 261@property (assign) [[clang::suppress]] SuppressedMissingInvalidationMethod *foobar16_warn; 262// FIXME: Suppression should have worked but decl-with-issue is the ivar, not the property. 263#if RUN_IVAR_INVALIDATION 264// expected-warning@-3 {{Property foobar16_warn needs to be invalidated; no invalidation method is defined in the @implementation for SuppressedMissingInvalidationMethod}} 265#endif 266 267@end 268@implementation SuppressedMissingInvalidationMethod 269@end 270 271@interface MissingInvalidationMethod2 : Foo <FooBar_Protocol> { 272 Foo *Ivar1; 273#if RUN_IVAR_INVALIDATION 274// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod2}} 275#endif 276} 277@end 278@implementation MissingInvalidationMethod2 279@end 280 281@interface MissingInvalidationMethodDecl : NSObject { 282 Foo *Ivar1; 283#if RUN_MISSING_INVALIDATION_METHOD 284// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl}} 285#endif 286} 287@end 288@implementation MissingInvalidationMethodDecl 289@end 290 291@interface MissingInvalidationMethodDecl2 : NSObject { 292@private 293 Foo *_foo1; 294#if RUN_MISSING_INVALIDATION_METHOD 295// expected-warning@-2 {{Instance variable _foo1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl2}} 296#endif 297} 298@property (strong) Foo *bar1; 299@end 300@implementation MissingInvalidationMethodDecl2 301@end 302 303@interface InvalidatedInPartial : SomeInvalidationImplementingObject { 304 SomeInvalidationImplementingObject *Ivar1; 305 SomeInvalidationImplementingObject *Ivar2; 306 [[clang::suppress]] 307 SomeInvalidationImplementingObject *Ivar3; // no-warning 308} 309-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 310@end 311@implementation InvalidatedInPartial 312-(void)partialInvalidator { 313 [Ivar1 invalidate]; 314 Ivar2 = 0; 315} 316@end 317 318@interface NotInvalidatedInPartial : SomeInvalidationImplementingObject { 319 SomeInvalidationImplementingObject *Ivar1; 320} 321-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 322-(void)partialInvalidatorCallsPartial __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 323@end 324@implementation NotInvalidatedInPartial 325-(void)partialInvalidator { 326} 327-(void)partialInvalidatorCallsPartial { 328 [self partialInvalidator]; 329} 330 331-(void)invalidate { 332} 333#if RUN_IVAR_INVALIDATION 334// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated or set to nil}} 335#endif 336@end 337 338@interface SomeNotInvalidatedInPartial : SomeInvalidationImplementingObject { 339 SomeInvalidationImplementingObject *Ivar1; 340 SomeInvalidationImplementingObject *Ivar2; 341#if RUN_IVAR_INVALIDATION 342 // expected-warning@-2 {{Instance variable Ivar2 needs to be invalidated or set to nil}} 343#endif 344} 345-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 346-(void)partialInvalidatorCallsPartial __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 347@end 348@implementation SomeNotInvalidatedInPartial { 349 SomeInvalidationImplementingObject *Ivar3; 350#if RUN_IVAR_INVALIDATION 351 // expected-warning@-2 {{Instance variable Ivar3 needs to be invalidated or set to nil}} 352#endif 353} 354-(void)partialInvalidator { 355 Ivar1 = 0; 356} 357-(void)partialInvalidatorCallsPartial { 358 [self partialInvalidator]; 359} 360@end 361 362@interface OnlyPartialDeclsBase : NSObject 363-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 364@end 365@implementation OnlyPartialDeclsBase 366-(void)partialInvalidator {} 367@end 368 369@interface OnlyPartialDecls : OnlyPartialDeclsBase { 370 SomeInvalidationImplementingObject *Ivar1; 371#if RUN_IVAR_INVALIDATION 372 // expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for OnlyPartialDecls}} 373#endif 374} 375@end 376@implementation OnlyPartialDecls 377@end 378 379// False negative. 380@interface PartialCallsFull : SomeInvalidationImplementingObject { 381 SomeInvalidationImplementingObject *Ivar1; 382} 383-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); 384@end 385@implementation PartialCallsFull 386-(void)partialInvalidator { 387 [self invalidate]; 388} // TODO: It would be nice to check that the full invalidation method actually invalidates the ivar. 389@end 390 391