xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/misc/no-recursion.cpp (revision 89a1d03e2b379e325daa5249411e414bbd995b5e)
1*89a1d03eSRichard // RUN: %check_clang_tidy %s misc-no-recursion %t
2*89a1d03eSRichard 
3*89a1d03eSRichard // We don't have the definition of this function,
4*89a1d03eSRichard // so we can't tell anything about it..
5*89a1d03eSRichard void external();
6*89a1d03eSRichard 
7*89a1d03eSRichard // This function is obviously not recursive.
no_recursion()8*89a1d03eSRichard void no_recursion() {
9*89a1d03eSRichard }
10*89a1d03eSRichard 
11*89a1d03eSRichard // Since we don't know what `external()` does,
12*89a1d03eSRichard // we don't know if this is recursive or not.
maybe_no_recursion()13*89a1d03eSRichard void maybe_no_recursion() {
14*89a1d03eSRichard   external();
15*89a1d03eSRichard }
16*89a1d03eSRichard 
17*89a1d03eSRichard // Function calls itself - obviously a recursion.
endless_recursion()18*89a1d03eSRichard void endless_recursion() {
19*89a1d03eSRichard   endless_recursion();
20*89a1d03eSRichard }
21*89a1d03eSRichard 
22*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-4]]:6: warning: function 'endless_recursion' is within a recursive call chain [misc-no-recursion]
23*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-5]]:6: note: example recursive call chain, starting from function 'endless_recursion'
24*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-5]]:3: note: Frame #1: function 'endless_recursion' calls function 'endless_recursion' here:
25*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-6]]:3: note: ... which was the starting point of the recursive call chain; there may be other cycles
26*89a1d03eSRichard 
27*89a1d03eSRichard bool external_oracle();
28*89a1d03eSRichard bool another_external_oracle();
29*89a1d03eSRichard 
30*89a1d03eSRichard // Function calls itself if some external function said so - recursion.
maybe_endless_recursion()31*89a1d03eSRichard void maybe_endless_recursion() {
32*89a1d03eSRichard   if (external_oracle())
33*89a1d03eSRichard     maybe_endless_recursion();
34*89a1d03eSRichard }
35*89a1d03eSRichard 
36*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-5]]:6: warning: function 'maybe_endless_recursion' is within a recursive call chain [misc-no-recursion]
37*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-6]]:6: note: example recursive call chain, starting from function 'maybe_endless_recursion'
38*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-5]]:5: note: Frame #1: function 'maybe_endless_recursion' calls function 'maybe_endless_recursion' here:
39*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-6]]:5: note: ... which was the starting point of the recursive call chain; there may be other cycles
40*89a1d03eSRichard 
41*89a1d03eSRichard // Obviously-constrained recursion.
recursive_countdown(unsigned x)42*89a1d03eSRichard void recursive_countdown(unsigned x) {
43*89a1d03eSRichard   if (x == 0)
44*89a1d03eSRichard     return;
45*89a1d03eSRichard   recursive_countdown(x - 1);
46*89a1d03eSRichard }
47*89a1d03eSRichard 
48*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-6]]:6: warning: function 'recursive_countdown' is within a recursive call chain [misc-no-recursion]
49*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-7]]:6: note: example recursive call chain, starting from function 'recursive_countdown'
50*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-5]]:3: note: Frame #1: function 'recursive_countdown' calls function 'recursive_countdown' here:
51*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-6]]:3: note: ... which was the starting point of the recursive call chain; there may be other cycles
52*89a1d03eSRichard 
53*89a1d03eSRichard void indirect_recursion();
conditionally_executed()54*89a1d03eSRichard void conditionally_executed() {
55*89a1d03eSRichard   if (external_oracle())
56*89a1d03eSRichard     indirect_recursion();
57*89a1d03eSRichard }
indirect_recursion()58*89a1d03eSRichard void indirect_recursion() {
59*89a1d03eSRichard   if (external_oracle())
60*89a1d03eSRichard     conditionally_executed();
61*89a1d03eSRichard }
62*89a1d03eSRichard 
63*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-9]]:6: warning: function 'conditionally_executed' is within a recursive call chain [misc-no-recursion]
64*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-6]]:6: note: example recursive call chain, starting from function 'indirect_recursion'
65*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-5]]:5: note: Frame #1: function 'indirect_recursion' calls function 'conditionally_executed' here:
66*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-10]]:5: note: Frame #2: function 'conditionally_executed' calls function 'indirect_recursion' here:
67*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-11]]:5: note: ... which was the starting point of the recursive call chain; there may be other cycles
68*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-10]]:6: warning: function 'indirect_recursion' is within a recursive call chain [misc-no-recursion]
69*89a1d03eSRichard 
70*89a1d03eSRichard void taint();
maybe_selfrecursion_with_two_backedges()71*89a1d03eSRichard void maybe_selfrecursion_with_two_backedges() {
72*89a1d03eSRichard   if (external_oracle())
73*89a1d03eSRichard     maybe_selfrecursion_with_two_backedges();
74*89a1d03eSRichard   taint();
75*89a1d03eSRichard   if (another_external_oracle())
76*89a1d03eSRichard     maybe_selfrecursion_with_two_backedges();
77*89a1d03eSRichard }
78*89a1d03eSRichard 
79*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-8]]:6: warning: function 'maybe_selfrecursion_with_two_backedges' is within a recursive call chain [misc-no-recursion]
80*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-9]]:6: note: example recursive call chain, starting from function 'maybe_selfrecursion_with_two_backedges'
81*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-8]]:5: note: Frame #1: function 'maybe_selfrecursion_with_two_backedges' calls function 'maybe_selfrecursion_with_two_backedges' here:
82*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-9]]:5: note: ... which was the starting point of the recursive call chain; there may be other cycles
83*89a1d03eSRichard 
84*89a1d03eSRichard void indirect_recursion_with_alternatives();
conditionally_executed_choice_0()85*89a1d03eSRichard void conditionally_executed_choice_0() {
86*89a1d03eSRichard   if (external_oracle())
87*89a1d03eSRichard     indirect_recursion_with_alternatives();
88*89a1d03eSRichard }
conditionally_executed_choice_1()89*89a1d03eSRichard void conditionally_executed_choice_1() {
90*89a1d03eSRichard   if (external_oracle())
91*89a1d03eSRichard     indirect_recursion_with_alternatives();
92*89a1d03eSRichard }
indirect_recursion_with_alternatives()93*89a1d03eSRichard void indirect_recursion_with_alternatives() {
94*89a1d03eSRichard   if (external_oracle())
95*89a1d03eSRichard     conditionally_executed_choice_0();
96*89a1d03eSRichard   else
97*89a1d03eSRichard     conditionally_executed_choice_1();
98*89a1d03eSRichard }
99*89a1d03eSRichard 
100*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-15]]:6: warning: function 'conditionally_executed_choice_0' is within a recursive call chain [misc-no-recursion]
101*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-8]]:6: note: example recursive call chain, starting from function 'indirect_recursion_with_alternatives'
102*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-7]]:5: note: Frame #1: function 'indirect_recursion_with_alternatives' calls function 'conditionally_executed_choice_0' here:
103*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-16]]:5: note: Frame #2: function 'conditionally_executed_choice_0' calls function 'indirect_recursion_with_alternatives' here:
104*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-17]]:5: note: ... which was the starting point of the recursive call chain; there may be other cycles
105*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-16]]:6: warning: function 'conditionally_executed_choice_1' is within a recursive call chain [misc-no-recursion]
106*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-13]]:6: warning: function 'indirect_recursion_with_alternatives' is within a recursive call chain [misc-no-recursion]
107*89a1d03eSRichard 
108*89a1d03eSRichard static void indirect_recursion_with_depth2();
conditionally_executed_depth1()109*89a1d03eSRichard static void conditionally_executed_depth1() {
110*89a1d03eSRichard   if (external_oracle())
111*89a1d03eSRichard     indirect_recursion_with_depth2();
112*89a1d03eSRichard }
conditionally_executed_depth0()113*89a1d03eSRichard static void conditionally_executed_depth0() {
114*89a1d03eSRichard   if (external_oracle())
115*89a1d03eSRichard     conditionally_executed_depth1();
116*89a1d03eSRichard }
indirect_recursion_with_depth2()117*89a1d03eSRichard void indirect_recursion_with_depth2() {
118*89a1d03eSRichard   if (external_oracle())
119*89a1d03eSRichard     conditionally_executed_depth0();
120*89a1d03eSRichard }
121*89a1d03eSRichard 
122*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-13]]:13: warning: function 'conditionally_executed_depth1' is within a recursive call chain [misc-no-recursion]
123*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-10]]:13: note: example recursive call chain, starting from function 'conditionally_executed_depth0'
124*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-9]]:5: note: Frame #1: function 'conditionally_executed_depth0' calls function 'conditionally_executed_depth1' here:
125*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-14]]:5: note: Frame #2: function 'conditionally_executed_depth1' calls function 'indirect_recursion_with_depth2' here:
126*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-7]]:5: note: Frame #3: function 'indirect_recursion_with_depth2' calls function 'conditionally_executed_depth0' here:
127*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-8]]:5: note: ... which was the starting point of the recursive call chain; there may be other cycles
128*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-15]]:13: warning: function 'conditionally_executed_depth0' is within a recursive call chain [misc-no-recursion]
129*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-12]]:6: warning: function 'indirect_recursion_with_depth2' is within a recursive call chain [misc-no-recursion]
130*89a1d03eSRichard 
131*89a1d03eSRichard int boo();
foo(int x=boo ())132*89a1d03eSRichard void foo(int x = boo()) {}
bar()133*89a1d03eSRichard void bar() {
134*89a1d03eSRichard   foo();
135*89a1d03eSRichard   foo();
136*89a1d03eSRichard }
boo()137*89a1d03eSRichard int boo() {
138*89a1d03eSRichard   bar();
139*89a1d03eSRichard   return 0;
140*89a1d03eSRichard }
141*89a1d03eSRichard 
142*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-9]]:6: warning: function 'bar' is within a recursive call chain [misc-no-recursion]
143*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-6]]:5: note: example recursive call chain, starting from function 'boo'
144*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-6]]:3: note: Frame #1: function 'boo' calls function 'bar' here:
145*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-13]]:18: note: Frame #2: function 'bar' calls function 'boo' here:
146*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-14]]:18: note: ... which was the starting point of the recursive call chain; there may be other cycles
147*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-10]]:5: warning: function 'boo' is within a recursive call chain [misc-no-recursion]
148*89a1d03eSRichard 
recursion_through_function_ptr()149*89a1d03eSRichard int recursion_through_function_ptr() {
150*89a1d03eSRichard   auto *ptr = &recursion_through_function_ptr;
151*89a1d03eSRichard   if (external_oracle())
152*89a1d03eSRichard     return ptr();
153*89a1d03eSRichard   return 0;
154*89a1d03eSRichard }
155*89a1d03eSRichard 
recursion_through_lambda()156*89a1d03eSRichard int recursion_through_lambda() {
157*89a1d03eSRichard   auto zz = []() {
158*89a1d03eSRichard     if (external_oracle())
159*89a1d03eSRichard       return recursion_through_lambda();
160*89a1d03eSRichard     return 0;
161*89a1d03eSRichard   };
162*89a1d03eSRichard   return zz();
163*89a1d03eSRichard }
164*89a1d03eSRichard 
165*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-9]]:5: warning: function 'recursion_through_lambda' is within a recursive call chain [misc-no-recursion]
166*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-9]]:13: note: example recursive call chain, starting from function 'operator()'
167*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-8]]:14: note: Frame #1: function 'operator()' calls function 'recursion_through_lambda' here:
168*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-6]]:10: note: Frame #2: function 'recursion_through_lambda' calls function 'operator()' here:
169*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-7]]:10: note: ... which was the starting point of the recursive call chain; there may be other cycles
170*89a1d03eSRichard // CHECK-NOTES: :[[@LINE-13]]:13: warning: function 'operator()' is within a recursive call chain [misc-no-recursion]
171*89a1d03eSRichard 
172*89a1d03eSRichard struct recursion_through_destructor {
~recursion_through_destructorrecursion_through_destructor173*89a1d03eSRichard   ~recursion_through_destructor() {
174*89a1d03eSRichard     if (external_oracle()) {
175*89a1d03eSRichard       recursion_through_destructor variable;
176*89a1d03eSRichard       // variable goes out of scope, it's destructor runs, and we are back here.
177*89a1d03eSRichard     }
178*89a1d03eSRichard   }
179*89a1d03eSRichard };
180