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: no-shadow-restricted-names lets unassigned vars shadow undefined #11341

Merged
merged 2 commits into from Feb 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion docs/rules/no-shadow-restricted-names.md
Expand Up @@ -19,7 +19,7 @@ function NaN(){}

!function(Infinity){};

var undefined;
var undefined = 5;

try {} catch(eval){}
```
Expand All @@ -32,6 +32,9 @@ Examples of **correct** code for this rule:
var Object;

function f(a, b){}

// Exception: `undefined` may be shadowed if the variable is never assigned a value.
var undefined;
```

## Further Reading
Expand Down
18 changes: 16 additions & 2 deletions lib/rules/no-shadow-restricted-names.js
Expand Up @@ -4,6 +4,19 @@
*/
"use strict";

/**
* Determines if a variable safely shadows undefined.
* This is the case when a variable named `undefined` is never assigned to a value (i.e. it always shares the same value
* as the global).
* @param {eslintScope.Variable} variable The variable to check
* @returns {boolean} true if this variable safely shadows `undefined`
*/
function safelyShadowsUndefined(variable) {
return variable.name === "undefined" &&
variable.references.every(ref => !ref.isWrite()) &&
variable.defs.every(def => def.node.type === "VariableDeclarator" && def.node.init === null);
}
aladdin-add marked this conversation as resolved.
Show resolved Hide resolved

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
Expand All @@ -24,12 +37,13 @@ module.exports = {

create(context) {

const RESTRICTED = ["undefined", "NaN", "Infinity", "arguments", "eval"];

const RESTRICTED = new Set(["undefined", "NaN", "Infinity", "arguments", "eval"]);

return {
"VariableDeclaration, :function, CatchClause"(node) {
for (const variable of context.getDeclaredVariables(node)) {
if (variable.defs.length > 0 && RESTRICTED.includes(variable.name)) {
if (variable.defs.length > 0 && RESTRICTED.has(variable.name) && !safelyShadowsUndefined(variable)) {
context.report({
node: variable.defs[0].name,
message: "Shadowing of global property '{{idName}}'.",
Expand Down
16 changes: 14 additions & 2 deletions tests/lib/rules/no-shadow-restricted-names.js
Expand Up @@ -24,6 +24,13 @@ ruleTester.run("no-shadow-restricted-names", rule, {
{
code: "try {} catch {}",
parserOptions: { ecmaVersion: 2019 }
},
"var undefined;",
"var undefined; doSomething(undefined);",
"var undefined; var undefined;",
{
code: "let undefined",
parserOptions: { ecmaVersion: 2015 }
}
],
invalid: [
Expand All @@ -39,13 +46,12 @@ ruleTester.run("no-shadow-restricted-names", rule, {
]
},
{
code: "function undefined(undefined) { var undefined; !function undefined(undefined) { try {} catch(undefined) {} }; }",
code: "function undefined(undefined) { !function undefined(undefined) { try {} catch(undefined) {} }; }",
errors: [
{ message: "Shadowing of global property 'undefined'.", type: "Identifier" },
{ message: "Shadowing of global property 'undefined'.", type: "Identifier" },
{ message: "Shadowing of global property 'undefined'.", type: "Identifier" },
{ message: "Shadowing of global property 'undefined'.", type: "Identifier" },
{ message: "Shadowing of global property 'undefined'.", type: "Identifier" },
{ message: "Shadowing of global property 'undefined'.", type: "Identifier" }
]
},
Expand Down Expand Up @@ -110,6 +116,12 @@ ruleTester.run("no-shadow-restricted-names", rule, {
{ message: "Shadowing of global property 'undefined'.", type: "Identifier" },
{ message: "Shadowing of global property 'undefined'.", type: "Identifier" }
]
},
{
code: "var undefined; undefined = 5;",
errors: [
{ message: "Shadowing of global property 'undefined'.", type: "Identifier" }
]
}
]
});