Skip to content

Commit

Permalink
Fix: Remove warning in initialized variables (fixes #12687)
Browse files Browse the repository at this point in the history
  • Loading branch information
boutahlilsoufiane committed Aug 22, 2021
1 parent 1f5d088 commit 9546417
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 5 deletions.
6 changes: 3 additions & 3 deletions CHANGELOG.md
Expand Up @@ -2742,7 +2742,7 @@ v3.16.0 - February 20, 2017
* c7e64f3 Upgrade: mock-fs (#8070) (Toru Nagashima)
* acc3301 Update: handle uncommon linebreaks consistently in rules (fixes #7949) (#8049) (Teddy Katz)
* 591b74a Chore: enable operator-linebreak on ESLint codebase (#8064) (Teddy Katz)
* 6445d2a Docs: Add documentation for /* exported */ (fixes #7998) (#8065) (Lee Yi Min)
* 6445d2a Docs: Add documentation for /*exported*/ (fixes #7998) (#8065) (Lee Yi Min)
* fcc38db Chore: simplify and improve performance for autofix (#8035) (Toru Nagashima)
* b04fde7 Chore: improve performance of SourceCode constructor (#8054) (Teddy Katz)
* 90fd555 Update: improve null detection in eqeqeq for ES6 regexes (fixes #8020) (#8042) (Teddy Katz)
Expand Down Expand Up @@ -6358,7 +6358,7 @@ v0.0.9 - October 5, 2013
* Rule: no-loop-func (Ilya Volodin)
* Merge branch 'master' of https://github.com/nzakas/eslint into no-underscore-dangle (Matt DuVall)
* Use proper node declarations and __proto__ exception (Matt DuVall)
* Updating no-undef patch (see pull request #164) - Simplify parseBoolean() - Make knowledge of```/*jshint*/``` and ```/*global */``` internal to eslint object - Put user-declared globals in Program scope (Mark Macdonald)
* Updating no-undef patch (see pull request #164) - Simplify parseBoolean() - Make knowledge of```/*jshint*/``` and ```/*global*/``` internal to eslint object - Put user-declared globals in Program scope (Mark Macdonald)
* Rule: no-eq-null (Ian Christian Myers)
* fixed broken merge (Raphael Pigulla)
* fixes #143 (Raphael Pigulla)
Expand All @@ -6367,7 +6367,7 @@ v0.0.9 - October 5, 2013
* Update eslint.json with no-underscore-dangle rule (Matt DuVall)
* Rule: no-underscore-dangle for func/var declarations (Matt DuVall)
* Warn on finding the bitwise NOT operator (James Allardice)
* Updating no-undef patch (see pull request #164) 3. Move parsing of ```/*global */``` and ```/*jshint */``` to eslint.js (Mark Macdonald)
* Updating no-undef patch (see pull request #164) 3. Move parsing of ```/*global*/``` and ```/*jshint*/``` to eslint.js (Mark Macdonald)
* Warn on finding a bitwise shift operator (fixes #170) (James Allardice)
* Fix broken test (James Allardice)
* Add support for the do-while statement to the curly rule (closes #167) (James Allardice)
Expand Down
76 changes: 75 additions & 1 deletion lib/rules/no-shadow.js
Expand Up @@ -11,6 +11,16 @@

const astUtils = require("./utils/ast-utils");

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

const INIT_NODE_TYPES = [
"AssignmentPattern",
"ForInStatement",
"ForOfStatement"
];

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
Expand Down Expand Up @@ -57,6 +67,70 @@ module.exports = {
allow: (context.options[0] && context.options[0].allow) || []
};

/**
* @callback CheckNodeCallback
* @param {ASTNode} node A node to check.
*/

/**
* Traverses AST from a given node to find a node that verifies checkNodeCB condition.
* @param {ASTNode} node a node to get.
* @param {CheckNodeCallback} checkNodeCB a callback that checks whether or not the node verifies its condition or not.
* @returns {ASTNode} the node that verifies checkNodeCB condition.
*/
function getNode(node, checkNodeCB) {
let currentNode = node;

while (currentNode && !checkNodeCB(currentNode)) {
currentNode = currentNode.parent;
}
return currentNode;
}

/**
* Checks if a variable and a shadowedVariable have the same init pattern node parent.
* @param {Object} variable a variable to check.
* @param {Object} shadowedVariable a shadowedVariable to check.
* @returns {boolean} Whether or not the variable and the shadowedVariable have the same init pattern node parent.
*/
function areOnInitPatternNode(variable, shadowedVariable) {
const outerDef = shadowedVariable.defs[0];
const innerDef = variable.defs[0];

const callExpressionNode = getNode(
innerDef.node,
node => node.type === "CallExpression"
);

if (callExpressionNode) {
const initNode1 = getNode(
outerDef && outerDef.name && outerDef.name.parent,
node => {
const { type, init, right } = node;
let nodeType;

if (type === "VariableDeclarator" && init) {
nodeType = node.init.type;
}
if (INIT_NODE_TYPES.includes(type)) {
nodeType = right.type;
}
return nodeType === "CallExpression";
}
);

const initNode2 = getNode(
callExpressionNode,
node => node === initNode1
);

if (initNode2) {
return true;
}
}
return false;
}

/**
* Check if variable name is allowed.
* @param {ASTNode} variable The variable to check.
Expand Down Expand Up @@ -186,7 +260,7 @@ module.exports = {

if (shadowed &&
(shadowed.identifiers.length > 0 || (options.builtinGlobals && "writeable" in shadowed)) &&
!isOnInitializer(variable, shadowed) &&
!isOnInitializer(variable, shadowed) && !areOnInitPatternNode(variable, shadowed) &&
!(options.hoist !== "all" && isInTdz(variable, shadowed))
) {
const location = getDeclaredLocation(shadowed);
Expand Down
11 changes: 10 additions & 1 deletion tests/lib/rules/no-shadow.js
Expand Up @@ -58,7 +58,16 @@ ruleTester.run("no-shadow", rule, {
{ code: "var Object = 0;", options: [{ builtinGlobals: true }] },
{ code: "var top = 0;", options: [{ builtinGlobals: true }], env: { browser: true } },
{ code: "function foo(cb) { (function (cb) { cb(42); })(cb); }", options: [{ allow: ["cb"] }] },
{ code: "class C { foo; foo() { let foo; } }", parserOptions: { ecmaVersion: 2022 } }
{ code: "class C { foo; foo() { let foo; } }", parserOptions: { ecmaVersion: 2022 } },
{ code: "const a = [].find(a=>a)", parserOptions: { ecmaVersion: 6 } },
{ code: "const [a = [].find(a => true)] = dummy", parserOptions: { ecmaVersion: 6 } },
{ code: "const { a = [].find(a => true) } = dummy", parserOptions: { ecmaVersion: 6 } },
{ code: "function func(a = [].find(a => true)) {}", parserOptions: { ecmaVersion: 6 } },
{ code: "for (const a in [].find(a => true)) {}", parserOptions: { ecmaVersion: 6 } },
{ code: "for (const a of [].find(a => true)) {}", parserOptions: { ecmaVersion: 6 } },
{ code: "const a = [].map(a => true).filter(a => a === 'b')", parserOptions: { ecmaVersion: 6 } },
{ code: "const { a } = (({ a }) => ({ a }))();", parserOptions: { ecmaVersion: 6 } },
{ code: "const person = people.find(item => {const person = item.name; return person === 'ahmed'})", parserOptions: { ecmaVersion: 6 } }
],
invalid: [
{
Expand Down

0 comments on commit 9546417

Please sign in to comment.