1// RUN: %check_clang_tidy %s readability-else-after-return %t -- -- -fexceptions -std=c++17
2
3namespace std {
4struct string {
5 string(const char *);
6 ~string();
7};
8} // namespace std
9
10struct my_exception {
11 my_exception(const std::string &s);
12};
13
14void f(int a) {
15 if (a > 0)
16 return;
17 else // comment-0
18 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'else' after 'return'
19 // CHECK-FIXES: {{^}} // comment-0
20 return;
21
22 if (a > 0) {
23 return;
24 } else { // comment-1
25 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
26 // CHECK-FIXES: {{^}} } // comment-1
27 return;
28 }
29
30 if (a > 0) {
31 f(a: 0);
32 if (a > 10)
33 return;
34 } else {
35 return;
36 }
37
38 if (a > 0)
39 f(a: 0);
40 else if (a > 10)
41 return;
42 else // comment-2
43 // CHECK-FIXES-NOT: {{^}} // comment-2
44 f(a: 0);
45
46 if (a > 0)
47 if (a < 10)
48 return;
49 else // comment-3
50 // CHECK-FIXES-NOT: {{^}} // comment-3
51 f(a: 0);
52 else
53 if (a > 10)
54 return;
55 else // comment-4
56 // CHECK-FIXES-NOT: {{^}} // comment-4
57 f(a: 0);
58
59 if (a > 0) {
60 if (a < 10)
61 return;
62 else // comment-5
63 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
64 // CHECK-FIXES: {{^}} // comment-5
65 f(a: 0);
66 } else {
67 if (a > 10)
68 return;
69 else // comment-6
70 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
71 // CHECK-FIXES: {{^}} // comment-6
72 f(a: 0);
73 }
74}
75
76void foo() {
77 for (unsigned x = 0; x < 42; ++x) {
78 if (x) {
79 continue;
80 } else { // comment-7
81 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'continue'
82 // CHECK-FIXES: {{^}} } // comment-7
83 x++;
84 }
85 if (x) {
86 break;
87 } else { // comment-8
88 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'break'
89 // CHECK-FIXES: {{^}} } // comment-8
90 x++;
91 }
92 if (x) {
93 throw 42;
94 } else { // comment-9
95 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'throw'
96 // CHECK-FIXES: {{^}} } // comment-9
97 x++;
98 }
99 if (x) {
100 throw my_exception("foo");
101 } else { // comment-10
102 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'throw'
103 // CHECK-FIXES: {{^}} } // comment-10
104 x++;
105 }
106 }
107}
108
109int g();
110int h(int);
111
112int declInConditionUsedInElse() {
113 if (int X = g()) { // comment-11
114 // CHECK-FIXES: {{^}} int X = g();
115 // CHECK-FIXES-NEXT: {{^}}if (X) { // comment-11
116 return X;
117 } else { // comment-11
118 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
119 // CHECK-FIXES: {{^}} } // comment-11
120 return h(X);
121 }
122}
123int declInConditionUnusedInElse() {
124 if (int X = g()) {
125 return h(X);
126 } else { // comment-12
127 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
128 // CHECK-FIXES: {{^}} } // comment-12
129 return 0;
130 }
131}
132
133int varInitAndCondition() {
134 if (int X = g(); X != 0) { // comment-13
135 // CHECK-FIXES: {{^}} int X = g();
136 // CHECK-FIXES-NEXT: {{^}}if ( X != 0) { // comment-13
137 return X;
138 } else { // comment-13
139 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
140 // CHECK-FIXES: {{^}} } // comment-13
141 return h(X);
142 }
143}
144
145int varInitAndConditionUnusedInElse() {
146 if (int X = g(); X != 0) {
147 return X;
148 } else { // comment-14
149 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
150 // CHECK-FIXES: {{^}} } // comment-14
151 return 0;
152 }
153}
154
155int initAndCondition() {
156 int X;
157 if (X = g(); X != 0) {
158 return X;
159 } else { // comment-15
160 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
161 // CHECK-FIXES: {{^}} } // comment-15
162 return h(X);
163 }
164}
165
166int varInitAndConditionUnusedInElseWithDecl() {
167 int Y = g();
168 if (int X = g(); X != 0) {
169 return X;
170 } else { // comment-16
171 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
172 // CHECK-FIXES-NOT: {{^}} } //comment-16
173 int Y = g();
174 h(Y);
175 }
176 return Y;
177}
178
179int varInitAndCondVarUsedInElse() {
180 if (int X = g(); int Y = g()) { // comment-17
181 // CHECK-FIXES: {{^}} int X = g();
182 // CHECK-FIXES-NEXT: {{^}}int Y = g();
183 // CHECK-FIXES-NEXT: {{^}}if ( Y) { // comment-17
184 return X ? X : Y;
185 } else { // comment-17
186 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
187 // CHECK-FIXES: {{^}} } // comment-17
188 return X ? X : h(Y);
189 }
190}
191
192int lifeTimeExtensionTests(int a) {
193 if (a > 0) {
194 return a;
195 } else {
196 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
197 int b = 0;
198 h(b);
199 }
200 if (int b = a; (b & 1) == 0) {
201 return a;
202 } else {
203 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
204 b++;
205 }
206 if (int b = a; b > 1) { // comment-18
207 // CHECK-FIXES: {{^}} int b = a;
208 // CHECK-FIXES-NEXT: {{^}}if ( b > 1) { // comment-18
209 return a;
210 } else { // comment-18
211 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
212 // CHECK-FIXES: {{^}} } // comment-18
213 return b;
214 }
215}
216
217void test_B44745() {
218 // This is the actual minimum test case for the crash in bug 44745. We aren't
219 // too worried about the warning or fix here, more we don't want a crash.
220 // CHECK-MESSAGES: :[[@LINE+3]]:5: warning: do not use 'else' after 'return' [readability-else-after-return]
221 if (auto X = false) {
222 return;
223 } else {
224 for (;;) {
225 }
226 }
227 return;
228}
229
230void testPPConditionals() {
231
232 // These cases the return isn't inside the conditional so diagnose as normal.
233 if (true) {
234 return;
235#if 1
236#endif
237 } else {
238 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
239 return;
240 }
241 if (true) {
242#if 1
243#endif
244 return;
245 } else {
246 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
247 return;
248 }
249
250 // No return here in the AST, no special handling needed.
251 if (true) {
252#if 0
253 return;
254#endif
255 } else {
256 return;
257 }
258
259 // Return here is inside a preprocessor conditional block, ignore this case.
260 if (true) {
261#if 1
262 return;
263#endif
264 } else {
265 return;
266 }
267
268 // These cases, same as above but with an #else block.
269 if (true) {
270#if 1
271 return;
272#else
273#endif
274 } else {
275 return;
276 }
277 if (true) {
278#if 0
279#else
280 return;
281#endif
282 } else {
283 return;
284 }
285
286// Ensure it can handle macros.
287#define RETURN return
288 if (true) {
289#if 1
290 RETURN;
291#endif
292 } else {
293 return;
294 }
295#define ELSE else
296 if (true) {
297#if 1
298 return;
299#endif
300 }
301 ELSE {
302 return;
303 }
304
305 // Whole statement is in a conditional block so diagnose as normal.
306#if 1
307 if (true) {
308 return;
309 } else {
310 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
311 return;
312 }
313#endif
314}
315

source code of clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return.cpp