Home | History | Annotate | Download | only in Analysis
      1 // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -DRUN_IVAR_INVALIDATION -fobjc-default-synthesize-properties -verify %s
      2 // RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.osx.cocoa.MissingInvalidationMethod -DRUN_MISSING_INVALIDATION_METHOD -fobjc-default-synthesize-properties -verify %s
      3 extern 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 
     24 extern 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 // False negative.
    326 @interface PartialCallsFull : SomeInvalidationImplementingObject {
    327   SomeInvalidationImplementingObject *Ivar1;
    328 }
    329 -(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial")));
    330 @end
    331 @implementation PartialCallsFull
    332 -(void)partialInvalidator {
    333  [self invalidate];
    334 } // TODO: It would be nice to check that the full invalidation method actually invalidates the ivar. 
    335 @end
    336 
    337