Skip to content

Commit

Permalink
Fixes #7863; Add fixer for no-else-return
Browse files Browse the repository at this point in the history
  • Loading branch information
Xander Dumaine committed Jan 17, 2017
1 parent ca1f841 commit 7c08544
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 16 deletions.
2 changes: 2 additions & 0 deletions docs/rules/no-else-return.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

If an `if` block contains a `return` statement, the `else` block becomes unnecessary. Its contents can be placed outside of the block.

(fixable) The `--fix` option on the [command line](../user-guide/command-line-interface#fix) automatically fixes problems reported by this rule.

```js
function foo() {
if (x) {
Expand Down
44 changes: 42 additions & 2 deletions lib/rules/no-else-return.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ module.exports = {
recommended: false
},

schema: []
schema: [],

fixable: "code"
},

create(context) {
Expand All @@ -33,7 +35,45 @@ module.exports = {
* @returns {void}
*/
function displayReport(node) {
context.report({ node, message: "Unnecessary 'else' after 'return'." });
context.report({
node,
message: "Unnecessary 'else' after 'return'.",
fix: fixer => {
const sourceCode = context.getSourceCode();
const startToken = sourceCode.getTokenByRangeStart(node.start);
const elseToken = sourceCode.getTokenBefore(startToken);
const source = sourceCode.getText(node);
const lastIfToken = sourceCode.getTokenBefore(elseToken);
let fixedSource;

if (startToken.type === "Punctuator" && startToken.value === "{") {
const firstTokenOfElseBlock = sourceCode.getTokenAfter(startToken);

if (lastIfToken.value !== "}" &&
lastIfToken.value !== ";" &&
/^[([/+`-]/.test(firstTokenOfElseBlock.value)) {
return null;
}

const endToken = sourceCode.getLastToken(node);
const lastTokenOfElseBlock = sourceCode.getTokenBefore(endToken);

