mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(ast): add CatchParameter node (#3049)
This commit is contained in:
parent
1f7033e7ab
commit
92d709bf21
13 changed files with 81 additions and 46 deletions
|
|
@ -1641,10 +1641,19 @@ pub struct TryStatement<'a> {
|
||||||
pub struct CatchClause<'a> {
|
pub struct CatchClause<'a> {
|
||||||
#[cfg_attr(feature = "serialize", serde(flatten))]
|
#[cfg_attr(feature = "serialize", serde(flatten))]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub param: Option<BindingPattern<'a>>,
|
pub param: Option<CatchParameter<'a>>,
|
||||||
pub body: Box<'a, BlockStatement<'a>>,
|
pub body: Box<'a, BlockStatement<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Hash)]
|
||||||
|
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||||
|
#[cfg_attr(feature = "serialize", serde(tag = "type"))]
|
||||||
|
pub struct CatchParameter<'a> {
|
||||||
|
#[cfg_attr(feature = "serialize", serde(flatten))]
|
||||||
|
pub span: Span,
|
||||||
|
pub pattern: BindingPattern<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Debugger Statement
|
/// Debugger Statement
|
||||||
#[derive(Debug, Hash)]
|
#[derive(Debug, Hash)]
|
||||||
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
|
||||||
|
|
|
||||||
|
|
@ -395,12 +395,16 @@ impl<'a> AstBuilder<'a> {
|
||||||
pub fn catch_clause(
|
pub fn catch_clause(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
param: Option<BindingPattern<'a>>,
|
param: Option<CatchParameter<'a>>,
|
||||||
body: Box<'a, BlockStatement<'a>>,
|
body: Box<'a, BlockStatement<'a>>,
|
||||||
) -> Box<'a, CatchClause<'a>> {
|
) -> Box<'a, CatchClause<'a>> {
|
||||||
self.alloc(CatchClause { span, param, body })
|
self.alloc(CatchClause { span, param, body })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn catch_parameter(&self, span: Span, pattern: BindingPattern<'a>) -> CatchParameter<'a> {
|
||||||
|
CatchParameter { span, pattern }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn while_statement(
|
pub fn while_statement(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,7 @@ ast_kinds! {
|
||||||
FunctionBody(&'a FunctionBody<'a>),
|
FunctionBody(&'a FunctionBody<'a>),
|
||||||
FormalParameters(&'a FormalParameters<'a>),
|
FormalParameters(&'a FormalParameters<'a>),
|
||||||
FormalParameter(&'a FormalParameter<'a>),
|
FormalParameter(&'a FormalParameter<'a>),
|
||||||
|
CatchParameter(&'a CatchParameter<'a>),
|
||||||
|
|
||||||
Class(&'a Class<'a>),
|
Class(&'a Class<'a>),
|
||||||
ClassBody(&'a ClassBody<'a>),
|
ClassBody(&'a ClassBody<'a>),
|
||||||
|
|
@ -443,6 +444,7 @@ impl<'a> GetSpan for AstKind<'a> {
|
||||||
Self::FunctionBody(x) => x.span,
|
Self::FunctionBody(x) => x.span,
|
||||||
Self::FormalParameters(x) => x.span,
|
Self::FormalParameters(x) => x.span,
|
||||||
Self::FormalParameter(x) => x.span,
|
Self::FormalParameter(x) => x.span,
|
||||||
|
Self::CatchParameter(x) => x.span,
|
||||||
|
|
||||||
Self::Class(x) => x.span,
|
Self::Class(x) => x.span,
|
||||||
Self::ClassBody(x) => x.span,
|
Self::ClassBody(x) => x.span,
|
||||||
|
|
@ -640,6 +642,7 @@ impl<'a> AstKind<'a> {
|
||||||
Self::FunctionBody(_) => "FunctionBody".into(),
|
Self::FunctionBody(_) => "FunctionBody".into(),
|
||||||
Self::FormalParameters(_) => "FormalParameters".into(),
|
Self::FormalParameters(_) => "FormalParameters".into(),
|
||||||
Self::FormalParameter(_) => "FormalParameter".into(),
|
Self::FormalParameter(_) => "FormalParameter".into(),
|
||||||
|
Self::CatchParameter(_) => "CatchParameter".into(),
|
||||||
|
|
||||||
Self::Class(c) => format!(
|
Self::Class(c) => format!(
|
||||||
"Class({})",
|
"Class({})",
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,10 @@ pub trait Visit<'a>: Sized {
|
||||||
walk_catch_clause(self, clause);
|
walk_catch_clause(self, clause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_catch_parameter(&mut self, param: &CatchParameter<'a>) {
|
||||||
|
walk_catch_parameter(self, param);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_finally_clause(&mut self, clause: &BlockStatement<'a>) {
|
fn visit_finally_clause(&mut self, clause: &BlockStatement<'a>) {
|
||||||
walk_finally_clause(self, clause);
|
walk_finally_clause(self, clause);
|
||||||
}
|
}
|
||||||
|
|
@ -1145,13 +1149,20 @@ pub mod walk {
|
||||||
visitor.enter_scope(ScopeFlags::empty());
|
visitor.enter_scope(ScopeFlags::empty());
|
||||||
visitor.enter_node(kind);
|
visitor.enter_node(kind);
|
||||||
if let Some(param) = &clause.param {
|
if let Some(param) = &clause.param {
|
||||||
visitor.visit_binding_pattern(param);
|
visitor.visit_catch_parameter(param);
|
||||||
}
|
}
|
||||||
visitor.visit_statements(&clause.body.body);
|
visitor.visit_statements(&clause.body.body);
|
||||||
visitor.leave_node(kind);
|
visitor.leave_node(kind);
|
||||||
visitor.leave_scope();
|
visitor.leave_scope();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn walk_catch_parameter<'a, V: Visit<'a>>(visitor: &mut V, param: &CatchParameter<'a>) {
|
||||||
|
let kind = AstKind::CatchParameter(visitor.alloc(param));
|
||||||
|
visitor.enter_node(kind);
|
||||||
|
visitor.visit_binding_pattern(¶m.pattern);
|
||||||
|
visitor.leave_node(kind);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn walk_finally_clause<'a, V: Visit<'a>>(visitor: &mut V, clause: &BlockStatement<'a>) {
|
pub fn walk_finally_clause<'a, V: Visit<'a>>(visitor: &mut V, clause: &BlockStatement<'a>) {
|
||||||
let kind = AstKind::FinallyClause(visitor.alloc(clause));
|
let kind = AstKind::FinallyClause(visitor.alloc(clause));
|
||||||
visitor.enter_scope(ScopeFlags::empty());
|
visitor.enter_scope(ScopeFlags::empty());
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,10 @@ pub trait VisitMut<'a>: Sized {
|
||||||
walk_catch_clause_mut(self, clause);
|
walk_catch_clause_mut(self, clause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_catch_parameter(&mut self, param: &mut CatchParameter<'a>) {
|
||||||
|
walk_catch_parameter_mut(self, param);
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_finally_clause(&mut self, clause: &mut BlockStatement<'a>) {
|
fn visit_finally_clause(&mut self, clause: &mut BlockStatement<'a>) {
|
||||||
walk_finally_clause_mut(self, clause);
|
walk_finally_clause_mut(self, clause);
|
||||||
}
|
}
|
||||||
|
|
@ -1147,13 +1151,23 @@ pub mod walk_mut {
|
||||||
visitor.enter_scope(ScopeFlags::empty());
|
visitor.enter_scope(ScopeFlags::empty());
|
||||||
visitor.enter_node(kind);
|
visitor.enter_node(kind);
|
||||||
if let Some(param) = &mut clause.param {
|
if let Some(param) = &mut clause.param {
|
||||||
visitor.visit_binding_pattern(param);
|
visitor.visit_catch_parameter(param);
|
||||||
}
|
}
|
||||||
visitor.visit_statements(&mut clause.body.body);
|
visitor.visit_statements(&mut clause.body.body);
|
||||||
visitor.leave_node(kind);
|
visitor.leave_node(kind);
|
||||||
visitor.leave_scope();
|
visitor.leave_scope();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn walk_catch_parameter_mut<'a, V: VisitMut<'a>>(
|
||||||
|
visitor: &mut V,
|
||||||
|
param: &mut CatchParameter<'a>,
|
||||||
|
) {
|
||||||
|
let kind = AstType::CatchParameter;
|
||||||
|
visitor.enter_node(kind);
|
||||||
|
visitor.visit_binding_pattern(&mut param.pattern);
|
||||||
|
visitor.leave_node(kind);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn walk_finally_clause_mut<'a, V: VisitMut<'a>>(
|
pub fn walk_finally_clause_mut<'a, V: VisitMut<'a>>(
|
||||||
visitor: &mut V,
|
visitor: &mut V,
|
||||||
clause: &mut BlockStatement<'a>,
|
clause: &mut BlockStatement<'a>,
|
||||||
|
|
|
||||||
|
|
@ -455,7 +455,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TryStatement<'a> {
|
||||||
p.print_str(b"catch");
|
p.print_str(b"catch");
|
||||||
if let Some(param) = &handler.param {
|
if let Some(param) = &handler.param {
|
||||||
p.print_str(b"(");
|
p.print_str(b"(");
|
||||||
param.gen(p, ctx);
|
param.pattern.gen(p, ctx);
|
||||||
p.print_str(b")");
|
p.print_str(b")");
|
||||||
}
|
}
|
||||||
p.print_block1(&handler.body, ctx);
|
p.print_block1(&handler.body, ctx);
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ impl Rule for NoUselessCatch {
|
||||||
let AstKind::TryStatement(try_stmt) = node.kind() else { return };
|
let AstKind::TryStatement(try_stmt) = node.kind() else { return };
|
||||||
let Some(catch_clause) = &try_stmt.handler else { return };
|
let Some(catch_clause) = &try_stmt.handler else { return };
|
||||||
let Some(BindingPatternKind::BindingIdentifier(binding_ident)) =
|
let Some(BindingPatternKind::BindingIdentifier(binding_ident)) =
|
||||||
catch_clause.param.as_ref().map(|pattern| &pattern.kind)
|
catch_clause.param.as_ref().map(|param| ¶m.pattern.kind)
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -84,32 +84,30 @@ impl Rule for CatchErrorName {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||||
if let AstKind::CatchClause(catch_node) = node.kind() {
|
if let AstKind::CatchParameter(catch_param) = node.kind() {
|
||||||
if let Some(catch_param) = &catch_node.param {
|
if let oxc_ast::ast::BindingPatternKind::BindingIdentifier(binding_ident) =
|
||||||
if let oxc_ast::ast::BindingPatternKind::BindingIdentifier(binding_ident) =
|
&catch_param.pattern.kind
|
||||||
&catch_param.kind
|
{
|
||||||
{
|
if self.is_name_allowed(&binding_ident.name) {
|
||||||
if self.is_name_allowed(&binding_ident.name) {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if binding_ident.name.starts_with('_') {
|
|
||||||
if symbol_has_references(binding_ident.symbol_id.get(), ctx) {
|
|
||||||
ctx.diagnostic(CatchErrorNameDiagnostic(
|
|
||||||
binding_ident.name.to_compact_str(),
|
|
||||||
self.name.clone(),
|
|
||||||
binding_ident.span,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.diagnostic(CatchErrorNameDiagnostic(
|
|
||||||
binding_ident.name.to_compact_str(),
|
|
||||||
self.name.clone(),
|
|
||||||
binding_ident.span,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if binding_ident.name.starts_with('_') {
|
||||||
|
if symbol_has_references(binding_ident.symbol_id.get(), ctx) {
|
||||||
|
ctx.diagnostic(CatchErrorNameDiagnostic(
|
||||||
|
binding_ident.name.to_compact_str(),
|
||||||
|
self.name.clone(),
|
||||||
|
binding_ident.span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.diagnostic(CatchErrorNameDiagnostic(
|
||||||
|
binding_ident.name.to_compact_str(),
|
||||||
|
self.name.clone(),
|
||||||
|
binding_ident.span,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,17 +46,12 @@ declare_oxc_lint!(
|
||||||
|
|
||||||
impl Rule for PreferOptionalCatchBinding {
|
impl Rule for PreferOptionalCatchBinding {
|
||||||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||||
let AstKind::CatchClause(catch_clause) = node.kind() else { return };
|
let AstKind::CatchParameter(catch_param) = node.kind() else { return };
|
||||||
|
let references_count = get_param_references_count(&catch_param.pattern, ctx);
|
||||||
let Some(catch_param) = &catch_clause.param else { return };
|
|
||||||
|
|
||||||
let references_count = get_param_references_count(catch_param, ctx);
|
|
||||||
|
|
||||||
if references_count != 0 {
|
if references_count != 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ctx.diagnostic(PreferOptionalCatchBindingDiagnostic(catch_param.pattern.span()));
|
||||||
ctx.diagnostic(PreferOptionalCatchBindingDiagnostic(catch_param.span()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use oxc_allocator::{Box, Vec};
|
use oxc_allocator::{Box, Vec};
|
||||||
use oxc_ast::ast::*;
|
use oxc_ast::ast::*;
|
||||||
use oxc_diagnostics::Result;
|
use oxc_diagnostics::Result;
|
||||||
use oxc_span::{Atom, Span};
|
use oxc_span::{Atom, GetSpan, Span};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
declaration::{VariableDeclarationContext, VariableDeclarationParent},
|
declaration::{VariableDeclarationContext, VariableDeclarationParent},
|
||||||
|
|
@ -530,7 +530,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
fn parse_catch_clause(&mut self) -> Result<Box<'a, CatchClause<'a>>> {
|
fn parse_catch_clause(&mut self) -> Result<Box<'a, CatchClause<'a>>> {
|
||||||
let span = self.start_span();
|
let span = self.start_span();
|
||||||
self.bump_any(); // advance `catch`
|
self.bump_any(); // advance `catch`
|
||||||
let param = if self.eat(Kind::LParen) {
|
let pattern = if self.eat(Kind::LParen) {
|
||||||
let pattern = self.parse_binding_pattern(false)?;
|
let pattern = self.parse_binding_pattern(false)?;
|
||||||
self.expect(Kind::RParen)?;
|
self.expect(Kind::RParen)?;
|
||||||
Some(pattern)
|
Some(pattern)
|
||||||
|
|
@ -538,6 +538,7 @@ impl<'a> ParserImpl<'a> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let body = self.parse_block()?;
|
let body = self.parse_block()?;
|
||||||
|
let param = pattern.map(|pattern| self.ast.catch_parameter(pattern.kind.span(), pattern));
|
||||||
Ok(self.ast.catch_clause(self.end_span(span), param, body))
|
Ok(self.ast.catch_clause(self.end_span(span), param, body))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -501,7 +501,7 @@ impl<'a> Format<'a> for CatchClause<'a> {
|
||||||
parts.push(ss!("catch "));
|
parts.push(ss!("catch "));
|
||||||
if let Some(param) = &self.param {
|
if let Some(param) = &self.param {
|
||||||
parts.push(ss!("("));
|
parts.push(ss!("("));
|
||||||
parts.push(format!(p, param));
|
parts.push(format!(p, param.pattern));
|
||||||
parts.push(ss!(") "));
|
parts.push(ss!(") "));
|
||||||
}
|
}
|
||||||
parts.push(format!(p, self.body));
|
parts.push(format!(p, self.body));
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,7 @@ impl<'a> Binder for CatchClause<'a> {
|
||||||
// https://tc39.es/ecma262/#sec-variablestatements-in-catch-blocks
|
// https://tc39.es/ecma262/#sec-variablestatements-in-catch-blocks
|
||||||
// It is a Syntax Error if any element of the BoundNames of CatchParameter also occurs in the VarDeclaredNames of Block
|
// It is a Syntax Error if any element of the BoundNames of CatchParameter also occurs in the VarDeclaredNames of Block
|
||||||
// unless CatchParameter is CatchParameter : BindingIdentifier
|
// unless CatchParameter is CatchParameter : BindingIdentifier
|
||||||
if let BindingPatternKind::BindingIdentifier(ident) = ¶m.kind {
|
if let BindingPatternKind::BindingIdentifier(ident) = ¶m.pattern.kind {
|
||||||
let includes = SymbolFlags::FunctionScopedVariable | SymbolFlags::CatchVariable;
|
let includes = SymbolFlags::FunctionScopedVariable | SymbolFlags::CatchVariable;
|
||||||
let symbol_id = builder.declare_shadow_symbol(
|
let symbol_id = builder.declare_shadow_symbol(
|
||||||
&ident.name,
|
&ident.name,
|
||||||
|
|
@ -258,7 +258,7 @@ impl<'a> Binder for CatchClause<'a> {
|
||||||
);
|
);
|
||||||
ident.symbol_id.set(Some(symbol_id));
|
ident.symbol_id.set(Some(symbol_id));
|
||||||
} else {
|
} else {
|
||||||
param.bound_names(&mut |ident| {
|
param.pattern.bound_names(&mut |ident| {
|
||||||
let symbol_id = builder.declare_symbol(
|
let symbol_id = builder.declare_symbol(
|
||||||
ident.span,
|
ident.span,
|
||||||
&ident.name,
|
&ident.name,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue