forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			378 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
			
		
		
	
	
			378 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Objective-C
		
	
	
	
| // 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 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; 
 | |
| }
 | |
| -(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
 | |
| 
 |