Skip to content

Commit 74d1513

Browse files
mdjermanovicsrijan-deepsource
authored andcommitted
feat: fix no-eval logic for this in arrow functions (eslint#15755)
1 parent 97e0137 commit 74d1513

File tree

2 files changed

+24
-16
lines changed

2 files changed

+24
-16
lines changed

lib/rules/no-eval.js

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,18 @@ module.exports = {
7272
let funcInfo = null;
7373

7474
/**
75-
* Pushs a variable scope (Program or Function) information to the stack.
75+
* Pushs a `this` scope (non-arrow function, class static block, or class field initializer) information to the stack.
76+
* Top-level scopes are handled separately.
7677
*
7778
* This is used in order to check whether or not `this` binding is a
7879
* reference to the global object.
79-
* @param {ASTNode} node A node of the scope. This is one of Program,
80-
* FunctionDeclaration, FunctionExpression, and ArrowFunctionExpression.
80+
* @param {ASTNode} node A node of the scope.
81+
* For functions, this is one of FunctionDeclaration, FunctionExpression.
82+
* For class static blocks, this is StaticBlock.
83+
* For class field initializers, this can be any node that is PropertyDefinition#value.
8184
* @returns {void}
8285
*/
83-
function enterVarScope(node) {
86+
function enterThisScope(node) {
8487
const strict = context.getScope().isStrict;
8588

8689
funcInfo = {
@@ -97,7 +100,7 @@ module.exports = {
97100
* Pops a variable scope from the stack.
98101
* @returns {void}
99102
*/
100-
function exitVarScope() {
103+
function exitThisScope() {
101104
funcInfo = funcInfo.upper;
102105
}
103106

@@ -239,21 +242,19 @@ module.exports = {
239242
"Program:exit"() {
240243
const globalScope = context.getScope();
241244

242-
exitVarScope();
245+
exitThisScope();
243246
reportAccessingEval(globalScope);
244247
reportAccessingEvalViaGlobalObject(globalScope);
245248
},
246249

247-
FunctionDeclaration: enterVarScope,
248-
"FunctionDeclaration:exit": exitVarScope,
249-
FunctionExpression: enterVarScope,
250-
"FunctionExpression:exit": exitVarScope,
251-
ArrowFunctionExpression: enterVarScope,
252-
"ArrowFunctionExpression:exit": exitVarScope,
253-
"PropertyDefinition > *.value": enterVarScope,
254-
"PropertyDefinition > *.value:exit": exitVarScope,
255-
StaticBlock: enterVarScope,
256-
"StaticBlock:exit": exitVarScope,
250+
FunctionDeclaration: enterThisScope,
251+
"FunctionDeclaration:exit": exitThisScope,
252+
FunctionExpression: enterThisScope,
253+
"FunctionExpression:exit": exitThisScope,
254+
"PropertyDefinition > *.value": enterThisScope,
255+
"PropertyDefinition > *.value:exit": exitThisScope,
256+
StaticBlock: enterThisScope,
257+
"StaticBlock:exit": exitThisScope,
257258

258259
ThisExpression(node) {
259260
if (!isMember(node.parent, "eval")) {

tests/lib/rules/no-eval.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ ruleTester.run("no-eval", rule, {
4848
{ code: "function foo() { this.eval('foo'); }", parserOptions: { ecmaFeatures: { impliedStrict: true } } },
4949
"var obj = {foo: function() { this.eval('foo'); }}",
5050
"var obj = {}; obj.foo = function() { this.eval('foo'); }",
51+
{ code: "() => { this.eval('foo') }", parserOptions: { ecmaVersion: 6, sourceType: "module" } },
52+
{ code: "function f() { 'use strict'; () => { this.eval('foo') } }", parserOptions: { ecmaVersion: 6 } },
53+
{ code: "(function f() { 'use strict'; () => { this.eval('foo') } })", parserOptions: { ecmaVersion: 6 } },
5154
{ code: "class A { foo() { this.eval(); } }", parserOptions: { ecmaVersion: 6 } },
5255
{ code: "class A { static foo() { this.eval(); } }", parserOptions: { ecmaVersion: 6 } },
5356
{ code: "class A { field = this.eval(); }", parserOptions: { ecmaVersion: 2022 } },
@@ -95,6 +98,10 @@ ruleTester.run("no-eval", rule, {
9598
{ code: "var EVAL = eval; EVAL('foo')", errors: [{ messageId: "unexpected", type: "Identifier", column: 12, endColumn: 16 }] },
9699
{ code: "var EVAL = this.eval; EVAL('foo')", errors: [{ messageId: "unexpected", type: "MemberExpression", column: 17, endColumn: 21 }] },
97100
{ code: "'use strict'; var EVAL = this.eval; EVAL('foo')", errors: [{ messageId: "unexpected", type: "MemberExpression", column: 31, endColumn: 35 }] },
101+
{ code: "() => { this.eval('foo'); }", parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "unexpected", type: "CallExpression", column: 14, endColumn: 18 }] },
102+
{ code: "() => { 'use strict'; this.eval('foo'); }", parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "unexpected", type: "CallExpression", column: 28, endColumn: 32 }] },
103+
{ code: "'use strict'; () => { this.eval('foo'); }", parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "unexpected", type: "CallExpression", column: 28, endColumn: 32 }] },
104+
{ code: "() => { 'use strict'; () => { this.eval('foo'); } }", parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "unexpected", type: "CallExpression", column: 36, endColumn: 40 }] },
98105
{ code: "(function(exe){ exe('foo') })(eval);", errors: [{ messageId: "unexpected", type: "Identifier", column: 31, endColumn: 35 }] },
99106
{ code: "window.eval('foo')", env: { browser: true }, errors: [{ messageId: "unexpected", type: "CallExpression", column: 8, endColumn: 12 }] },
100107
{ code: "window.window.eval('foo')", env: { browser: true }, errors: [{ messageId: "unexpected", type: "CallExpression", column: 15, endColumn: 19 }] },

0 commit comments

Comments
 (0)