if (lastTokenOfElseBlock.value !== ";") {
const nextToken = sourceCode.getTokenAfter(endToken);

if (/^[([/+`-]/.test(nextToken.value) ||
nextToken.loc.start.line === lastTokenOfElseBlock.loc.start.line) {
return null;
}
}

fixedSource = source.substr(1, source.length - 2);
} else {
fixedSource = source;
}
return fixer.replaceTextRange([elseToken.start, node.end], fixedSource);
}
});
}

/**
Expand Down
85 changes: 71 additions & 14 deletions tests/lib/rules/no-else-return.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,79 @@ ruleTester.run("no-else-return", rule, {
"if (0) { if (0) {} else {} } else {}"
],
invalid: [
{ code: "function foo() { if (true) { return x; } else { return y; } }", errors: [{ message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }] },
{ code: "function foo() { if (true) { var x = bar; return x; } else { var y = baz; return y; } }", errors: [{ message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }] },
{ code: "function foo() { if (true) return x; else return y; }", errors: [{ message: "Unnecessary 'else' after 'return'.", type: "ReturnStatement" }] },
{ code: "function foo() { if (true) { if (false) return x; else return y; } else { return z; } }", errors: [{ message: "Unnecessary 'else' after 'return'.", type: "ReturnStatement" }, { message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }] },
{ code: "function foo() { if (true) { if (false) { if (true) return x; else w = y; } else { w = x; } } else { return z; } }", errors: [{ message: "Unnecessary 'else' after 'return'.", type: "ExpressionStatement" }] },
{ code: "function foo() { if (true) { if (false) { if (true) return x; else return y; } } else { return z; } }", errors: [{ message: "Unnecessary 'else' after 'return'.", type: "ReturnStatement" }] },
{ code: "function foo() { if (true) { if (false) { if (true) return x; else return y; } return w; } else { return z; } }", errors: [
{ message: "Unnecessary 'else' after 'return'.", type: "ReturnStatement" },
{ message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }
] },
{ code: "function foo() { if (true) { if (false) { if (true) return x; else return y; } else { w = x; } } else { return z; } }", errors: [
{ message: "Unnecessary 'else' after 'return'.", type: "ReturnStatement" },
{ message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }
] },
{
code: "function foo() { if (true) { return x; } else { return y; } }",
output: "function foo() { if (true) { return x; } return y; }",
errors: [{ message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }]
},
{
code: "function foo() { if (true) { var x = bar; return x; } else { var y = baz; return y; } }",
output: "function foo() { if (true) { var x = bar; return x; } var y = baz; return y; }",
errors: [{ message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }]
},
{
code: "function foo() { if (true) return x; else return y; }",
output: "function foo() { if (true) return x; return y; }",
errors: [{ message: "Unnecessary 'else' after 'return'.", type: "ReturnStatement" }] },
{
code: "function foo() { if (true) { if (false) return x; else return y; } else { return z; } }",
output: "function foo() { if (true) { if (false) return x; return y; } return z; }",
errors: [{ message: "Unnecessary 'else' after 'return'.", type: "ReturnStatement" }, { message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }]
},
{
code: "function foo() { if (true) { if (false) { if (true) return x; else { w = y; } } else { w = x; } } else { return z; } }",
output: "function foo() { if (true) { if (false) { if (true) return x; w = y; } else { w = x; } } else { return z; } }",
errors: [{ message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }]
},
{
code: "function foo() { if (true) { if (false) { if (true) return x; else return y; } } else { return z; } }",
output: "function foo() { if (true) { if (false) { if (true) return x; return y; } } else { return z; } }",
errors: [{ message: "Unnecessary 'else' after 'return'.", type: "ReturnStatement" }]
},
{
code: "function foo() { if (true) { if (false) { if (true) return x; else return y; } return w; } else { return z; } }",
output: "function foo() { if (true) { if (false) { if (true) return x; return y; } return w; } return z; }",
errors: [
{ message: "Unnecessary 'else' after 'return'.", type: "ReturnStatement" },
{ message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }
]
},
{
code: "function foo() { if (true) { if (false) { if (true) return x; else return y; } else { w = x; } } else { return z; } }",
output: "function foo() { if (true) { if (false) { if (true) return x; return y; } w = x; } else { return z; } }",
errors: [
{ message: "Unnecessary 'else' after 'return'.", type: "ReturnStatement" },
{ message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }
]
},
{
code: "function foo() {if (x) { return true; } else if (y) { return true; } else { notAReturn(); } }",
output: "function foo() {if (x) { return true; } else if (y) { return true; } notAReturn(); }",
errors: [{ message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }]
},
{
code: "function foo() { if (foo) return bar; else (foo).bar(); }",
output: "function foo() { if (foo) return bar; (foo).bar(); }",
errors: [{ message: "Unnecessary 'else' after 'return'.", type: "ExpressionStatement" }]
},
{
code: "function foo() { if (foo) return bar \nelse { [1, 2, 3].map(foo) } }",
output: "function foo() { if (foo) return bar \nelse { [1, 2, 3].map(foo) } }",
errors: [{ message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }]
},
{
code: "function foo() { if (foo) return bar \nelse { baz() } \n[1, 2, 3].map(foo) }",
output: "function foo() { if (foo) return bar \nelse { baz() } \n[1, 2, 3].map(foo) }",
errors: [{ message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }]
},
{
code: "function foo() { if (foo) return bar \nelse { baz() } qaz() }",
output: "function foo() { if (foo) return bar \nelse { baz() } qaz() }",
errors: [{ message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }]
},
{
code: "function foo() { if (foo) return bar \nelse { baz() } \nqaz() }",
output: "function foo() { if (foo) return bar \n baz() \nqaz() }",
errors: [{ message: "Unnecessary 'else' after 'return'.", type: "BlockStatement" }]
}
]
Expand Down

0 comments on commit 7c08544

Please sign in to comment.