|  | // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -DRUN_IVAR_INVALIDATION -verify %s | 
|  | // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.osx.cocoa.MissingInvalidationMethod -DRUN_MISSING_INVALIDATION_METHOD -verify %s | 
|  | extern void __assert_fail (__const char *__assertion, __const char *__file, | 
|  | unsigned int __line, __const char *__function) | 
|  | __attribute__ ((__noreturn__)); | 
|  |  | 
|  | #define assert(expr) \ | 
|  | ((expr)  ? (void)(0)  : __assert_fail (#expr, __FILE__, __LINE__, __func__)) | 
|  |  | 
|  | @protocol NSObject | 
|  | @end | 
|  | @interface NSObject <NSObject> {} | 
|  | +(id)alloc; | 
|  | +(id)new; | 
|  | -(id)init; | 
|  | -(id)autorelease; | 
|  | -(id)copy; | 
|  | - (Class)class; | 
|  | -(id)retain; | 
|  | -(id)description; | 
|  | @end | 
|  | @class NSString; | 
|  |  | 
|  | extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); | 
|  |  | 
|  | @protocol Invalidation1 <NSObject> | 
|  | - (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); | 
|  | @end | 
|  |  | 
|  | @protocol Invalidation2 <NSObject> | 
|  | - (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); | 
|  | @end | 
|  |  | 
|  | @protocol Invalidation3 <NSObject> | 
|  | - (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); | 
|  | - (void) invalidate2 __attribute__((annotate("objc_instance_variable_invalidator"))); | 
|  | @end | 
|  |  | 
|  | @protocol Invalidation3; | 
|  | @protocol Invalidation2; | 
|  |  | 
|  | @interface Invalidation2Class <Invalidation2> | 
|  | @end | 
|  |  | 
|  | @interface Invalidation1Class <Invalidation1> | 
|  | @end | 
|  |  | 
|  | @interface ClassWithInvalidationMethodInCategory <NSObject> | 
|  | @end | 
|  |  | 
|  | @interface ClassWithInvalidationMethodInCategory () | 
|  | - (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); | 
|  | @end | 
|  |  | 
|  | @interface SomeInvalidationImplementingObject: NSObject <Invalidation3, Invalidation2> { | 
|  | SomeInvalidationImplementingObject *ObjA; // invalidation in the parent | 
|  | } | 
|  | @end | 
|  |  | 
|  | @implementation SomeInvalidationImplementingObject | 
|  | - (void)invalidate{ | 
|  | ObjA = 0; | 
|  | } | 
|  | - (void)invalidate2 { | 
|  | [self invalidate]; | 
|  | } | 
|  | @end | 
|  |  | 
|  | @interface SomeSubclassInvalidatableObject : SomeInvalidationImplementingObject { | 
|  | SomeInvalidationImplementingObject *Ivar1; // regular ivar | 
|  | SomeInvalidationImplementingObject *Ivar2; // regular ivar, sending invalidate message | 
|  | SomeInvalidationImplementingObject *_Ivar3; // no property, call -description | 
|  | SomeInvalidationImplementingObject *_Ivar4; // no property, provide as argument to NSLog() | 
|  |  | 
|  | SomeInvalidationImplementingObject *_Prop1; // partially implemented property, set to 0 with dot syntax | 
|  | SomeInvalidationImplementingObject *_Prop2; // fully implemented prop, set to 0 with dot syntax | 
|  | SomeInvalidationImplementingObject *_propIvar; // property with custom named ivar, set to 0 via setter | 
|  | Invalidation1Class *MultipleProtocols; // regular ivar belonging to a different class | 
|  | Invalidation2Class *MultInheritance; // regular ivar belonging to a different class | 
|  | SomeInvalidationImplementingObject *_Prop3; // property, invalidate via sending a message to a getter method | 
|  | SomeInvalidationImplementingObject *_Prop4; // property with @synthesize, invalidate via property | 
|  | SomeInvalidationImplementingObject *_Prop5; // property with @synthesize, invalidate via getter method | 
|  | SomeInvalidationImplementingObject *_Prop8; | 
|  |  | 
|  | // Ivars invalidated by the partial invalidator. | 
|  | SomeInvalidationImplementingObject *Ivar9; | 
|  | SomeInvalidationImplementingObject *_Prop10; | 
|  | SomeInvalidationImplementingObject *Ivar11; | 
|  |  | 
|  | // No warnings on these as they are not invalidatable. | 
|  | NSObject *NIvar1; | 
|  | NSObject *NObj2; | 
|  | NSObject *_NProp1; | 
|  | NSObject *_NpropIvar; | 
|  | } | 
|  |  | 
|  | @property (assign) SomeInvalidationImplementingObject* Prop0; | 
|  | @property (nonatomic, assign) SomeInvalidationImplementingObject* Prop1; | 
|  | @property (assign) SomeInvalidationImplementingObject* Prop2; | 
|  | @property (assign) SomeInvalidationImplementingObject* Prop3; | 
|  | @property (assign) SomeInvalidationImplementingObject *Prop5; | 
|  | @property (assign) SomeInvalidationImplementingObject *Prop4; | 
|  |  | 
|  | @property (assign) SomeInvalidationImplementingObject* Prop6; // automatically synthesized prop | 
|  | @property (assign) SomeInvalidationImplementingObject* Prop7; // automatically synthesized prop | 
|  | @property (assign) SomeInvalidationImplementingObject *SynthIvarProp; | 
|  |  | 
|  | @property (assign) NSObject* NProp0; | 
|  | @property (nonatomic, assign) NSObject* NProp1; | 
|  | @property (assign) NSObject* NProp2; | 
|  |  | 
|  | -(void)setProp1: (SomeInvalidationImplementingObject*) InO; | 
|  | -(void)setNProp1: (NSObject*) InO; | 
|  |  | 
|  | -(void)invalidate; | 
|  |  | 
|  | // Partial invalidators invalidate only some ivars. They are guaranteed to be | 
|  | // called before the invalidation methods. | 
|  | -(void)partialInvalidator1 __attribute__((annotate("objc_instance_variable_invalidator_partial"))); | 
|  | -(void)partialInvalidator2 __attribute__((annotate("objc_instance_variable_invalidator_partial"))); | 
|  | @end | 
|  |  | 
|  | @interface SomeSubclassInvalidatableObject() | 
|  | @property (assign) SomeInvalidationImplementingObject* Prop8; | 
|  | @property (assign) SomeInvalidationImplementingObject* Prop10; | 
|  | @end | 
|  |  | 
|  | @implementation SomeSubclassInvalidatableObject{ | 
|  | @private | 
|  | SomeInvalidationImplementingObject *Ivar5; | 
|  | ClassWithInvalidationMethodInCategory *Ivar13; | 
|  | } | 
|  |  | 
|  | @synthesize Prop7 = _propIvar; | 
|  | @synthesize Prop3 = _Prop3; | 
|  | @synthesize Prop5 = _Prop5; | 
|  | @synthesize Prop4 = _Prop4; | 
|  | @synthesize Prop8 = _Prop8; | 
|  | @synthesize Prop10 = _Prop10; | 
|  |  | 
|  |  | 
|  | - (void) setProp1: (SomeInvalidationImplementingObject*) InObj { | 
|  | _Prop1 = InObj; | 
|  | } | 
|  |  | 
|  | - (void) setProp2: (SomeInvalidationImplementingObject*) InObj { | 
|  | _Prop2 = InObj; | 
|  | } | 
|  | - (SomeInvalidationImplementingObject*) Prop2 { | 
|  | return _Prop2; | 
|  | } | 
|  |  | 
|  | @synthesize NProp2 = _NpropIvar; | 
|  |  | 
|  | - (void) setNProp1: (NSObject*) InObj { | 
|  | _NProp1 = InObj; | 
|  | } | 
|  |  | 
|  | - (void) invalidate { | 
|  | [Ivar2 invalidate]; | 
|  | self.Prop0 = 0; | 
|  | self.Prop1 = 0; | 
|  | [self setProp2:0]; | 
|  | [self setProp3:0]; | 
|  | [[self Prop5] invalidate2]; | 
|  | [self.Prop4 invalidate]; | 
|  | [self.Prop8 invalidate]; | 
|  | self.Prop6 = 0; | 
|  | [[self Prop7] invalidate]; | 
|  |  | 
|  | [_Ivar3 description]; | 
|  | NSLog(@"%@", _Ivar4); | 
|  | [super invalidate]; | 
|  | } | 
|  | #if RUN_IVAR_INVALIDATION | 
|  | // expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated}} | 
|  | // expected-warning@-3 {{Instance variable MultipleProtocols needs to be invalidated}} | 
|  | // expected-warning@-4 {{Instance variable MultInheritance needs to be invalidated}} | 
|  | // expected-warning@-5 {{Property SynthIvarProp needs to be invalidated or set to nil}} | 
|  | // expected-warning@-6 {{Instance variable _Ivar3 needs to be invalidated}} | 
|  | // expected-warning@-7 {{Instance variable _Ivar4 needs to be invalidated}} | 
|  | // expected-warning@-8 {{Instance variable Ivar5 needs to be invalidated or set to nil}} | 
|  | // expected-warning@-9 {{Instance variable Ivar13 needs to be invalidated or set to nil}} | 
|  | #endif | 
|  |  | 
|  | -(void)partialInvalidator1 { | 
|  | [Ivar9 invalidate]; | 
|  | [_Prop10 invalidate]; | 
|  | } | 
|  |  | 
|  | -(void)partialInvalidator2 { | 
|  | [Ivar11 invalidate]; | 
|  | } | 
|  |  | 
|  | @end | 
|  |  | 
|  | // Example, where the same property is inherited through | 
|  | // the parent and directly through a protocol. If a property backing ivar is | 
|  | // synthesized in the parent, let the parent invalidate it. | 
|  |  | 
|  | @protocol IDEBuildable <NSObject> | 
|  | @property (readonly, strong) id <Invalidation2> ObjB; | 
|  | @end | 
|  |  | 
|  | @interface Parent : NSObject <IDEBuildable, Invalidation2> { | 
|  | Invalidation2Class *_ObjB; // Invalidation of ObjB happens in the parent. | 
|  | } | 
|  | @end | 
|  |  | 
|  | @interface Child: Parent <Invalidation2, IDEBuildable> | 
|  | @end | 
|  |  | 
|  | @implementation Parent{ | 
|  | @private | 
|  | Invalidation2Class *Ivar10; | 
|  | Invalidation2Class *Ivar11; | 
|  | Invalidation2Class *Ivar12; | 
|  | } | 
|  |  | 
|  | @synthesize ObjB = _ObjB; | 
|  | - (void)invalidate{ | 
|  | _ObjB = ((void*)0); | 
|  |  | 
|  | assert(Ivar10 == 0); | 
|  |  | 
|  | if (__builtin_expect(!(Ivar11 == ((void*)0)), 0)) | 
|  | assert(0); | 
|  |  | 
|  | assert(0 == Ivar12); | 
|  |  | 
|  | } | 
|  | @end | 
|  |  | 
|  | @implementation Child | 
|  | - (void)invalidate{ | 
|  | // no-warning | 
|  | } | 
|  | @end | 
|  |  | 
|  | @protocol Invalidation <NSObject> | 
|  | - (void)invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); | 
|  | @end | 
|  |  | 
|  | @interface Foo : NSObject <Invalidation> | 
|  | @end | 
|  |  | 
|  | @class FooBar; | 
|  | @protocol FooBar_Protocol <NSObject> | 
|  | @end | 
|  |  | 
|  | @interface MissingInvalidationMethod : Foo <FooBar_Protocol> | 
|  | @property (assign) MissingInvalidationMethod *foobar15_warn; | 
|  | #if RUN_IVAR_INVALIDATION | 
|  | // expected-warning@-2 {{Property foobar15_warn needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod}} | 
|  | #endif | 
|  | @end | 
|  | @implementation MissingInvalidationMethod | 
|  | @end | 
|  |  | 
|  | @interface SuppressedMissingInvalidationMethod : Foo <FooBar_Protocol> | 
|  | @property (assign) [[clang::suppress]] SuppressedMissingInvalidationMethod *foobar16_warn; | 
|  | // FIXME: Suppression should have worked but decl-with-issue is the ivar, not the property. | 
|  | #if RUN_IVAR_INVALIDATION | 
|  | // expected-warning@-3 {{Property foobar16_warn needs to be invalidated; no invalidation method is defined in the @implementation for SuppressedMissingInvalidationMethod}} | 
|  | #endif | 
|  |  | 
|  | @end | 
|  | @implementation SuppressedMissingInvalidationMethod | 
|  | @end | 
|  |  | 
|  | @interface MissingInvalidationMethod2 : Foo <FooBar_Protocol> { | 
|  | Foo *Ivar1; | 
|  | #if RUN_IVAR_INVALIDATION | 
|  | // expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod2}} | 
|  | #endif | 
|  | } | 
|  | @end | 
|  | @implementation MissingInvalidationMethod2 | 
|  | @end | 
|  |  | 
|  | @interface MissingInvalidationMethodDecl : NSObject { | 
|  | Foo *Ivar1; | 
|  | #if RUN_MISSING_INVALIDATION_METHOD | 
|  | // expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl}} | 
|  | #endif | 
|  | } | 
|  | @end | 
|  | @implementation MissingInvalidationMethodDecl | 
|  | @end | 
|  |  | 
|  | @interface MissingInvalidationMethodDecl2 : NSObject { | 
|  | @private | 
|  | Foo *_foo1; | 
|  | #if RUN_MISSING_INVALIDATION_METHOD | 
|  | // expected-warning@-2 {{Instance variable _foo1 needs to be invalidated; no invalidation method is declared for MissingInvalidationMethodDecl2}} | 
|  | #endif | 
|  | } | 
|  | @property (strong) Foo *bar1; | 
|  | @end | 
|  | @implementation MissingInvalidationMethodDecl2 | 
|  | @end | 
|  |  | 
|  | @interface InvalidatedInPartial : SomeInvalidationImplementingObject { | 
|  | SomeInvalidationImplementingObject *Ivar1; | 
|  | SomeInvalidationImplementingObject *Ivar2; | 
|  | [[clang::suppress]] | 
|  | SomeInvalidationImplementingObject *Ivar3; // no-warning | 
|  | } | 
|  | -(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); | 
|  | @end | 
|  | @implementation InvalidatedInPartial | 
|  | -(void)partialInvalidator { | 
|  | [Ivar1 invalidate]; | 
|  | Ivar2 = 0; | 
|  | } | 
|  | @end | 
|  |  | 
|  | @interface NotInvalidatedInPartial : SomeInvalidationImplementingObject { | 
|  | SomeInvalidationImplementingObject *Ivar1; | 
|  | } | 
|  | -(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); | 
|  | -(void)partialInvalidatorCallsPartial __attribute__((annotate("objc_instance_variable_invalidator_partial"))); | 
|  | @end | 
|  | @implementation NotInvalidatedInPartial | 
|  | -(void)partialInvalidator { | 
|  | } | 
|  | -(void)partialInvalidatorCallsPartial { | 
|  | [self partialInvalidator]; | 
|  | } | 
|  |  | 
|  | -(void)invalidate { | 
|  | } | 
|  | #if RUN_IVAR_INVALIDATION | 
|  | // expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated or set to nil}} | 
|  | #endif | 
|  | @end | 
|  |  | 
|  | @interface SomeNotInvalidatedInPartial : SomeInvalidationImplementingObject { | 
|  | SomeInvalidationImplementingObject *Ivar1; | 
|  | SomeInvalidationImplementingObject *Ivar2; | 
|  | #if RUN_IVAR_INVALIDATION | 
|  | // expected-warning@-2 {{Instance variable Ivar2 needs to be invalidated or set to nil}} | 
|  | #endif | 
|  | } | 
|  | -(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); | 
|  | -(void)partialInvalidatorCallsPartial __attribute__((annotate("objc_instance_variable_invalidator_partial"))); | 
|  | @end | 
|  | @implementation SomeNotInvalidatedInPartial { | 
|  | SomeInvalidationImplementingObject *Ivar3; | 
|  | #if RUN_IVAR_INVALIDATION | 
|  | // expected-warning@-2 {{Instance variable Ivar3 needs to be invalidated or set to nil}} | 
|  | #endif | 
|  | } | 
|  | -(void)partialInvalidator { | 
|  | Ivar1 = 0; | 
|  | } | 
|  | -(void)partialInvalidatorCallsPartial { | 
|  | [self partialInvalidator]; | 
|  | } | 
|  | @end | 
|  |  | 
|  | @interface OnlyPartialDeclsBase : NSObject | 
|  | -(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); | 
|  | @end | 
|  | @implementation OnlyPartialDeclsBase | 
|  | -(void)partialInvalidator {} | 
|  | @end | 
|  |  | 
|  | @interface OnlyPartialDecls : OnlyPartialDeclsBase { | 
|  | SomeInvalidationImplementingObject *Ivar1; | 
|  | #if RUN_IVAR_INVALIDATION | 
|  | // expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for OnlyPartialDecls}} | 
|  | #endif | 
|  | } | 
|  | @end | 
|  | @implementation OnlyPartialDecls | 
|  | @end | 
|  |  | 
|  | // False negative. | 
|  | @interface PartialCallsFull : SomeInvalidationImplementingObject { | 
|  | SomeInvalidationImplementingObject *Ivar1; | 
|  | } | 
|  | -(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); | 
|  | @end | 
|  | @implementation PartialCallsFull | 
|  | -(void)partialInvalidator { | 
|  | [self invalidate]; | 
|  | } // TODO: It would be nice to check that the full invalidation method actually invalidates the ivar. | 
|  | @end | 
|  |  |