Skip to content

Commit

Permalink
[clang-tidy] enhance readability-else-after-return
Browse files Browse the repository at this point in the history
`readability-else-after-return` only warns about `return` calls, but LLVM Coding
Standars stat that `throw`, `continue`, `goto`, etc after `return` calls are
bad, too.

Reviwers: alexfh, aaron.ballman

Differential Revision: https://reviews.llvm.org/D23265

llvm-svn: 278257
  • Loading branch information
kirillbobyrev committed Aug 10, 2016
1 parent 0bbad0f commit 34789ed
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 16 deletions.
23 changes: 16 additions & 7 deletions clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp
Expand Up @@ -19,20 +19,29 @@ namespace tidy {
namespace readability {

void ElseAfterReturnCheck::registerMatchers(MatchFinder *Finder) {
// FIXME: Support continue, break and throw.
const auto ControlFlowInterruptorMatcher =
stmt(anyOf(returnStmt().bind("return"), continueStmt().bind("continue"),
breakStmt().bind("break"), cxxThrowExpr().bind("throw")));
Finder->addMatcher(
compoundStmt(
forEach(ifStmt(hasThen(stmt(anyOf(returnStmt(),
compoundStmt(has(returnStmt()))))),
hasElse(stmt().bind("else")))
.bind("if"))),
stmt(forEach(
ifStmt(hasThen(stmt(
anyOf(ControlFlowInterruptorMatcher,
compoundStmt(has(ControlFlowInterruptorMatcher))))),
hasElse(stmt().bind("else")))
.bind("if"))),
this);
}

void ElseAfterReturnCheck::check(const MatchFinder::MatchResult &Result) {
const auto *If = Result.Nodes.getNodeAs<IfStmt>("if");
SourceLocation ElseLoc = If->getElseLoc();
DiagnosticBuilder Diag = diag(ElseLoc, "don't use else after return");
std::string ControlFlowInterruptor;
for (const auto *BindingName : {"return", "continue", "break", "throw"})
if (Result.Nodes.getNodeAs<Stmt>(BindingName))
ControlFlowInterruptor = BindingName;

DiagnosticBuilder Diag = diag(ElseLoc, "do not use 'else' after '%0'")
<< ControlFlowInterruptor;
Diag << tooling::fixit::createRemoval(ElseLoc);

// FIXME: Removing the braces isn't always safe. Do a more careful analysis.
Expand Down
Expand Up @@ -3,7 +3,62 @@
readability-else-after-return
=============================

`LLVM Coding Standards <http://llvm.org/docs/CodingStandards.html>`_ advises to
reduce indentation where possible and where it makes understanding code easier.
Early exit is one of the suggested enforcements of that. Please do not use
`else` or `else if` after something that interrupts control flow - like
`return`, `break`, `continue`, `throw`.

Flags the usages of ``else`` after ``return``.
The following piece of code illustrates how the check works. This piece of code:

http://llvm.org/docs/CodingStandards.html#don-t-use-else-after-a-return
.. code-block:: c++

void foo(int Value) {
int Local = 0;
for (int i = 0; i < 42; i++) {
if (Value == 1) {
return;
} else {
Local++;
}

if (Value == 2)
continue;
else
Local++;

if (Value == 3) {
throw 42;
} else {
Local++;
}
}
}


Would be transformed into:

.. code-block:: c++

void foo(int Value) {
int Local = 0;
for (int i = 0; i < 42; i++) {
if (Value == 1) {
return;
}
Local++;

if (Value == 2)
continue;
Local++;

if (Value == 3) {
throw 42;
}
Local++;
}
}


This checks helps to enforce this `Coding Standars recommendation
<http://llvm.org/docs/CodingStandards.html#don-t-use-else-after-a-return>`_.
Expand Up @@ -3,16 +3,16 @@
void f(int a) {
if (a > 0)
return;
else // comment
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: don't use else after return
// CHECK-FIXES: {{^}} // comment
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
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: don't use else after return
// CHECK-FIXES: } // comment
} else { // comment-1
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: do not use 'else' after 'return'
// CHECK-FIXES: {{^}} } // comment-1
return;
}

Expand All @@ -28,7 +28,34 @@ void f(int a) {
f(0);
else if (a > 10)
return;
else
else // comment-2
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'else' after 'return'
// CHECK-FIXES: {{^}} // comment-2
f(0);
}

void foo() {
for (unsigned x = 0; x < 42; ++x) {
if (x) {
continue;
} else { // comment-3
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'continue'
// CHECK-FIXES: {{^}} } // comment-3
x++;
}
if (x) {
break;
} else { // comment-4
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'break'
// CHECK-FIXES: {{^}} } // comment-4
x++;
}
if (x) {
throw 42;
} else { // comment-5
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: do not use 'else' after 'throw'
// CHECK-FIXES: {{^}} } // comment-5
x++;
}
}
}

0 comments on commit 34789ed

Please sign in to comment.