mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(linter): check WithStatement in javascript
This commit is contained in:
parent
0fb8887d3c
commit
4a582f0487
7 changed files with 158 additions and 24 deletions
|
|
@ -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<Message<'a>> {
|
||||
|
|
@ -52,11 +63,6 @@ impl<'a> LintContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn semantic(&self) -> &Semantic<'a> {
|
||||
&self.semantic
|
||||
}
|
||||
|
||||
/* Nodes */
|
||||
|
||||
#[must_use]
|
||||
|
|
|
|||
|
|
@ -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()]
|
||||
|
|
|
|||
|
|
@ -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<Trivias>) -> 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>) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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() {} }
|
||||
|
|
|
|||
|
|
@ -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 │
|
||||
|
|
|
|||
|
|
@ -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 │ <a:b></a:b>;
|
||||
|
|
@ -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<T>
|
||||
|
|
|
|||
Loading…
Reference in a new issue