llvm-project/clang-tools-extra/test/clang-tidy/checkers/bugprone-branch-clone.cpp

1027 lines
26 KiB
C++

// 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 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 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 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);
}
}