mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
refactor(semantic): expose 1 checker function instead of 2 (#3694)
This commit is contained in:
parent
de0690f2e5
commit
a94a72dc68
4 changed files with 158 additions and 154 deletions
|
|
@ -14,7 +14,7 @@ use oxc_syntax::{
|
|||
|
||||
use crate::{
|
||||
binder::Binder,
|
||||
checker::{EarlyErrorJavaScript, EarlyErrorTypeScript},
|
||||
checker,
|
||||
class::ClassTableBuilder,
|
||||
control_flow::{
|
||||
ControlFlowGraphBuilder, CtxCursor, CtxFlags, EdgeType, ErrorEdgeKind,
|
||||
|
|
@ -151,7 +151,7 @@ impl<'a> SemanticBuilder<'a> {
|
|||
|
||||
// Checking syntax error on module record requires scope information from the previous AST pass
|
||||
if self.check_syntax_error {
|
||||
EarlyErrorJavaScript::check_module_record(&self);
|
||||
checker::check_module_record(&self);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -449,8 +449,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
fn leave_node(&mut self, kind: AstKind<'a>) {
|
||||
if self.check_syntax_error {
|
||||
let node = self.nodes.get_node(self.current_node_id);
|
||||
EarlyErrorJavaScript::run(node, self);
|
||||
EarlyErrorTypeScript::run(node, self);
|
||||
checker::check(node, self);
|
||||
}
|
||||
self.leave_kind(kind);
|
||||
self.pop_ast_node();
|
||||
|
|
|
|||
|
|
@ -16,93 +16,7 @@ use rustc_hash::FxHashMap;
|
|||
|
||||
use crate::{builder::SemanticBuilder, diagnostics::redeclaration, scope::ScopeFlags, AstNode};
|
||||
|
||||
pub struct EarlyErrorJavaScript;
|
||||
|
||||
impl EarlyErrorJavaScript {
|
||||
pub fn run<'a>(node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
|
||||
let kind = node.kind();
|
||||
|
||||
match kind {
|
||||
AstKind::Program(_) => {
|
||||
check_labeled_statement(ctx);
|
||||
check_duplicate_class_elements(ctx);
|
||||
}
|
||||
AstKind::BindingIdentifier(ident) => {
|
||||
check_identifier(&ident.name, ident.span, node, ctx);
|
||||
check_binding_identifier(ident, node, ctx);
|
||||
}
|
||||
AstKind::IdentifierReference(ident) => {
|
||||
check_identifier(&ident.name, ident.span, node, ctx);
|
||||
check_identifier_reference(ident, node, ctx);
|
||||
}
|
||||
AstKind::LabelIdentifier(ident) => check_identifier(&ident.name, ident.span, node, ctx),
|
||||
AstKind::PrivateIdentifier(ident) => check_private_identifier_outside_class(ident, ctx),
|
||||
AstKind::NumericLiteral(lit) => check_number_literal(lit, ctx),
|
||||
AstKind::StringLiteral(lit) => check_string_literal(lit, ctx),
|
||||
AstKind::RegExpLiteral(lit) => check_regexp_literal(lit, ctx),
|
||||
|
||||
AstKind::Directive(dir) => check_directive(dir, ctx),
|
||||
AstKind::ModuleDeclaration(decl) => {
|
||||
check_module_declaration(decl, node, ctx);
|
||||
}
|
||||
AstKind::MetaProperty(prop) => check_meta_property(prop, node, ctx),
|
||||
|
||||
AstKind::WithStatement(stmt) => {
|
||||
check_function_declaration(&stmt.body, false, ctx);
|
||||
check_with_statement(stmt, ctx);
|
||||
}
|
||||
AstKind::SwitchStatement(stmt) => check_switch_statement(stmt, ctx),
|
||||
AstKind::BreakStatement(stmt) => check_break_statement(stmt, node, ctx),
|
||||
AstKind::ContinueStatement(stmt) => check_continue_statement(stmt, node, ctx),
|
||||
AstKind::LabeledStatement(stmt) => {
|
||||
check_function_declaration(&stmt.body, true, ctx);
|
||||
}
|
||||
AstKind::ForInStatement(stmt) => {
|
||||
check_function_declaration(&stmt.body, false, ctx);
|
||||
check_for_statement_left(&stmt.left, true, node, ctx);
|
||||
}
|
||||
AstKind::ForOfStatement(stmt) => {
|
||||
check_function_declaration(&stmt.body, false, ctx);
|
||||
check_for_statement_left(&stmt.left, false, node, ctx);
|
||||
}
|
||||
AstKind::WhileStatement(WhileStatement { body, .. })
|
||||
| AstKind::DoWhileStatement(DoWhileStatement { body, .. })
|
||||
| AstKind::ForStatement(ForStatement { body, .. }) => {
|
||||
check_function_declaration(body, false, ctx);
|
||||
}
|
||||
AstKind::IfStatement(stmt) => {
|
||||
check_function_declaration(&stmt.consequent, true, ctx);
|
||||
if let Some(alternate) = &stmt.alternate {
|
||||
check_function_declaration(alternate, true, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
AstKind::Class(class) => check_class(class, node, ctx),
|
||||
AstKind::MethodDefinition(method) => check_method_definition(method, ctx),
|
||||
AstKind::ObjectProperty(prop) => check_object_property(prop, ctx),
|
||||
AstKind::Super(sup) => check_super(sup, node, ctx),
|
||||
|
||||
AstKind::FormalParameters(params) => check_formal_parameters(params, node, ctx),
|
||||
AstKind::ArrayPattern(pat) => check_array_pattern(pat, ctx),
|
||||
|
||||
AstKind::AssignmentExpression(expr) => check_assignment_expression(expr, ctx),
|
||||
AstKind::AwaitExpression(expr) => check_await_expression(expr, node, ctx),
|
||||
AstKind::BinaryExpression(expr) => check_binary_expression(expr, ctx),
|
||||
AstKind::LogicalExpression(expr) => check_logical_expression(expr, ctx),
|
||||
AstKind::MemberExpression(expr) => check_member_expression(expr, ctx),
|
||||
AstKind::ObjectExpression(expr) => check_object_expression(expr, ctx),
|
||||
AstKind::UnaryExpression(expr) => check_unary_expression(expr, node, ctx),
|
||||
AstKind::YieldExpression(expr) => check_yield_expression(expr, node, ctx),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_module_record(ctx: &SemanticBuilder<'_>) {
|
||||
check_module_record(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_duplicate_class_elements(ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_duplicate_class_elements(ctx: &SemanticBuilder<'_>) {
|
||||
let classes = &ctx.class_table_builder.classes;
|
||||
classes.iter_enumerated().for_each(|(class_id, _)| {
|
||||
let mut defined_elements = FxHashMap::default();
|
||||
|
|
@ -149,7 +63,7 @@ fn duplicate_export(x0: &str, span1: Span, span2: Span) -> OxcDiagnostic {
|
|||
])
|
||||
}
|
||||
|
||||
fn check_module_record(ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_module_record(ctx: &SemanticBuilder<'_>) {
|
||||
// Skip checkking for exports in TypeScript for now
|
||||
if ctx.source_type.is_typescript() {
|
||||
return;
|
||||
|
|
@ -214,7 +128,12 @@ pub const STRICT_MODE_NAMES: Set<&'static str> = phf_set! {
|
|||
"yield",
|
||||
};
|
||||
|
||||
fn check_identifier<'a>(name: &Atom, span: Span, node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
|
||||
pub fn check_identifier<'a>(
|
||||
name: &Atom,
|
||||
span: Span,
|
||||
node: &AstNode<'a>,
|
||||
ctx: &SemanticBuilder<'a>,
|
||||
) {
|
||||
// ts module block allows revered keywords
|
||||
if ctx.current_scope_flags().is_ts_module_block() {
|
||||
return;
|
||||
|
|
@ -248,7 +167,7 @@ fn invalid_let_declaration(x0: &str, span1: Span) -> OxcDiagnostic {
|
|||
.with_labels([span1.into()])
|
||||
}
|
||||
|
||||
fn check_binding_identifier<'a>(
|
||||
pub fn check_binding_identifier<'a>(
|
||||
ident: &BindingIdentifier,
|
||||
node: &AstNode<'a>,
|
||||
ctx: &SemanticBuilder<'a>,
|
||||
|
|
@ -280,7 +199,7 @@ fn unexpected_arguments(x0: &str, span1: Span) -> OxcDiagnostic {
|
|||
OxcDiagnostic::error(format!("'arguments' is not allowed in {x0}")).with_labels([span1.into()])
|
||||
}
|
||||
|
||||
fn check_identifier_reference<'a>(
|
||||
pub fn check_identifier_reference<'a>(
|
||||
ident: &IdentifierReference,
|
||||
node: &AstNode<'a>,
|
||||
ctx: &SemanticBuilder<'a>,
|
||||
|
|
@ -326,7 +245,10 @@ fn private_not_in_class(x0: &str, span1: Span) -> OxcDiagnostic {
|
|||
.with_labels([span1.into()])
|
||||
}
|
||||
|
||||
fn check_private_identifier_outside_class(ident: &PrivateIdentifier, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_private_identifier_outside_class(
|
||||
ident: &PrivateIdentifier,
|
||||
ctx: &SemanticBuilder<'_>,
|
||||
) {
|
||||
if ctx.class_table_builder.current_class_id.is_none() {
|
||||
ctx.error(private_not_in_class(&ident.name, ident.span));
|
||||
}
|
||||
|
|
@ -365,7 +287,7 @@ fn leading_zero_decimal(span0: Span) -> OxcDiagnostic {
|
|||
.with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_number_literal(lit: &NumericLiteral, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_number_literal(lit: &NumericLiteral, ctx: &SemanticBuilder<'_>) {
|
||||
// NumericLiteral :: legacy_octalIntegerLiteral
|
||||
// DecimalIntegerLiteral :: NonOctalDecimalIntegerLiteral
|
||||
// * It is a Syntax Error if the source text matched by this production is strict mode code.
|
||||
|
|
@ -398,7 +320,7 @@ fn non_octal_decimal_escape_sequence(span0: Span) -> OxcDiagnostic {
|
|||
.with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_string_literal(lit: &StringLiteral, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_string_literal(lit: &StringLiteral, ctx: &SemanticBuilder<'_>) {
|
||||
// 12.9.4.1 Static Semantics: Early Errors
|
||||
// EscapeSequence ::
|
||||
// legacy_octalEscapeSequence
|
||||
|
|
@ -437,7 +359,7 @@ fn illegal_use_strict(span0: Span) -> OxcDiagnostic {
|
|||
|
||||
// It is a Syntax Error if FunctionBodyContainsUseStrict of AsyncFunctionBody is true and IsSimpleParameterList of FormalParameters is false.
|
||||
// background: https://humanwhocodes.com/blog/2016/10/the-ecmascript-2016-change-you-probably-dont-know/
|
||||
fn check_directive(directive: &Directive, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_directive(directive: &Directive, ctx: &SemanticBuilder<'_>) {
|
||||
if directive.directive != "use strict" {
|
||||
return;
|
||||
}
|
||||
|
|
@ -466,7 +388,7 @@ fn module_code(x0: &str, span1: Span) -> OxcDiagnostic {
|
|||
OxcDiagnostic::error(format!("Cannot use {x0} outside a module")).with_labels([span1.into()])
|
||||
}
|
||||
|
||||
fn check_module_declaration<'a>(
|
||||
pub fn check_module_declaration<'a>(
|
||||
decl: &ModuleDeclaration,
|
||||
node: &AstNode<'a>,
|
||||
ctx: &SemanticBuilder<'a>,
|
||||
|
|
@ -523,7 +445,7 @@ fn import_meta_property(span0: Span) -> OxcDiagnostic {
|
|||
.with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_meta_property<'a>(prop: &MetaProperty, node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
|
||||
pub fn check_meta_property<'a>(prop: &MetaProperty, node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
|
||||
match prop.meta.name.as_str() {
|
||||
"import" => {
|
||||
if prop.property.name == "meta" {
|
||||
|
|
@ -573,7 +495,7 @@ fn function_declaration_non_strict(span0: Span) -> OxcDiagnostic {
|
|||
.with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_function_declaration<'a>(
|
||||
pub fn check_function_declaration<'a>(
|
||||
stmt: &Statement<'a>,
|
||||
is_if_stmt_or_labeled_stmt: bool,
|
||||
ctx: &SemanticBuilder<'a>,
|
||||
|
|
@ -595,7 +517,7 @@ fn reg_exp_flag_u_and_v(span0: Span) -> OxcDiagnostic {
|
|||
.with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_regexp_literal(lit: &RegExpLiteral, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_regexp_literal(lit: &RegExpLiteral, ctx: &SemanticBuilder<'_>) {
|
||||
let flags = lit.regex.flags;
|
||||
if flags.contains(RegExpFlags::U | RegExpFlags::V) {
|
||||
ctx.error(reg_exp_flag_u_and_v(lit.span));
|
||||
|
|
@ -606,13 +528,13 @@ fn with_statement(span0: Span) -> OxcDiagnostic {
|
|||
OxcDiagnostic::error("'with' statements are not allowed").with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_with_statement(stmt: &WithStatement, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_with_statement(stmt: &WithStatement, ctx: &SemanticBuilder<'_>) {
|
||||
if ctx.strict_mode() || ctx.source_type.is_typescript() {
|
||||
ctx.error(with_statement(Span::new(stmt.span.start, stmt.span.start + 4)));
|
||||
}
|
||||
}
|
||||
|
||||
fn check_switch_statement<'a>(stmt: &SwitchStatement<'a>, ctx: &SemanticBuilder<'a>) {
|
||||
pub fn check_switch_statement<'a>(stmt: &SwitchStatement<'a>, ctx: &SemanticBuilder<'a>) {
|
||||
let mut previous_default: Option<Span> = None;
|
||||
for case in &stmt.cases {
|
||||
if case.test.is_none() {
|
||||
|
|
@ -669,7 +591,11 @@ fn invalid_break(span0: Span) -> OxcDiagnostic {
|
|||
.with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_break_statement<'a>(stmt: &BreakStatement, node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
|
||||
pub fn check_break_statement<'a>(
|
||||
stmt: &BreakStatement,
|
||||
node: &AstNode<'a>,
|
||||
ctx: &SemanticBuilder<'a>,
|
||||
) {
|
||||
if let Some(label) = &stmt.label {
|
||||
return check_label(label, ctx, false);
|
||||
}
|
||||
|
|
@ -697,7 +623,7 @@ fn invalid_continue(span0: Span) -> OxcDiagnostic {
|
|||
.with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_continue_statement<'a>(
|
||||
pub fn check_continue_statement<'a>(
|
||||
stmt: &ContinueStatement,
|
||||
node: &AstNode<'a>,
|
||||
ctx: &SemanticBuilder<'a>,
|
||||
|
|
@ -719,7 +645,7 @@ fn check_continue_statement<'a>(
|
|||
}
|
||||
|
||||
#[allow(clippy::option_if_let_else)]
|
||||
fn check_labeled_statement(ctx: &SemanticBuilder) {
|
||||
pub fn check_labeled_statement(ctx: &SemanticBuilder) {
|
||||
ctx.label_builder.labels.iter().for_each(|labels| {
|
||||
let mut defined = FxHashMap::default();
|
||||
for labeled in labels {
|
||||
|
|
@ -744,7 +670,7 @@ fn unexpected_initializer_in_for_loop_head(x0: &str, span1: Span) -> OxcDiagnost
|
|||
.with_labels([span1.into()])
|
||||
}
|
||||
|
||||
fn check_for_statement_left<'a>(
|
||||
pub fn check_for_statement_left<'a>(
|
||||
left: &ForStatementLeft,
|
||||
is_for_in: bool,
|
||||
_node: &AstNode<'a>,
|
||||
|
|
@ -790,7 +716,7 @@ fn require_class_name(span0: Span) -> OxcDiagnostic {
|
|||
OxcDiagnostic::error("A class name is required.").with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_class(class: &Class, node: &AstNode<'_>, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_class(class: &Class, node: &AstNode<'_>, ctx: &SemanticBuilder<'_>) {
|
||||
check_private_identifier(ctx);
|
||||
|
||||
if class.is_declaration()
|
||||
|
|
@ -855,7 +781,7 @@ fn check_getter(function: &Function<'_>, ctx: &SemanticBuilder<'_>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_method_definition(method: &MethodDefinition<'_>, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_method_definition(method: &MethodDefinition<'_>, ctx: &SemanticBuilder<'_>) {
|
||||
match method.kind {
|
||||
MethodDefinitionKind::Set => check_setter(&method.value, ctx),
|
||||
MethodDefinitionKind::Get => check_getter(&method.value, ctx),
|
||||
|
|
@ -882,7 +808,7 @@ fn unexpected_super_reference(span0: Span) -> OxcDiagnostic {
|
|||
.with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_super<'a>(sup: &Super, node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
|
||||
pub fn check_super<'a>(sup: &Super, node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
|
||||
let super_call_span = match ctx.nodes.parent_kind(node.id()) {
|
||||
Some(AstKind::CallExpression(expr)) => Some(expr.span),
|
||||
Some(AstKind::NewExpression(expr)) => Some(expr.span),
|
||||
|
|
@ -973,7 +899,7 @@ fn cover_initialized_name(span0: Span) -> OxcDiagnostic {
|
|||
.with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_object_property(prop: &ObjectProperty, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_object_property(prop: &ObjectProperty, ctx: &SemanticBuilder<'_>) {
|
||||
// PropertyDefinition : cover_initialized_name
|
||||
// It is a Syntax Error if any source text is matched by this production.
|
||||
if let Some(expr) = &prop.init {
|
||||
|
|
@ -993,7 +919,7 @@ fn a_rest_parameter_cannot_have_an_initializer(span0: Span) -> OxcDiagnostic {
|
|||
OxcDiagnostic::error("A rest parameter cannot have an initializer").with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_formal_parameters<'a>(
|
||||
pub fn check_formal_parameters<'a>(
|
||||
params: &FormalParameters,
|
||||
_node: &AstNode<'a>,
|
||||
ctx: &SemanticBuilder<'a>,
|
||||
|
|
@ -1005,7 +931,7 @@ fn check_formal_parameters<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn check_array_pattern(pattern: &ArrayPattern, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_array_pattern(pattern: &ArrayPattern, ctx: &SemanticBuilder<'_>) {
|
||||
// function foo([...x = []]) { }
|
||||
// ^^^^ A rest element cannot have an initializer
|
||||
if let Some(rest) = &pattern.rest {
|
||||
|
|
@ -1019,7 +945,7 @@ fn assignment_is_not_simple(span0: Span) -> OxcDiagnostic {
|
|||
OxcDiagnostic::error("Invalid left-hand side in assignment").with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_assignment_expression(assign_expr: &AssignmentExpression, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_assignment_expression(assign_expr: &AssignmentExpression, ctx: &SemanticBuilder<'_>) {
|
||||
// AssignmentExpression :
|
||||
// LeftHandSideExpression AssignmentOperator AssignmentExpression
|
||||
// LeftHandSideExpression &&= AssignmentExpression
|
||||
|
|
@ -1033,7 +959,7 @@ fn check_assignment_expression(assign_expr: &AssignmentExpression, ctx: &Semanti
|
|||
}
|
||||
}
|
||||
|
||||
fn check_object_expression(obj_expr: &ObjectExpression, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_object_expression(obj_expr: &ObjectExpression, ctx: &SemanticBuilder<'_>) {
|
||||
// ObjectLiteral : { PropertyDefinitionList }
|
||||
// It is a Syntax Error if PropertyNameList of PropertyDefinitionList contains any duplicate entries for "__proto__"
|
||||
// and at least two of those entries were obtained from productions of the form PropertyDefinition : PropertyName : AssignmentExpression
|
||||
|
|
@ -1055,7 +981,7 @@ fn unexpected_exponential(x0: &str, span1: Span) -> OxcDiagnostic {
|
|||
.with_labels([span1.into()])
|
||||
}
|
||||
|
||||
fn check_binary_expression(binary_expr: &BinaryExpression, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_binary_expression(binary_expr: &BinaryExpression, ctx: &SemanticBuilder<'_>) {
|
||||
if binary_expr.operator == BinaryOperator::Exponential {
|
||||
match binary_expr.left {
|
||||
// async () => await 5 ** 6
|
||||
|
|
@ -1078,7 +1004,7 @@ fn mixed_coalesce(span0: Span) -> OxcDiagnostic {
|
|||
.with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_logical_expression(logical_expr: &LogicalExpression, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_logical_expression(logical_expr: &LogicalExpression, ctx: &SemanticBuilder<'_>) {
|
||||
// check mixed coalesce
|
||||
// a ?? b || c - a ?? (b || c)
|
||||
// a ?? b && c - a ?? (b && c)
|
||||
|
|
@ -1103,7 +1029,7 @@ fn super_private(span0: Span) -> OxcDiagnostic {
|
|||
OxcDiagnostic::error("Private fields cannot be accessed on super").with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_member_expression(member_expr: &MemberExpression, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_member_expression(member_expr: &MemberExpression, ctx: &SemanticBuilder<'_>) {
|
||||
if let MemberExpression::PrivateFieldExpression(private_expr) = member_expr {
|
||||
// super.#m
|
||||
if let Expression::Super(_) = &private_expr.object {
|
||||
|
|
@ -1121,7 +1047,7 @@ fn delete_private_field(span0: Span) -> OxcDiagnostic {
|
|||
OxcDiagnostic::error("Private fields can not be deleted").with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_unary_expression<'a>(
|
||||
pub fn check_unary_expression<'a>(
|
||||
unary_expr: &'a UnaryExpression,
|
||||
_node: &AstNode<'a>,
|
||||
ctx: &SemanticBuilder<'a>,
|
||||
|
|
@ -1162,7 +1088,7 @@ fn await_or_yield_in_parameter(x0: &str, span1: Span) -> OxcDiagnostic {
|
|||
])
|
||||
}
|
||||
|
||||
fn check_await_expression<'a>(
|
||||
pub fn check_await_expression<'a>(
|
||||
expr: &AwaitExpression,
|
||||
node: &AstNode<'a>,
|
||||
ctx: &SemanticBuilder<'a>,
|
||||
|
|
@ -1177,7 +1103,7 @@ fn check_await_expression<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn check_yield_expression<'a>(
|
||||
pub fn check_yield_expression<'a>(
|
||||
expr: &YieldExpression,
|
||||
node: &AstNode<'a>,
|
||||
ctx: &SemanticBuilder<'a>,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,105 @@
|
|||
mod javascript;
|
||||
mod typescript;
|
||||
|
||||
pub use javascript::EarlyErrorJavaScript;
|
||||
pub use typescript::EarlyErrorTypeScript;
|
||||
use javascript as js;
|
||||
use typescript as ts;
|
||||
|
||||
use oxc_ast::{
|
||||
ast::{DoWhileStatement, ForStatement, WhileStatement},
|
||||
AstKind,
|
||||
};
|
||||
|
||||
use crate::{builder::SemanticBuilder, AstNode};
|
||||
|
||||
pub use javascript::check_module_record;
|
||||
|
||||
pub fn check<'a>(node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
|
||||
let kind = node.kind();
|
||||
|
||||
match kind {
|
||||
AstKind::Program(_) => {
|
||||
js::check_labeled_statement(ctx);
|
||||
js::check_duplicate_class_elements(ctx);
|
||||
}
|
||||
AstKind::BindingIdentifier(ident) => {
|
||||
js::check_identifier(&ident.name, ident.span, node, ctx);
|
||||
js::check_binding_identifier(ident, node, ctx);
|
||||
}
|
||||
AstKind::IdentifierReference(ident) => {
|
||||
js::check_identifier(&ident.name, ident.span, node, ctx);
|
||||
js::check_identifier_reference(ident, node, ctx);
|
||||
}
|
||||
AstKind::LabelIdentifier(ident) => js::check_identifier(&ident.name, ident.span, node, ctx),
|
||||
AstKind::PrivateIdentifier(ident) => js::check_private_identifier_outside_class(ident, ctx),
|
||||
AstKind::NumericLiteral(lit) => js::check_number_literal(lit, ctx),
|
||||
AstKind::StringLiteral(lit) => js::check_string_literal(lit, ctx),
|
||||
AstKind::RegExpLiteral(lit) => js::check_regexp_literal(lit, ctx),
|
||||
|
||||
AstKind::Directive(dir) => js::check_directive(dir, ctx),
|
||||
AstKind::ModuleDeclaration(decl) => {
|
||||
js::check_module_declaration(decl, node, ctx);
|
||||
}
|
||||
AstKind::MetaProperty(prop) => js::check_meta_property(prop, node, ctx),
|
||||
|
||||
AstKind::WithStatement(stmt) => {
|
||||
js::check_function_declaration(&stmt.body, false, ctx);
|
||||
js::check_with_statement(stmt, ctx);
|
||||
}
|
||||
AstKind::SwitchStatement(stmt) => js::check_switch_statement(stmt, ctx),
|
||||
AstKind::BreakStatement(stmt) => js::check_break_statement(stmt, node, ctx),
|
||||
AstKind::ContinueStatement(stmt) => js::check_continue_statement(stmt, node, ctx),
|
||||
AstKind::LabeledStatement(stmt) => {
|
||||
js::check_function_declaration(&stmt.body, true, ctx);
|
||||
}
|
||||
AstKind::ForInStatement(stmt) => {
|
||||
js::check_function_declaration(&stmt.body, false, ctx);
|
||||
js::check_for_statement_left(&stmt.left, true, node, ctx);
|
||||
}
|
||||
AstKind::ForOfStatement(stmt) => {
|
||||
js::check_function_declaration(&stmt.body, false, ctx);
|
||||
js::check_for_statement_left(&stmt.left, false, node, ctx);
|
||||
}
|
||||
AstKind::WhileStatement(WhileStatement { body, .. })
|
||||
| AstKind::DoWhileStatement(DoWhileStatement { body, .. })
|
||||
| AstKind::ForStatement(ForStatement { body, .. }) => {
|
||||
js::check_function_declaration(body, false, ctx);
|
||||
}
|
||||
AstKind::IfStatement(stmt) => {
|
||||
js::check_function_declaration(&stmt.consequent, true, ctx);
|
||||
if let Some(alternate) = &stmt.alternate {
|
||||
js::check_function_declaration(alternate, true, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
AstKind::Class(class) => js::check_class(class, node, ctx),
|
||||
AstKind::MethodDefinition(method) => js::check_method_definition(method, ctx),
|
||||
AstKind::ObjectProperty(prop) => js::check_object_property(prop, ctx),
|
||||
AstKind::Super(sup) => js::check_super(sup, node, ctx),
|
||||
|
||||
AstKind::FormalParameters(params) => {
|
||||
js::check_formal_parameters(params, node, ctx);
|
||||
ts::check_formal_parameters(params, ctx);
|
||||
}
|
||||
AstKind::ArrayPattern(pat) => {
|
||||
js::check_array_pattern(pat, ctx);
|
||||
ts::check_array_pattern(pat, ctx);
|
||||
}
|
||||
|
||||
AstKind::AssignmentExpression(expr) => js::check_assignment_expression(expr, ctx),
|
||||
AstKind::AwaitExpression(expr) => js::check_await_expression(expr, node, ctx),
|
||||
AstKind::BinaryExpression(expr) => js::check_binary_expression(expr, ctx),
|
||||
AstKind::LogicalExpression(expr) => js::check_logical_expression(expr, ctx),
|
||||
AstKind::MemberExpression(expr) => js::check_member_expression(expr, ctx),
|
||||
AstKind::ObjectExpression(expr) => js::check_object_expression(expr, ctx),
|
||||
AstKind::UnaryExpression(expr) => js::check_unary_expression(expr, node, ctx),
|
||||
AstKind::YieldExpression(expr) => js::check_yield_expression(expr, node, ctx),
|
||||
AstKind::VariableDeclarator(decl) => ts::check_variable_declarator(decl, ctx),
|
||||
AstKind::SimpleAssignmentTarget(target) => ts::check_simple_assignment_target(target, ctx),
|
||||
AstKind::TSTypeParameterDeclaration(declaration) => {
|
||||
ts::check_ts_type_parameter_declaration(declaration, ctx);
|
||||
}
|
||||
AstKind::TSModuleDeclaration(decl) => ts::check_ts_module_declaration(decl, ctx),
|
||||
AstKind::TSEnumDeclaration(decl) => ts::check_ts_enum_declaration(decl, ctx),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,34 +5,13 @@ use oxc_diagnostics::OxcDiagnostic;
|
|||
use oxc_span::{Atom, GetSpan, Span};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{builder::SemanticBuilder, diagnostics::redeclaration, AstNode};
|
||||
|
||||
pub struct EarlyErrorTypeScript;
|
||||
|
||||
impl EarlyErrorTypeScript {
|
||||
pub fn run<'a>(node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
|
||||
let kind = node.kind();
|
||||
|
||||
match kind {
|
||||
AstKind::VariableDeclarator(decl) => check_variable_declarator(decl, ctx),
|
||||
AstKind::SimpleAssignmentTarget(target) => check_simple_assignment_target(target, ctx),
|
||||
AstKind::FormalParameters(params) => check_formal_parameters(params, ctx),
|
||||
AstKind::ArrayPattern(pattern) => check_array_pattern(pattern, ctx),
|
||||
AstKind::TSTypeParameterDeclaration(declaration) => {
|
||||
check_ts_type_parameter_declaration(declaration, ctx);
|
||||
}
|
||||
AstKind::TSModuleDeclaration(decl) => check_ts_module_declaration(decl, ctx),
|
||||
AstKind::TSEnumDeclaration(decl) => check_ts_enum_declaration(decl, ctx),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
use crate::{builder::SemanticBuilder, diagnostics::redeclaration};
|
||||
|
||||
fn empty_type_parameter_list(span0: Span) -> OxcDiagnostic {
|
||||
OxcDiagnostic::error("Type parameter list cannot be empty.").with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_ts_type_parameter_declaration(
|
||||
pub fn check_ts_type_parameter_declaration(
|
||||
declaration: &TSTypeParameterDeclaration<'_>,
|
||||
ctx: &SemanticBuilder<'_>,
|
||||
) {
|
||||
|
|
@ -46,7 +25,7 @@ fn unexpected_optional(span0: Span) -> OxcDiagnostic {
|
|||
}
|
||||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn check_variable_declarator(decl: &VariableDeclarator, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_variable_declarator(decl: &VariableDeclarator, ctx: &SemanticBuilder<'_>) {
|
||||
if decl.id.optional {
|
||||
let start = decl.id.span().end;
|
||||
let Some(offset) = ctx.source_text[start as usize..].find('?') else { return };
|
||||
|
|
@ -65,7 +44,7 @@ fn parameter_property_outside_constructor(span0: Span) -> OxcDiagnostic {
|
|||
.with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_formal_parameters(params: &FormalParameters, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_formal_parameters(params: &FormalParameters, ctx: &SemanticBuilder<'_>) {
|
||||
if !params.is_empty() && params.kind == FormalParameterKind::Signature {
|
||||
check_duplicate_bound_names(params, ctx);
|
||||
}
|
||||
|
|
@ -105,7 +84,7 @@ fn unexpected_assignment(span0: Span) -> OxcDiagnostic {
|
|||
.with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_simple_assignment_target<'a>(
|
||||
pub fn check_simple_assignment_target<'a>(
|
||||
target: &SimpleAssignmentTarget<'a>,
|
||||
ctx: &SemanticBuilder<'a>,
|
||||
) {
|
||||
|
|
@ -125,7 +104,7 @@ fn unexpected_type_annotation(span0: Span) -> OxcDiagnostic {
|
|||
OxcDiagnostic::error("Unexpected type annotation").with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_array_pattern<'a>(pattern: &ArrayPattern<'a>, ctx: &SemanticBuilder<'a>) {
|
||||
pub fn check_array_pattern<'a>(pattern: &ArrayPattern<'a>, ctx: &SemanticBuilder<'a>) {
|
||||
for element in &pattern.elements {
|
||||
let _ = element.as_ref().map(|element| {
|
||||
if let Some(type_annotation) = &element.type_annotation {
|
||||
|
|
@ -142,7 +121,7 @@ fn not_allowed_namespace_declaration(span0: Span) -> OxcDiagnostic {
|
|||
.with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_ts_module_declaration<'a>(decl: &TSModuleDeclaration<'a>, ctx: &SemanticBuilder<'a>) {
|
||||
pub fn check_ts_module_declaration<'a>(decl: &TSModuleDeclaration<'a>, ctx: &SemanticBuilder<'a>) {
|
||||
// skip current node
|
||||
for node in ctx.nodes.iter_parents(ctx.current_node_id).skip(1) {
|
||||
match node.kind() {
|
||||
|
|
@ -165,7 +144,7 @@ fn enum_member_must_have_initializer(span0: Span) -> OxcDiagnostic {
|
|||
OxcDiagnostic::error("Enum member must have initializer.").with_labels([span0.into()])
|
||||
}
|
||||
|
||||
fn check_ts_enum_declaration(decl: &TSEnumDeclaration<'_>, ctx: &SemanticBuilder<'_>) {
|
||||
pub fn check_ts_enum_declaration(decl: &TSEnumDeclaration<'_>, ctx: &SemanticBuilder<'_>) {
|
||||
let mut need_initializer = false;
|
||||
|
||||
decl.members.iter().for_each(|member| {
|
||||
|
|
|
|||
Loading…
Reference in a new issue