// RUN: %check_clang_tidy %s bugprone-branch-clone %t -- -- -fno-delayed-template-parsing 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; else (out) += (2); } void test_basic15(int in, int &out) { if (in > 77) ((out += 2)); else 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-2]]: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-9]]: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-21]]: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]]:3: warning: if with identical then and else branches [bugprone-branch-clone] out++; CONCAT(el, se) // CHECK-MESSAGES: :[[@LINE-1]]:3: note: else branch starts here out++; } #define PROBLEM (-1) int test_macro11(int count) { if (!count) return PROBLEM; else if (count == 13) 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-11]]:16: note: expanded from macro 'ELSE' 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] CASE(1) out++; out++; CASE(2) out++; out++; CASE(3) out++; out++; // CHECK-MESSAGES: :[[@LINE-15]]:24: note: expanded from macro 'CASE' // CHECK-MESSAGES: :[[@LINE+1]]:9: note: last of these clones ends here CASE(4) out++; CASE(5) // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] CASE(6) out--; CASE(7) out--; // CHECK-MESSAGES: :[[@LINE-25]]:24: note: expanded from macro 'CASE' // CHECK-MESSAGES: :[[@LINE+2]]:9: note: last of these clones ends here // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] CASE(8) out++; out++; CASE(9) out++; out++; // CHECK-MESSAGES: :[[@LINE-34]]:24: note: expanded from macro 'CASE' // CHECK-MESSAGES: :[[@LINE+2]]:12: note: last of these clones ends here // CHECK-MESSAGES: :[[@LINE+1]]:5: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] DEFAULT out--; out--; CASE(10) out--; out--; // CHECK-MESSAGES: :[[@LINE-42]]:24: note: expanded from macro 'DEFAULT' // CHECK-MESSAGES: :[[@LINE+1]]:9: note: last of these clones ends here 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 body 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 body 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 body 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 body 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 body 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 body 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 body 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 body 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 body 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 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 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(const int &t); template 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 t, int a); template 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 t, int a); template 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 t, int &a); template void test_template_two_instances(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 necessarily 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 body 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; } #define SWITCH_WITH_LBRACE(b) switch (b) { #define SEMICOLON_CASE_COLON(b) \ ; \ case b: int d, e; void dontCrash() { SWITCH_WITH_LBRACE(d) // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: switch has 2 consecutive identical branches [bugprone-branch-clone] SEMICOLON_CASE_COLON(1) e++; e++; SEMICOLON_CASE_COLON(2) e++; e++; // CHECK-MESSAGES: :[[@LINE-11]]:3: note: expanded from macro 'SEMICOLON_CASE_COLON' // CHECK-MESSAGES: :[[@LINE+1]]:23: note: last of these clones ends here SEMICOLON_CASE_COLON(3); } } namespace PR62693 { class Object { public: template bool ConvertableTo() const; template void Handle(); }; template void update(Object &a) { if (a.ConvertableTo()) { a.Handle(); } else { a.Handle(); } } template void update2(Object &a) { if (a.ConvertableTo()) { a.Handle(); } else { a.Handle(); } } void foo(Object &a) { update(a); update2(a); } template int branch_clone_in_template(T t) { // CHECK-MESSAGES: :[[@LINE+2]]:5: warning: if with identical then and else branches [bugprone-branch-clone] // CHECK-MESSAGES: :[[@LINE+3]]:7: note: else branch starts here if (t) { return 42; } else { return 42; } } }