From 8bccdab2e91ebbc5bfaa0f164bc5357632ba75d0 Mon Sep 17 00:00:00 2001 From: Dunqing Date: Mon, 22 Jan 2024 14:23:39 +0800 Subject: [PATCH] refactor(semantic): add binder for FormalParameters and RestElement, replacing the binder for FormalParameters (#2114) Similar with #2013. This way we will be able to find the corresponding Ast accurately. The snapshots look a little strange but the change is expected. --- crates/oxc_ast/src/ast/js.rs | 6 +++ .../src/rules/eslint/no_redeclare.rs | 10 ++-- .../src/rules/oxc/no_accumulating_spread.rs | 6 ++- crates/oxc_semantic/src/binder.rs | 49 ++++++++++++++----- crates/oxc_semantic/src/builder.rs | 7 ++- 5 files changed, 57 insertions(+), 21 deletions(-) diff --git a/crates/oxc_ast/src/ast/js.rs b/crates/oxc_ast/src/ast/js.rs index d4abb3169..c74464981 100644 --- a/crates/oxc_ast/src/ast/js.rs +++ b/crates/oxc_ast/src/ast/js.rs @@ -1648,6 +1648,12 @@ pub enum FormalParameterKind { Signature, } +impl FormalParameterKind { + pub fn is_signature(&self) -> bool { + matches!(self, Self::Signature) + } +} + impl<'a> FormalParameters<'a> { pub fn is_empty(&self) -> bool { self.items.is_empty() diff --git a/crates/oxc_linter/src/rules/eslint/no_redeclare.rs b/crates/oxc_linter/src/rules/eslint/no_redeclare.rs index 2633349ca..1f5f7ef3a 100644 --- a/crates/oxc_linter/src/rules/eslint/no_redeclare.rs +++ b/crates/oxc_linter/src/rules/eslint/no_redeclare.rs @@ -86,12 +86,10 @@ impl Rule for NoRedeclare { } } } - AstKind::FormalParameters(params) => { - for item in ¶ms.items { - if let BindingPatternKind::BindingIdentifier(ident) = &item.pattern.kind { - if *symbol_table.get_name(variable.symbol_id) == ident.name { - self.report_diagnostic(ctx, variable, ident); - } + AstKind::FormalParameter(param) => { + if let BindingPatternKind::BindingIdentifier(ident) = ¶m.pattern.kind { + if *symbol_table.get_name(variable.symbol_id) == ident.name { + self.report_diagnostic(ctx, variable, ident); } } } diff --git a/crates/oxc_linter/src/rules/oxc/no_accumulating_spread.rs b/crates/oxc_linter/src/rules/oxc/no_accumulating_spread.rs index 86f56151f..e0b4a6c08 100644 --- a/crates/oxc_linter/src/rules/oxc/no_accumulating_spread.rs +++ b/crates/oxc_linter/src/rules/oxc/no_accumulating_spread.rs @@ -89,8 +89,10 @@ impl Rule for NoAccumulatingSpread { let reference = symbols.get_reference(reference_id); let Some(referenced_symbol_id) = reference.symbol_id() else { return }; let declaration_id = symbols.get_declaration(referenced_symbol_id); - let declaration = ctx.semantic().nodes().get_node(declaration_id); - let AstKind::FormalParameters(params) = declaration.kind() else { return }; + let Some(declaration) = ctx.semantic().nodes().parent_node(declaration_id) else { return }; + let AstKind::FormalParameters(params) = declaration.kind() else { + return; + }; // We're only looking for the first parameter, since that's where acc is. // Skip non-parameter or non-first-parameter declarations. diff --git a/crates/oxc_semantic/src/binder.rs b/crates/oxc_semantic/src/binder.rs index f659b1dd9..e56a65819 100644 --- a/crates/oxc_semantic/src/binder.rs +++ b/crates/oxc_semantic/src/binder.rs @@ -182,13 +182,42 @@ impl<'a> Binder for Function<'a> { } } -impl<'a> Binder for FormalParameters<'a> { - // Binds the formal parameters of a function or method. +impl<'a> Binder for RestElement<'a> { + // Binds the FormalParameters's rest of a function or method. fn bind(&self, builder: &mut SemanticBuilder) { + let parent_kind = builder.nodes.parent_kind(builder.current_node_id).unwrap(); + let AstKind::FormalParameters(parameters) = parent_kind else { + return; + }; + + if parameters.kind.is_signature() { + return; + } + + let includes = SymbolFlags::FunctionScopedVariable; + let excludes = + SymbolFlags::FunctionScopedVariable | SymbolFlags::FunctionScopedVariableExcludes; + self.bound_names(&mut |ident| { + let symbol_id = builder.declare_symbol(ident.span, &ident.name, includes, excludes); + ident.symbol_id.set(Some(symbol_id)); + }); + } +} + +impl<'a> Binder for FormalParameter<'a> { + // Binds the FormalParameter of a function or method. + fn bind(&self, builder: &mut SemanticBuilder) { + let parent_kind = builder.nodes.parent_kind(builder.current_node_id).unwrap(); + let AstKind::FormalParameters(parameters) = parent_kind else { unreachable!() }; + + if parameters.kind.is_signature() { + return; + } + let includes = SymbolFlags::FunctionScopedVariable; let is_not_allowed_duplicate_parameters = matches!( - self.kind, + parameters.kind, // ArrowFormalParameters: UniqueFormalParameters FormalParameterKind::ArrowFormalParameters | // UniqueFormalParameters : FormalParameters @@ -199,20 +228,18 @@ impl<'a> Binder for FormalParameters<'a> { builder.strict_mode() || // FormalParameters : FormalParameterList // * It is a Syntax Error if IsSimpleParameterList of FormalParameterList is false and BoundNames of FormalParameterList contains any duplicate elements. - !self.is_simple_parameter_list(); + !parameters.is_simple_parameter_list(); let excludes = if is_not_allowed_duplicate_parameters { SymbolFlags::FunctionScopedVariable | SymbolFlags::FunctionScopedVariableExcludes } else { SymbolFlags::FunctionScopedVariableExcludes }; - let is_signature = self.kind == FormalParameterKind::Signature; - if !is_signature { - self.bound_names(&mut |ident| { - let symbol_id = builder.declare_symbol(ident.span, &ident.name, includes, excludes); - ident.symbol_id.set(Some(symbol_id)); - }); - } + + self.bound_names(&mut |ident| { + let symbol_id = builder.declare_symbol(ident.span, &ident.name, includes, excludes); + ident.symbol_id.set(Some(symbol_id)); + }); } } diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index d88f52b81..dfa587159 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -450,8 +450,11 @@ impl<'a> SemanticBuilder<'a> { &self.nodes, ); } - AstKind::FormalParameters(params) => { - params.bind(self); + AstKind::RestElement(element) => { + element.bind(self); + } + AstKind::FormalParameter(param) => { + param.bind(self); } AstKind::CatchClause(clause) => { clause.bind(self);