diff --git a/crates/oxc_linter/src/context.rs b/crates/oxc_linter/src/context.rs index 87920de2a..bafcaa496 100644 --- a/crates/oxc_linter/src/context.rs +++ b/crates/oxc_linter/src/context.rs @@ -1,7 +1,7 @@ use std::{cell::RefCell, rc::Rc}; use indextree::{Ancestors, NodeId}; -use oxc_ast::AstKind; +use oxc_ast::{AstKind, SourceType}; use oxc_diagnostics::Error; use oxc_semantic::{AstNodes, Scope, ScopeTree, Semantic, SemanticNode}; @@ -26,10 +26,21 @@ impl<'a> LintContext<'a> { Self { source_text, semantic, diagnostics: RefCell::new(vec![]), fix } } + #[must_use] + pub fn semantic(&self) -> &Semantic<'a> { + &self.semantic + } + + #[must_use] pub fn source_text(&self) -> &'a str { self.source_text } + #[must_use] + pub fn source_type(&self) -> &SourceType { + self.semantic().source_type() + } + /* Diagnostics */ pub fn into_message(self) -> Vec> { @@ -52,11 +63,6 @@ impl<'a> LintContext<'a> { } } - #[must_use] - pub fn semantic(&self) -> &Semantic<'a> { - &self.semantic - } - /* Nodes */ #[must_use] diff --git a/crates/oxc_linter/src/rules/early_error/javascript.rs b/crates/oxc_linter/src/rules/early_error/javascript.rs index fa87b39ab..5dd83dfe9 100644 --- a/crates/oxc_linter/src/rules/early_error/javascript.rs +++ b/crates/oxc_linter/src/rules/early_error/javascript.rs @@ -18,6 +18,7 @@ impl Rule for EarlyErrorJavaScript { AstKind::NumberLiteral(lit) => check_number_literal(lit, node, ctx), AstKind::StringLiteral(lit) => check_string_literal(lit, node, ctx), AstKind::RegExpLiteral(lit) => check_regexp_literal(lit, ctx), + AstKind::WithStatement(stmt) => check_with_statement(stmt, node, ctx), AstKind::BreakStatement(stmt) => check_break_statement(stmt, node, ctx), AstKind::ContinueStatement(stmt) => check_continue_statement(stmt, node, ctx), AstKind::LabeledStatement(stmt) => check_labeled_statement(stmt, node, ctx), @@ -178,6 +179,17 @@ fn check_regexp_literal(lit: &RegExpLiteral, ctx: &LintContext) { } } +fn check_with_statement<'a>(stmt: &WithStatement, node: &AstNode<'a>, ctx: &LintContext<'a>) { + #[derive(Debug, Error, Diagnostic)] + #[error("'with' statements are not allowed")] + #[diagnostic()] + struct WithStatement(#[label] Span); + + if ctx.strict_mode(node) || ctx.source_type().is_typescript() { + ctx.diagnostic(WithStatement(Span::new(stmt.span.start, stmt.span.start + 4))); + } +} + #[derive(Debug, Error, Diagnostic)] #[error("Jump target cannot cross function boundary.")] #[diagnostic()] diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index 41e3390ef..710bb280b 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -14,6 +14,8 @@ use crate::{ }; pub struct SemanticBuilder<'a> { + source_type: SourceType, + // states current_node_id: AstNodeId, current_node_flags: NodeFlags, @@ -31,14 +33,19 @@ impl<'a> SemanticBuilder<'a> { let semantic_node = SemanticNode::new(AstKind::Root, scope.current_scope_id, NodeFlags::empty()); let current_node_id = nodes.new_node(semantic_node).into(); - Self { current_node_id, nodes, scope, current_node_flags: NodeFlags::empty() } + Self { source_type, current_node_id, nodes, scope, current_node_flags: NodeFlags::empty() } } #[must_use] pub fn build(mut self, program: &'a Program<'a>, trivias: Rc) -> Semantic<'a> { // AST pass self.visit_program(program); - Semantic { nodes: self.nodes, scopes: self.scope.scopes, trivias } + Semantic { + source_type: self.source_type, + nodes: self.nodes, + scopes: self.scope.scopes, + trivias, + } } fn create_ast_node(&mut self, kind: AstKind<'a>) { diff --git a/crates/oxc_semantic/src/lib.rs b/crates/oxc_semantic/src/lib.rs index 580b35559..740c8c69c 100644 --- a/crates/oxc_semantic/src/lib.rs +++ b/crates/oxc_semantic/src/lib.rs @@ -6,10 +6,12 @@ use std::rc::Rc; pub use builder::SemanticBuilder; pub use node::{AstNode, AstNodes, SemanticNode}; -use oxc_ast::Trivias; +use oxc_ast::{SourceType, Trivias}; pub use scope::{Scope, ScopeTree}; pub struct Semantic<'a> { + source_type: SourceType, + nodes: AstNodes<'a>, scopes: ScopeTree, @@ -18,6 +20,11 @@ pub struct Semantic<'a> { } impl<'a> Semantic<'a> { + #[must_use] + pub fn source_type(&self) -> &SourceType { + &self.source_type + } + #[must_use] pub fn nodes(&self) -> &AstNodes<'a> { &self.nodes diff --git a/tasks/coverage/babel.snap b/tasks/coverage/babel.snap index 9f267d7da..41ffda48d 100644 --- a/tasks/coverage/babel.snap +++ b/tasks/coverage/babel.snap @@ -1,7 +1,7 @@ Babel Summary: AST Parsed : 2056/2069 (99.37%) Positive Passed: 2056/2069 (99.37%) -Negative Passed: 911/1502 (60.65%) +Negative Passed: 912/1502 (60.72%) Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js" Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-if-body/input.js" Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-multiple-labels/input.js" @@ -122,7 +122,6 @@ Expect Syntax Error: "core/uncategorised/552/input.js" Expect Syntax Error: "es2015/class-methods/direct-super-in-object-method/input.js" Expect Syntax Error: "es2015/class-methods/direct-super-outside-constructor/input.js" Expect Syntax Error: "es2015/class-methods/disallow-duplicate-method-params/input.js" -Expect Syntax Error: "es2015/class/extends-strict/input.js" Expect Syntax Error: "es2015/destructuring/binding-arguments-module/input.js" Expect Syntax Error: "es2015/destructuring/binding-arguments-strict/input.js" Expect Syntax Error: "es2015/destructuring/binding-eval/input.js" @@ -2043,6 +2042,14 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts" ╰──── help: replace with `super()` or `super.prop` or `super[prop]` + × 'with' statements are not allowed + ╭─[es2015/class/extends-strict/input.js:1:1] + 1 │ class C extends (function B() { + 2 │ with ({}); + · ──── + 3 │ return B; + ╰──── + × Keywords cannot contain escape characters ╭─[es2015/class/invalid-escape-get/input.js:1:1] 1 │ class X { ge\u0074 x() {} } diff --git a/tasks/coverage/test262.snap b/tasks/coverage/test262.snap index 858e4cc75..7d907e2d7 100644 --- a/tasks/coverage/test262.snap +++ b/tasks/coverage/test262.snap @@ -1,7 +1,7 @@ Test262 Summary: AST Parsed : 44000/44009 (99.98%) Positive Passed: 44000/44009 (99.98%) -Negative Passed: 2225/3917 (56.80%) +Negative Passed: 2231/3917 (56.96%) Expect Syntax Error: "annexB/language/statements/for-in/const-initializer.js" Expect Syntax Error: "annexB/language/statements/for-in/let-initializer.js" Expect Syntax Error: "annexB/language/statements/for-in/strict-initializer.js" @@ -1322,7 +1322,6 @@ Expect Syntax Error: "language/statements/class/static-init-invalid-return.js" Expect Syntax Error: "language/statements/class/static-init-invalid-super-call.js" Expect Syntax Error: "language/statements/class/static-init-invalid-yield.js" Expect Syntax Error: "language/statements/class/static-method-param-yield.js" -Expect Syntax Error: "language/statements/class/strict-mode/with.js" Expect Syntax Error: "language/statements/class/syntax/early-errors/class-definition-evaluation-block-duplicate-binding.js" Expect Syntax Error: "language/statements/class/syntax/early-errors/class-definition-evaluation-scriptbody-duplicate-binding.js" Expect Syntax Error: "language/statements/const/dstr/ary-ptrn-rest-init-ary.js" @@ -1685,15 +1684,10 @@ Expect Syntax Error: "language/statements/variable/id-eval-strict.js" Expect Syntax Error: "language/statements/variable/static-init-await-binding-invalid.js" Expect Syntax Error: "language/statements/while/decl-fun.js" Expect Syntax Error: "language/statements/while/labelled-fn-stmt.js" -Expect Syntax Error: "language/statements/with/12.10.1-11gs.js" Expect Syntax Error: "language/statements/with/decl-fun.js" -Expect Syntax Error: "language/statements/with/labelled-fn-stmt.js" -Expect Syntax Error: "language/statements/with/stict-script.js" Expect Syntax Error: "language/statements/with/strict-fn-decl-nested-1.js" Expect Syntax Error: "language/statements/with/strict-fn-decl-nested-2.js" Expect Syntax Error: "language/statements/with/strict-fn-decl.js" -Expect Syntax Error: "language/statements/with/strict-fn-expr.js" -Expect Syntax Error: "language/statements/with/strict-fn-method.js" Expect to Parse: "language/expressions/class/decorator/syntax/class-valid/decorator-member-expr-private-identifier.js" × Unexpected token @@ -18461,6 +18455,14 @@ Expect to Parse: "language/statements/class/decorator/syntax/class-valid/decorat 23 │ } ╰──── + × 'with' statements are not allowed + ╭─[language/statements/class/strict-mode/with.js:13:1] + 13 │ + 14 │ class C extends (function B() { with ({}); return B; }()) {} + · ──── + 15 │ + ╰──── + × Keywords cannot contain escape characters ╭─[language/statements/class/syntax/escaped-static.js:23:1] 23 │ class C { @@ -21418,6 +21420,13 @@ Expect to Parse: "language/statements/class/decorator/syntax/class-valid/decorat ╰──── help: Wrap this declaration in a block statement + × 'with' statements are not allowed + ╭─[language/statements/with/12.10.1-11gs.js:14:1] + 14 │ + 15 │ with ({}) { } + · ──── + ╰──── + × Async functions can only be declared at the top level or inside a block ╭─[language/statements/with/decl-async-fun.js:20:1] 20 │ @@ -21468,6 +21477,13 @@ Expect to Parse: "language/statements/class/decorator/syntax/class-valid/decorat ╰──── help: Try insert a semicolon here + × 'with' statements are not allowed + ╭─[language/statements/with/labelled-fn-stmt.js:25:1] + 25 │ + 26 │ with ({}) label1: label2: function test262() {} + · ──── + ╰──── + × Lexical declaration cannot appear in a single-statement context ╭─[language/statements/with/let-array-with-newline.js:21:1] 21 │ if (false) { @@ -21478,6 +21494,28 @@ Expect to Parse: "language/statements/class/decorator/syntax/class-valid/decorat ╰──── help: Wrap this declaration in a block statement + × 'with' statements are not allowed + ╭─[language/statements/with/stict-script.js:16:1] + 16 │ + 17 │ with ({}) {} + · ──── + ╰──── + + × 'with' statements are not allowed + ╭─[language/statements/with/strict-fn-expr.js:17:1] + 17 │ var o = {}; + 18 │ with (o) {}; + · ──── + 19 │ }; + ╰──── + + × 'with' statements are not allowed + ╭─[language/statements/with/strict-fn-method.js:16:1] + 16 │ + 17 │ var obj = { get(a) { with(a){} } }; + · ──── + ╰──── + × Invalid assignment ╭─[language/types/boolean/S8.3_A2.1.js:14:1] 14 │ diff --git a/tasks/coverage/typescript.snap b/tasks/coverage/typescript.snap index bee6ff695..b0fae205b 100644 --- a/tasks/coverage/typescript.snap +++ b/tasks/coverage/typescript.snap @@ -1,7 +1,7 @@ TypeScript Summary: AST Parsed : 2310/2338 (98.80%) Positive Passed: 2310/2338 (98.80%) -Negative Passed: 560/2531 (22.13%) +Negative Passed: 565/2531 (22.32%) Expect Syntax Error: "Symbols/ES5SymbolProperty2.ts" Expect Syntax Error: "Symbols/ES5SymbolProperty6.ts" Expect Syntax Error: "additionalChecks/noPropertyAccessFromIndexSignature1.ts" @@ -784,7 +784,6 @@ Expect Syntax Error: "expressions/functionCalls/typeArgumentInferenceConstructSi Expect Syntax Error: "expressions/functionCalls/typeArgumentInferenceErrors.ts" Expect Syntax Error: "expressions/functionCalls/typeArgumentInferenceWithConstraints.ts" Expect Syntax Error: "expressions/functionCalls/typeArgumentInferenceWithObjectLiteral.ts" -Expect Syntax Error: "expressions/functions/arrowFunctionContexts.ts" Expect Syntax Error: "expressions/functions/contextuallyTypedIifeStrict.ts" Expect Syntax Error: "expressions/identifiers/scopeResolutionIdentifiers.ts" Expect Syntax Error: "expressions/literals/literals.ts" @@ -1380,15 +1379,12 @@ Expect Syntax Error: "parser/ecmascript5/Statements/parserTryStatement1.d.ts" Expect Syntax Error: "parser/ecmascript5/Statements/parserVariableStatement1.d.ts" Expect Syntax Error: "parser/ecmascript5/Statements/parserVariableStatement2.d.ts" Expect Syntax Error: "parser/ecmascript5/Statements/parserWhileStatement1.d.ts" -Expect Syntax Error: "parser/ecmascript5/Statements/parserWithStatement1.d.ts" -Expect Syntax Error: "parser/ecmascript5/Statements/parserWithStatement2.ts" Expect Syntax Error: "parser/ecmascript5/StrictMode/octalLiteralInStrictModeES3.ts" Expect Syntax Error: "parser/ecmascript5/StrictMode/parserStrictMode1.ts" Expect Syntax Error: "parser/ecmascript5/StrictMode/parserStrictMode10.ts" Expect Syntax Error: "parser/ecmascript5/StrictMode/parserStrictMode11.ts" Expect Syntax Error: "parser/ecmascript5/StrictMode/parserStrictMode12.ts" Expect Syntax Error: "parser/ecmascript5/StrictMode/parserStrictMode13.ts" -Expect Syntax Error: "parser/ecmascript5/StrictMode/parserStrictMode14.ts" Expect Syntax Error: "parser/ecmascript5/StrictMode/parserStrictMode15-negative.ts" Expect Syntax Error: "parser/ecmascript5/StrictMode/parserStrictMode15.ts" Expect Syntax Error: "parser/ecmascript5/StrictMode/parserStrictMode16.ts" @@ -1587,7 +1583,6 @@ Expect Syntax Error: "statements/forStatements/forStatementsMultipleInvalidDecl. Expect Syntax Error: "statements/returnStatements/invalidReturnStatements.ts" Expect Syntax Error: "statements/switchStatements/switchStatements.ts" Expect Syntax Error: "statements/tryStatements/catchClauseWithTypeAnnotation.ts" -Expect Syntax Error: "statements/withStatements/withStatements.ts" Expect Syntax Error: "types/any/anyAsConstructor.ts" Expect Syntax Error: "types/any/anyAsGenericFunctionCall.ts" Expect Syntax Error: "types/any/assignAnyToEveryType.ts" @@ -5340,6 +5335,22 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" 18 │ (, BOOLEAN); ╰──── + × 'with' statements are not allowed + ╭─[expressions/functions/arrowFunctionContexts.ts:2:1] + 2 │ // Arrow function used in with statement + 3 │ with (window) { + · ──── + 4 │ var p = () => this; + ╰──── + + × 'with' statements are not allowed + ╭─[expressions/functions/arrowFunctionContexts.ts:43:1] + 43 │ // Arrow function used in with statement + 44 │ with (window) { + · ──── + 45 │ var p = () => this; + ╰──── + × Automatic Semicolon Insertion ╭─[expressions/newOperator/newOperatorErrorCases.ts:26:1] 26 │ // Construct expression with no parentheses for construct signature with > 0 parameters @@ -5846,6 +5857,14 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" ╰──── help: A `continue` statement can only be used within an enclosing `for`, `while` or `do while` + × 'with' statements are not allowed + ╭─[jsdoc/typedefOnStatements.ts:38:1] + 38 │ /** @typedef {{ m: string }} M */ + 39 │ with (name) { + · ──── + 40 │ } + ╰──── + × Unexpected token ╭─[jsx/checkJsxNamespaceNamesQuestionableForms.tsx:12:1] 12 │ ; @@ -7531,6 +7550,28 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" 2 │ } ╰──── + × 'with' statements are not allowed + ╭─[parser/ecmascript5/Statements/parserWithStatement1.d.ts:1:1] + 1 │ with (foo) { + · ──── + 2 │ } + ╰──── + + × 'with' statements are not allowed + ╭─[parser/ecmascript5/Statements/parserWithStatement2.ts:1:1] + 1 │ with (1) + · ──── + 2 │ return; + ╰──── + + × 'with' statements are not allowed + ╭─[parser/ecmascript5/StrictMode/parserStrictMode14.ts:1:1] + 1 │ "use strict"; + 2 │ with (a) { + · ──── + 3 │ } + ╰──── + × 'super' can only be used with function calls or in property accesses ╭─[parser/ecmascript5/SuperExpressions/parserSuperExpression2.ts:2:1] 2 │ M() { @@ -7832,6 +7873,14 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" ╰──── help: for octal literals use the '0o' prefix instead + × 'with' statements are not allowed + ╭─[salsa/plainJSBinderErrors.ts:30:1] + 30 │ const redundant = 010 + 31 │ with (redundant) { + · ──── + 32 │ return toFixed() + ╰──── + × Jump target cannot cross function boundary. ╭─[salsa/plainJSBinderErrors.ts:37:1] 37 │ label: var x = 1 @@ -8488,6 +8537,14 @@ Expect to Parse: "salsa/privateIdentifierExpando.ts" 3 │ ╰──── + × 'with' statements are not allowed + ╭─[statements/withStatements/withStatements.ts:1:1] + 1 │ var x = 12; + 2 │ with (x) { + · ──── + 3 │ name = 'twelve' + ╰──── + × Expect token ╭─[types/import/importWithTypeArguments.ts:1:1] 1 │ import