fix: non-directive "use strict" should not enable parsing in strict mode (#11188)

* fix: non-directive "use strict" should not enable parsing in strict mode

* Remove dead code

* Add stricter type annotations

* set oldStrict explicitly to null

* Fix error

* label callback argument

* update comment

* Address feedback

* Remove this.state.octalPosition

* Add additional tests

* Revert "Remove this.state.octalPosition"

This reverts commit bcc78c9530f8c840f85e86053b75efce662f34d1.

* Remove containsOctal

* Report multiple octal literals in single token

* Fix comments

* remove Array.prototype.flat()
This commit is contained in:
Kai Cataldo
2020-03-05 17:34:27 -05:00
committed by GitHub
parent e297e406ce
commit 2057d2b159
24 changed files with 5300 additions and 123 deletions

View File

@@ -55,6 +55,7 @@ export default class ExpressionParser extends LValParser {
+parseBlock: (
allowDirectives?: boolean,
createNewLexicalScope?: boolean,
afterBlockParse?: (hasStrictModeDirective: boolean) => void,
) => N.BlockStatement;
+parseClass: (
node: N.Class,
@@ -1877,9 +1878,6 @@ export default class ExpressionParser extends LValParser {
isMethod?: boolean = false,
): void {
const isExpression = allowExpression && !this.match(tt.braceL);
const oldStrict = this.state.strict;
let useStrict = false;
const oldInParameters = this.state.inParameters;
this.state.inParameters = false;
@@ -1887,58 +1885,63 @@ export default class ExpressionParser extends LValParser {
node.body = this.parseMaybeAssign();
this.checkParams(node, false, allowExpression, false);
} else {
const nonSimple = !this.isSimpleParamList(node.params);
if (!oldStrict || nonSimple) {
useStrict = this.strictDirective(this.state.end);
// If this is a strict mode function, verify that argument names
// are not repeated, and it does not try to bind the words `eval`
// or `arguments`.
if (useStrict && nonSimple) {
// This logic is here to align the error location with the estree plugin
const errorPos =
// $FlowIgnore
(node.kind === "method" || node.kind === "constructor") &&
// $FlowIgnore
!!node.key
? node.key.end
: node.start;
this.raise(errorPos, Errors.IllegalLanguageModeDirective);
}
}
const oldStrict = this.state.strict;
// Start a new scope with regard to labels
// flag (restore them to their old value afterwards).
const oldLabels = this.state.labels;
this.state.labels = [];
if (useStrict) this.state.strict = true;
// Add the params to varDeclaredNames to ensure that an error is thrown
// if a let/const declaration in the function clashes with one of the params.
this.checkParams(
node,
!oldStrict && !useStrict && !allowExpression && !isMethod && !nonSimple,
allowExpression,
!oldStrict && useStrict,
);
// FunctionBody[Yield, Await]:
// StatementList[?Yield, ?Await, +Return] opt
this.prodParam.enter(this.prodParam.currentFlags() | PARAM_RETURN);
node.body = this.parseBlock(true, false);
node.body = this.parseBlock(
true,
false,
// Strict mode function checks after we parse the statements in the function body.
(hasStrictModeDirective: boolean) => {
const nonSimple = !this.isSimpleParamList(node.params);
if (hasStrictModeDirective && nonSimple) {
// This logic is here to align the error location with the ESTree plugin.
const errorPos =
// $FlowIgnore
(node.kind === "method" || node.kind === "constructor") &&
// $FlowIgnore
!!node.key
? node.key.end
: node.start;
this.raise(errorPos, Errors.IllegalLanguageModeDirective);
}
const strictModeChanged = !oldStrict && this.state.strict;
// Add the params to varDeclaredNames to ensure that an error is thrown
// if a let/const declaration in the function clashes with one of the params.
this.checkParams(
node,
!this.state.strict && !allowExpression && !isMethod && !nonSimple,
allowExpression,
strictModeChanged,
);
// Ensure the function name isn't a forbidden identifier in strict mode, e.g. 'eval'
if (this.state.strict && node.id) {
this.checkLVal(
node.id,
BIND_OUTSIDE,
undefined,
"function name",
undefined,
strictModeChanged,
);
}
},
);
this.prodParam.exit();
this.state.labels = oldLabels;
}
this.state.inParameters = oldInParameters;
// Ensure the function name isn't a forbidden identifier in strict mode, e.g. 'eval'
if (this.state.strict && node.id) {
this.checkLVal(
node.id,
BIND_OUTSIDE,
undefined,
"function name",
undefined,
!oldStrict && useStrict,
);
}
this.state.strict = oldStrict;
}
isSimpleParamList(