1 | // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.cplusplus.UninitializedObject \ |
2 | // RUN: -analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true -DPEDANTIC \ |
3 | // RUN: -analyzer-config alpha.cplusplus.UninitializedObject:IgnoreGuardedFields=true \ |
4 | // RUN: -std=c++11 -verify %s |
5 | |
6 | //===----------------------------------------------------------------------===// |
7 | // Helper functions for tests. |
8 | //===----------------------------------------------------------------------===// |
9 | |
10 | [[noreturn]] void halt(); |
11 | |
12 | void assert(int b) { |
13 | if (!b) |
14 | halt(); |
15 | } |
16 | |
17 | int rand(); |
18 | |
19 | //===----------------------------------------------------------------------===// |
20 | // Tests for fields properly guarded by asserts. |
21 | //===----------------------------------------------------------------------===// |
22 | |
23 | class NoUnguardedFieldsTest { |
24 | public: |
25 | enum Kind { |
26 | V, |
27 | A |
28 | }; |
29 | |
30 | private: |
31 | int Volume, Area; |
32 | Kind K; |
33 | |
34 | public: |
35 | NoUnguardedFieldsTest(Kind K) : K(K) { |
36 | switch (K) { |
37 | case V: |
38 | Volume = 0; |
39 | break; |
40 | case A: |
41 | Area = 0; |
42 | break; |
43 | } |
44 | } |
45 | |
46 | void operator-() { |
47 | assert(K == Kind::A); |
48 | (void)Area; |
49 | } |
50 | |
51 | void operator+() { |
52 | assert(K == Kind::V); |
53 | (void)Volume; |
54 | } |
55 | }; |
56 | |
57 | void fNoUnguardedFieldsTest() { |
58 | NoUnguardedFieldsTest T1(NoUnguardedFieldsTest::Kind::A); |
59 | NoUnguardedFieldsTest T2(NoUnguardedFieldsTest::Kind::V); |
60 | } |
61 | |
62 | class NoUngardedFieldsNoReturnFuncCalledTest { |
63 | public: |
64 | enum Kind { |
65 | V, |
66 | A |
67 | }; |
68 | |
69 | private: |
70 | int Volume, Area; |
71 | Kind K; |
72 | |
73 | public: |
74 | NoUngardedFieldsNoReturnFuncCalledTest(Kind K) : K(K) { |
75 | switch (K) { |
76 | case V: |
77 | Volume = 0; |
78 | break; |
79 | case A: |
80 | Area = 0; |
81 | break; |
82 | } |
83 | } |
84 | |
85 | void operator-() { |
86 | halt(); |
87 | (void)Area; |
88 | } |
89 | |
90 | void operator+() { |
91 | halt(); |
92 | (void)Volume; |
93 | } |
94 | }; |
95 | |
96 | void fNoUngardedFieldsNoReturnFuncCalledTest() { |
97 | NoUngardedFieldsNoReturnFuncCalledTest |
98 | T1(NoUngardedFieldsNoReturnFuncCalledTest::Kind::A); |
99 | NoUngardedFieldsNoReturnFuncCalledTest |
100 | T2(NoUngardedFieldsNoReturnFuncCalledTest::Kind::V); |
101 | } |
102 | |
103 | class NoUnguardedFieldsWithUndefMethodTest { |
104 | public: |
105 | enum Kind { |
106 | V, |
107 | A |
108 | }; |
109 | |
110 | private: |
111 | int Volume, Area; |
112 | Kind K; |
113 | |
114 | public: |
115 | NoUnguardedFieldsWithUndefMethodTest(Kind K) : K(K) { |
116 | switch (K) { |
117 | case V: |
118 | Volume = 0; |
119 | break; |
120 | case A: |
121 | Area = 0; |
122 | break; |
123 | } |
124 | } |
125 | |
126 | void operator-() { |
127 | assert(K == Kind::A); |
128 | (void)Area; |
129 | } |
130 | |
131 | void operator+() { |
132 | assert(K == Kind::V); |
133 | (void)Volume; |
134 | } |
135 | |
136 | // We're checking method definitions for guards, so this is a no-crash test |
137 | // whether we handle methods without definitions. |
138 | void methodWithoutDefinition(); |
139 | }; |
140 | |
141 | void fNoUnguardedFieldsWithUndefMethodTest() { |
142 | NoUnguardedFieldsWithUndefMethodTest |
143 | T1(NoUnguardedFieldsWithUndefMethodTest::Kind::A); |
144 | NoUnguardedFieldsWithUndefMethodTest |
145 | T2(NoUnguardedFieldsWithUndefMethodTest::Kind::V); |
146 | } |
147 | |
148 | class UnguardedFieldThroughMethodTest { |
149 | public: |
150 | enum Kind { |
151 | V, |
152 | A |
153 | }; |
154 | |
155 | private: |
156 | int Volume, Area; // expected-note {{uninitialized field 'this->Volume'}} |
157 | Kind K; |
158 | |
159 | public: |
160 | UnguardedFieldThroughMethodTest(Kind K) : K(K) { |
161 | switch (K) { |
162 | case V: |
163 | Volume = 0; |
164 | break; |
165 | case A: |
166 | Area = 0; // expected-warning {{1 uninitialized field}} |
167 | break; |
168 | } |
169 | } |
170 | |
171 | void operator-() { |
172 | assert(K == Kind::A); |
173 | (void)Area; |
174 | } |
175 | |
176 | void operator+() { |
177 | (void)Volume; |
178 | } |
179 | }; |
180 | |
181 | void fUnguardedFieldThroughMethodTest() { |
182 | UnguardedFieldThroughMethodTest T1(UnguardedFieldThroughMethodTest::Kind::A); |
183 | } |
184 | |
185 | class UnguardedPublicFieldsTest { |
186 | public: |
187 | enum Kind { |
188 | V, |
189 | A |
190 | }; |
191 | |
192 | public: |
193 | // Note that fields are public. |
194 | int Volume, Area; // expected-note {{uninitialized field 'this->Volume'}} |
195 | Kind K; |
196 | |
197 | public: |
198 | UnguardedPublicFieldsTest(Kind K) : K(K) { |
199 | switch (K) { |
200 | case V: |
201 | Volume = 0; |
202 | break; |
203 | case A: |
204 | Area = 0; // expected-warning {{1 uninitialized field}} |
205 | break; |
206 | } |
207 | } |
208 | |
209 | void operator-() { |
210 | assert(K == Kind::A); |
211 | (void)Area; |
212 | } |
213 | |
214 | void operator+() { |
215 | assert(K == Kind::V); |
216 | (void)Volume; |
217 | } |
218 | }; |
219 | |
220 | void fUnguardedPublicFieldsTest() { |
221 | UnguardedPublicFieldsTest T1(UnguardedPublicFieldsTest::Kind::A); |
222 | } |
223 | |
224 | //===----------------------------------------------------------------------===// |
225 | // Highlights of some false negatives due to syntactic checking. |
226 | //===----------------------------------------------------------------------===// |
227 | |
228 | class UnguardedFalseNegativeTest1 { |
229 | public: |
230 | enum Kind { |
231 | V, |
232 | A |
233 | }; |
234 | |
235 | private: |
236 | int Volume, Area; |
237 | Kind K; |
238 | |
239 | public: |
240 | UnguardedFalseNegativeTest1(Kind K) : K(K) { |
241 | switch (K) { |
242 | case V: |
243 | Volume = 0; |
244 | break; |
245 | case A: |
246 | Area = 0; |
247 | break; |
248 | } |
249 | } |
250 | |
251 | void operator-() { |
252 | if (rand()) |
253 | assert(K == Kind::A); |
254 | (void)Area; |
255 | } |
256 | |
257 | void operator+() { |
258 | if (rand()) |
259 | assert(K == Kind::V); |
260 | (void)Volume; |
261 | } |
262 | }; |
263 | |
264 | void fUnguardedFalseNegativeTest1() { |
265 | UnguardedFalseNegativeTest1 T1(UnguardedFalseNegativeTest1::Kind::A); |
266 | } |
267 | |
268 | class UnguardedFalseNegativeTest2 { |
269 | public: |
270 | enum Kind { |
271 | V, |
272 | A |
273 | }; |
274 | |
275 | private: |
276 | int Volume, Area; |
277 | Kind K; |
278 | |
279 | public: |
280 | UnguardedFalseNegativeTest2(Kind K) : K(K) { |
281 | switch (K) { |
282 | case V: |
283 | Volume = 0; |
284 | break; |
285 | case A: |
286 | Area = 0; |
287 | break; |
288 | } |
289 | } |
290 | |
291 | void operator-() { |
292 | assert(rand()); |
293 | (void)Area; |
294 | } |
295 | |
296 | void operator+() { |
297 | assert(rand()); |
298 | (void)Volume; |
299 | } |
300 | }; |
301 | |
302 | void fUnguardedFalseNegativeTest2() { |
303 | UnguardedFalseNegativeTest2 T1(UnguardedFalseNegativeTest2::Kind::A); |
304 | } |
305 | |
306 | //===----------------------------------------------------------------------===// |
307 | // Tests for other guards. These won't be as thorough, as other guards are |
308 | // matched the same way as asserts, so if they are recognized, they are expected |
309 | // to work as well as asserts do. |
310 | // |
311 | // None of these tests expect warnings, since the flag works correctly if these |
312 | // fields are regarded properly guarded. |
313 | //===----------------------------------------------------------------------===// |
314 | |
315 | class IfGuardedFieldsTest { |
316 | public: |
317 | enum Kind { |
318 | V, |
319 | A |
320 | }; |
321 | |
322 | private: |
323 | int Volume, Area; |
324 | Kind K; |
325 | |
326 | public: |
327 | IfGuardedFieldsTest(Kind K) : K(K) { |
328 | switch (K) { |
329 | case V: |
330 | Volume = 0; |
331 | break; |
332 | case A: |
333 | Area = 0; |
334 | break; |
335 | } |
336 | } |
337 | |
338 | void operator-() { |
339 | if (K != Kind::A) |
340 | return; |
341 | (void)Area; |
342 | } |
343 | |
344 | void operator+() { |
345 | if (K != Kind::V) |
346 | return; |
347 | (void)Volume; |
348 | } |
349 | }; |
350 | |
351 | void fIfGuardedFieldsTest() { |
352 | IfGuardedFieldsTest T1(IfGuardedFieldsTest::Kind::A); |
353 | IfGuardedFieldsTest T2(IfGuardedFieldsTest::Kind::V); |
354 | } |
355 | |
356 | class SwitchGuardedFieldsTest { |
357 | public: |
358 | enum Kind { |
359 | V, |
360 | A |
361 | }; |
362 | |
363 | private: |
364 | int Volume, Area; |
365 | Kind K; |
366 | |
367 | public: |
368 | SwitchGuardedFieldsTest(Kind K) : K(K) { |
369 | switch (K) { |
370 | case V: |
371 | Volume = 0; |
372 | break; |
373 | case A: |
374 | Area = 0; |
375 | break; |
376 | } |
377 | } |
378 | |
379 | int operator-() { |
380 | switch (K) { |
381 | case Kind::A: |
382 | return Area; |
383 | case Kind::V: |
384 | return -1; |
385 | } |
386 | } |
387 | |
388 | int operator+() { |
389 | switch (K) { |
390 | case Kind::A: |
391 | return Area; |
392 | case Kind::V: |
393 | return -1; |
394 | } |
395 | } |
396 | }; |
397 | |
398 | void fSwitchGuardedFieldsTest() { |
399 | SwitchGuardedFieldsTest T1(SwitchGuardedFieldsTest::Kind::A); |
400 | SwitchGuardedFieldsTest T2(SwitchGuardedFieldsTest::Kind::V); |
401 | } |
402 | |
403 | class ConditionalOperatorGuardedFieldsTest { |
404 | public: |
405 | enum Kind { |
406 | V, |
407 | A |
408 | }; |
409 | |
410 | private: |
411 | int Volume, Area; |
412 | Kind K; |
413 | |
414 | public: |
415 | ConditionalOperatorGuardedFieldsTest(Kind K) : K(K) { |
416 | switch (K) { |
417 | case V: |
418 | Volume = 0; |
419 | break; |
420 | case A: |
421 | Area = 0; |
422 | break; |
423 | } |
424 | } |
425 | |
426 | int operator-() { |
427 | return K == Kind::A ? Area : -1; |
428 | } |
429 | |
430 | int operator+() { |
431 | return K == Kind::V ? Volume : -1; |
432 | } |
433 | }; |
434 | |
435 | void fConditionalOperatorGuardedFieldsTest() { |
436 | ConditionalOperatorGuardedFieldsTest |
437 | T1(ConditionalOperatorGuardedFieldsTest::Kind::A); |
438 | ConditionalOperatorGuardedFieldsTest |
439 | T2(ConditionalOperatorGuardedFieldsTest::Kind::V); |
440 | } |
441 | |