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

feat(parser): better errors for reserved words used as identifier names #6478

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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions crates/oxc_parser/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,14 @@ pub fn identifier_generator(x0: &str, span1: Span) -> OxcDiagnostic {
.with_label(span1)
}

#[cold]
pub fn identifier_reserved_word(span: Span, reserved: &str) -> OxcDiagnostic {
OxcDiagnostic::error(format!(
"Identifier expected. '{reserved}' is a reserved word that cannot be used here."
))
.with_label(span)
}

#[cold]
pub fn constructor_generator(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error("Constructor can't be a generator").with_label(span)
Expand Down
10 changes: 8 additions & 2 deletions crates/oxc_parser/src/js/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,14 @@ impl<'a> ParserImpl<'a> {

/// `BindingIdentifier` : Identifier
pub(crate) fn parse_binding_identifier(&mut self) -> Result<BindingIdentifier<'a>> {
if !self.cur_kind().is_binding_identifier() {
return Err(self.unexpected());
let cur = self.cur_kind();
if !cur.is_binding_identifier() {
let err = if cur.is_reserved_keyword() {
diagnostics::identifier_reserved_word(self.cur_token().span(), cur.to_str())
} else {
self.unexpected()
};
return Err(err);
}
let (span, name) = self.parse_identifier_kind(Kind::Ident);
self.check_identifier(span, &name);
Expand Down
46 changes: 23 additions & 23 deletions tasks/coverage/snapshots/parser_babel.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1316,7 +1316,7 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
· ──
╰────

× Unexpected token
× Identifier expected. 'if' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/core/uncategorised/382/input.js:1:5]
1 │ var if = 42
· ──
Expand Down Expand Up @@ -1411,25 +1411,25 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
· ───────
╰────

× Unexpected token
× Identifier expected. 'if' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/core/uncategorised/397/input.js:1:12]
1 │ function t(if) { }
· ──
╰────

× Unexpected token
× Identifier expected. 'true' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/core/uncategorised/398/input.js:1:12]
1 │ function t(true) { }
· ────
╰────

× Unexpected token
× Identifier expected. 'false' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/core/uncategorised/399/input.js:1:12]
1 │ function t(false) { }
· ─────
╰────

× Unexpected token
× Identifier expected. 'null' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/core/uncategorised/400/input.js:1:12]
1 │ function t(null) { }
· ────
Expand Down Expand Up @@ -2192,7 +2192,7 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
╰────
help: for octal literals use the '0o' prefix instead

× Unexpected token
× Identifier expected. 'this' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/core/uncategorised/523/input.js:1:5]
1 │ var this = 10;
· ────
Expand Down Expand Up @@ -2669,14 +2669,14 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
╰────
help: In non-strict mode code, functions can only be declared at top level, inside a block, or as the body of an if statement

× Unexpected token
× Identifier expected. 'const' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-const/input.js:1:5]
1 │ var co\u{6e}st = 123;
· ──────────
2 │
╰────

× Unexpected token
× Identifier expected. 'export' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-export/input.js:1:5]
1 │ var expor\u{74} = 123;
· ───────────
Expand All @@ -2689,7 +2689,7 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
· ────────────
╰────

× Unexpected token
× Identifier expected. 'import' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/es2015/identifiers/invalid-escape-seq-import/input.js:1:5]
1 │ var \u{69}\u{6d}\u{70}\u{6f}\u{72}\u{74} = 123;
· ────────────────────────────────────
Expand Down Expand Up @@ -3331,13 +3331,13 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
2 │ return `<div class="bar">Hola</div>`;
╰────

× Unexpected token
× Identifier expected. 'debugger' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/es2015/modules/import-invalid-keyword/input.js:1:10]
1 │ import { debugger } from "foo";
· ────────
╰────

× Unexpected token
× Identifier expected. 'typeof' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/es2015/modules/import-invalid-keyword-typeof/input.js:1:10]
1 │ import { typeof } from "foo";
· ──────
Expand Down Expand Up @@ -3734,25 +3734,25 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
· ╰── `t` has already been declared here
╰────

× Unexpected token
× Identifier expected. 'super' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/es2015/uncategorised/229/input.js:1:5]
1 │ var super
· ─────
╰────

× Unexpected token
× Identifier expected. 'default' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/es2015/uncategorised/230/input.js:1:5]
1 │ var default
· ───────
╰────

× Unexpected token
× Identifier expected. 'default' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/es2015/uncategorised/231/input.js:1:5]
1 │ let default
· ───────
╰────

× Unexpected token
× Identifier expected. 'default' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/es2015/uncategorised/232/input.js:1:7]
1 │ const default = 2
· ───────
Expand Down Expand Up @@ -4244,13 +4244,13 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
╰────
help: Try insert a semicolon here

× Unexpected token
× Identifier expected. 'enum' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/es2015/uncategorised/370/input.js:1:7]
1 │ const enum = foo();
· ────
╰────

× Unexpected token
× Identifier expected. 'enum' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/es2015/uncategorised/371/input.js:1:7]
1 │ const enum = foo();
· ────
Expand Down Expand Up @@ -8378,7 +8378,7 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
· ──
╰────

× Unexpected token
× Identifier expected. 'if' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0064/input.js:1:5]
1 │ var if = 42
· ──
Expand Down Expand Up @@ -9636,7 +9636,7 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
╰────
help: Try insert a semicolon here

× Unexpected token
× Identifier expected. 'enum' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/esprima/invalid-syntax/migrated_0277/input.js:1:12]
1 │ class A {a(enum){}}
· ────
Expand Down Expand Up @@ -10812,7 +10812,7 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
╰────
help: Try insert a semicolon here

× Unexpected token
× Identifier expected. 'if' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/typescript/type-only-import-export-specifiers/export-invalid-type-only-keyword/input.ts:1:7]
1 │ const if = {};
· ──
Expand All @@ -10831,19 +10831,19 @@ Expect to Parse: tasks/coverage/babel/packages/babel-parser/test/fixtures/typesc
· ─────────
╰────

× Unexpected token
× Identifier expected. 'if' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/typescript/type-only-import-export-specifiers/import-invalid-named-type-as-keyword/input.ts:1:18]
1 │ import { type as if } from "mod";
· ──
╰────

× Unexpected token
× Identifier expected. 'if' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/typescript/type-only-import-export-specifiers/import-invalid-type-named-keywords/input.ts:1:15]
1 │ import { type if } from "./mod.js";
· ──
╰────

× Unexpected token
× Identifier expected. 'if' is a reserved word that cannot be used here.
╭─[babel/packages/babel-parser/test/fixtures/typescript/type-only-import-export-specifiers/import-invalid-type-only-as-as-keyword/input.ts:1:21]
1 │ import { type as as if } from "mod";
· ──
Expand Down
Loading