Skip to content

Commit

Permalink
feat: fix no-eval logic for this in arrow functions (#15755)
Browse files Browse the repository at this point in the history
  • Loading branch information
mdjermanovic committed Apr 8, 2022
1 parent bb4c0d5 commit 274acbd
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 16 deletions.
33 changes: 17 additions & 16 deletions lib/rules/no-eval.js
Expand Up @@ -72,15 +72,18 @@ module.exports = {
let funcInfo = null;

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

funcInfo = {
Expand All @@ -97,7 +100,7 @@ module.exports = {
* Pops a variable scope from the stack.

This comment has been minimized.

Copy link
@dowdy359

dowdy359 Apr 11, 2022

#module.exports = {
parserOptions: {
ecmaVersion: 2015
}
};

* @returns {void}
*/
function exitVarScope() {
function exitThisScope() {
funcInfo = funcInfo.upper;
}

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

exitVarScope();
exitThisScope();
reportAccessingEval(globalScope);
reportAccessingEvalViaGlobalObject(globalScope);
},

FunctionDeclaration: enterVarScope,
"FunctionDeclaration:exit": exitVarScope,
FunctionExpression: enterVarScope,
"FunctionExpression:exit": exitVarScope,
ArrowFunctionExpression: enterVarScope,
"ArrowFunctionExpression:exit": exitVarScope,
"PropertyDefinition > *.value": enterVarScope,
"PropertyDefinition > *.value:exit": exitVarScope,
StaticBlock: enterVarScope,
"StaticBlock:exit": exitVarScope,
FunctionDeclaration: enterThisScope,
"FunctionDeclaration:exit": exitThisScope,
FunctionExpression: enterThisScope,
"FunctionExpression:exit": exitThisScope,
"PropertyDefinition > *.value": enterThisScope,
"PropertyDefinition > *.value:exit": exitThisScope,
StaticBlock: enterThisScope,
"StaticBlock:exit": exitThisScope,

ThisExpression(node) {
if (!isMember(node.parent, "eval")) {
Expand Down
7 changes: 7 additions & 0 deletions tests/lib/rules/no-eval.js
Expand Up @@ -48,6 +48,9 @@ ruleTester.run("no-eval", rule, {
{ code: "function foo() { this.eval('foo'); }", parserOptions: { ecmaFeatures: { impliedStrict: true } } },
"var obj = {foo: function() { this.eval('foo'); }}",
"var obj = {}; obj.foo = function() { this.eval('foo'); }",
{ code: "() => { this.eval('foo') }", parserOptions: { ecmaVersion: 6, sourceType: "module" } },
{ code: "function f() { 'use strict'; () => { this.eval('foo') } }", parserOptions: { ecmaVersion: 6 } },
{ code: "(function f() { 'use strict'; () => { this.eval('foo') } })", parserOptions: { ecmaVersion: 6 } },
{ code: "class A { foo() { this.eval(); } }", parserOptions: { ecmaVersion: 6 } },
{ code: "class A { static foo() { this.eval(); } }", parserOptions: { ecmaVersion: 6 } },
{ code: "class A { field = this.eval(); }", parserOptions: { ecmaVersion: 2022 } },
Expand Down Expand Up @@ -95,6 +98,10 @@ ruleTester.run("no-eval", rule, {
{ code: "var EVAL = eval; EVAL('foo')", errors: [{ messageId: "unexpected", type: "Identifier", column: 12, endColumn: 16 }] },
{ code: "var EVAL = this.eval; EVAL('foo')", errors: [{ messageId: "unexpected", type: "MemberExpression", column: 17, endColumn: 21 }] },
{ code: "'use strict'; var EVAL = this.eval; EVAL('foo')", errors: [{ messageId: "unexpected", type: "MemberExpression", column: 31, endColumn: 35 }] },
{ code: "() => { this.eval('foo'); }", parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "unexpected", type: "CallExpression", column: 14, endColumn: 18 }] },
{ code: "() => { 'use strict'; this.eval('foo'); }", parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "unexpected", type: "CallExpression", column: 28, endColumn: 32 }] },
{ code: "'use strict'; () => { this.eval('foo'); }", parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "unexpected", type: "CallExpression", column: 28, endColumn: 32 }] },
{ code: "() => { 'use strict'; () => { this.eval('foo'); } }", parserOptions: { ecmaVersion: 6 }, errors: [{ messageId: "unexpected", type: "CallExpression", column: 36, endColumn: 40 }] },
{ code: "(function(exe){ exe('foo') })(eval);", errors: [{ messageId: "unexpected", type: "Identifier", column: 31, endColumn: 35 }] },
{ code: "window.eval('foo')", env: { browser: true }, errors: [{ messageId: "unexpected", type: "CallExpression", column: 8, endColumn: 12 }] },
{ code: "window.window.eval('foo')", env: { browser: true }, errors: [{ messageId: "unexpected", type: "CallExpression", column: 15, endColumn: 19 }] },
Expand Down

0 comments on commit 274acbd

Please sign in to comment.