From 6bc9e7ebdad881995131d333adc761f3b97ffe6d Mon Sep 17 00:00:00 2001 From: Daniel Tschinder Date: Tue, 26 Mar 2019 15:32:14 -0700 Subject: [PATCH] Correctly check for-in and for-of loop for invalid left-hand side (#9768) * Correctly check for-in and for-of loop for invalid left-hand side * Overwrite with env variable --- packages/babel-parser/src/parser/statement.js | 54 ++--- .../for-in/bare-initializer/options.json | 3 + .../for-in/bare-initializer/output.json | 184 ------------------ .../for-in/const-initializer/options.json | 4 +- .../for-in/let-initializer/options.json | 4 +- .../for-in/strict-initializer/options.json | 4 +- .../options.json | 4 +- .../options.json | 4 +- .../es2015/for-of/bare-initializer/input.js | 2 + .../for-of/bare-initializer/options.json | 3 + .../es2015/uncategorised/109/options.json | 4 +- .../es2015/uncategorised/235/options.json | 4 +- .../es2015/uncategorised/236/options.json | 4 +- .../for-await-no-in/options.json | 4 +- .../invalid-const-init/options.json | 4 +- .../invalid-let-init/options.json | 4 +- .../invalid-var-init/options.json | 4 +- .../invalid_const_forin/options.json | 4 +- .../invalid_let_forin/options.json | 4 +- .../test/helpers/runFixtureTests.js | 8 + scripts/tests/test262/test262_whitelist.txt | 2 - 21 files changed, 75 insertions(+), 237 deletions(-) create mode 100644 packages/babel-parser/test/fixtures/es2015/for-in/bare-initializer/options.json delete mode 100644 packages/babel-parser/test/fixtures/es2015/for-in/bare-initializer/output.json create mode 100644 packages/babel-parser/test/fixtures/es2015/for-of/bare-initializer/input.js create mode 100644 packages/babel-parser/test/fixtures/es2015/for-of/bare-initializer/options.json diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index 49e26fe9fb..2488e1557b 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -519,21 +519,11 @@ export default class StatementParser extends ExpressionParser { this.parseVar(init, true, kind); this.finishNode(init, "VariableDeclaration"); - if (this.match(tt._in) || this.isContextual("of")) { - if (init.declarations.length === 1) { - const declaration = init.declarations[0]; - const isForInInitializer = - kind === "var" && - declaration.init && - declaration.id.type != "ObjectPattern" && - declaration.id.type != "ArrayPattern" && - !this.isContextual("of"); - if (this.state.strict && isForInInitializer) { - this.raise(this.state.start, "for-in initializer in strict mode"); - } else if (isForInInitializer || !declaration.init) { - return this.parseForIn(node, init, awaitAt); - } - } + if ( + (this.match(tt._in) || this.isContextual("of")) && + init.declarations.length === 1 + ) { + return this.parseForIn(node, init, awaitAt); } if (awaitAt > -1) { this.unexpected(awaitAt); @@ -938,18 +928,36 @@ export default class StatementParser extends ExpressionParser { parseForIn( node: N.ForInOf, - init: N.VariableDeclaration, + init: N.VariableDeclaration | N.AssignmentPattern, awaitAt: number, ): N.ForInOf { - const type = this.match(tt._in) ? "ForInStatement" : "ForOfStatement"; - if (awaitAt > -1) { - this.eatContextual("of"); + const isForIn = this.match(tt._in); + this.next(); + + if (isForIn) { + if (awaitAt > -1) this.unexpected(awaitAt); } else { - this.next(); - } - if (type === "ForOfStatement") { node.await = awaitAt > -1; } + + if ( + init.type === "VariableDeclaration" && + init.declarations[0].init != null && + (!isForIn || + this.state.strict || + init.kind !== "var" || + init.declarations[0].id.type !== "Identifier") + ) { + this.raise( + init.start, + `${ + isForIn ? "for-in" : "for-of" + } loop variable declaration may not have an initializer`, + ); + } else if (init.type === "AssignmentPattern") { + this.raise(init.start, "Invalid left-hand side in for-loop"); + } + node.left = init; node.right = type === "ForInStatement" @@ -969,7 +977,7 @@ export default class StatementParser extends ExpressionParser { this.scope.exit(); this.state.labels.pop(); - return this.finishNode(node, type); + return this.finishNode(node, isForIn ? "ForInStatement" : "ForOfStatement"); } // Parse a list of variable declarations. diff --git a/packages/babel-parser/test/fixtures/es2015/for-in/bare-initializer/options.json b/packages/babel-parser/test/fixtures/es2015/for-in/bare-initializer/options.json new file mode 100644 index 0000000000..f5710cd7a9 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/for-in/bare-initializer/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Invalid left-hand side in for-loop (2:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/for-in/bare-initializer/output.json b/packages/babel-parser/test/fixtures/es2015/for-in/bare-initializer/output.json deleted file mode 100644 index 5a1b605cbc..0000000000 --- a/packages/babel-parser/test/fixtures/es2015/for-in/bare-initializer/output.json +++ /dev/null @@ -1,184 +0,0 @@ -{ - "type": "File", - "start": 0, - "end": 25, - "loc": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 2, - "column": 18 - } - }, - "program": { - "type": "Program", - "start": 0, - "end": 25, - "loc": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 2, - "column": 18 - } - }, - "sourceType": "script", - "interpreter": null, - "body": [ - { - "type": "VariableDeclaration", - "start": 0, - "end": 6, - "loc": { - "start": { - "line": 1, - "column": 0 - }, - "end": { - "line": 1, - "column": 6 - } - }, - "declarations": [ - { - "type": "VariableDeclarator", - "start": 4, - "end": 5, - "loc": { - "start": { - "line": 1, - "column": 4 - }, - "end": { - "line": 1, - "column": 5 - } - }, - "id": { - "type": "Identifier", - "start": 4, - "end": 5, - "loc": { - "start": { - "line": 1, - "column": 4 - }, - "end": { - "line": 1, - "column": 5 - }, - "identifierName": "a" - }, - "name": "a" - }, - "init": null - } - ], - "kind": "var" - }, - { - "type": "ForInStatement", - "start": 7, - "end": 25, - "loc": { - "start": { - "line": 2, - "column": 0 - }, - "end": { - "line": 2, - "column": 18 - } - }, - "left": { - "type": "AssignmentPattern", - "start": 12, - "end": 17, - "loc": { - "start": { - "line": 2, - "column": 5 - }, - "end": { - "line": 2, - "column": 10 - } - }, - "left": { - "type": "Identifier", - "start": 12, - "end": 13, - "loc": { - "start": { - "line": 2, - "column": 5 - }, - "end": { - "line": 2, - "column": 6 - }, - "identifierName": "a" - }, - "name": "a" - }, - "right": { - "type": "NumericLiteral", - "start": 16, - "end": 17, - "loc": { - "start": { - "line": 2, - "column": 9 - }, - "end": { - "line": 2, - "column": 10 - } - }, - "extra": { - "rawValue": 0, - "raw": "0" - }, - "value": 0 - } - }, - "right": { - "type": "ObjectExpression", - "start": 21, - "end": 23, - "loc": { - "start": { - "line": 2, - "column": 14 - }, - "end": { - "line": 2, - "column": 16 - } - }, - "properties": [] - }, - "body": { - "type": "EmptyStatement", - "start": 24, - "end": 25, - "loc": { - "start": { - "line": 2, - "column": 17 - }, - "end": { - "line": 2, - "column": 18 - } - } - } - } - ], - "directives": [] - } -} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/for-in/const-initializer/options.json b/packages/babel-parser/test/fixtures/es2015/for-in/const-initializer/options.json index 85e8252d6f..dd3b73e5d5 100644 --- a/packages/babel-parser/test/fixtures/es2015/for-in/const-initializer/options.json +++ b/packages/babel-parser/test/fixtures/es2015/for-in/const-initializer/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \";\" (1:17)" -} + "throws": "for-in loop variable declaration may not have an initializer (1:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/for-in/let-initializer/options.json b/packages/babel-parser/test/fixtures/es2015/for-in/let-initializer/options.json index a717ca0fa7..dd3b73e5d5 100644 --- a/packages/babel-parser/test/fixtures/es2015/for-in/let-initializer/options.json +++ b/packages/babel-parser/test/fixtures/es2015/for-in/let-initializer/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \";\" (1:15)" -} + "throws": "for-in loop variable declaration may not have an initializer (1:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/for-in/strict-initializer/options.json b/packages/babel-parser/test/fixtures/es2015/for-in/strict-initializer/options.json index 497c2b2bde..0048427255 100644 --- a/packages/babel-parser/test/fixtures/es2015/for-in/strict-initializer/options.json +++ b/packages/babel-parser/test/fixtures/es2015/for-in/strict-initializer/options.json @@ -1,3 +1,3 @@ { - "throws": "for-in initializer in strict mode (2:15)" -} + "throws": "for-in loop variable declaration may not have an initializer (2:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/for-in/var-arraybindingpattern-initializer/options.json b/packages/babel-parser/test/fixtures/es2015/for-in/var-arraybindingpattern-initializer/options.json index 85e8252d6f..dd3b73e5d5 100644 --- a/packages/babel-parser/test/fixtures/es2015/for-in/var-arraybindingpattern-initializer/options.json +++ b/packages/babel-parser/test/fixtures/es2015/for-in/var-arraybindingpattern-initializer/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \";\" (1:17)" -} + "throws": "for-in loop variable declaration may not have an initializer (1:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/for-in/var-objectbindingpattern-initializer/options.json b/packages/babel-parser/test/fixtures/es2015/for-in/var-objectbindingpattern-initializer/options.json index 85e8252d6f..dd3b73e5d5 100644 --- a/packages/babel-parser/test/fixtures/es2015/for-in/var-objectbindingpattern-initializer/options.json +++ b/packages/babel-parser/test/fixtures/es2015/for-in/var-objectbindingpattern-initializer/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \";\" (1:17)" -} + "throws": "for-in loop variable declaration may not have an initializer (1:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/for-of/bare-initializer/input.js b/packages/babel-parser/test/fixtures/es2015/for-of/bare-initializer/input.js new file mode 100644 index 0000000000..1afade4a7f --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/for-of/bare-initializer/input.js @@ -0,0 +1,2 @@ +var a; +for (a = 0 of {}); diff --git a/packages/babel-parser/test/fixtures/es2015/for-of/bare-initializer/options.json b/packages/babel-parser/test/fixtures/es2015/for-of/bare-initializer/options.json new file mode 100644 index 0000000000..f5710cd7a9 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/for-of/bare-initializer/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Invalid left-hand side in for-loop (2:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/uncategorised/109/options.json b/packages/babel-parser/test/fixtures/es2015/uncategorised/109/options.json index 715f71e32a..c145a86bc6 100644 --- a/packages/babel-parser/test/fixtures/es2015/uncategorised/109/options.json +++ b/packages/babel-parser/test/fixtures/es2015/uncategorised/109/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \";\" (1:16)" -} + "throws": "for-of loop variable declaration may not have an initializer (1:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/uncategorised/235/options.json b/packages/babel-parser/test/fixtures/es2015/uncategorised/235/options.json index 715f71e32a..dd3b73e5d5 100644 --- a/packages/babel-parser/test/fixtures/es2015/uncategorised/235/options.json +++ b/packages/babel-parser/test/fixtures/es2015/uncategorised/235/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \";\" (1:16)" -} + "throws": "for-in loop variable declaration may not have an initializer (1:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/uncategorised/236/options.json b/packages/babel-parser/test/fixtures/es2015/uncategorised/236/options.json index 715f71e32a..c145a86bc6 100644 --- a/packages/babel-parser/test/fixtures/es2015/uncategorised/236/options.json +++ b/packages/babel-parser/test/fixtures/es2015/uncategorised/236/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \";\" (1:16)" -} + "throws": "for-of loop variable declaration may not have an initializer (1:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2018/async-generators/for-await-no-in/options.json b/packages/babel-parser/test/fixtures/es2018/async-generators/for-await-no-in/options.json index f8dd5c55d9..f86bbd48e9 100644 --- a/packages/babel-parser/test/fixtures/es2018/async-generators/for-await-no-in/options.json +++ b/packages/babel-parser/test/fixtures/es2018/async-generators/for-await-no-in/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token (2:19)" -} + "throws": "Unexpected token (2:6)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/esprima/es2015-for-of/invalid-const-init/options.json b/packages/babel-parser/test/fixtures/esprima/es2015-for-of/invalid-const-init/options.json index 85e8252d6f..c145a86bc6 100644 --- a/packages/babel-parser/test/fixtures/esprima/es2015-for-of/invalid-const-init/options.json +++ b/packages/babel-parser/test/fixtures/esprima/es2015-for-of/invalid-const-init/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \";\" (1:17)" -} + "throws": "for-of loop variable declaration may not have an initializer (1:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/esprima/es2015-for-of/invalid-let-init/options.json b/packages/babel-parser/test/fixtures/esprima/es2015-for-of/invalid-let-init/options.json index a717ca0fa7..c145a86bc6 100644 --- a/packages/babel-parser/test/fixtures/esprima/es2015-for-of/invalid-let-init/options.json +++ b/packages/babel-parser/test/fixtures/esprima/es2015-for-of/invalid-let-init/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \";\" (1:15)" -} + "throws": "for-of loop variable declaration may not have an initializer (1:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/esprima/es2015-for-of/invalid-var-init/options.json b/packages/babel-parser/test/fixtures/esprima/es2015-for-of/invalid-var-init/options.json index a717ca0fa7..c145a86bc6 100644 --- a/packages/babel-parser/test/fixtures/esprima/es2015-for-of/invalid-var-init/options.json +++ b/packages/babel-parser/test/fixtures/esprima/es2015-for-of/invalid-var-init/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \";\" (1:15)" -} + "throws": "for-of loop variable declaration may not have an initializer (1:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/esprima/es2015-lexical-declaration/invalid_const_forin/options.json b/packages/babel-parser/test/fixtures/esprima/es2015-lexical-declaration/invalid_const_forin/options.json index 85e8252d6f..dd3b73e5d5 100644 --- a/packages/babel-parser/test/fixtures/esprima/es2015-lexical-declaration/invalid_const_forin/options.json +++ b/packages/babel-parser/test/fixtures/esprima/es2015-lexical-declaration/invalid_const_forin/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \";\" (1:17)" -} + "throws": "for-in loop variable declaration may not have an initializer (1:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/esprima/es2015-lexical-declaration/invalid_let_forin/options.json b/packages/babel-parser/test/fixtures/esprima/es2015-lexical-declaration/invalid_let_forin/options.json index a717ca0fa7..dd3b73e5d5 100644 --- a/packages/babel-parser/test/fixtures/esprima/es2015-lexical-declaration/invalid_let_forin/options.json +++ b/packages/babel-parser/test/fixtures/esprima/es2015-lexical-declaration/invalid_let_forin/options.json @@ -1,3 +1,3 @@ { - "throws": "Unexpected token, expected \";\" (1:15)" -} + "throws": "for-in loop variable declaration may not have an initializer (1:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/helpers/runFixtureTests.js b/packages/babel-parser/test/helpers/runFixtureTests.js index a3915587f4..32d6f0e954 100644 --- a/packages/babel-parser/test/helpers/runFixtureTests.js +++ b/packages/babel-parser/test/helpers/runFixtureTests.js @@ -131,6 +131,14 @@ function runTest(test, parseFunction) { if (err.message === opts.throws) { return; } else { + if (process.env.OVERWRITE) { + const fn = path.dirname(test.expect.loc) + "/options.json"; + test.options = test.options || {}; + test.options.throws = err.message; + fs.writeFileSync(fn, JSON.stringify(test.options, null, " ")); + return; + } + err.message = "Expected error message: " + opts.throws + diff --git a/scripts/tests/test262/test262_whitelist.txt b/scripts/tests/test262/test262_whitelist.txt index 7afcaf42e4..a90c625054 100644 --- a/scripts/tests/test262/test262_whitelist.txt +++ b/scripts/tests/test262/test262_whitelist.txt @@ -1,5 +1,3 @@ -annexB/language/statements/for-in/bare-initializer.js(default) -annexB/language/statements/for-in/bare-initializer.js(strict mode) built-ins/RegExp/property-escapes/binary-property-with-value-ASCII_-_F-negated.js(default) built-ins/RegExp/property-escapes/binary-property-with-value-ASCII_-_F-negated.js(strict mode) built-ins/RegExp/property-escapes/binary-property-with-value-ASCII_-_F.js(default)