summaryrefslogtreecommitdiff
path: root/clang-tools-extra/test
diff options
context:
space:
mode:
authorJonas Toth <jonas.toth@gmail.com>2018-12-05 09:16:25 +0000
committerJonas Toth <jonas.toth@gmail.com>2018-12-05 09:16:25 +0000
commitc4cad3dc217a3e4a8c04b1aa77a002a5a2ce32ae (patch)
treedb683f22eaf777c6a10d26d8cac0004328ddca3b /clang-tools-extra/test
parent7a7df0bb5cb87954e8828cb67b2998ca8bbdf5a4 (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.cpp1017
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;
+}