summaryrefslogtreecommitdiff
path: root/tools/eslint/lib/rules/no-extra-parens.js
diff options
context:
space:
mode:
Diffstat (limited to 'tools/eslint/lib/rules/no-extra-parens.js')
-rw-r--r--tools/eslint/lib/rules/no-extra-parens.js63
1 files changed, 47 insertions, 16 deletions
diff --git a/tools/eslint/lib/rules/no-extra-parens.js b/tools/eslint/lib/rules/no-extra-parens.js
index 763e9235bd..50f5160b20 100644
--- a/tools/eslint/lib/rules/no-extra-parens.js
+++ b/tools/eslint/lib/rules/no-extra-parens.js
@@ -10,8 +10,10 @@
// Rule Definition
//------------------------------------------------------------------------------
-module.exports = function(context) {
+var astUtils = require("../ast-utils.js");
+module.exports = function(context) {
+ var isParenthesised = astUtils.isParenthesised.bind(astUtils, context);
var ALL_NODES = context.options[0] !== "functions";
var EXCEPT_COND_ASSIGN = ALL_NODES && context.options[1] && context.options[1].conditionalAssign === false;
var sourceCode = context.getSourceCode();
@@ -27,21 +29,6 @@ module.exports = function(context) {
}
/**
- * Determines if a node is surrounded by parentheses.
- * @param {ASTNode} node - The node to be checked.
- * @returns {boolean} True if the node is parenthesised.
- * @private
- */
- function isParenthesised(node) {
- var previousToken = context.getTokenBefore(node),
- nextToken = context.getTokenAfter(node);
-
- return previousToken && nextToken &&
- previousToken.value === "(" && previousToken.range[1] <= node.range[0] &&
- nextToken.value === ")" && nextToken.range[0] >= node.range[1];
- }
-
- /**
* Determines if a node is surrounded by parentheses twice.
* @param {ASTNode} node - The node to be checked.
* @returns {boolean} True if the node is doubly parenthesised.
@@ -110,6 +97,7 @@ module.exports = function(context) {
*/
function isHeadOfExpressionStatement(node) {
var parent = node.parent;
+
while (parent) {
switch (parent.type) {
case "SequenceExpression":
@@ -191,11 +179,14 @@ module.exports = function(context) {
return 4;
case "&&":
return 5;
+
// no default
}
/* falls through */
+
case "BinaryExpression":
+
switch (node.operator) {
case "|":
return 6;
@@ -226,21 +217,29 @@ module.exports = function(context) {
case "/":
case "%":
return 13;
+
// no default
}
+
/* falls through */
+
case "UnaryExpression":
return 14;
+
case "UpdateExpression":
return 15;
+
case "CallExpression":
+
// IIFE is allowed to have parens in any position (#655)
if (node.callee.type === "FunctionExpression") {
return -1;
}
return 16;
+
case "NewExpression":
return 17;
+
// no default
}
return 18;
@@ -254,6 +253,7 @@ module.exports = function(context) {
*/
function report(node) {
var previousToken = context.getTokenBefore(node);
+
context.report(node, previousToken.loc.start, "Gratuitous parentheses around expression.");
}
@@ -279,6 +279,7 @@ module.exports = function(context) {
if (hasExcessParens(node.callee) && precedence(node.callee) >= precedence(node) && !(
node.type === "CallExpression" &&
node.callee.type === "FunctionExpression" &&
+
// One set of parentheses are allowed for a function expression
!hasDoubleExcessParens(node.callee)
)) {
@@ -305,6 +306,7 @@ module.exports = function(context) {
*/
function dryBinaryLogical(node) {
var prec = precedence(node);
+
if (hasExcessParens(node.left) && precedence(node.left) >= prec) {
report(node.left);
}
@@ -321,6 +323,7 @@ module.exports = function(context) {
}
});
},
+
"ArrowFunctionExpression": function(node) {
if (node.body.type !== "BlockStatement") {
if (node.body.type !== "ObjectExpression" && hasExcessParens(node.body) && precedence(node.body) >= precedence({type: "AssignmentExpression"})) {
@@ -335,13 +338,16 @@ module.exports = function(context) {
}
}
},
+
"AssignmentExpression": function(node) {
if (hasExcessParens(node.right) && precedence(node.right) >= precedence(node)) {
report(node.right);
}
},
+
"BinaryExpression": dryBinaryLogical,
"CallExpression": dryCallNew,
+
"ConditionalExpression": function(node) {
if (hasExcessParens(node.test) && precedence(node.test) >= precedence({type: "LogicalExpression", operator: "||"})) {
report(node.test);
@@ -353,13 +359,16 @@ module.exports = function(context) {
report(node.alternate);
}
},
+
"DoWhileStatement": function(node) {
if (hasDoubleExcessParens(node.test) && !isCondAssignException(node)) {
report(node.test);
}
},
+
"ExpressionStatement": function(node) {
var firstToken, secondToken, firstTokens;
+
if (hasExcessParens(node.expression)) {
firstTokens = context.getFirstTokens(node.expression, 2);
firstToken = firstTokens[0];
@@ -380,16 +389,19 @@ module.exports = function(context) {
}
}
},
+
"ForInStatement": function(node) {
if (hasExcessParens(node.right)) {
report(node.right);
}
},
+
"ForOfStatement": function(node) {
if (hasExcessParens(node.right)) {
report(node.right);
}
},
+
"ForStatement": function(node) {
if (node.init && hasExcessParens(node.init)) {
report(node.init);
@@ -403,12 +415,15 @@ module.exports = function(context) {
report(node.update);
}
},
+
"IfStatement": function(node) {
if (hasDoubleExcessParens(node.test) && !isCondAssignException(node)) {
report(node.test);
}
},
+
"LogicalExpression": dryBinaryLogical,
+
"MemberExpression": function(node) {
if (
hasExcessParens(node.object) &&
@@ -420,6 +435,7 @@ module.exports = function(context) {
typeof node.object.value === "number" &&
/^[0-9]+$/.test(context.getFirstToken(node.object).value))
||
+
// RegExp literal is allowed to have parens (#1589)
(node.object.type === "Literal" && node.object.regex)
)
@@ -436,25 +452,31 @@ module.exports = function(context) {
report(node.property);
}
},
+
"NewExpression": dryCallNew,
+
"ObjectExpression": function(node) {
[].forEach.call(node.properties, function(e) {
var v = e.value;
+
if (v && hasExcessParens(v) && precedence(v) >= precedence({type: "AssignmentExpression"})) {
report(v);
}
});
},
+
"ReturnStatement": function(node) {
var returnToken = sourceCode.getFirstToken(node);
if (node.argument &&
hasExcessParensNoLineTerminator(returnToken, node.argument) &&
+
// RegExp literal is allowed to have parens (#1589)
!(node.argument.type === "Literal" && node.argument.regex)) {
report(node.argument);
}
},
+
"SequenceExpression": function(node) {
[].forEach.call(node.expressions, function(e) {
if (hasExcessParens(e) && precedence(e) >= precedence(node)) {
@@ -462,16 +484,19 @@ module.exports = function(context) {
}
});
},
+
"SwitchCase": function(node) {
if (node.test && hasExcessParens(node.test)) {
report(node.test);
}
},
+
"SwitchStatement": function(node) {
if (hasDoubleExcessParens(node.discriminant)) {
report(node.discriminant);
}
},
+
"ThrowStatement": function(node) {
var throwToken = sourceCode.getFirstToken(node);
@@ -479,26 +504,32 @@ module.exports = function(context) {
report(node.argument);
}
},
+
"UnaryExpression": dryUnaryUpdate,
"UpdateExpression": dryUnaryUpdate,
+
"VariableDeclarator": function(node) {
if (node.init && hasExcessParens(node.init) &&
precedence(node.init) >= precedence({type: "AssignmentExpression"}) &&
+
// RegExp literal is allowed to have parens (#1589)
!(node.init.type === "Literal" && node.init.regex)) {
report(node.init);
}
},
+
"WhileStatement": function(node) {
if (hasDoubleExcessParens(node.test) && !isCondAssignException(node)) {
report(node.test);
}
},
+
"WithStatement": function(node) {
if (hasDoubleExcessParens(node.object)) {
report(node.object);
}
},
+
"YieldExpression": function(node) {
var yieldToken;