diff options
author | Jonas Toth <jonas.toth@gmail.com> | 2018-12-05 09:16:25 +0000 |
---|---|---|
committer | Jonas Toth <jonas.toth@gmail.com> | 2018-12-05 09:16:25 +0000 |
commit | c4cad3dc217a3e4a8c04b1aa77a002a5a2ce32ae (patch) | |
tree | db683f22eaf777c6a10d26d8cac0004328ddca3b /clang-tools-extra/test | |
parent | 7a7df0bb5cb87954e8828cb67b2998ca8bbdf5a4 (diff) |
[clang-tidy] new check: bugprone-branch-clone
Summary:
Implement a check for detecting if/else if/else chains where two or more
branches are Type I clones of each other (that is, they contain identical code)
and for detecting switch statements where two or more consecutive branches are
Type I clones of each other.
Patch by donat.nagy.
Reviewers: alexfh, hokein, aaron.ballman, JonasToth
Reviewed By: JonasToth
Subscribers: MTC, lebedev.ri, whisperity, xazax.hun, Eugene.Zelenko, mgorny, rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D54757
Diffstat (limited to 'clang-tools-extra/test')
-rw-r--r-- | clang-tools-extra/test/clang-tidy/bugprone-branch-clone.cpp | 1017 |
1 files changed, 1017 insertions, 0 deletions
diff --git a/clang-tools-extra/test/clang-tidy/bugprone-branch-clone.cpp b/clang-tools-extra/test/clang-tidy/bugprone-branch-clone.cpp new file mode 100644 index 00000000000..8caa917b4d0 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/bugprone-branch-clone.cpp @@ -0,0 +1,1017 @@ +// RUN: %check_clang_tidy %s bugprone-branch-clone %t + +void test_basic1(int in, int &out) { + if (in > 77) +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + else +// CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here + out++; + + out++; +} + +void test_basic2(int in, int &out) { + if (in > 77) { +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + } + else { +// CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here + out++; + } + + out++; +} + +void test_basic3(int in, int &out) { + if (in > 77) { +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + } + else +// CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here + out++; + + out++; +} + +void test_basic4(int in, int &out) { + if (in > 77) { + out--; + } + else { + out++; + } +} + +void test_basic5(int in, int &out) { + if (in > 77) { + out++; + } + else { + out++; + out++; + } +} + +void test_basic6(int in, int &out) { + if (in > 77) { + out++; + } + else { + out++, out++; + } +} + +void test_basic7(int in, int &out) { + if (in > 77) { + out++; + out++; + } + else + out++; + + out++; +} + +void test_basic8(int in, int &out) { + if (in > 77) { +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + out++; + } else { +// CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here + out++; + out++; + } + + if (in % 2) + out++; +} + +void test_basic9(int in, int &out) { + if (in > 77) { +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + if (in % 2) + out++; + else + out--; + } else { +// CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here + if (in % 2) + out++; + else + out--; + } +} + +// If we remove the braces from the previous example, the check recognizes it +// as an `else if`. +void test_basic10(int in, int &out) { + if (in > 77) + if (in % 2) + out++; + else + out--; + else + if (in % 2) + out++; + else + out--; + +} + +void test_basic11(int in, int &out) { + if (in > 77) { +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + if (in % 2) + out++; + else + out--; + if (in % 3) + out++; + else + out--; + } else { +// CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here + if (in % 2) + out++; + else + out--; + if (in % 3) + out++; + else + out--; + } +} + +void test_basic12(int in, int &out) { + if (in > 77) { +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + } else { +// CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here + } +} + +void test_basic13(int in, int &out) { + if (in > 77) { + // Empty compound statement is not identical to null statement. + } else; +} + +// We use a comparison that ignores redundant parentheses: +void test_basic14(int in, int &out) { + if (in > 77) + out += 2; +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + else +// CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here + (out) += (2); +} + +void test_basic15(int in, int &out) { + if (in > 77) +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + ((out += 2)); + else +// CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here + out += 2; +} + +// ..but does not apply additional simplifications: +void test_basic16(int in, int &out) { + if (in > 77) + out += 2; + else + out += 1 + 1; +} + +// ..and does not forget important parentheses: +int test_basic17(int a, int b, int c, int mode) { + if (mode>8) + return (a + b) * c; + else + return a + b * c; +} + +//=========--------------------==========// + +#define PASTE_CODE(x) x + +void test_macro1(int in, int &out) { + PASTE_CODE( + if (in > 77) +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + else +// CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here + out++; + ) + + out--; +} + +void test_macro2(int in, int &out) { + PASTE_CODE( + if (in > 77) +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + ) + else +// CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here + out++; +} + +void test_macro3(int in, int &out) { + if (in > 77) +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + PASTE_CODE( + else +// CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here + out++; + ) +} + +void test_macro4(int in, int &out) { + if (in > 77) +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + else +// CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here + PASTE_CODE( + out++; + ) +} + +void test_macro5(int in, int &out) { + PASTE_CODE(if) (in > 77) +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + PASTE_CODE(else) +// CHECK-MESSAGES: :[[@LINE-1]]:14: note: else branch starts here + out++; +} + +#define OTHERWISE_INCREASE else out++ + +void test_macro6(int in, int &out) { + if (in > 77) + out++; +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + OTHERWISE_INCREASE; +// CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here +// CHECK-MESSAGES: :[[@LINE-8]]:28: note: expanded from macro 'OTHERWISE_INCREASE' +} + +#define COND_INCR(a, b, c) \ + do { \ + if ((a)) \ + (b)++; \ + else \ + (c)++; \ + } while (0) + +void test_macro7(int in, int &out1, int &out2) { + COND_INCR(in, out1, out1); +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] +// CHECK-MESSAGES: :[[@LINE-9]]:5: note: expanded from macro 'COND_INCR' +// CHECK-MESSAGES: :[[@LINE-3]]:3: note: else branch starts here +// CHECK-MESSAGES: :[[@LINE-8]]:5: note: expanded from macro 'COND_INCR' +} + +void test_macro8(int in, int &out1, int &out2) { + COND_INCR(in, out1, out2); +} + +void test_macro9(int in, int &out1, int &out2) { + COND_INCR(in, out2, out2); +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] +// CHECK-MESSAGES: :[[@LINE-21]]:5: note: expanded from macro 'COND_INCR' +// CHECK-MESSAGES: :[[@LINE-3]]:3: note: else branch starts here +// CHECK-MESSAGES: :[[@LINE-20]]:5: note: expanded from macro 'COND_INCR' +} + +#define CONCAT(a, b) a##b + +void test_macro10(int in, int &out) { + CONCAT(i, f) (in > 77) +// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + CONCAT(el, se) +// CHECK-MESSAGES: :[[@LINE-1]]:10: note: else branch starts here + out++; +} + +#define PROBLEM (-1) + +int test_macro11(int count) { + if (!count) +// CHECK-MESSAGES: :[[@LINE+1]]:5: warning: repeated branch in conditional chain [bugprone-branch-clone] + return PROBLEM; +// CHECK-MESSAGES: :[[@LINE-1]]:10: note: end of the original + else if (count == 13) +// CHECK-MESSAGES: :[[@LINE+1]]:5: note: clone 1 starts here + return -1; + else + return count * 2; +} + +#define IF if ( +#define THEN ) { +#define ELSE } else { +#define END } + +void test_macro12(int in, int &out) { + IF in > 77 THEN +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] +// CHECK-MESSAGES: :[[@LINE-8]]:12: note: expanded from macro 'IF' + out++; + out++; + ELSE +// CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here +// CHECK-MESSAGES: :[[@LINE-12]]:14: note: expanded from macro 'IF' + out++; + out++; + END +} + +// A hack for implementing a switch with no fallthrough: +#define SWITCH(x) switch (x) { +#define CASE(x) break; case (x): +#define DEFAULT break; default: + +void test_macro13(int in, int &out) { + SWITCH(in) +// CHECK-MESSAGES: :[[@LINE+1]]:5: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] +// CHECK-MESSAGES: :[[@LINE-6]]:24: note: expanded from macro 'CASE' + CASE(1) + out++; + out++; + CASE(2) + out++; + out++; + CASE(3) + out++; + out++; +// CHECK-MESSAGES: :[[@LINE+1]]:5: note: last of these clones ends here +// CHECK-MESSAGES: :[[@LINE-17]]:22: note: expanded from macro 'CASE' + CASE(4) + out++; + CASE(5) +// CHECK-MESSAGES: :[[@LINE+1]]:3: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] +// CHECK-MESSAGES: :[[@LINE-22]]:24: note: expanded from macro 'CASE' + CASE(6) + out--; + CASE(7) + out--; +// CHECK-MESSAGES: :[[@LINE+1]]:5: note: last of these clones ends here +// CHECK-MESSAGES: :[[@LINE-28]]:22: note: expanded from macro 'CASE' +// CHECK-MESSAGES: :[[@LINE+1]]:3: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] +// CHECK-MESSAGES: :[[@LINE-30]]:24: note: expanded from macro 'CASE' + CASE(8) + out++; + out++; + CASE(9) + out++; + out++; +// CHECK-MESSAGES: :[[@LINE+1]]:5: note: last of these clones ends here +// CHECK-MESSAGES: :[[@LINE-37]]:22: note: expanded from macro 'DEFAULT' +// CHECK-MESSAGES: :[[@LINE+1]]:3: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] +// CHECK-MESSAGES: :[[@LINE-39]]:24: note: expanded from macro 'DEFAULT' + DEFAULT + out--; + out--; + CASE(10) + out--; + out--; +// CHECK-MESSAGES: :[[@LINE+1]]:5: note: last of these clones ends here +// CHECK-MESSAGES: :[[@LINE-48]]:22: note: expanded from macro 'CASE' + CASE(12) + out++; + CASE(13) + out++; + END +} + +//=========--------------------==========// + +void test_chain1(int in, int &out) { + if (in > 77) +// CHECK-MESSAGES: :[[@LINE+1]]:5: warning: repeated branch in conditional chain [bugprone-branch-clone] + out++; +// CHECK-MESSAGES: :[[@LINE-1]]:10: note: end of the original + else if (in > 55) +// CHECK-MESSAGES: :[[@LINE+1]]:5: note: clone 1 starts here + out++; + + out++; +} + +void test_chain2(int in, int &out) { + if (in > 77) +// CHECK-MESSAGES: :[[@LINE+1]]:5: warning: repeated branch in conditional chain [bugprone-branch-clone] + out++; +// CHECK-MESSAGES: :[[@LINE-1]]:10: note: end of the original + else if (in > 55) +// CHECK-MESSAGES: :[[@LINE+1]]:5: note: clone 1 starts here + out++; + else if (in > 42) + out--; + else if (in > 28) +// CHECK-MESSAGES: :[[@LINE+1]]:5: note: clone 2 starts here + out++; + else if (in > 12) { + out++; + out *= 7; + } else if (in > 7) { +// CHECK-MESSAGES: :[[@LINE-1]]:22: note: clone 3 starts here + out++; + } +} + +void test_chain3(int in, int &out) { + if (in > 77) { +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: repeated branch in conditional chain [bugprone-branch-clone] + out++; + out++; +// CHECK-MESSAGES: :[[@LINE+1]]:4: note: end of the original + } else if (in > 55) { +// CHECK-MESSAGES: :[[@LINE-1]]:23: note: clone 1 starts here + out++; + out++; + } else if (in > 42) + out--; + else if (in > 28) { +// CHECK-MESSAGES: :[[@LINE-1]]:21: note: clone 2 starts here + out++; + out++; + } else if (in > 12) { + out++; + out++; + out++; + out *= 7; + } else if (in > 7) { +// CHECK-MESSAGES: :[[@LINE-1]]:22: note: clone 3 starts here + out++; + out++; + } +} + +// In this chain there are two clone families; notice that the checker +// describes all branches of the first one before mentioning the second one. +void test_chain4(int in, int &out) { + if (in > 77) { +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: repeated branch in conditional chain [bugprone-branch-clone] + out++; + out++; +// CHECK-MESSAGES: :[[@LINE+1]]:4: note: end of the original + } else if (in > 55) { +// CHECK-MESSAGES: :[[@LINE-1]]:23: note: clone 1 starts here +// CHECK-MESSAGES: :[[@LINE+8]]:21: note: clone 2 starts here +// CHECK-MESSAGES: :[[@LINE+15]]:22: note: clone 3 starts here + out++; + out++; + } else if (in > 42) +// CHECK-MESSAGES: :[[@LINE+1]]:5: warning: repeated branch in conditional chain [bugprone-branch-clone] + out--; +// CHECK-MESSAGES: :[[@LINE-1]]:10: note: end of the original + else if (in > 28) { + out++; + out++; + } else if (in > 12) { + out++; + out++; + out++; + out *= 7; + } else if (in > 7) { + out++; + out++; + } else if (in > -3) { +// CHECK-MESSAGES: :[[@LINE-1]]:23: note: clone 1 starts here + out--; + } +} + +void test_chain5(int in, int &out) { + if (in > 77) +// CHECK-MESSAGES: :[[@LINE+1]]:5: warning: repeated branch in conditional chain [bugprone-branch-clone] + out++; +// CHECK-MESSAGES: :[[@LINE-1]]:10: note: end of the original + else if (in > 55) +// CHECK-MESSAGES: :[[@LINE+1]]:5: note: clone 1 starts here + out++; + else if (in > 42) + out--; + else if (in > 28) +// CHECK-MESSAGES: :[[@LINE+1]]:5: note: clone 2 starts here + out++; + else if (in > 12) { + out++; + out *= 7; + } else { +// CHECK-MESSAGES: :[[@LINE-1]]:10: note: clone 3 starts here + out++; + } +} + +void test_chain6(int in, int &out) { + if (in > 77) { +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: repeated branch in conditional chain [bugprone-branch-clone] + out++; + out++; +// CHECK-MESSAGES: :[[@LINE+1]]:4: note: end of the original + } else if (in > 55) { +// CHECK-MESSAGES: :[[@LINE-1]]:23: note: clone 1 starts here + out++; + out++; + } else if (in > 42) + out--; + else if (in > 28) { +// CHECK-MESSAGES: :[[@LINE-1]]:21: note: clone 2 starts here + out++; + out++; + } else if (in > 12) { + out++; + out++; + out++; + out *= 7; + } else { +// CHECK-MESSAGES: :[[@LINE-1]]:10: note: clone 3 starts here + out++; + out++; + } +} + +void test_nested(int a, int b, int c, int &out) { + if (a > 5) { +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] +// CHECK-MESSAGES: :[[@LINE+27]]:5: note: else branch starts here + if (b > 5) { +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: repeated branch in conditional chain [bugprone-branch-clone] +// CHECK-MESSAGES: :[[@LINE+9]]:6: note: end of the original +// CHECK-MESSAGES: :[[@LINE+8]]:24: note: clone 1 starts here +// CHECK-MESSAGES: :[[@LINE+14]]:12: note: clone 2 starts here + if (c > 5) +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + else +// CHECK-MESSAGES: :[[@LINE-1]]:7: note: else branch starts here + out++; + } else if (b > 15) { + if (c > 5) +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + else +// CHECK-MESSAGES: :[[@LINE-1]]:7: note: else branch starts here + out++; + } else { + if (c > 5) +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + else +// CHECK-MESSAGES: :[[@LINE-1]]:7: note: else branch starts here + out++; + } + } else { + if (b > 5) { +// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: repeated branch in conditional chain [bugprone-branch-clone] +// CHECK-MESSAGES: :[[@LINE+9]]:6: note: end of the original +// CHECK-MESSAGES: :[[@LINE+8]]:24: note: clone 1 starts here +// CHECK-MESSAGES: :[[@LINE+14]]:12: note: clone 2 starts here + if (c > 5) +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + else +// CHECK-MESSAGES: :[[@LINE-1]]:7: note: else branch starts here + out++; + } else if (b > 15) { + if (c > 5) +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + else +// CHECK-MESSAGES: :[[@LINE-1]]:7: note: else branch starts here + out++; + } else { + if (c > 5) +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: if with identical then and else branches [bugprone-branch-clone] + out++; + else +// CHECK-MESSAGES: :[[@LINE-1]]:7: note: else branch starts here + out++; + } + } +} + +//=========--------------------==========// + +template <class T> +void test_template_not_instantiated(const T &t) { + int a; + if (t) +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + a++; + else +// CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here + a++; +} + +template <class T> +void test_template_instantiated(const T &t) { + int a; + if (t) +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + a++; + else +// CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here + a++; +} + +template void test_template_instantiated<int>(const int &t); + +template <class T> +void test_template2(T t, int a) { + if (a) { + T b(0); + a += b; + } else { + int b(0); + a += b; + } +} + +template void test_template2<int>(int t, int a); + +template <class T> +void test_template3(T t, int a) { + if (a) { + T b(0); + a += b; + } else { + int b(0); + a += b; + } +} + +template void test_template3<short>(short t, int a); + +template <class T> +void test_template_two_instances(T t, int &a) { + if (a) { +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + a += int(t); + } else { +// CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here + a += int(t); + } +} + +template void test_template_two_instances<short>(short t, int &a); +template void test_template_two_instances<long>(long t, int &a); + +class C { + int member; + void inline_method(int arg) { + if (arg) +// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: if with identical then and else branches [bugprone-branch-clone] + member = 3; + else +// CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here + member = 3; + } + int other_method(); +}; + +int C::other_method() { + if (member) { +// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone] + return 8; + } else { +// CHECK-MESSAGES: :[[@LINE-1]]:5: note: else branch starts here + return 8; + } +} + +//=========--------------------==========// + +int simple_switch(char ch) { + switch (ch) { +// CHECK-MESSAGES: :[[@LINE+1]]:3: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] + case 'a': + return 10; + case 'A': + return 10; +// CHECK-MESSAGES: :[[@LINE-1]]:14: note: last of these clones ends here +// CHECK-MESSAGES: :[[@LINE+1]]:3: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] + case 'b': + return 11; + case 'B': + return 11; +// CHECK-MESSAGES: :[[@LINE-1]]:14: note: last of these clones ends here +// CHECK-MESSAGES: :[[@LINE+1]]:3: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] + case 'c': + return 10; + case 'C': + return 10; +// CHECK-MESSAGES: :[[@LINE-1]]:14: note: last of these clones ends here + default: + return 0; + } +} + +int long_sequence_switch(char ch) { + switch (ch) { +// CHECK-MESSAGES: :[[@LINE+1]]:3: warning: switch has 7 consecutive identical branches [bugprone-branch-clone] + case 'a': + return 10; + case 'A': + return 10; + case 'b': + return 10; + case 'B': + return 10; + case 'c': + return 10; + case 'C': + return 10; + default: + return 10; +// CHECK-MESSAGES: :[[@LINE-1]]:14: note: last of these clones ends here + } +} + +int nested_switch(int a, int b, int c) { + switch (a) { +// CHECK-MESSAGES: :[[@LINE+2]]:3: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] +// CHECK-MESSAGES: :[[@LINE+114]]:6: note: last of these clones ends here + case 1: + switch (b) { +// CHECK-MESSAGES: :[[@LINE+2]]:5: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] +// CHECK-MESSAGES: :[[@LINE+33]]:8: note: last of these clones ends here + case 1: + switch (c) { +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] + case 1: + return 42; + case 2: + return 42; + default: + return 42; +// CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here + } + case 2: + switch (c) { +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] + case 1: + return 42; + case 2: + return 42; + default: + return 42; +// CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here + } + default: + switch (c) { +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] + case 1: + return 42; + case 2: + return 42; + default: + return 42; +// CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here + } + } + case 2: + switch (b) { +// CHECK-MESSAGES: :[[@LINE+2]]:5: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] +// CHECK-MESSAGES: :[[@LINE+33]]:8: note: last of these clones ends here + case 1: + switch (c) { +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] + case 1: + return 42; + case 2: + return 42; + default: + return 42; +// CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here + } + case 2: + switch (c) { +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] + case 1: + return 42; + case 2: + return 42; + default: + return 42; +// CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here + } + default: + switch (c) { +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] + case 1: + return 42; + case 2: + return 42; + default: + return 42; +// CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here + } + } + default: + switch (b) { +// CHECK-MESSAGES: :[[@LINE+2]]:5: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] +// CHECK-MESSAGES: :[[@LINE+33]]:8: note: last of these clones ends here + case 1: + switch (c) { +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] + case 1: + return 42; + case 2: + return 42; + default: + return 42; +// CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here + } + case 2: + switch (c) { +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] + case 1: + return 42; + case 2: + return 42; + default: + return 42; +// CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here + } + default: + switch (c) { +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: switch has 3 consecutive identical branches [bugprone-branch-clone] + case 1: + return 42; + case 2: + return 42; + default: + return 42; +// CHECK-MESSAGES: :[[@LINE-1]]:18: note: last of these clones ends here + } + } + } +} + +//=========--------------------==========// + +// This should not produce warnings, as in switch statements we only report +// identical branches when they are consecutive. Also note that a branch +// terminated by a break is different from a branch terminated by the end of +// the switch statement. +int interleaved_cases(int a, int b) { + switch (a) { + case 3: + case 4: + b = 2; + break; + case 5: + b = 3; + break; + case 6: + b = 2; + break; + case 7: + if (b % 2) { + b++; + } else { + b++; + break; + } + b = 2; + break; + case 8: + b = 2; + case 9: + b = 3; + break; + default: + b = 3; + } + return b; +} + + +// 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 +int buried_cases(int foo) { + switch (foo) { + { + case 36: + return 8; + default: + return 8; + } + } +} + +// Here the `case 7:` is a child statement of the GotoLabelStmt, so the checker +// thinks that it is part of the `case 9:` branch. While this result is +// counterintuitve, mixing goto labels and switch statements in this fashion is +// pretty rare, so it does not deserve a special case in the checker code. +int decorated_cases(int z) { + if (!(z % 777)) { + goto lucky; + } + switch (z) { +// CHECK-MESSAGES: :[[@LINE+1]]:3: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] + case 1: + case 2: + case 3: + z++; + break; + case 4: + case 5: + z++; + break; +// CHECK-MESSAGES: :[[@LINE-1]]:10: note: last of these clones ends here + case 9: + z++; + break; + lucky: + case 7: + z += 3; + z *= 2; + break; + case 92: + z += 3; + z *= 2; + break; + default: + z++; + } + return z + 92; +} + +// The child of the switch statement is not neccessarily a compound statement, +// do not crash in this unusual case. +char no_real_body(int in, int &out) { + switch (in) + case 42: + return 'A'; + + if (in > 77) +// CHECK-MESSAGES: :[[@LINE+1]]:5: warning: repeated branch in conditional chain [bugprone-branch-clone] + out++; +// CHECK-MESSAGES: :[[@LINE-1]]:10: note: end of the original + else if (in > 55) +// CHECK-MESSAGES: :[[@LINE+1]]:5: note: clone 1 starts here + out++; + else if (in > 34) +// CHECK-MESSAGES: :[[@LINE+1]]:5: note: clone 2 starts here + out++; + + return '|'; +} + +// Duff's device [https://en.wikipedia.org/wiki/Duff's_device] +// The check does not try to distinguish branches in this sort of convoluted +// code, but it should avoid crashing. +void send(short *to, short *from, int count) +{ + int n = (count + 7) / 8; + switch (count % 8) { + case 0: do { *to = *from++; + case 7: *to = *from++; + case 6: *to = *from++; + case 5: *to = *from++; + case 4: *to = *from++; + case 3: *to = *from++; + case 2: *to = *from++; + case 1: *to = *from++; + } while (--n > 0); + } +} + +//=========--------------------==========// + +void ternary1(bool b, int &x) { +// CHECK-MESSAGES: :[[@LINE+1]]:6: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] + (b ? x : x) = 42; +} + +int ternary2(bool b, int x) { +// CHECK-MESSAGES: :[[@LINE+1]]:12: warning: conditional operator with identical true and false expressions [bugprone-branch-clone] + return b ? 42 : 42; +} + +int ternary3(bool b, int x) { + return b ? 42 : 43; +} + +int ternary4(bool b, int x) { + return b ? true ? 45 : 44 : false ? 45 : 44; +} + +// We do not detect chains of conditional operators. +int ternary5(bool b1, bool b2 int x) { + return b1 ? 42 : b2 ? 43 : 42; +} |