1 // RUN: %check_clang_tidy %s readability-else-after-return %t -- -- -fexceptions -std=c++17
2 
3 namespace std {
4 struct string {
5   string(const char *);
6   ~string();
7 };
8 } // namespace std
9 
10 struct my_exception {
11   my_exception(const std::string &s);
12 };
13 
f(int a)14 void 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(0);
32     if (a > 10)
33       return;
34   } else {
35     return;
36   }
37 
38   if (a > 0)
39     f(0);
40   else if (a > 10)
41     return;
42   else // comment-2
43   // CHECK-FIXES-NOT: {{^}}  // comment-2
44     f(0);
45 
46   if (a > 0)
47     if (a < 10)
48       return;
49     else // comment-3
50     // CHECK-FIXES-NOT: {{^}}    // comment-3
51       f(0);
52   else
53     if (a > 10)
54       return;
55     else // comment-4
56     // CHECK-FIXES-NOT: {{^}}    // comment-4
57       f(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(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(0);
73   }
74 }
75 
foo()76 void 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 
109 int g();
110 int h(int);
111 
declInConditionUsedInElse()112 int 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 }
declInConditionUnusedInElse()123 int 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 
varInitAndCondition()133 int 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 
varInitAndConditionUnusedInElse()145 int 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 
initAndCondition()155 int 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 
varInitAndConditionUnusedInElseWithDecl()166 int 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 
varInitAndCondVarUsedInElse()179 int 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 
lifeTimeExtensionTests(int a)192 int 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 
test_B44745()217 void 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 
testPPConditionals()230 void 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