1 | // RUN: %check_clang_tidy %s bugprone-branch-clone %t -- -- -fno-delayed-template-parsing |
2 | |
3 | void test_basic1(int in, int &out) { |
4 | if (in > 77) |
5 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
6 | out++; |
7 | else |
8 | // CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here |
9 | out++; |
10 | |
11 | out++; |
12 | } |
13 | |
14 | void test_basic2(int in, int &out) { |
15 | if (in > 77) { |
16 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
17 | out++; |
18 | } |
19 | else { |
20 | // CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here |
21 | out++; |
22 | } |
23 | |
24 | out++; |
25 | } |
26 | |
27 | void test_basic3(int in, int &out) { |
28 | if (in > 77) { |
29 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
30 | out++; |
31 | } |
32 | else |
33 | // CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here |
34 | out++; |
35 | |
36 | out++; |
37 | } |
38 | |
39 | void test_basic4(int in, int &out) { |
40 | if (in > 77) { |
41 | out--; |
42 | } |
43 | else { |
44 | out++; |
45 | } |
46 | } |
47 | |
48 | void test_basic5(int in, int &out) { |
49 | if (in > 77) { |
50 | out++; |
51 | } |
52 | else { |
53 | out++; |
54 | out++; |
55 | } |
56 | } |
57 | |
58 | void test_basic6(int in, int &out) { |
59 | if (in > 77) { |
60 | out++; |
61 | } |
62 | else { |
63 | out++, out++; |
64 | } |
65 | } |
66 | |
67 | void test_basic7(int in, int &out) { |
68 | if (in > 77) { |
69 | out++; |
70 | out++; |
71 | } |
72 | else |
73 | out++; |
74 | |
75 | out++; |
76 | } |
77 | |
78 | void test_basic8(int in, int &out) { |
79 | if (in > 77) { |
80 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
81 | out++; |
82 | out++; |
83 | } else { |
84 | // CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here |
85 | out++; |
86 | out++; |
87 | } |
88 | |
89 | if (in % 2) |
90 | out++; |
91 | } |
92 | |
93 | void test_basic9(int in, int &out) { |
94 | if (in > 77) { |
95 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
96 | if (in % 2) |
97 | out++; |
98 | else |
99 | out--; |
100 | } else { |
101 | // CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here |
102 | if (in % 2) |
103 | out++; |
104 | else |
105 | out--; |
106 | } |
107 | } |
108 | |
109 | // If we remove the braces from the previous example, the check recognizes it |
110 | // as an `else if`. |
111 | void test_basic10(int in, int &out) { |
112 | if (in > 77) |
113 | if (in % 2) |
114 | out++; |
115 | else |
116 | out--; |
117 | else |
118 | if (in % 2) |
119 | out++; |
120 | else |
121 | out--; |
122 | |
123 | } |
124 | |
125 | void test_basic11(int in, int &out) { |
126 | if (in > 77) { |
127 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
128 | if (in % 2) |
129 | out++; |
130 | else |
131 | out--; |
132 | if (in % 3) |
133 | out++; |
134 | else |
135 | out--; |
136 | } else { |
137 | // CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here |
138 | if (in % 2) |
139 | out++; |
140 | else |
141 | out--; |
142 | if (in % 3) |
143 | out++; |
144 | else |
145 | out--; |
146 | } |
147 | } |
148 | |
149 | void test_basic12(int in, int &out) { |
150 | if (in > 77) { |
151 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
152 | } else { |
153 | // CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here |
154 | } |
155 | } |
156 | |
157 | void test_basic13(int in, int &out) { |
158 | if (in > 77) { |
159 | // Empty compound statement is not identical to null statement. |
160 | } else; |
161 | } |
162 | |
163 | // We use a comparison that ignores redundant parentheses: |
164 | void test_basic14(int in, int &out) { |
165 | if (in > 77) |
166 | out += 2; |
167 | else |
168 | (out) += (2); |
169 | } |
170 | |
171 | void test_basic15(int in, int &out) { |
172 | if (in > 77) |
173 | ((out += 2)); |
174 | else |
175 | out += 2; |
176 | } |
177 | |
178 | // ..but does not apply additional simplifications: |
179 | void test_basic16(int in, int &out) { |
180 | if (in > 77) |
181 | out += 2; |
182 | else |
183 | out += 1 + 1; |
184 | } |
185 | |
186 | // ..and does not forget important parentheses: |
187 | int test_basic17(int a, int b, int c, int mode) { |
188 | if (mode>8) |
189 | return (a + b) * c; |
190 | else |
191 | return a + b * c; |
192 | } |
193 | |
194 | //=========--------------------==========// |
195 | |
196 | #define PASTE_CODE(x) x |
197 | |
198 | void test_macro1(int in, int &out) { |
199 | PASTE_CODE( |
200 | if (in > 77) |
201 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: if with identical then and else branches [bugprone-branch-clone] |
202 | out++; |
203 | else |
204 | // CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here |
205 | out++; |
206 | ) |
207 | |
208 | out--; |
209 | } |
210 | |
211 | void test_macro2(int in, int &out) { |
212 | PASTE_CODE( |
213 | if (in > 77) |
214 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: if with identical then and else branches [bugprone-branch-clone] |
215 | out++; |
216 | ) |
217 | else |
218 | // CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here |
219 | out++; |
220 | } |
221 | |
222 | void test_macro3(int in, int &out) { |
223 | if (in > 77) |
224 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
225 | out++; |
226 | PASTE_CODE( |
227 | else |
228 | // CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here |
229 | out++; |
230 | ) |
231 | } |
232 | |
233 | void test_macro4(int in, int &out) { |
234 | if (in > 77) |
235 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
236 | out++; |
237 | else |
238 | // CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here |
239 | PASTE_CODE( |
240 | out++; |
241 | ) |
242 | } |
243 | |
244 | void test_macro5(int in, int &out) { |
245 | PASTE_CODE(if) (in > 77) |
246 | // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: if with identical then and else branches [bugprone-branch-clone] |
247 | out++; |
248 | PASTE_CODE(else) |
249 | // CHECK-MESSAGES: :[[@LINE-1]]:14: note: else branch starts here |
250 | out++; |
251 | } |
252 | |
253 | #define OTHERWISE_INCREASE else out++ |
254 | |
255 | void test_macro6(int in, int &out) { |
256 | if (in > 77) |
257 | out++; |
258 | // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
259 | OTHERWISE_INCREASE; |
260 | // CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here |
261 | // CHECK-MESSAGES: :[[@LINE-8]]:28: note: expanded from macro 'OTHERWISE_INCREASE' |
262 | } |
263 | |
264 | #define COND_INCR(a, b, c) \ |
265 | do { \ |
266 | if ((a)) \ |
267 | (b)++; \ |
268 | else \ |
269 | (c)++; \ |
270 | } while (0) |
271 | |
272 | void test_macro7(int in, int &out1, int &out2) { |
273 | COND_INCR(in, out1, out1); |
274 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
275 | // CHECK-MESSAGES: :[[@LINE-9]]:5: note: expanded from macro 'COND_INCR' |
276 | // CHECK-MESSAGES: :[[@LINE-3]]:3: note: else branch starts here |
277 | // CHECK-MESSAGES: :[[@LINE-9]]:5: note: expanded from macro 'COND_INCR' |
278 | } |
279 | |
280 | void test_macro8(int in, int &out1, int &out2) { |
281 | COND_INCR(in, out1, out2); |
282 | } |
283 | |
284 | void test_macro9(int in, int &out1, int &out2) { |
285 | COND_INCR(in, out2, out2); |
286 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
287 | // CHECK-MESSAGES: :[[@LINE-21]]:5: note: expanded from macro 'COND_INCR' |
288 | // CHECK-MESSAGES: :[[@LINE-3]]:3: note: else branch starts here |
289 | // CHECK-MESSAGES: :[[@LINE-21]]:5: note: expanded from macro 'COND_INCR' |
290 | } |
291 | |
292 | #define CONCAT(a, b) a##b |
293 | |
294 | void test_macro10(int in, int &out) { |
295 | CONCAT(i, f) (in > 77) |
296 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
297 | out++; |
298 | CONCAT(el, se) |
299 | // CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here |
300 | out++; |
301 | } |
302 | |
303 | #define PROBLEM (-1) |
304 | |
305 | int test_macro11(int count) { |
306 | if (!count) |
307 | return PROBLEM; |
308 | else if (count == 13) |
309 | return -1; |
310 | else |
311 | return count * 2; |
312 | } |
313 | |
314 | #define IF if ( |
315 | #define THEN ) { |
316 | #define ELSE } else { |
317 | #define END } |
318 | |
319 | void test_macro12(int in, int &out) { |
320 | IF in > 77 THEN |
321 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
322 | // CHECK-MESSAGES: :[[@LINE-8]]:12: note: expanded from macro 'IF' |
323 | out++; |
324 | out++; |
325 | ELSE |
326 | // CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here |
327 | // CHECK-MESSAGES: :[[@LINE-11]]:16: note: expanded from macro 'ELSE' |
328 | out++; |
329 | out++; |
330 | END |
331 | } |
332 | |
333 | // A hack for implementing a switch with no fallthrough: |
334 | #define SWITCH(x) switch (x) { |
335 | #define CASE(x) break; case (x): |
336 | #define DEFAULT break; default: |
337 | |
338 | void test_macro13(int in, int &out) { |
339 | SWITCH(in) |
340 | // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] |
341 | CASE(1) |
342 | out++; |
343 | out++; |
344 | CASE(2) |
345 | out++; |
346 | out++; |
347 | CASE(3) |
348 | out++; |
349 | out++; |
350 | // CHECK-MESSAGES: :[[@LINE-15]]:24: note: expanded from macro 'CASE' |
351 | // CHECK-MESSAGES: :[[@LINE+1]]:9: note: last of these clones ends here |
352 | CASE(4) |
353 | out++; |
354 | CASE(5) |
355 | // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] |
356 | CASE(6) |
357 | out--; |
358 | CASE(7) |
359 | out--; |
360 | // CHECK-MESSAGES: :[[@LINE-25]]:24: note: expanded from macro 'CASE' |
361 | // CHECK-MESSAGES: :[[@LINE+2]]:9: note: last of these clones ends here |
362 | // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] |
363 | CASE(8) |
364 | out++; |
365 | out++; |
366 | CASE(9) |
367 | out++; |
368 | out++; |
369 | // CHECK-MESSAGES: :[[@LINE-34]]:24: note: expanded from macro 'CASE' |
370 | // CHECK-MESSAGES: :[[@LINE+2]]:12: note: last of these clones ends here |
371 | // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] |
372 | DEFAULT |
373 | out--; |
374 | out--; |
375 | CASE(10) |
376 | out--; |
377 | out--; |
378 | // CHECK-MESSAGES: :[[@LINE-42]]:24: note: expanded from macro 'DEFAULT' |
379 | // CHECK-MESSAGES: :[[@LINE+1]]:9: note: last of these clones ends here |
380 | CASE(12) |
381 | out++; |
382 | CASE(13) |
383 | out++; |
384 | END |
385 | } |
386 | |
387 | //=========--------------------==========// |
388 | |
389 | void test_chain1(int in, int &out) { |
390 | if (in > 77) |
391 | // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] |
392 | out++; |
393 | // CHECK-MESSAGES: :[[@LINE-1]]:10: note: end of the original |
394 | else if (in > 55) |
395 | // CHECK-MESSAGES: :[[@LINE+1]]:5: note: clone 1 starts here |
396 | out++; |
397 | |
398 | out++; |
399 | } |
400 | |
401 | void test_chain2(int in, int &out) { |
402 | if (in > 77) |
403 | // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] |
404 | out++; |
405 | // CHECK-MESSAGES: :[[@LINE-1]]:10: note: end of the original |
406 | else if (in > 55) |
407 | // CHECK-MESSAGES: :[[@LINE+1]]:5: note: clone 1 starts here |
408 | out++; |
409 | else if (in > 42) |
410 | out--; |
411 | else if (in > 28) |
412 | // CHECK-MESSAGES: :[[@LINE+1]]:5: note: clone 2 starts here |
413 | out++; |
414 | else if (in > 12) { |
415 | out++; |
416 | out *= 7; |
417 | } else if (in > 7) { |
418 | // CHECK-MESSAGES: :[[@LINE-1]]:22: note: clone 3 starts here |
419 | out++; |
420 | } |
421 | } |
422 | |
423 | void test_chain3(int in, int &out) { |
424 | if (in > 77) { |
425 | // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: repeated branch body in conditional chain [bugprone-branch-clone] |
426 | out++; |
427 | out++; |
428 | // CHECK-MESSAGES: :[[@LINE+1]]:4: note: end of the original |
429 | } else if (in > 55) { |
430 | // CHECK-MESSAGES: :[[@LINE-1]]:23: note: clone 1 starts here |
431 | out++; |
432 | out++; |
433 | } else if (in > 42) |
434 | out--; |
435 | else if (in > 28) { |
436 | // CHECK-MESSAGES: :[[@LINE-1]]:21: note: clone 2 starts here |
437 | out++; |
438 | out++; |
439 | } else if (in > 12) { |
440 | out++; |
441 | out++; |
442 | out++; |
443 | out *= 7; |
444 | } else if (in > 7) { |
445 | // CHECK-MESSAGES: :[[@LINE-1]]:22: note: clone 3 starts here |
446 | out++; |
447 | out++; |
448 | } |
449 | } |
450 | |
451 | // In this chain there are two clone families; notice that the checker |
452 | // describes all branches of the first one before mentioning the second one. |
453 | void test_chain4(int in, int &out) { |
454 | if (in > 77) { |
455 | // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: repeated branch body in conditional chain [bugprone-branch-clone] |
456 | out++; |
457 | out++; |
458 | // CHECK-MESSAGES: :[[@LINE+1]]:4: note: end of the original |
459 | } else if (in > 55) { |
460 | // CHECK-MESSAGES: :[[@LINE-1]]:23: note: clone 1 starts here |
461 | // CHECK-MESSAGES: :[[@LINE+8]]:21: note: clone 2 starts here |
462 | // CHECK-MESSAGES: :[[@LINE+15]]:22: note: clone 3 starts here |
463 | out++; |
464 | out++; |
465 | } else if (in > 42) |
466 | // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] |
467 | out--; |
468 | // CHECK-MESSAGES: :[[@LINE-1]]:10: note: end of the original |
469 | else if (in > 28) { |
470 | out++; |
471 | out++; |
472 | } else if (in > 12) { |
473 | out++; |
474 | out++; |
475 | out++; |
476 | out *= 7; |
477 | } else if (in > 7) { |
478 | out++; |
479 | out++; |
480 | } else if (in > -3) { |
481 | // CHECK-MESSAGES: :[[@LINE-1]]:23: note: clone 1 starts here |
482 | out--; |
483 | } |
484 | } |
485 | |
486 | void test_chain5(int in, int &out) { |
487 | if (in > 77) |
488 | // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] |
489 | out++; |
490 | // CHECK-MESSAGES: :[[@LINE-1]]:10: note: end of the original |
491 | else if (in > 55) |
492 | // CHECK-MESSAGES: :[[@LINE+1]]:5: note: clone 1 starts here |
493 | out++; |
494 | else if (in > 42) |
495 | out--; |
496 | else if (in > 28) |
497 | // CHECK-MESSAGES: :[[@LINE+1]]:5: note: clone 2 starts here |
498 | out++; |
499 | else if (in > 12) { |
500 | out++; |
501 | out *= 7; |
502 | } else { |
503 | // CHECK-MESSAGES: :[[@LINE-1]]:10: note: clone 3 starts here |
504 | out++; |
505 | } |
506 | } |
507 | |
508 | void test_chain6(int in, int &out) { |
509 | if (in > 77) { |
510 | // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: repeated branch body in conditional chain [bugprone-branch-clone] |
511 | out++; |
512 | out++; |
513 | // CHECK-MESSAGES: :[[@LINE+1]]:4: note: end of the original |
514 | } else if (in > 55) { |
515 | // CHECK-MESSAGES: :[[@LINE-1]]:23: note: clone 1 starts here |
516 | out++; |
517 | out++; |
518 | } else if (in > 42) |
519 | out--; |
520 | else if (in > 28) { |
521 | // CHECK-MESSAGES: :[[@LINE-1]]:21: note: clone 2 starts here |
522 | out++; |
523 | out++; |
524 | } else if (in > 12) { |
525 | out++; |
526 | out++; |
527 | out++; |
528 | out *= 7; |
529 | } else { |
530 | // CHECK-MESSAGES: :[[@LINE-1]]:10: note: clone 3 starts here |
531 | out++; |
532 | out++; |
533 | } |
534 | } |
535 | |
536 | void test_nested(int a, int b, int c, int &out) { |
537 | if (a > 5) { |
538 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
539 | // CHECK-MESSAGES: :[[@LINE+27]]:5: note: else branch starts here |
540 | if (b > 5) { |
541 | // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: repeated branch body in conditional chain [bugprone-branch-clone] |
542 | // CHECK-MESSAGES: :[[@LINE+9]]:6: note: end of the original |
543 | // CHECK-MESSAGES: :[[@LINE+8]]:24: note: clone 1 starts here |
544 | // CHECK-MESSAGES: :[[@LINE+14]]:12: note: clone 2 starts here |
545 | if (c > 5) |
546 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: if with identical then and else branches [bugprone-branch-clone] |
547 | out++; |
548 | else |
549 | // CHECK-MESSAGES: :[[@LINE-1]]:7: note: else branch starts here |
550 | out++; |
551 | } else if (b > 15) { |
552 | if (c > 5) |
553 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: if with identical then and else branches [bugprone-branch-clone] |
554 | out++; |
555 | else |
556 | // CHECK-MESSAGES: :[[@LINE-1]]:7: note: else branch starts here |
557 | out++; |
558 | } else { |
559 | if (c > 5) |
560 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: if with identical then and else branches [bugprone-branch-clone] |
561 | out++; |
562 | else |
563 | // CHECK-MESSAGES: :[[@LINE-1]]:7: note: else branch starts here |
564 | out++; |
565 | } |
566 | } else { |
567 | if (b > 5) { |
568 | // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: repeated branch body in conditional chain [bugprone-branch-clone] |
569 | // CHECK-MESSAGES: :[[@LINE+9]]:6: note: end of the original |
570 | // CHECK-MESSAGES: :[[@LINE+8]]:24: note: clone 1 starts here |
571 | // CHECK-MESSAGES: :[[@LINE+14]]:12: note: clone 2 starts here |
572 | if (c > 5) |
573 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: if with identical then and else branches [bugprone-branch-clone] |
574 | out++; |
575 | else |
576 | // CHECK-MESSAGES: :[[@LINE-1]]:7: note: else branch starts here |
577 | out++; |
578 | } else if (b > 15) { |
579 | if (c > 5) |
580 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: if with identical then and else branches [bugprone-branch-clone] |
581 | out++; |
582 | else |
583 | // CHECK-MESSAGES: :[[@LINE-1]]:7: note: else branch starts here |
584 | out++; |
585 | } else { |
586 | if (c > 5) |
587 | // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: if with identical then and else branches [bugprone-branch-clone] |
588 | out++; |
589 | else |
590 | // CHECK-MESSAGES: :[[@LINE-1]]:7: note: else branch starts here |
591 | out++; |
592 | } |
593 | } |
594 | } |
595 | |
596 | //=========--------------------==========// |
597 | |
598 | template <class T> |
599 | void test_template_not_instantiated(const T &t) { |
600 | int a; |
601 | if (t) |
602 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
603 | a++; |
604 | else |
605 | // CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here |
606 | a++; |
607 | } |
608 | |
609 | template <class T> |
610 | void test_template_instantiated(const T &t) { |
611 | int a; |
612 | if (t) |
613 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
614 | a++; |
615 | else |
616 | // CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here |
617 | a++; |
618 | } |
619 | |
620 | template void test_template_instantiated<int>(const int &t); |
621 | |
622 | template <class T> |
623 | void test_template2(T t, int a) { |
624 | if (a) { |
625 | T b(0); |
626 | a += b; |
627 | } else { |
628 | int b(0); |
629 | a += b; |
630 | } |
631 | } |
632 | |
633 | template void test_template2<int>(int t, int a); |
634 | |
635 | template <class T> |
636 | void test_template3(T t, int a) { |
637 | if (a) { |
638 | T b(0); |
639 | a += b; |
640 | } else { |
641 | int b(0); |
642 | a += b; |
643 | } |
644 | } |
645 | |
646 | template void test_template3<short>(short t, int a); |
647 | |
648 | template <class T> |
649 | void test_template_two_instances(T t, int &a) { |
650 | if (a) { |
651 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
652 | a += int(t); |
653 | } else { |
654 | // CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here |
655 | a += int(t); |
656 | } |
657 | } |
658 | |
659 | template void test_template_two_instances<short>(short t, int &a); |
660 | template void test_template_two_instances<long>(long t, int &a); |
661 | |
662 | class C { |
663 | int member; |
664 | void inline_method(int arg) { |
665 | if (arg) |
666 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: if with identical then and else branches [bugprone-branch-clone] |
667 | member = 3; |
668 | else |
669 | // CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here |
670 | member = 3; |
671 | } |
672 | int other_method(); |
673 | }; |
674 | |
675 | int C::other_method() { |
676 | if (member) { |
677 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] |
678 | return 8; |
679 | } else { |
680 | // CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here |
681 | return 8; |
682 | } |
683 | } |
684 | |
685 | //=========--------------------==========// |
686 | |
687 | int simple_switch(char ch) { |
688 | switch (ch) { |
689 | // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] |
690 | case 'a': |
691 | return 10; |
692 | case 'A': |
693 | return 10; |
694 | // CHECK-MESSAGES: :[[@LINE-1]]:14: note: last of these clones ends here |
695 | // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] |
696 | case 'b': |
697 | return 11; |
698 | case 'B': |
699 | return 11; |
700 | // CHECK-MESSAGES: :[[@LINE-1]]:14: note: last of these clones ends here |
701 | // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] |
702 | case 'c': |
703 | return 10; |
704 | case 'C': |
705 | return 10; |
706 | // CHECK-MESSAGES: :[[@LINE-1]]:14: note: last of these clones ends here |
707 | default: |
708 | return 0; |
709 | } |
710 | } |
711 | |
712 | int long_sequence_switch(char ch) { |
713 | switch (ch) { |
714 | // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: switch has 7 consecutive identical branches [bugprone-branch-clone] |
715 | case 'a': |
716 | return 10; |
717 | case 'A': |
718 | return 10; |
719 | case 'b': |
720 | return 10; |
721 | case 'B': |
722 | return 10; |
723 | case 'c': |
724 | return 10; |
725 | case 'C': |
726 | return 10; |
727 | default: |
728 | return 10; |
729 | // CHECK-MESSAGES: :[[@LINE-1]]:14: note: last of these clones ends here |
730 | } |
731 | } |
732 | |
733 | int nested_switch(int a, int b, int c) { |
734 | switch (a) { |
735 | // CHECK-MESSAGES: :[[@LINE+2]]:3: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] |
736 | // CHECK-MESSAGES: :[[@LINE+114]]:6: note: last of these clones ends here |
737 | case 1: |
738 | switch (b) { |
739 | // CHECK-MESSAGES: :[[@LINE+2]]:5: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] |
740 | // CHECK-MESSAGES: :[[@LINE+33]]:8: note: last of these clones ends here |
741 | case 1: |
742 | switch (c) { |
743 | // CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] |
744 | case 1: |
745 | return 42; |
746 | case 2: |
747 | return 42; |
748 | default: |
749 | return 42; |
750 | // CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here |
751 | } |
752 | case 2: |
753 | switch (c) { |
754 | // CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] |
755 | case 1: |
756 | return 42; |
757 | case 2: |
758 | return 42; |
759 | default: |
760 | return 42; |
761 | // CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here |
762 | } |
763 | default: |
764 | switch (c) { |
765 | // CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] |
766 | case 1: |
767 | return 42; |
768 | case 2: |
769 | return 42; |
770 | default: |
771 | return 42; |
772 | // CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here |
773 | } |
774 | } |
775 | case 2: |
776 | switch (b) { |
777 | // CHECK-MESSAGES: :[[@LINE+2]]:5: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] |
778 | // CHECK-MESSAGES: :[[@LINE+33]]:8: note: last of these clones ends here |
779 | case 1: |
780 | switch (c) { |
781 | // CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] |
782 | case 1: |
783 | return 42; |
784 | case 2: |
785 | return 42; |
786 | default: |
787 | return 42; |
788 | // CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here |
789 | } |
790 | case 2: |
791 | switch (c) { |
792 | // CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] |
793 | case 1: |
794 | return 42; |
795 | case 2: |
796 | return 42; |
797 | default: |
798 | return 42; |
799 | // CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here |
800 | } |
801 | default: |
802 | switch (c) { |
803 | // CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] |
804 | case 1: |
805 | return 42; |
806 | case 2: |
807 | return 42; |
808 | default: |
809 | return 42; |
810 | // CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here |
811 | } |
812 | } |
813 | default: |
814 | switch (b) { |
815 | // CHECK-MESSAGES: :[[@LINE+2]]:5: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] |
816 | // CHECK-MESSAGES: :[[@LINE+33]]:8: note: last of these clones ends here |
817 | case 1: |
818 | switch (c) { |
819 | // CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] |
820 | case 1: |
821 | return 42; |
822 | case 2: |
823 | return 42; |
824 | default: |
825 | return 42; |
826 | // CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here |
827 | } |
828 | case 2: |
829 | switch (c) { |
830 | // CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] |
831 | case 1: |
832 | return 42; |
833 | case 2: |
834 | return 42; |
835 | default: |
836 | return 42; |
837 | // CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here |
838 | } |
839 | default: |
840 | switch (c) { |
841 | // CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] |
842 | case 1: |
843 | return 42; |
844 | case 2: |
845 | return 42; |
846 | default: |
847 | return 42; |
848 | // CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here |
849 | } |
850 | } |
851 | } |
852 | } |
853 | |
854 | //=========--------------------==========// |
855 | |
856 | // This should not produce warnings, as in switch statements we only report |
857 | // identical branches when they are consecutive. Also note that a branch |
858 | // terminated by a break is different from a branch terminated by the end of |
859 | // the switch statement. |
860 | int interleaved_cases(int a, int b) { |
861 | switch (a) { |
862 | case 3: |
863 | case 4: |
864 | b = 2; |
865 | break; |
866 | case 5: |
867 | b = 3; |
868 | break; |
869 | case 6: |
870 | b = 2; |
871 | break; |
872 | case 7: |
873 | if (b % 2) { |
874 | b++; |
875 | } else { |
876 | b++; |
877 | break; |
878 | } |
879 | b = 2; |
880 | break; |
881 | case 8: |
882 | b = 2; |
883 | case 9: |
884 | b = 3; |
885 | break; |
886 | default: |
887 | b = 3; |
888 | } |
889 | return b; |
890 | } |
891 | |
892 | |
893 | // A case: or default: is only considered to be the start of a branch if it is a direct child of the CompoundStmt forming the body of the switch |
894 | int buried_cases(int foo) { |
895 | switch (foo) { |
896 | { |
897 | case 36: |
898 | return 8; |
899 | default: |
900 | return 8; |
901 | } |
902 | } |
903 | } |
904 | |
905 | // Here the `case 7:` is a child statement of the GotoLabelStmt, so the checker |
906 | // thinks that it is part of the `case 9:` branch. While this result is |
907 | // counterintuitve, mixing goto labels and switch statements in this fashion is |
908 | // pretty rare, so it does not deserve a special case in the checker code. |
909 | int decorated_cases(int z) { |
910 | if (!(z % 777)) { |
911 | goto lucky; |
912 | } |
913 | switch (z) { |
914 | // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] |
915 | case 1: |
916 | case 2: |
917 | case 3: |
918 | z++; |
919 | break; |
920 | case 4: |
921 | case 5: |
922 | z++; |
923 | break; |
924 | // CHECK-MESSAGES: :[[@LINE-1]]:10: note: last of these clones ends here |
925 | case 9: |
926 | z++; |
927 | break; |
928 | lucky: |
929 | case 7: |
930 | z += 3; |
931 | z *= 2; |
932 | break; |
933 | case 92: |
934 | z += 3; |
935 | z *= 2; |
936 | break; |
937 | default: |
938 | z++; |
939 | } |
940 | return z + 92; |
941 | } |
942 | |
943 | // The child of the switch statement is not necessarily a compound statement, |
944 | // do not crash in this unusual case. |
945 | char no_real_body(int in, int &out) { |
946 | switch (in) |
947 | case 42: |
948 | return 'A'; |
949 | |
950 | if (in > 77) |
951 | // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone] |
952 | out++; |
953 | // CHECK-MESSAGES: :[[@LINE-1]]:10: note: end of the original |
954 | else if (in > 55) |
955 | // CHECK-MESSAGES: :[[@LINE+1]]:5: note: clone 1 starts here |
956 | out++; |
957 | else if (in > 34) |
958 | // CHECK-MESSAGES: :[[@LINE+1]]:5: note: clone 2 starts here |
959 | out++; |
960 | |
961 | return '|'; |
962 | } |
963 | |
964 | // Duff's device [https://en.wikipedia.org/wiki/Duff's_device] |
965 | // The check does not try to distinguish branches in this sort of convoluted |
966 | // code, but it should avoid crashing. |
967 | void send(short *to, short *from, int count) |
968 | { |
969 | int n = (count + 7) / 8; |
970 | switch (count % 8) { |
971 | case 0: do { *to = *from++; |
972 | case 7: *to = *from++; |
973 | case 6: *to = *from++; |
974 | case 5: *to = *from++; |
975 | case 4: *to = *from++; |
976 | case 3: *to = *from++; |
977 | case 2: *to = *from++; |
978 | case 1: *to = *from++; |
979 | } while (--n > 0); |
980 | } |
981 | } |
982 | |
983 | //=========--------------------==========// |
984 | |
985 | void ternary1(bool b, int &x) { |
986 | // CHECK-MESSAGES: :[[@LINE+1]]:6: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] |
987 | (b ? x : x) = 42; |
988 | } |
989 | |
990 | int ternary2(bool b, int x) { |
991 | // CHECK-MESSAGES: :[[@LINE+1]]:12: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] |
992 | return b ? 42 : 42; |
993 | } |
994 | |
995 | int ternary3(bool b, int x) { |
996 | return b ? 42 : 43; |
997 | } |
998 | |
999 | int ternary4(bool b, int x) { |
1000 | return b ? true ? 45 : 44 : false ? 45 : 44; |
1001 | } |
1002 | |
1003 | // We do not detect chains of conditional operators. |
1004 | int ternary5(bool b1, bool b2, int x) { |
1005 | return b1 ? 42 : b2 ? 43 : 42; |
1006 | } |
1007 | |
1008 | #define SWITCH_WITH_LBRACE(b) switch (b) { |
1009 | #define SEMICOLON_CASE_COLON(b) \ |
1010 | ; \ |
1011 | case b: |
1012 | int d, e; |
1013 | void dontCrash() { |
1014 | SWITCH_WITH_LBRACE(d) |
1015 | // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] |
1016 | SEMICOLON_CASE_COLON(1) |
1017 | e++; |
1018 | e++; |
1019 | SEMICOLON_CASE_COLON(2) |
1020 | e++; |
1021 | e++; |
1022 | // CHECK-MESSAGES: :[[@LINE-11]]:3: note: expanded from macro 'SEMICOLON_CASE_COLON' |
1023 | // CHECK-MESSAGES: :[[@LINE+1]]:23: note: last of these clones ends here |
1024 | SEMICOLON_CASE_COLON(3); |
1025 | } |
1026 | } |
1027 | |
1028 | namespace PR62693 { |
1029 | class Object { |
1030 | public: |
1031 | template <typename T> |
1032 | bool ConvertableTo() const; |
1033 | |
1034 | template <typename T> |
1035 | void Handle(); |
1036 | }; |
1037 | |
1038 | template <typename T> |
1039 | void update(Object &a) { |
1040 | if (a.ConvertableTo<char *>()) { |
1041 | a.Handle<char *>(); |
1042 | } else { |
1043 | a.Handle<T>(); |
1044 | } |
1045 | } |
1046 | |
1047 | template <typename T> |
1048 | void update2(Object &a) { |
1049 | if (a.ConvertableTo<char *>()) { |
1050 | a.Handle<char *>(); |
1051 | } else { |
1052 | a.Handle<T>(); |
1053 | } |
1054 | } |
1055 | |
1056 | void foo(Object &a) { |
1057 | update<int>(a); |
1058 | update2<char *>(a); |
1059 | } |
1060 | |
1061 | template <typename T> |
1062 | int branch_clone_in_template(T t) { |
1063 | // CHECK-MESSAGES: :[[@LINE+2]]:5: warning: if with identical then and else branches [bugprone-branch-clone] |
1064 | // CHECK-MESSAGES: :[[@LINE+3]]:7: note: else branch starts here |
1065 | if (t) { |
1066 | return 42; |
1067 | } else { |
1068 | return 42; |
1069 | } |
1070 | } |
1071 | } |
1072 | |