diff --git a/docs/rules/no-constant-condition.md b/docs/rules/no-constant-condition.md index 8566d8caa65..036bbb786b9 100644 --- a/docs/rules/no-constant-condition.md +++ b/docs/rules/no-constant-condition.md @@ -28,6 +28,14 @@ if (void x) { doSomethingUnfinished(); } +if (x &&= false) { + doSomethingNever(); +} + +if (x ||= true) { + doSomethingAlways(); +} + for (;-2;) { doSomethingForever(); } diff --git a/lib/rules/no-constant-condition.js b/lib/rules/no-constant-condition.js index 7d324634244..3c2d68cbf6c 100644 --- a/lib/rules/no-constant-condition.js +++ b/lib/rules/no-constant-condition.js @@ -106,10 +106,15 @@ module.exports = { */ return operator === node.operator && ( - isLogicalIdentity(node.left, node.operator) || - isLogicalIdentity(node.right, node.operator) + isLogicalIdentity(node.left, operator) || + isLogicalIdentity(node.right, operator) ); + case "AssignmentExpression": + return ["||=", "&&="].includes(node.operator) && + operator === node.operator.slice(0, -1) && + isLogicalIdentity(node.right, operator); + // no default } return false; @@ -177,7 +182,15 @@ module.exports = { } case "AssignmentExpression": - return (node.operator === "=") && isConstant(node.right, inBooleanPosition); + if (node.operator === "=") { + return isConstant(node.right, inBooleanPosition); + } + + if (["||=", "&&="].includes(node.operator) && inBooleanPosition) { + return isLogicalIdentity(node.right, node.operator.slice(0, -1)); + } + + return false; case "SequenceExpression": return isConstant(node.expressions[node.expressions.length - 1], inBooleanPosition); diff --git a/tests/lib/rules/no-constant-condition.js b/tests/lib/rules/no-constant-condition.js index 565a8a53dd6..ecb6de53426 100644 --- a/tests/lib/rules/no-constant-condition.js +++ b/tests/lib/rules/no-constant-condition.js @@ -16,13 +16,58 @@ const rule = require("../../../lib/rules/no-constant-condition"), // Tests //------------------------------------------------------------------------------ -const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2021 } }); ruleTester.run("no-constant-condition", rule, { valid: [ "if(a);", "if(a == 0);", "if(a = f());", + "if(a += 1);", + "if(a |= 1);", + "if(a |= true);", + "if(a |= false);", + "if(a &= 1);", + "if(a &= true);", + "if(a &= false);", + "if(a >>= 1);", + "if(a >>= true);", + "if(a >>= false);", + "if(a >>>= 1);", + "if(a ??= 1);", + "if(a ??= true);", + "if(a ??= false);", + "if(a ||= b);", + "if(a ||= false);", + "if(a ||= 0);", + "if(a ||= void 0);", + "if(+(a ||= 1));", + "if(f(a ||= true));", + "if((a ||= 1) + 2);", + "if(1 + (a ||= true));", + "if(a ||= '' || false);", + "if(a ||= void 0 || null);", + "if((a ||= false) || b);", + "if(a || (b ||= false));", + "if((a ||= true) && b);", + "if(a && (b ||= true));", + "if(a &&= b);", + "if(a &&= true);", + "if(a &&= 1);", + "if(a &&= 'foo');", + "if((a &&= '') + false);", + "if('' + (a &&= null));", + "if(a &&= 1 && 2);", + "if((a &&= true) && b);", + "if(a && (b &&= true));", + "if((a &&= false) || b);", + "if(a || (b &&= false));", + "if(a ||= b ||= false);", + "if(a &&= b &&= true);", + "if(a ||= b &&= false);", + "if(a ||= b &&= true);", + "if(a &&= b ||= false);", + "if(a &&= b ||= true);", "if(1, a);", "if ('every' in []);", "if (`\\\n${a}`) {}", @@ -175,7 +220,32 @@ ruleTester.run("no-constant-condition", rule, { { code: "if(!typeof a === 'string');", errors: [{ messageId: "unexpected", type: "BinaryExpression" }] }, { code: "if(-('foo' || a));", errors: [{ messageId: "unexpected", type: "UnaryExpression" }] }, { code: "if(+(void a && b) === ~(1 || c));", errors: [{ messageId: "unexpected", type: "BinaryExpression" }] }, - + { code: "if(a ||= true);", errors: [{ messageId: "unexpected", type: "AssignmentExpression" }] }, + { code: "if(a ||= 5);", errors: [{ messageId: "unexpected", type: "AssignmentExpression" }] }, + { code: "if(a ||= 'foo' || b);", errors: [{ messageId: "unexpected", type: "AssignmentExpression" }] }, + { code: "if(a ||= b || /regex/);", errors: [{ messageId: "unexpected", type: "AssignmentExpression" }] }, + { code: "if(a ||= b ||= true);", errors: [{ messageId: "unexpected", type: "AssignmentExpression" }] }, + { code: "if(a ||= b ||= c || 1);", errors: [{ messageId: "unexpected", type: "AssignmentExpression" }] }, + { code: "if(!(a ||= true));", errors: [{ messageId: "unexpected", type: "UnaryExpression" }] }, + { code: "if(!(a ||= 'foo') === true);", errors: [{ messageId: "unexpected", type: "BinaryExpression" }] }, + { code: "if(!(a ||= 'foo') === false);", errors: [{ messageId: "unexpected", type: "BinaryExpression" }] }, + { code: "if(a || (b ||= true));", errors: [{ messageId: "unexpected", type: "LogicalExpression" }] }, + { code: "if((a ||= 1) || b);", errors: [{ messageId: "unexpected", type: "LogicalExpression" }] }, + { code: "if((a ||= true) && true);", errors: [{ messageId: "unexpected", type: "LogicalExpression" }] }, + { code: "if(true && (a ||= true));", errors: [{ messageId: "unexpected", type: "LogicalExpression" }] }, + { code: "if(a &&= false);", errors: [{ messageId: "unexpected", type: "AssignmentExpression" }] }, + { code: "if(a &&= null);", errors: [{ messageId: "unexpected", type: "AssignmentExpression" }] }, + { code: "if(a &&= void b);", errors: [{ messageId: "unexpected", type: "AssignmentExpression" }] }, + { code: "if(a &&= 0 && b);", errors: [{ messageId: "unexpected", type: "AssignmentExpression" }] }, + { code: "if(a &&= b && '');", errors: [{ messageId: "unexpected", type: "AssignmentExpression" }] }, + { code: "if(a &&= b &&= false);", errors: [{ messageId: "unexpected", type: "AssignmentExpression" }] }, + { code: "if(a &&= b &&= c && false);", errors: [{ messageId: "unexpected", type: "AssignmentExpression" }] }, + { code: "if(!(a &&= false));", errors: [{ messageId: "unexpected", type: "UnaryExpression" }] }, + { code: "if(!(a &&= 0) + 1);", errors: [{ messageId: "unexpected", type: "BinaryExpression" }] }, + { code: "if(a && (b &&= false));", errors: [{ messageId: "unexpected", type: "LogicalExpression" }] }, + { code: "if((a &&= null) && b);", errors: [{ messageId: "unexpected", type: "LogicalExpression" }] }, + { code: "if(false || (a &&= false));", errors: [{ messageId: "unexpected", type: "LogicalExpression" }] }, + { code: "if((a &&= false) || false);", errors: [{ messageId: "unexpected", type: "LogicalExpression" }] }, { code: "while([]);", errors: [{ messageId: "unexpected", type: "ArrayExpression" }] }, { code: "while(~!0);", errors: [{ messageId: "unexpected", type: "UnaryExpression" }] },