Anna Zaks | 722cd9e | 2013-02-08 23:55:47 +0000 | [diff] [blame] | 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 |
Anna Zaks | 6503255 | 2013-01-10 23:34:16 +0000 | [diff] [blame] | 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__)) |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 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; |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 20 | -(id)description; |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 21 | @end |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 22 | @class NSString; |
| 23 | |
| 24 | extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 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"))); |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 36 | - (void) invalidate2 __attribute__((annotate("objc_instance_variable_invalidator"))); |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 37 | @end |
| 38 | |
Anna Zaks | b8f6678 | 2013-01-11 03:52:40 +0000 | [diff] [blame] | 39 | @protocol Invalidation3; |
| 40 | @protocol Invalidation2; |
| 41 | |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 42 | @interface Invalidation2Class <Invalidation2> |
| 43 | @end |
| 44 | |
| 45 | @interface Invalidation1Class <Invalidation1> |
| 46 | @end |
| 47 | |
Anna Zaks | ae81e17 | 2013-01-11 03:52:37 +0000 | [diff] [blame] | 48 | @interface ClassWithInvalidationMethodInCategory <NSObject> |
| 49 | @end |
| 50 | |
| 51 | @interface ClassWithInvalidationMethodInCategory () |
| 52 | - (void) invalidate __attribute__((annotate("objc_instance_variable_invalidator"))); |
| 53 | @end |
| 54 | |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 55 | @interface SomeInvalidationImplementingObject: NSObject <Invalidation3, Invalidation2> { |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 56 | SomeInvalidationImplementingObject *ObjA; // invalidation in the parent |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 57 | } |
| 58 | @end |
| 59 | |
| 60 | @implementation SomeInvalidationImplementingObject |
| 61 | - (void)invalidate{ |
| 62 | ObjA = 0; |
| 63 | } |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 64 | - (void)invalidate2 { |
| 65 | [self invalidate]; |
| 66 | } |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 67 | @end |
| 68 | |
| 69 | @interface SomeSubclassInvalidatableObject : SomeInvalidationImplementingObject { |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 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 |
Anna Zaks | c3c26b7 | 2012-10-18 19:17:57 +0000 | [diff] [blame] | 83 | SomeInvalidationImplementingObject *_Prop8; |
Anna Zaks | b087bbf | 2012-09-27 19:45:08 +0000 | [diff] [blame] | 84 | |
Anna Zaks | 26db7db | 2013-02-08 23:55:43 +0000 | [diff] [blame] | 85 | // Ivars invalidated by the partial invalidator. |
| 86 | SomeInvalidationImplementingObject *Ivar9; |
| 87 | SomeInvalidationImplementingObject *_Prop10; |
| 88 | SomeInvalidationImplementingObject *Ivar11; |
| 89 | |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 90 | // No warnings on these as they are not invalidatable. |
| 91 | NSObject *NIvar1; |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 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; |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 101 | @property (assign) SomeInvalidationImplementingObject *Prop5; |
| 102 | @property (assign) SomeInvalidationImplementingObject *Prop4; |
Anna Zaks | 377945c | 2012-09-27 21:57:14 +0000 | [diff] [blame] | 103 | |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 104 | @property (assign) SomeInvalidationImplementingObject* Prop6; // automatically synthesized prop |
| 105 | @property (assign) SomeInvalidationImplementingObject* Prop7; // automatically synthesized prop |
| 106 | @property (assign) SomeInvalidationImplementingObject *SynthIvarProp; |
Anna Zaks | 377945c | 2012-09-27 21:57:14 +0000 | [diff] [blame] | 107 | |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 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 | |
Anna Zaks | 26db7db | 2013-02-08 23:55:43 +0000 | [diff] [blame] | 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"))); |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 121 | @end |
| 122 | |
Anna Zaks | e0c50fa | 2012-10-16 19:36:37 +0000 | [diff] [blame] | 123 | @interface SomeSubclassInvalidatableObject() |
| 124 | @property (assign) SomeInvalidationImplementingObject* Prop8; |
Anna Zaks | 26db7db | 2013-02-08 23:55:43 +0000 | [diff] [blame] | 125 | @property (assign) SomeInvalidationImplementingObject* Prop10; |
Anna Zaks | e0c50fa | 2012-10-16 19:36:37 +0000 | [diff] [blame] | 126 | @end |
| 127 | |
| 128 | @implementation SomeSubclassInvalidatableObject{ |
| 129 | @private |
| 130 | SomeInvalidationImplementingObject *Ivar5; |
Anna Zaks | ae81e17 | 2013-01-11 03:52:37 +0000 | [diff] [blame] | 131 | ClassWithInvalidationMethodInCategory *Ivar13; |
Anna Zaks | e0c50fa | 2012-10-16 19:36:37 +0000 | [diff] [blame] | 132 | } |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 133 | |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 134 | @synthesize Prop7 = _propIvar; |
| 135 | @synthesize Prop3 = _Prop3; |
| 136 | @synthesize Prop5 = _Prop5; |
| 137 | @synthesize Prop4 = _Prop4; |
Anna Zaks | c3c26b7 | 2012-10-18 19:17:57 +0000 | [diff] [blame] | 138 | @synthesize Prop8 = _Prop8; |
Anna Zaks | 26db7db | 2013-02-08 23:55:43 +0000 | [diff] [blame] | 139 | @synthesize Prop10 = _Prop10; |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 140 | |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 141 | |
| 142 | - (void) setProp1: (SomeInvalidationImplementingObject*) InObj { |
| 143 | _Prop1 = InObj; |
| 144 | } |
| 145 | |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 146 | - (void) setProp2: (SomeInvalidationImplementingObject*) InObj { |
| 147 | _Prop2 = InObj; |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 148 | } |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 149 | - (SomeInvalidationImplementingObject*) Prop2 { |
| 150 | return _Prop2; |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 151 | } |
| 152 | |
| 153 | @synthesize NProp2 = _NpropIvar; |
| 154 | |
| 155 | - (void) setNProp1: (NSObject*) InObj { |
| 156 | _NProp1 = InObj; |
| 157 | } |
| 158 | |
| 159 | - (void) invalidate { |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 160 | [Ivar2 invalidate]; |
Anna Zaks | 377945c | 2012-09-27 21:57:14 +0000 | [diff] [blame] | 161 | self.Prop0 = 0; |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 162 | self.Prop1 = 0; |
| 163 | [self setProp2:0]; |
| 164 | [self setProp3:0]; |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 165 | [[self Prop5] invalidate2]; |
| 166 | [self.Prop4 invalidate]; |
Anna Zaks | c3c26b7 | 2012-10-18 19:17:57 +0000 | [diff] [blame] | 167 | [self.Prop8 invalidate]; |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 168 | self.Prop6 = 0; |
| 169 | [[self Prop7] invalidate]; |
| 170 | |
| 171 | [_Ivar3 description]; |
| 172 | NSLog(@"%@", _Ivar4); |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 173 | [super invalidate]; |
Anna Zaks | 31f69cc | 2012-09-29 00:20:38 +0000 | [diff] [blame] | 174 | } |
Anna Zaks | 722cd9e | 2013-02-08 23:55:47 +0000 | [diff] [blame] | 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 |
Anna Zaks | 26db7db | 2013-02-08 23:55:43 +0000 | [diff] [blame] | 185 | |
| 186 | -(void)partialInvalidator1 { |
| 187 | [Ivar9 invalidate]; |
| 188 | [_Prop10 invalidate]; |
| 189 | } |
| 190 | |
| 191 | -(void)partialInvalidator2 { |
| 192 | [Ivar11 invalidate]; |
| 193 | } |
| 194 | |
Anna Zaks | 5bf5c2e | 2012-09-26 18:55:16 +0000 | [diff] [blame] | 195 | @end |
Anna Zaks | 5879fb3 | 2013-01-07 19:12:56 +0000 | [diff] [blame] | 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 | |
Anna Zaks | 6503255 | 2013-01-10 23:34:16 +0000 | [diff] [blame] | 213 | @implementation Parent{ |
| 214 | @private |
| 215 | Invalidation2Class *Ivar10; |
| 216 | Invalidation2Class *Ivar11; |
| 217 | Invalidation2Class *Ivar12; |
| 218 | } |
| 219 | |
Anna Zaks | 5879fb3 | 2013-01-07 19:12:56 +0000 | [diff] [blame] | 220 | @synthesize ObjB = _ObjB; |
| 221 | - (void)invalidate{ |
| 222 | _ObjB = ((void*)0); |
Anna Zaks | 6503255 | 2013-01-10 23:34:16 +0000 | [diff] [blame] | 223 | |
| 224 | assert(Ivar10 == 0); |
| 225 | |
| 226 | if (__builtin_expect(!(Ivar11 == ((void*)0)), 0)) |
| 227 | assert(0); |
| 228 | |
| 229 | assert(0 == Ivar12); |
| 230 | |
Anna Zaks | 5879fb3 | 2013-01-07 19:12:56 +0000 | [diff] [blame] | 231 | } |
| 232 | @end |
| 233 | |
| 234 | @implementation Child |
| 235 | - (void)invalidate{ |
| 236 | // no-warning |
| 237 | } |
| 238 | @end |
Anna Zaks | b1fc673 | 2013-01-10 20:59:51 +0000 | [diff] [blame] | 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> |
Anna Zaks | 722cd9e | 2013-02-08 23:55:47 +0000 | [diff] [blame] | 252 | @property (assign) MissingInvalidationMethod *foobar15_warn; |
| 253 | #if RUN_MISSING_INVALIDATION_METHOD |
| 254 | // expected-warning@-2 {{Property foobar15_warn needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod}} |
| 255 | #endif |
Anna Zaks | b1fc673 | 2013-01-10 20:59:51 +0000 | [diff] [blame] | 256 | @end |
| 257 | @implementation MissingInvalidationMethod |
| 258 | @end |
| 259 | |
| 260 | @interface MissingInvalidationMethod2 : Foo <FooBar_Protocol> { |
Anna Zaks | 722cd9e | 2013-02-08 23:55:47 +0000 | [diff] [blame] | 261 | Foo *Ivar1; |
| 262 | #if RUN_MISSING_INVALIDATION_METHOD |
| 263 | // expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for MissingInvalidationMethod2}} |
| 264 | #endif |
Anna Zaks | b1fc673 | 2013-01-10 20:59:51 +0000 | [diff] [blame] | 265 | } |
| 266 | @end |
| 267 | @implementation MissingInvalidationMethod2 |
| 268 | @end |
| 269 | |
| 270 | @interface MissingInvalidationMethodDecl : NSObject { |
Anna Zaks | 722cd9e | 2013-02-08 23:55:47 +0000 | [diff] [blame] | 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 |
Anna Zaks | b1fc673 | 2013-01-10 20:59:51 +0000 | [diff] [blame] | 275 | } |
| 276 | @end |
| 277 | @implementation MissingInvalidationMethodDecl |
| 278 | @end |
| 279 | |
| 280 | @interface MissingInvalidationMethodDecl2 : NSObject { |
| 281 | @private |
Anna Zaks | 722cd9e | 2013-02-08 23:55:47 +0000 | [diff] [blame] | 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 |
Anna Zaks | b1fc673 | 2013-01-10 20:59:51 +0000 | [diff] [blame] | 286 | } |
Anna Zaks | 664566c | 2013-01-10 22:44:16 +0000 | [diff] [blame] | 287 | @property (strong) Foo *bar1; |
Anna Zaks | b1fc673 | 2013-01-10 20:59:51 +0000 | [diff] [blame] | 288 | @end |
| 289 | @implementation MissingInvalidationMethodDecl2 |
| 290 | @end |
Anna Zaks | 26db7db | 2013-02-08 23:55:43 +0000 | [diff] [blame] | 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 { |
Anna Zaks | 722cd9e | 2013-02-08 23:55:47 +0000 | [diff] [blame] | 319 | } |
| 320 | #if RUN_IVAR_INVALIDATION |
| 321 | // expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated or set to nil}} |
| 322 | #endif |
Anna Zaks | 26db7db | 2013-02-08 23:55:43 +0000 | [diff] [blame] | 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 | |