391 lines · plain
1// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -DRUN_IVAR_INVALIDATION -verify %s2// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.osx.cocoa.MissingInvalidationMethod -DRUN_MISSING_INVALIDATION_METHOD -verify %s3extern 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 NSObject11@end12@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@end22@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@end38 39@protocol Invalidation3;40@protocol Invalidation2;41 42@interface Invalidation2Class <Invalidation2>43@end44 45@interface Invalidation1Class <Invalidation1>46@end47 48@interface ClassWithInvalidationMethodInCategory <NSObject>49@end50 51@interface ClassWithInvalidationMethodInCategory ()52- (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator")));53@end54 55@interface SomeInvalidationImplementingObject: NSObject <Invalidation3, Invalidation2> {56 SomeInvalidationImplementingObject *ObjA; // invalidation in the parent57}58@end59 60@implementation SomeInvalidationImplementingObject61- (void)invalidate{62 ObjA = 0;63}64- (void)invalidate2 {65 [self invalidate];66}67@end68 69@interface SomeSubclassInvalidatableObject : SomeInvalidationImplementingObject {70 SomeInvalidationImplementingObject *Ivar1; // regular ivar71 SomeInvalidationImplementingObject *Ivar2; // regular ivar, sending invalidate message72 SomeInvalidationImplementingObject *_Ivar3; // no property, call -description73 SomeInvalidationImplementingObject *_Ivar4; // no property, provide as argument to NSLog()74 75 SomeInvalidationImplementingObject *_Prop1; // partially implemented property, set to 0 with dot syntax76 SomeInvalidationImplementingObject *_Prop2; // fully implemented prop, set to 0 with dot syntax77 SomeInvalidationImplementingObject *_propIvar; // property with custom named ivar, set to 0 via setter78 Invalidation1Class *MultipleProtocols; // regular ivar belonging to a different class79 Invalidation2Class *MultInheritance; // regular ivar belonging to a different class80 SomeInvalidationImplementingObject *_Prop3; // property, invalidate via sending a message to a getter method81 SomeInvalidationImplementingObject *_Prop4; // property with @synthesize, invalidate via property82 SomeInvalidationImplementingObject *_Prop5; // property with @synthesize, invalidate via getter method83 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 prop105@property (assign) SomeInvalidationImplementingObject* Prop7; // automatically synthesized prop106@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@end122 123@interface SomeSubclassInvalidatableObject()124@property (assign) SomeInvalidationImplementingObject* Prop8;125@property (assign) SomeInvalidationImplementingObject* Prop10;126@end127 128@implementation SomeSubclassInvalidatableObject{129 @private130 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_INVALIDATION176// 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#endif185 186-(void)partialInvalidator1 {187 [Ivar9 invalidate];188 [_Prop10 invalidate];189}190 191-(void)partialInvalidator2 {192 [Ivar11 invalidate];193}194 195@end196 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@end204 205@interface Parent : NSObject <IDEBuildable, Invalidation2> {206 Invalidation2Class *_ObjB; // Invalidation of ObjB happens in the parent.207}208@end209 210@interface Child: Parent <Invalidation2, IDEBuildable> 211@end212 213@implementation Parent{214 @private215 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@end233 234@implementation Child235- (void)invalidate{ 236 // no-warning237} 238@end239 240@protocol Invalidation <NSObject>241- (void)invalidate __attribute__((annotate("objc_instance_variable_invalidator")));242@end243 244@interface Foo : NSObject <Invalidation>245@end246 247@class FooBar;248@protocol FooBar_Protocol <NSObject>249@end250 251@interface MissingInvalidationMethod : Foo <FooBar_Protocol>252@property (assign) MissingInvalidationMethod *foobar15_warn;253#if RUN_IVAR_INVALIDATION254// expected-warning@-2 {{Property foobar15_warn needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod}}255#endif256@end257@implementation MissingInvalidationMethod258@end259 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_INVALIDATION264// expected-warning@-3 {{Property foobar16_warn needs to be invalidated; no invalidation method is defined in the @implementation for SuppressedMissingInvalidationMethod}}265#endif266 267@end268@implementation SuppressedMissingInvalidationMethod269@end270 271@interface MissingInvalidationMethod2 : Foo <FooBar_Protocol> {272 Foo *Ivar1;273#if RUN_IVAR_INVALIDATION274// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod2}}275#endif276}277@end278@implementation MissingInvalidationMethod2279@end280 281@interface MissingInvalidationMethodDecl : NSObject {282 Foo *Ivar1;283#if RUN_MISSING_INVALIDATION_METHOD284// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl}}285#endif286}287@end288@implementation MissingInvalidationMethodDecl289@end290 291@interface MissingInvalidationMethodDecl2 : NSObject {292@private293 Foo *_foo1;294#if RUN_MISSING_INVALIDATION_METHOD295// expected-warning@-2 {{Instance variable _foo1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl2}}296#endif297}298@property (strong) Foo *bar1; 299@end300@implementation MissingInvalidationMethodDecl2301@end302 303@interface InvalidatedInPartial : SomeInvalidationImplementingObject {304 SomeInvalidationImplementingObject *Ivar1;305 SomeInvalidationImplementingObject *Ivar2;306 [[clang::suppress]]307 SomeInvalidationImplementingObject *Ivar3; // no-warning308}309-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial")));310@end311@implementation InvalidatedInPartial312-(void)partialInvalidator {313 [Ivar1 invalidate];314 Ivar2 = 0;315}316@end317 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@end324@implementation NotInvalidatedInPartial325-(void)partialInvalidator {326}327-(void)partialInvalidatorCallsPartial {328 [self partialInvalidator];329}330 331-(void)invalidate {332} 333#if RUN_IVAR_INVALIDATION334// expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated or set to nil}}335#endif336@end337 338@interface SomeNotInvalidatedInPartial : SomeInvalidationImplementingObject {339 SomeInvalidationImplementingObject *Ivar1;340 SomeInvalidationImplementingObject *Ivar2;341#if RUN_IVAR_INVALIDATION342 // expected-warning@-2 {{Instance variable Ivar2 needs to be invalidated or set to nil}}343#endif344}345-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial")));346-(void)partialInvalidatorCallsPartial __attribute__((annotate("objc_instance_variable_invalidator_partial")));347@end348@implementation SomeNotInvalidatedInPartial {349 SomeInvalidationImplementingObject *Ivar3;350#if RUN_IVAR_INVALIDATION351 // expected-warning@-2 {{Instance variable Ivar3 needs to be invalidated or set to nil}}352#endif353}354-(void)partialInvalidator {355 Ivar1 = 0;356}357-(void)partialInvalidatorCallsPartial {358 [self partialInvalidator];359}360@end361 362@interface OnlyPartialDeclsBase : NSObject363-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial")));364@end365@implementation OnlyPartialDeclsBase366-(void)partialInvalidator {}367@end368 369@interface OnlyPartialDecls : OnlyPartialDeclsBase {370 SomeInvalidationImplementingObject *Ivar1;371#if RUN_IVAR_INVALIDATION372 // expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for OnlyPartialDecls}}373#endif374}375@end376@implementation OnlyPartialDecls377@end378 379// False negative.380@interface PartialCallsFull : SomeInvalidationImplementingObject {381 SomeInvalidationImplementingObject *Ivar1;382}383-(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial")));384@end385@implementation PartialCallsFull386-(void)partialInvalidator {387 [self invalidate];388} // TODO: It would be nice to check that the full invalidation method actually invalidates the ivar. 389@end390 391