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: Report constructor calls in no-obj-calls #12909

Merged
merged 3 commits into from Mar 24, 2020
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
18 changes: 18 additions & 0 deletions docs/rules/no-obj-calls.md
Expand Up @@ -18,27 +18,45 @@ And the [ECMAScript 2017 specification](https://www.ecma-international.org/ecma-

This rule disallows calling the `Math`, `JSON`, `Reflect` and `Atomics` objects as functions.

This rule also disallows using these objects as constructors with the `new` operator.

Examples of **incorrect** code for this rule:

```js
/*eslint no-obj-calls: "error"*/
/*eslint-env es2017*/

var math = Math();

var newMath = new Math();

var json = JSON();

var newJSON = new JSON();

var reflect = Reflect();

var newReflect = new Reflect();

var atomics = Atomics();

var newAtomics = new Atomics();
```

Examples of **correct** code for this rule:

```js
/*eslint no-obj-calls: "error"*/
/*eslint-env es2017*/

function area(r) {
return Math.PI * r * r;
}

var object = JSON.parse("{}");

var value = Reflect.get({ x: 1, y: 2 }, "x");

var first = Atomics.load(foo, 0);
```

Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-new-wrappers.js
Expand Up @@ -32,7 +32,7 @@ module.exports = {
return {

NewExpression(node) {
const wrapperObjects = ["String", "Number", "Boolean", "Math", "JSON"];
const wrapperObjects = ["String", "Number", "Boolean"];

if (wrapperObjects.indexOf(node.callee.name) > -1) {
context.report({
Expand Down
5 changes: 3 additions & 2 deletions lib/rules/no-obj-calls.js
Expand Up @@ -9,7 +9,7 @@
// Requirements
//------------------------------------------------------------------------------

const { CALL, ReferenceTracker } = require("eslint-utils");
const { CALL, CONSTRUCT, ReferenceTracker } = require("eslint-utils");
const getPropertyName = require("./utils/ast-utils").getStaticPropertyName;

//------------------------------------------------------------------------------
Expand Down Expand Up @@ -63,7 +63,8 @@ module.exports = {

for (const g of nonCallableGlobals) {
traceMap[g] = {
[CALL]: true
[CALL]: true,
[CONSTRUCT]: true
};
}

Expand Down
20 changes: 0 additions & 20 deletions tests/lib/rules/no-new-wrappers.js
Expand Up @@ -53,26 +53,6 @@ ruleTester.run("no-new-wrappers", rule, {
},
type: "NewExpression"
}]
},
{
code: "var a = new Math();",
errors: [{
messageId: "noConstructor",
data: {
fn: "Math"
},
type: "NewExpression"
}]
},
{
code: "var a = new JSON({ myProp: 10 });",
errors: [{
messageId: "noConstructor",
data: {
fn: "JSON"
},
type: "NewExpression"
}]
}
]
});
119 changes: 115 additions & 4 deletions tests/lib/rules/no-obj-calls.js
Expand Up @@ -24,9 +24,27 @@ ruleTester.run("no-obj-calls", rule, {
"var x = Math.random();",
"var x = Math.PI;",
"var x = foo.Math();",
"var x = new foo.Math();",
"var x = new Math.foo;",
"var x = new Math.foo();",
"JSON.parse(foo)",
"Reflect.get(foo, 'x')",
"Atomics.load(foo, 0)",
"new JSON.parse",
{
code: "Reflect.get(foo, 'x')",
env: { es6: true }
},
{
code: "new Reflect.foo(a, b)",
env: { es6: true }
},
{
code: "Atomics.load(foo, 0)",
env: { es2017: true }
},
{
code: "new Atomics.foo()",
env: { es2017: true }
},

{ code: "globalThis.Math();", env: { es6: true } },
{ code: "var x = globalThis.Math();", env: { es6: true } },
Expand All @@ -43,33 +61,56 @@ ruleTester.run("no-obj-calls", rule, {

// non-existing variables
"/*globals Math: off*/ Math();",
"/*globals Math: off*/ new Math();",
{
code: "JSON();",
globals: { JSON: "off" }
},
{
code: "new JSON();",
globals: { JSON: "off" }
},
"Reflect();",
"Atomics();",
"new Reflect();",
"new Atomics();",
{
code: "Atomics();",
env: { es6: true }
},

// shadowed variables
"var Math; Math();",
"var Math; new Math();",
{
code: "let JSON; JSON();",
parserOptions: { ecmaVersion: 2015 }
},
{
code: "let JSON; new JSON();",
parserOptions: { ecmaVersion: 2015 }
},
{
code: "if (foo) { const Reflect = 1; Reflect(); }",
parserOptions: { ecmaVersion: 2015 },
env: { es6: true }
},
{
code: "if (foo) { const Reflect = 1; new Reflect(); }",
parserOptions: { ecmaVersion: 2015 },
env: { es6: true }
},
"function foo(Math) { Math(); }",
"function foo(JSON) { new JSON(); }",
{
code: "function foo(Atomics) { Atomics(); }",
env: { es2017: true }
},
{
code: "function foo() { if (bar) { let Atomics; if (baz) { new Atomics(); } } }",
parserOptions: { ecmaVersion: 2015 },
env: { es2017: true }
},
"function foo() { var JSON; JSON(); }",
{
code: "function foo() { var Atomics = bar(); var baz = Atomics(5); }",
Expand All @@ -81,12 +122,10 @@ ruleTester.run("no-obj-calls", rule, {
}
],
invalid: [

{
code: "Math();",
errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "CallExpression" }]
},

{
code: "var x = Math();",
errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "CallExpression" }]
Expand All @@ -99,6 +138,26 @@ ruleTester.run("no-obj-calls", rule, {
code: "Math().foo;",
errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "CallExpression", column: 1, endColumn: 7 }]
},
{
code: "new Math;",
errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "NewExpression" }]
},
{
code: "new Math();",
errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "NewExpression" }]
},
{
code: "new Math(foo);",
errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "NewExpression" }]
},
{
code: "new Math().foo;",
errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "NewExpression" }]
},
{
code: "(new Math).foo();",
errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "NewExpression" }]
},
{
code: "var x = JSON();",
errors: [{ messageId: "unexpectedCall", data: { name: "JSON" }, type: "CallExpression" }]
Expand All @@ -107,6 +166,10 @@ ruleTester.run("no-obj-calls", rule, {
code: "x = JSON(str);",
errors: [{ messageId: "unexpectedCall", data: { name: "JSON" }, type: "CallExpression" }]
},
{
code: "var x = new JSON();",
errors: [{ messageId: "unexpectedCall", data: { name: "JSON" }, type: "NewExpression" }]
},
{
code: "Math( JSON() );",
errors: [
Expand All @@ -119,6 +182,11 @@ ruleTester.run("no-obj-calls", rule, {
env: { es6: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Reflect" }, type: "CallExpression" }]
},
{
code: "var x = new Reflect();",
env: { es6: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Reflect" }, type: "NewExpression" }]
},
{
code: "var x = Reflect();",
env: { es2017: true },
Expand All @@ -128,11 +196,20 @@ ruleTester.run("no-obj-calls", rule, {
code: "/*globals Reflect: true*/ Reflect();",
errors: [{ messageId: "unexpectedCall", data: { name: "Reflect" }, type: "CallExpression" }]
},
{
code: "/*globals Reflect: true*/ new Reflect();",
errors: [{ messageId: "unexpectedCall", data: { name: "Reflect" }, type: "NewExpression" }]
},
{
code: "var x = Atomics();",
env: { es2017: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Atomics" }, type: "CallExpression" }]
},
{
code: "var x = new Atomics();",
env: { es2017: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Atomics" }, type: "NewExpression" }]
},
{
code: "var x = Atomics();",
env: { es2020: true },
Expand All @@ -143,11 +220,21 @@ ruleTester.run("no-obj-calls", rule, {
globals: { Atomics: false },
errors: [{ messageId: "unexpectedCall", data: { name: "Atomics" }, type: "CallExpression" }]
},
{
code: "var x = new Atomics();",
globals: { Atomics: "writable" },
errors: [{ messageId: "unexpectedCall", data: { name: "Atomics" }, type: "NewExpression" }]
},
{
code: "var x = globalThis.Math();",
env: { es2020: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "CallExpression" }]
},
{
code: "var x = new globalThis.Math();",
env: { es2020: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "NewExpression" }]
},
{
code: "f(globalThis.Math());",
env: { es2020: true },
Expand All @@ -158,6 +245,11 @@ ruleTester.run("no-obj-calls", rule, {
env: { es2020: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "CallExpression", column: 1, endColumn: 18 }]
},
{
code: "new globalThis.Math().foo;",
env: { es2020: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Math" }, type: "NewExpression", column: 1, endColumn: 22 }]
},
{
code: "var x = globalThis.JSON();",
env: { es2020: true },
Expand All @@ -181,6 +273,11 @@ ruleTester.run("no-obj-calls", rule, {
env: { es2020: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Reflect" }, type: "CallExpression" }]
},
{
code: "var x = new globalThis.Reflect;",
env: { es2020: true },
errors: [{ messageId: "unexpectedCall", data: { name: "Reflect" }, type: "NewExpression" }]
},
{
code: "/*globals Reflect: true*/ Reflect();",
env: { es2020: true },
Expand All @@ -195,15 +292,29 @@ ruleTester.run("no-obj-calls", rule, {
code: "var foo = bar ? baz: JSON; foo();",
errors: [{ messageId: "unexpectedRefCall", data: { name: "foo", ref: "JSON" }, type: "CallExpression" }]
},
{
code: "var foo = bar ? baz: JSON; new foo();",
errors: [{ messageId: "unexpectedRefCall", data: { name: "foo", ref: "JSON" }, type: "NewExpression" }]
},
{
code: "var foo = bar ? baz: globalThis.JSON; foo();",
env: { es2020: true },
errors: [{ messageId: "unexpectedRefCall", data: { name: "foo", ref: "JSON" }, type: "CallExpression" }]
},
{
code: "var foo = bar ? baz: globalThis.JSON; new foo();",
env: { es2020: true },
errors: [{ messageId: "unexpectedRefCall", data: { name: "foo", ref: "JSON" }, type: "NewExpression" }]
},
{
code: "var foo = window.Atomics; foo();",
env: { es2020: true, browser: true },
errors: [{ messageId: "unexpectedRefCall", data: { name: "foo", ref: "Atomics" }, type: "CallExpression" }]
},
{
code: "var foo = window.Atomics; new foo;",
env: { es2020: true, browser: true },
errors: [{ messageId: "unexpectedRefCall", data: { name: "foo", ref: "Atomics" }, type: "NewExpression" }]
}
]
});