1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.osx.cocoa.InstanceVariableInvalidation -DRUN_IVAR_INVALIDATION -verify %s |
2 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.osx.cocoa.MissingInvalidationMethod -DRUN_MISSING_INVALIDATION_METHOD -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 | @interface SomeNotInvalidatedInPartial : SomeInvalidationImplementingObject { |
326 | SomeInvalidationImplementingObject *Ivar1; |
327 | SomeInvalidationImplementingObject *Ivar2; |
328 | #if RUN_IVAR_INVALIDATION |
329 | // expected-warning@-2 {{Instance variable Ivar2 needs to be invalidated or set to nil}} |
330 | #endif |
331 | } |
332 | -(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); |
333 | -(void)partialInvalidatorCallsPartial __attribute__((annotate("objc_instance_variable_invalidator_partial"))); |
334 | @end |
335 | @implementation SomeNotInvalidatedInPartial { |
336 | SomeInvalidationImplementingObject *Ivar3; |
337 | #if RUN_IVAR_INVALIDATION |
338 | // expected-warning@-2 {{Instance variable Ivar3 needs to be invalidated or set to nil}} |
339 | #endif |
340 | } |
341 | -(void)partialInvalidator { |
342 | Ivar1 = 0; |
343 | } |
344 | -(void)partialInvalidatorCallsPartial { |
345 | [self partialInvalidator]; |
346 | } |
347 | @end |
348 | |
349 | @interface OnlyPartialDeclsBase : NSObject |
350 | -(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); |
351 | @end |
352 | @implementation OnlyPartialDeclsBase |
353 | -(void)partialInvalidator {} |
354 | @end |
355 | |
356 | @interface OnlyPartialDecls : OnlyPartialDeclsBase { |
357 | SomeInvalidationImplementingObject *Ivar1; |
358 | #if RUN_IVAR_INVALIDATION |
359 | // expected-warning@-2 {{Instance variable Ivar1 needs to be invalidated; no invalidation method is defined in the @implementation for OnlyPartialDecls}} |
360 | #endif |
361 | } |
362 | @end |
363 | @implementation OnlyPartialDecls |
364 | @end |
365 | |
366 | // False negative. |
367 | @interface PartialCallsFull : SomeInvalidationImplementingObject { |
368 | SomeInvalidationImplementingObject *Ivar1; |
369 | } |
370 | -(void)partialInvalidator __attribute__((annotate("objc_instance_variable_invalidator_partial"))); |
371 | @end |
372 | @implementation PartialCallsFull |
373 | -(void)partialInvalidator { |
374 | [self invalidate]; |
375 | } // TODO: It would be nice to check that the full invalidation method actually invalidates the ivar. |
376 | @end |
377 | |
378 | |