// RUN: %check_clang_tidy %s readability-else-after-return %t -- -- -fexceptions -std=c++17
namespace std {
struct string {
string(const char *);
~string();
};
} // namespace std
struct my_exception {
my_exception(const std::string &s);
};
void f(int a) {
if (a > 0)
return;
else // comment-0
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'else' after 'return'
// CHECK-FIXES: {{^}} // comment-0
return;
if (a > 0) {
return;
} else { // comment-1
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
// CHECK-FIXES: {{^}} } // comment-1
return;
}
if (a > 0) {
f(0);
if (a > 10)
return;
} else {
return;
}
if (a > 0)
f(0);
else if (a > 10)
return;
else // comment-2
// CHECK-FIXES-NOT: {{^}} // comment-2
f(0);
if (a > 0)
if (a < 10)
return;
else // comment-3
// CHECK-FIXES-NOT: {{^}} // comment-3
f(0);
else
if (a > 10)
return;
else // comment-4
// CHECK-FIXES-NOT: {{^}} // comment-4
f(0);
if (a > 0) {
if (a < 10)
return;
else // comment-5
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
// CHECK-FIXES: {{^}} // comment-5
f(0);
} else {
if (a > 10)
return;
else // comment-6
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
// CHECK-FIXES: {{^}} // comment-6
f(0);
}
}
void foo() {
for (unsigned x = 0; x < 42; ++x) {
if (x) {
continue;
} else { // comment-7
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'continue'
// CHECK-FIXES: {{^}} } // comment-7
x++;
}
if (x) {
break;
} else { // comment-8
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'break'
// CHECK-FIXES: {{^}} } // comment-8
x++;
}
if (x) {
throw 42;
} else { // comment-9
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'throw'
// CHECK-FIXES: {{^}} } // comment-9
x++;
}
if (x) {
throw my_exception("foo");
} else { // comment-10
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'throw'
// CHECK-FIXES: {{^}} } // comment-10
x++;
}
}
}
int g();
int h(int);
int declInConditionUsedInElse() {
if (int X = g()) { // comment-11
// CHECK-FIXES: {{^}} int X = g();
// CHECK-FIXES-NEXT: {{^}}if (X) { // comment-11
return X;
} else { // comment-11
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
// CHECK-FIXES: {{^}} } // comment-11
return h(X);
}
}
int declInConditionUnusedInElse() {
if (int X = g()) {
return h(X);
} else { // comment-12
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
// CHECK-FIXES: {{^}} } // comment-12
return 0;
}
}
int varInitAndCondition() {
if (int X = g(); X != 0) { // comment-13
// CHECK-FIXES: {{^}} int X = g();
// CHECK-FIXES-NEXT: {{^}}if ( X != 0) { // comment-13
return X;
} else { // comment-13
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
// CHECK-FIXES: {{^}} } // comment-13
return h(X);
}
}
int varInitAndConditionUnusedInElse() {
if (int X = g(); X != 0) {
return X;
} else { // comment-14
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
// CHECK-FIXES: {{^}} } // comment-14
return 0;
}
}
int initAndCondition() {
int X;
if (X = g(); X != 0) {
return X;
} else { // comment-15
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
// CHECK-FIXES: {{^}} } // comment-15
return h(X);
}
}
int varInitAndConditionUnusedInElseWithDecl() {
int Y = g();
if (int X = g(); X != 0) {
return X;
} else { // comment-16
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
// CHECK-FIXES-NOT: {{^}} } //comment-16
int Y = g();
h(Y);
}
return Y;
}
int varInitAndCondVarUsedInElse() {
if (int X = g(); int Y = g()) { // comment-17
// CHECK-FIXES: {{^}} int X = g();
// CHECK-FIXES-NEXT: {{^}}int Y = g();
// CHECK-FIXES-NEXT: {{^}}if ( Y) { // comment-17
return X ? X : Y;
} else { // comment-17
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
// CHECK-FIXES: {{^}} } // comment-17
return X ? X : h(Y);
}
}
int lifeTimeExtensionTests(int a) {
if (a > 0) {
return a;
} else {
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
int b = 0;
h(b);
}
if (int b = a; (b & 1) == 0) {
return a;
} else {
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
b++;
}
if (int b = a; b > 1) { // comment-18
// CHECK-FIXES: {{^}} int b = a;
// CHECK-FIXES-NEXT: {{^}}if ( b > 1) { // comment-18
return a;
} else { // comment-18
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
// CHECK-FIXES: {{^}} } // comment-18
return b;
}
}
void test_B44745() {
// This is the actual minimum test case for the crash in bug 44745. We aren't
// too worried about the warning or fix here, more we don't want a crash.
// CHECK-MESSAGES: :[[@LINE+3]]:5: warning: do not use 'else' after 'return' [readability-else-after-return]
if (auto X = false) {
return;
} else {
for (;;) {
}
}
return;
}
void testPPConditionals() {
// These cases the return isn't inside the conditional so diagnose as normal.
if (true) {
return;
#if 1
#endif
} else {
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
return;
}
if (true) {
#if 1
#endif
return;
} else {
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
return;
}
// No return here in the AST, no special handling needed.
if (true) {
#if 0
return;
#endif
} else {
return;
}
// Return here is inside a preprocessor conditional block, ignore this case.
if (true) {
#if 1
return;
#endif
} else {
return;
}
// These cases, same as above but with an #else block.
if (true) {
#if 1
return;
#else
#endif
} else {
return;
}
if (true) {
#if 0
#else
return;
#endif
} else {
return;
}
// Ensure it can handle macros.
#define RETURN return
if (true) {
#if 1
RETURN;
#endif
} else {
return;
}
#define ELSE else
if (true) {
#if 1
return;
#endif
}
ELSE {
return;
}
// Whole statement is in a conditional block so diagnose as normal.
#if 1
if (true) {
return;
} else {
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
return;
}
#endif
}