Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update: report double extra parens in no-extra-parens (fixes #12127) #12697

Merged
merged 11 commits into from Jan 16, 2020
108 changes: 65 additions & 43 deletions lib/rules/no-extra-parens.js
Expand Up @@ -169,6 +169,28 @@ module.exports = {
return ruleApplies(node) && isParenthesisedTwice(node);
}

/**
* Determines if a node that is expected to be parenthesised is surrounded by
yeonjuan marked this conversation as resolved.
Show resolved Hide resolved
* (potentially) invalid extra parentheses with considering precedence level of the node.
* If the preference level of the node is not higher or equal to precedence lower limit, it also checks
* whether the node is surrounded by parentheses twice or not.
* @param {ASTNode} node The node to be checked.
* @param {number} precedenceLowerLimit The lower limit of precedence.
* @returns {boolean} True if the node is has an unexpected extra pair of parentheses.
* @private
*/
function hasExcessParensWithPrecedence(node, precedenceLowerLimit) {
if (ruleApplies(node) && isParenthesised(node)) {
if (
precedence(node) >= precedenceLowerLimit ||
isParenthesisedTwice(node)
) {
return true;
}
}
return false;
}

/**
* Determines if a node test expression is allowed to have a parenthesised assignment
* @param {ASTNode} node The node to be checked.
Expand Down Expand Up @@ -379,8 +401,7 @@ module.exports = {
if (node.type === "UnaryExpression" && node.argument.type === "BinaryExpression" && node.argument.operator === "**") {
return;
}

if (hasExcessParens(node.argument) && precedence(node.argument) >= precedence(node)) {
if (hasExcessParensWithPrecedence(node.argument, precedence(node))) {
report(node.argument);
}
mdjermanovic marked this conversation as resolved.
Show resolved Hide resolved
}
Expand Down Expand Up @@ -411,7 +432,7 @@ module.exports = {
function checkCallNew(node) {
const callee = node.callee;

if (hasExcessParens(callee) && precedence(callee) >= precedence(node)) {
if (hasExcessParensWithPrecedence(callee, precedence(node))) {
const hasNewParensException = callee.type === "NewExpression" && !isNewExpressionWithParens(callee);

if (
Expand All @@ -429,7 +450,7 @@ module.exports = {
}
}
node.arguments
.filter(arg => hasExcessParens(arg) && precedence(arg) >= PRECEDENCE_OF_ASSIGNMENT_EXPR)
.filter(arg => hasExcessParensWithPrecedence(arg, PRECEDENCE_OF_ASSIGNMENT_EXPR))
.forEach(report);
}

Expand All @@ -448,11 +469,22 @@ module.exports = {
node.left.type === "UnaryExpression" && isExponentiation;
const shouldSkipRight = NESTED_BINARY && (node.right.type === "BinaryExpression" || node.right.type === "LogicalExpression");

if (!shouldSkipLeft && hasExcessParens(node.left) && (leftPrecedence > prec || (leftPrecedence === prec && !isExponentiation))) {
report(node.left);
if (!shouldSkipLeft && hasExcessParens(node.left)) {
if (
(leftPrecedence > prec || (leftPrecedence === prec && !isExponentiation)) ||
isParenthesisedTwice(node.left)
) {
report(node.left);
}
}
mdjermanovic marked this conversation as resolved.
Show resolved Hide resolved
if (!shouldSkipRight && hasExcessParens(node.right) && (rightPrecedence > prec || (rightPrecedence === prec && isExponentiation))) {
report(node.right);

if (!shouldSkipRight && hasExcessParens(node.right)) {
if (
(rightPrecedence > prec || (rightPrecedence === prec && isExponentiation)) ||
isParenthesisedTwice(node.right)
) {
report(node.right);
}
}
}

Expand All @@ -470,11 +502,7 @@ module.exports = {
* If `node.superClass` is a LeftHandSideExpression, parentheses are extra.
* Otherwise, parentheses are needed.
*/
const hasExtraParens = precedence(node.superClass) > PRECEDENCE_OF_UPDATE_EXPR
? hasExcessParens(node.superClass)
: hasDoubleExcessParens(node.superClass);

if (hasExtraParens) {
if (hasExcessParensWithPrecedence(node.superClass, PRECEDENCE_OF_UPDATE_EXPR)) {
yeonjuan marked this conversation as resolved.
Show resolved Hide resolved
report(node.superClass);
}
}
Expand All @@ -485,11 +513,7 @@ module.exports = {
* @returns {void}
*/
function checkSpreadOperator(node) {
const hasExtraParens = precedence(node.argument) >= PRECEDENCE_OF_ASSIGNMENT_EXPR
? hasExcessParens(node.argument)
: hasDoubleExcessParens(node.argument);

if (hasExtraParens) {
if (hasExcessParensWithPrecedence(node.argument, PRECEDENCE_OF_ASSIGNMENT_EXPR)) {
report(node.argument);
}
}
Expand Down Expand Up @@ -651,7 +675,7 @@ module.exports = {
return {
ArrayExpression(node) {
node.elements
.filter(e => e && hasExcessParens(e) && precedence(e) >= PRECEDENCE_OF_ASSIGNMENT_EXPR)
.filter(e => e && hasExcessParensWithPrecedence(e, PRECEDENCE_OF_ASSIGNMENT_EXPR))
.forEach(report);
},

Expand All @@ -674,18 +698,14 @@ module.exports = {
if (astUtils.isOpeningParenToken(tokenBeforeFirst) && astUtils.isOpeningBraceToken(firstBodyToken)) {
tokensToIgnore.add(firstBodyToken);
}
if (hasExcessParens(node.body) && precedence(node.body) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
if (hasExcessParensWithPrecedence(node.body, PRECEDENCE_OF_ASSIGNMENT_EXPR)) {
report(node.body);
}
}
},

AssignmentExpression(node) {
if (isReturnAssignException(node)) {
return;
}

if (hasExcessParens(node.right) && precedence(node.right) >= precedence(node)) {
if (!isReturnAssignException(node) && hasExcessParensWithPrecedence(node.right, precedence(node))) {
report(node.right);
}
},
Expand All @@ -702,25 +722,27 @@ module.exports = {

ClassBody(node) {
node.body
.filter(member => member.type === "MethodDefinition" && member.computed &&
member.key && hasExcessParens(member.key) && precedence(member.key) >= PRECEDENCE_OF_ASSIGNMENT_EXPR)
.filter(member => member.type === "MethodDefinition" && member.computed && member.key)
.filter(member => hasExcessParensWithPrecedence(member.key, PRECEDENCE_OF_ASSIGNMENT_EXPR))
.forEach(member => report(member.key));
},

ConditionalExpression(node) {
if (isReturnAssignException(node)) {
return;
}

if (hasExcessParens(node.test) && precedence(node.test) >= precedence({ type: "LogicalExpression", operator: "||" })) {
if (
!isCondAssignException(node) &&
hasExcessParensWithPrecedence(node.test, precedence({ type: "LogicalExpression", operator: "||" }))
) {
report(node.test);
}

if (hasExcessParens(node.consequent) && precedence(node.consequent) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
if (hasExcessParensWithPrecedence(node.consequent, PRECEDENCE_OF_ASSIGNMENT_EXPR)) {
report(node.consequent);
}

if (hasExcessParens(node.alternate) && precedence(node.alternate) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
if (hasExcessParensWithPrecedence(node.alternate, PRECEDENCE_OF_ASSIGNMENT_EXPR)) {
report(node.alternate);
}
},
Expand Down Expand Up @@ -911,18 +933,15 @@ module.exports = {

ObjectExpression(node) {
node.properties
.filter(property => {
const value = property.value;

return value && hasExcessParens(value) && precedence(value) >= PRECEDENCE_OF_ASSIGNMENT_EXPR;
}).forEach(property => report(property.value));
.filter(property => property.value && hasExcessParensWithPrecedence(property.value, PRECEDENCE_OF_ASSIGNMENT_EXPR))
.forEach(property => report(property.value));
},

Property(node) {
if (node.computed) {
const { key } = node;

if (key && hasExcessParens(key) && precedence(key) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
if (key && hasExcessParensWithPrecedence(key, PRECEDENCE_OF_ASSIGNMENT_EXPR)) {
report(key);
}
}
Expand All @@ -945,8 +964,10 @@ module.exports = {
},

SequenceExpression(node) {
const precedenceOfNode = precedence(node);

node.expressions
.filter(e => hasExcessParens(e) && precedence(e) >= precedence(node))
.filter(e => hasExcessParensWithPrecedence(e, precedenceOfNode))
.forEach(report);
},

Expand Down Expand Up @@ -975,11 +996,12 @@ module.exports = {
AwaitExpression: checkUnaryUpdate,

VariableDeclarator(node) {
if (node.init && hasExcessParens(node.init) &&
precedence(node.init) >= PRECEDENCE_OF_ASSIGNMENT_EXPR &&
if (
node.init && hasExcessParensWithPrecedence(node.init, PRECEDENCE_OF_ASSIGNMENT_EXPR) &&

// RegExp literal is allowed to have parens (#1589)
!(node.init.type === "Literal" && node.init.regex)) {
// RegExp literal is allowed to have parens (#1589)
!(node.init.type === "Literal" && node.init.regex)
) {
report(node.init);
}
},
Expand Down Expand Up @@ -1024,7 +1046,7 @@ module.exports = {
AssignmentPattern(node) {
const { right } = node;

if (right && hasExcessParens(right) && precedence(right) >= PRECEDENCE_OF_ASSIGNMENT_EXPR) {
if (right && hasExcessParensWithPrecedence(right, PRECEDENCE_OF_ASSIGNMENT_EXPR)) {
report(right);
}
}
Expand Down