From ce6d5c574ceac1e6f7c274d62becec12b14c62cd Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Sat, 30 May 2020 19:00:39 +0900 Subject: [PATCH] Fix: false positive new with member in no-extra-parens (fixes #12740) --- lib/rules/no-extra-parens.js | 35 +++++++++++++++++++++++++++--- tests/lib/rules/no-extra-parens.js | 18 ++++++++++++++- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/lib/rules/no-extra-parens.js b/lib/rules/no-extra-parens.js index 7cbb7522ebe..b77a168ffa8 100644 --- a/lib/rules/no-extra-parens.js +++ b/lib/rules/no-extra-parens.js @@ -687,6 +687,34 @@ module.exports = { reportsBuffer.reports = reportsBuffer.reports.filter(r => r.node !== node); } + /** + * Checks whether a node is a MemberExpression at NewExpression's callee. + * @param {ASTNode} node node to check. + * @returns {boolean} True if the node is a MemberExpression at NewExpression's callee. false otherwise. + */ + function isMemberInNewCallee(node) { + if (node.type === "MemberExpression") { + return node.parent.type === "NewExpression" && node.parent.callee === node + ? true + : isMemberInNewCallee(node.parent); + } + return false; + } + + /** + * Checks whether a MemberExpression node contains a CallExpression in member chaining. + * @param {ASTNode} node node to check + * @returns {boolean} True if the MemberExpression contains a CallExpression in member chaining. false otherwise. + */ + function hasCallExpInMemberExp(node) { + if (node.type === "MemberExpression") { + return node.object.type === "CallExpression" + ? true + : hasCallExpInMemberExp(node.object); + } + return false; + } + return { ArrayExpression(node) { node.elements @@ -927,7 +955,8 @@ module.exports = { LogicalExpression: checkBinaryLogical, MemberExpression(node) { - const nodeObjHasExcessParens = hasExcessParens(node.object); + const shouldAllowWrapOnce = isMemberInNewCallee(node) && hasCallExpInMemberExp(node); + const nodeObjHasExcessParens = shouldAllowWrapOnce ? hasDoubleExcessParens(node.object) : hasExcessParens(node.object); if ( nodeObjHasExcessParens && @@ -946,8 +975,8 @@ module.exports = { } if (nodeObjHasExcessParens && - node.object.type === "CallExpression" && - node.parent.type !== "NewExpression") { + node.object.type === "CallExpression" + ) { report(node.object); } diff --git a/tests/lib/rules/no-extra-parens.js b/tests/lib/rules/no-extra-parens.js index 5062857e699..e838b15bae7 100644 --- a/tests/lib/rules/no-extra-parens.js +++ b/tests/lib/rules/no-extra-parens.js @@ -589,7 +589,15 @@ ruleTester.run("no-extra-parens", rule, { "for (let a = b; a; a); a; a;", "for (a; a; a); a; a;", "for (; a; a); a; a;", - "for (let a = (b && c) === d; ;);" + "for (let a = (b && c) === d; ;);", + + "new (a()).b.c;", + "new (a().b).c;", + "new (a().b.c);", + "new (a().b().d);", + "new a().b().d;", + "new (a(b()).c)", + "new (a.b()).c" ], invalid: [ @@ -741,6 +749,14 @@ ruleTester.run("no-extra-parens", rule, { invalid("((new A))()", "(new A)()", "NewExpression"), invalid("new (foo\n.baz\n.bar\n.foo.baz)", "new foo\n.baz\n.bar\n.foo.baz", "MemberExpression"), invalid("new (foo.baz.bar.baz)", "new foo.baz.bar.baz", "MemberExpression"), + invalid("new ((a.b())).c", "new (a.b()).c", "CallExpression"), + invalid("new ((a().b)).c", "new (a().b).c", "MemberExpression"), + invalid("new ((a().b().d))", "new (a().b().d)", "MemberExpression"), + invalid("new ((a())).b.d", "new (a()).b.d", "CallExpression"), + invalid("new (a.b).d;", "new a.b.d;", "MemberExpression"), + invalid("(a().b).d;", "a().b.d;", "MemberExpression"), + invalid("(a.b()).d;", "a.b().d;", "CallExpression"), + invalid("(a.b).d;", "a.b.d;", "MemberExpression"), invalid("0, (_ => 0)", "0, _ => 0", "ArrowFunctionExpression", 1), invalid("(_ => 0), 0", "_ => 0, 0", "ArrowFunctionExpression", 1),