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