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: treat all literals like boolean literal in no-constant-condition #13245
Changes from 2 commits
3afc750
96d0834
540bb20
6eb51a8
17787ea
b0c2e70
c4c8426
ce019be
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,9 +9,6 @@ | |
// Helpers | ||
//------------------------------------------------------------------------------ | ||
|
||
const EQUALITY_OPERATORS = ["===", "!==", "==", "!="]; | ||
const RELATIONAL_OPERATORS = [">", "<", ">=", "<=", "in", "instanceof"]; | ||
|
||
//------------------------------------------------------------------------------ | ||
// Rule Definition | ||
//------------------------------------------------------------------------------ | ||
|
@@ -66,15 +63,23 @@ module.exports = { | |
function isLogicalIdentity(node, operator) { | ||
switch (node.type) { | ||
case "Literal": | ||
return (operator === "||" && node.value === true) || | ||
(operator === "&&" && node.value === false); | ||
return (operator === "||" && !!node.value) || | ||
(operator === "&&" && !node.value); | ||
|
||
case "UnaryExpression": | ||
return (operator === "&&" && node.operator === "void"); | ||
|
||
case "LogicalExpression": | ||
return isLogicalIdentity(node.left, node.operator) || | ||
isLogicalIdentity(node.right, node.operator); | ||
|
||
/* | ||
* handles `a && false || b` | ||
* `false` is an identity element of `&&` but not `||` | ||
*/ | ||
return operator === node.operator && | ||
( | ||
isLogicalIdentity(node.left, node.operator) || | ||
isLogicalIdentity(node.right, node.operator) | ||
); | ||
|
||
// no default | ||
} | ||
|
@@ -129,21 +134,9 @@ module.exports = { | |
const isLeftConstant = isConstant(node.left, inBooleanPosition); | ||
const isRightConstant = isConstant(node.right, inBooleanPosition); | ||
const isLeftShortCircuit = (isLeftConstant && isLogicalIdentity(node.left, node.operator)); | ||
const isRightShortCircuit = (isRightConstant && isLogicalIdentity(node.right, node.operator)); | ||
const isRightShortCircuit = (inBooleanPosition && isRightConstant && isLogicalIdentity(node.right, node.operator)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is indeed a bug that should be fixed whether or not #13238 gets accepted. Could we maybe also this: (
!node.parent ||
node.parent.type !== "BinaryExpression" ||
!(EQUALITY_OPERATORS.includes(node.parent.operator) || RELATIONAL_OPERATORS.includes(node.parent.operator))
) replace with just I think it might fix similar bugs, such as: /*eslint no-constant-condition: "error"*/
if ((foo || 'bar' || 'bar') === 'bar'); // error, false positive Though, it seems that the whole condition starting with /*eslint no-constant-condition: "error"*/
if (a && false || b); // error, false positive There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The cause is an inappropriate propagation of short circuit. |
||
|
||
return (isLeftConstant && isRightConstant) || | ||
( | ||
|
||
// in the case of an "OR", we need to know if the right constant value is truthy | ||
node.operator === "||" && | ||
isRightConstant && | ||
node.right.value && | ||
( | ||
!node.parent || | ||
node.parent.type !== "BinaryExpression" || | ||
!(EQUALITY_OPERATORS.includes(node.parent.operator) || RELATIONAL_OPERATORS.includes(node.parent.operator)) | ||
) | ||
) || | ||
isLeftShortCircuit || | ||
isRightShortCircuit; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ESTree doesn't guarantee
node.value
is a valid value. For example, if you run ESLint on Node.js that doesn't support BigInt,node.value
isnull
at bigint literals. It will cause false positive/negative. Similarly, RegExp literals that contain new syntax, bigdecimal literals (stage 1) are, too.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about reporting an unsupported error like the following code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if the runtime doesn't support a syntax, ESLint should check the syntax successfully if ESLint supports it. In other words, the result of linting should be the same on all supported runtimes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we achieve runtime consistency by not supporting bigint on advanced runtime? Though bigint will not behave the same as numbers, just like numbers not behaving the same as booleans currently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per ESTree spec, the
Literal
nodes of BigInt havebigint
property with the text representation of the bigint value. And theLiteral
nodes of RegExp haveregex
property with{ pattern: string; flags: string }
. Thevalue
property ofLiteral
nodes of those may benull
, so we have to check thebigint
/regex
properties to distinguishnull
literal and the others.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, eslint is using espree 6.2.1, which does not support bigint or regex with
u
flag. 🤦There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The actual version is using espree 7.1.0
eslint/package.json
Line 59 in b7d79b1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was using an old version. Anyway, fallback handling is added. Your suggestions would be helpful.
https://github.com/eslint/eslint/pull/13245/files#diff-aee426385c16cd9eadb5fabd23dfa0bfR64-R84
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code below is working on node 10.0.0.