mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 20:28:58 +00:00
refactor(traverse)!: generate_uid return a BoundIdentifier (#6294)
Closes #5020. `TraverseCtx::generate_uid` and associated methods return a `BoundIdentifier`, containing both symbol ID and name. This reduces boilerplate code for the caller and avoids and unnecessary lookup to get the name. Also add a couple of helper methods to `BoundIdentifier` to reduce boilerplate further.
This commit is contained in:
parent
7b62966813
commit
409dffc8ab
14 changed files with 111 additions and 214 deletions
|
|
@ -18,8 +18,7 @@ use oxc_allocator::Vec;
|
|||
use oxc_ast::{ast::*, NONE};
|
||||
use oxc_data_structures::stack::SparseStack;
|
||||
use oxc_span::SPAN;
|
||||
use oxc_syntax::symbol::SymbolId;
|
||||
use oxc_traverse::{Ancestor, Traverse, TraverseCtx};
|
||||
use oxc_traverse::{Ancestor, BoundIdentifier, Traverse, TraverseCtx};
|
||||
|
||||
use crate::TransformCtx;
|
||||
|
||||
|
|
@ -68,15 +67,14 @@ impl<'a> VarDeclarationsStore<'a> {
|
|||
}
|
||||
|
||||
/// Add a `VariableDeclarator` to be inserted at top of current enclosing statement block,
|
||||
/// given `name` and `symbol_id`.
|
||||
/// given a `BoundIdentifier`.
|
||||
pub fn insert(
|
||||
&self,
|
||||
name: Atom<'a>,
|
||||
symbol_id: SymbolId,
|
||||
binding: &BoundIdentifier<'a>,
|
||||
init: Option<Expression<'a>>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
let ident = BindingIdentifier::new_with_symbol_id(SPAN, name, symbol_id);
|
||||
let ident = binding.create_binding_identifier();
|
||||
let ident = ctx.ast.binding_pattern_kind_from_binding_identifier(ident);
|
||||
let ident = ctx.ast.binding_pattern(ident, NONE, false);
|
||||
self.insert_binding_pattern(ident, init, ctx);
|
||||
|
|
|
|||
|
|
@ -284,13 +284,7 @@ impl<'a> ArrowFunctions<'a> {
|
|||
) && !scope_flags.contains(ScopeFlags::Arrow)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
BoundIdentifier::new_uid(
|
||||
"this",
|
||||
target_scope_id,
|
||||
SymbolFlags::FunctionScopedVariable,
|
||||
ctx,
|
||||
)
|
||||
ctx.generate_uid("this", target_scope_id, SymbolFlags::FunctionScopedVariable)
|
||||
});
|
||||
Some(this_var.create_spanned_read_reference(span, ctx))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -290,23 +290,18 @@ impl<'a, 'ctx> ExponentiationOperator<'a, 'ctx> {
|
|||
_ => "ref",
|
||||
};
|
||||
|
||||
let symbol_id =
|
||||
ctx.generate_uid_in_current_scope(name, SymbolFlags::FunctionScopedVariable);
|
||||
let symbol_name = ctx.ast.atom(ctx.symbols().get_name(symbol_id));
|
||||
let binding = ctx.generate_uid_in_current_scope(name, SymbolFlags::FunctionScopedVariable);
|
||||
|
||||
// var _name;
|
||||
self.ctx.var_declarations.insert(symbol_name.clone(), symbol_id, None, ctx);
|
||||
self.ctx.var_declarations.insert(&binding, None, ctx);
|
||||
|
||||
let ident =
|
||||
ctx.create_bound_reference_id(SPAN, symbol_name, symbol_id, ReferenceFlags::Read);
|
||||
|
||||
// let ident = self.create_new_var_with_expression(&expr);
|
||||
// Add new reference `_name = name` to nodes
|
||||
let left = ctx.ast.simple_assignment_target_from_identifier_reference(
|
||||
ctx.clone_identifier_reference(&ident, ReferenceFlags::Write),
|
||||
binding.create_write_reference(ctx),
|
||||
);
|
||||
let op = AssignmentOperator::Assign;
|
||||
nodes.push(ctx.ast.expression_assignment(SPAN, op, AssignmentTarget::from(left), expr));
|
||||
ctx.ast.expression_from_identifier_reference(ident)
|
||||
|
||||
ctx.ast.expression_from_identifier_reference(binding.create_read_reference(ctx))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
//! * Babel plugin implementation: <https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-optional-catch-binding>
|
||||
//! * Optional catch binding TC39 proposal: <https://github.com/tc39/proposal-optional-catch-binding>
|
||||
|
||||
use oxc_ast::{ast::*, NONE};
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_semantic::SymbolFlags;
|
||||
use oxc_span::SPAN;
|
||||
use oxc_traverse::{Traverse, TraverseCtx};
|
||||
|
|
@ -53,17 +53,12 @@ impl<'a> Traverse<'a> for OptionalCatchBinding {
|
|||
return;
|
||||
}
|
||||
|
||||
let block_scope_id = clause.body.scope_id.get().unwrap();
|
||||
let symbol_id = ctx.generate_uid(
|
||||
let binding = ctx.generate_uid(
|
||||
"unused",
|
||||
block_scope_id,
|
||||
clause.body.scope_id.get().unwrap(),
|
||||
SymbolFlags::CatchVariable | SymbolFlags::FunctionScopedVariable,
|
||||
);
|
||||
let name = ctx.ast.atom(ctx.symbols().get_name(symbol_id));
|
||||
let binding_identifier = BindingIdentifier::new_with_symbol_id(SPAN, name, symbol_id);
|
||||
let binding_pattern_kind =
|
||||
ctx.ast.binding_pattern_kind_from_binding_identifier(binding_identifier);
|
||||
let binding_pattern = ctx.ast.binding_pattern(binding_pattern_kind, NONE, false);
|
||||
let binding_pattern = binding.create_binding_pattern(ctx);
|
||||
let param = ctx.ast.catch_parameter(SPAN, binding_pattern);
|
||||
clause.param = Some(param);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,21 +148,16 @@ impl<'a, 'ctx> NullishCoalescingOperator<'a, 'ctx> {
|
|||
ctx: &mut TraverseCtx<'a>,
|
||||
) -> (BindingPattern<'a>, IdentifierReference<'a>) {
|
||||
// Add `var name` to scope
|
||||
let symbol_id = ctx.generate_uid_based_on_node(
|
||||
let binding = ctx.generate_uid_based_on_node(
|
||||
expr,
|
||||
current_scope_id,
|
||||
SymbolFlags::FunctionScopedVariable,
|
||||
);
|
||||
let symbol_name = ctx.ast.atom(ctx.symbols().get_name(symbol_id));
|
||||
|
||||
// var _name;
|
||||
let binding_identifier =
|
||||
BindingIdentifier::new_with_symbol_id(SPAN, symbol_name.clone(), symbol_id);
|
||||
let id = ctx.ast.binding_pattern_kind_from_binding_identifier(binding_identifier);
|
||||
let id = ctx.ast.binding_pattern(id, NONE, false);
|
||||
let reference =
|
||||
ctx.create_bound_reference_id(SPAN, symbol_name, symbol_id, ReferenceFlags::Read);
|
||||
let id = binding.create_binding_pattern(ctx);
|
||||
|
||||
let reference = binding.create_read_reference(ctx);
|
||||
(id, reference)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -342,13 +342,11 @@ impl<'a, 'ctx> LogicalAssignmentOperators<'a, 'ctx> {
|
|||
return None;
|
||||
}
|
||||
|
||||
let symbol_id = ctx
|
||||
.generate_uid_in_current_scope_based_on_node(expr, SymbolFlags::FunctionScopedVariable);
|
||||
let name = ctx.ast.atom(ctx.symbols().get_name(symbol_id));
|
||||
|
||||
// var _name;
|
||||
self.ctx.var_declarations.insert(name.clone(), symbol_id, None, ctx);
|
||||
let binding = ctx
|
||||
.generate_uid_in_current_scope_based_on_node(expr, SymbolFlags::FunctionScopedVariable);
|
||||
self.ctx.var_declarations.insert(&binding, None, ctx);
|
||||
|
||||
Some(BoundIdentifier::new(name, symbol_id))
|
||||
Some(binding)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,13 +195,11 @@ impl<'a, 'ctx> AutomaticScriptBindings<'a, 'ctx> {
|
|||
front: bool,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) -> BoundIdentifier<'a> {
|
||||
let symbol_id =
|
||||
let binding =
|
||||
ctx.generate_uid_in_root_scope(variable_name, SymbolFlags::FunctionScopedVariable);
|
||||
let variable_name = ctx.ast.atom(&ctx.symbols().names[symbol_id]);
|
||||
|
||||
let import = NamedImport::new(variable_name.clone(), None, symbol_id);
|
||||
let import = NamedImport::new(binding.name.clone(), None, binding.symbol_id);
|
||||
self.ctx.module_imports.add_import(source, import, front);
|
||||
BoundIdentifier { name: variable_name, symbol_id }
|
||||
binding
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -297,12 +295,11 @@ impl<'a, 'ctx> AutomaticModuleBindings<'a, 'ctx> {
|
|||
source: Atom<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) -> BoundIdentifier<'a> {
|
||||
let symbol_id = ctx.generate_uid_in_root_scope(name, SymbolFlags::Import);
|
||||
let local = ctx.ast.atom(&ctx.symbols().names[symbol_id]);
|
||||
|
||||
let import = NamedImport::new(Atom::from(name), Some(local.clone()), symbol_id);
|
||||
let binding = ctx.generate_uid_in_root_scope(name, SymbolFlags::Import);
|
||||
let import =
|
||||
NamedImport::new(Atom::from(name), Some(binding.name.clone()), binding.symbol_id);
|
||||
self.ctx.module_imports.add_import(source, import, false);
|
||||
BoundIdentifier { name: local, symbol_id }
|
||||
binding
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -220,14 +220,12 @@ impl<'a, 'ctx> ReactJsxSource<'a, 'ctx> {
|
|||
Some(decl)
|
||||
}
|
||||
|
||||
fn get_filename_var(&mut self, ctx: &mut TraverseCtx<'a>) -> BoundIdentifier<'a> {
|
||||
fn get_filename_var(&mut self, ctx: &mut TraverseCtx<'a>) -> &BoundIdentifier<'a> {
|
||||
if self.filename_var.is_none() {
|
||||
self.filename_var = Some(BoundIdentifier::new_uid_in_root_scope(
|
||||
FILE_NAME_VAR,
|
||||
SymbolFlags::FunctionScopedVariable,
|
||||
ctx,
|
||||
));
|
||||
self.filename_var = Some(
|
||||
ctx.generate_uid_in_root_scope(FILE_NAME_VAR, SymbolFlags::FunctionScopedVariable),
|
||||
);
|
||||
}
|
||||
self.filename_var.as_ref().unwrap().clone()
|
||||
self.filename_var.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -467,10 +467,9 @@ impl<'a, 'ctx> ReactRefresh<'a, 'ctx> {
|
|||
reference_flags: ReferenceFlags,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) -> AssignmentTarget<'a> {
|
||||
let symbol_id = ctx.generate_uid_in_root_scope("c", SymbolFlags::FunctionScopedVariable);
|
||||
self.registrations.push((symbol_id, persistent_id));
|
||||
let name = ctx.ast.atom(ctx.symbols().get_name(symbol_id));
|
||||
let ident = ctx.create_bound_reference_id(SPAN, name, symbol_id, reference_flags);
|
||||
let binding = ctx.generate_uid_in_root_scope("c", SymbolFlags::FunctionScopedVariable);
|
||||
self.registrations.push((binding.symbol_id, persistent_id));
|
||||
let ident = binding.create_reference(reference_flags, ctx);
|
||||
let ident = ctx.ast.simple_assignment_target_from_identifier_reference(ident);
|
||||
ctx.ast.assignment_target_simple(ident)
|
||||
}
|
||||
|
|
@ -683,12 +682,8 @@ impl<'a, 'ctx> ReactRefresh<'a, 'ctx> {
|
|||
.find(|scope_id| ctx.scopes().get_flags(*scope_id).is_var())
|
||||
.unwrap_or_else(|| ctx.current_scope_id());
|
||||
|
||||
let symbol_id = ctx.generate_uid("s", target_scope_id, SymbolFlags::FunctionScopedVariable);
|
||||
|
||||
let symbol_name = ctx.ast.atom(ctx.symbols().get_name(symbol_id));
|
||||
|
||||
let binding_identifier =
|
||||
BindingIdentifier::new_with_symbol_id(SPAN, symbol_name.clone(), symbol_id);
|
||||
let binding = ctx.generate_uid("s", target_scope_id, SymbolFlags::FunctionScopedVariable);
|
||||
let binding_identifier = binding.create_binding_identifier();
|
||||
|
||||
// _s();
|
||||
let call_expression = ctx.ast.statement_expression(
|
||||
|
|
|
|||
|
|
@ -158,8 +158,8 @@ impl<'a, 'ctx> TypeScriptNamespace<'a, 'ctx> {
|
|||
|
||||
// Reuse `TSModuleDeclaration`'s scope in transformed function
|
||||
let scope_id = decl.scope_id.get().unwrap();
|
||||
let symbol_id = ctx.generate_uid(&real_name, scope_id, SymbolFlags::FunctionScopedVariable);
|
||||
let name = ctx.ast.atom(ctx.symbols().get_name(symbol_id));
|
||||
let binding = ctx.generate_uid(&real_name, scope_id, SymbolFlags::FunctionScopedVariable);
|
||||
let name = binding.name;
|
||||
|
||||
let directives;
|
||||
let namespace_top_level;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
use oxc_ast::ast::{BindingIdentifier, IdentifierReference};
|
||||
use oxc_span::{Atom, Span, SPAN};
|
||||
use oxc_syntax::{
|
||||
reference::ReferenceFlags,
|
||||
scope::ScopeId,
|
||||
symbol::{SymbolFlags, SymbolId},
|
||||
use oxc_ast::{
|
||||
ast::{BindingIdentifier, BindingPattern, IdentifierReference},
|
||||
NONE,
|
||||
};
|
||||
use oxc_span::{Atom, Span, SPAN};
|
||||
use oxc_syntax::{reference::ReferenceFlags, symbol::SymbolId};
|
||||
|
||||
use crate::TraverseCtx;
|
||||
|
||||
|
|
@ -47,44 +46,18 @@ impl<'a> BoundIdentifier<'a> {
|
|||
Self { name, symbol_id }
|
||||
}
|
||||
|
||||
/// Create `BoundIdentifier` for new binding in specified scope
|
||||
pub fn new_uid(
|
||||
name: &str,
|
||||
scope_id: ScopeId,
|
||||
flags: SymbolFlags,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) -> Self {
|
||||
let symbol_id = ctx.generate_uid(name, scope_id, flags);
|
||||
let name = ctx.ast.atom(&ctx.symbols().names[symbol_id]);
|
||||
Self { name, symbol_id }
|
||||
}
|
||||
|
||||
/// Create `BoundIdentifier` for new binding in root scope
|
||||
pub fn new_uid_in_root_scope(
|
||||
name: &str,
|
||||
flags: SymbolFlags,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) -> Self {
|
||||
let scope_id = ctx.scopes().root_scope_id();
|
||||
Self::new_uid(name, scope_id, flags, ctx)
|
||||
}
|
||||
|
||||
/// Create `BoundIdentifier` for new binding in current scope
|
||||
#[allow(unused)]
|
||||
pub fn new_uid_in_current_scope(
|
||||
name: &str,
|
||||
flags: SymbolFlags,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) -> Self {
|
||||
let scope_id = ctx.current_scope_id();
|
||||
Self::new_uid(name, scope_id, flags, ctx)
|
||||
}
|
||||
|
||||
/// Create `BindingIdentifier` for this binding
|
||||
pub fn create_binding_identifier(&self) -> BindingIdentifier<'a> {
|
||||
BindingIdentifier::new_with_symbol_id(SPAN, self.name.clone(), self.symbol_id)
|
||||
}
|
||||
|
||||
/// Create `BindingPattern` for this binding
|
||||
pub fn create_binding_pattern(&self, ctx: &mut TraverseCtx<'a>) -> BindingPattern<'a> {
|
||||
let ident = self.create_binding_identifier();
|
||||
let binding_pattern_kind = ctx.ast.binding_pattern_kind_from_binding_identifier(ident);
|
||||
ctx.ast.binding_pattern(binding_pattern_kind, NONE, false)
|
||||
}
|
||||
|
||||
/// Create `IdentifierReference` referencing this binding, which is read from, with dummy `Span`
|
||||
pub fn create_read_reference(&self, ctx: &mut TraverseCtx<'a>) -> IdentifierReference<'a> {
|
||||
self.create_spanned_read_reference(SPAN, ctx)
|
||||
|
|
@ -134,6 +107,15 @@ impl<'a> BoundIdentifier<'a> {
|
|||
self.create_spanned_reference(span, ReferenceFlags::Read | ReferenceFlags::Write, ctx)
|
||||
}
|
||||
|
||||
/// Create `IdentifierReference` referencing this binding, with specified `ReferenceFlags`
|
||||
pub fn create_reference(
|
||||
&self,
|
||||
flags: ReferenceFlags,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) -> IdentifierReference<'a> {
|
||||
self.create_spanned_reference(SPAN, flags, ctx)
|
||||
}
|
||||
|
||||
/// Create `IdentifierReference` referencing this binding, with specified `Span` and `ReferenceFlags`
|
||||
pub fn create_spanned_reference(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ use oxc_ast::{
|
|||
ast::{Expression, IdentifierReference, Statement},
|
||||
AstBuilder,
|
||||
};
|
||||
use oxc_semantic::{ScopeTree, SymbolTable};
|
||||
use oxc_span::{Atom, CompactStr, Span};
|
||||
use oxc_semantic::{NodeId, ScopeTree, SymbolTable};
|
||||
use oxc_span::{Atom, CompactStr, Span, SPAN};
|
||||
use oxc_syntax::{
|
||||
reference::{ReferenceFlags, ReferenceId},
|
||||
scope::{ScopeFlags, ScopeId},
|
||||
|
|
@ -15,11 +15,13 @@ use crate::ancestor::{Ancestor, AncestorType};
|
|||
|
||||
mod ancestry;
|
||||
mod ast_operations;
|
||||
use ast_operations::GatherNodeParts;
|
||||
mod bound_identifier;
|
||||
use ancestry::PopToken;
|
||||
pub use ancestry::TraverseAncestry;
|
||||
pub use bound_identifier::BoundIdentifier;
|
||||
mod identifier;
|
||||
use identifier::to_identifier;
|
||||
mod scoping;
|
||||
pub use scoping::TraverseScoping;
|
||||
|
||||
|
|
@ -299,49 +301,73 @@ impl<'a> TraverseCtx<'a> {
|
|||
///
|
||||
/// See also comments on [`TraverseScoping::generate_uid_name`] for important information
|
||||
/// on how UIDs are generated. There are some potential "gotchas".
|
||||
///
|
||||
/// This is a shortcut for `ctx.scoping.generate_uid`.
|
||||
#[inline]
|
||||
pub fn generate_uid(&mut self, name: &str, scope_id: ScopeId, flags: SymbolFlags) -> SymbolId {
|
||||
self.scoping.generate_uid(name, scope_id, flags)
|
||||
pub fn generate_uid(
|
||||
&mut self,
|
||||
name: &str,
|
||||
scope_id: ScopeId,
|
||||
flags: SymbolFlags,
|
||||
) -> BoundIdentifier<'a> {
|
||||
// Get name for UID
|
||||
let name = self.generate_uid_name(name);
|
||||
let name_atom = self.ast.atom(&name);
|
||||
|
||||
// Add binding to scope
|
||||
let symbol_id =
|
||||
self.symbols_mut().create_symbol(SPAN, name.clone(), flags, scope_id, NodeId::DUMMY);
|
||||
self.scopes_mut().add_binding(scope_id, name, symbol_id);
|
||||
|
||||
BoundIdentifier::new(name_atom, symbol_id)
|
||||
}
|
||||
|
||||
/// Generate UID in current scope.
|
||||
///
|
||||
/// See also comments on [`TraverseScoping::generate_uid_name`] for important information
|
||||
/// on how UIDs are generated. There are some potential "gotchas".
|
||||
///
|
||||
/// This is a shortcut for `ctx.scoping.generate_uid_in_current_scope`.
|
||||
#[inline]
|
||||
pub fn generate_uid_in_current_scope(&mut self, name: &str, flags: SymbolFlags) -> SymbolId {
|
||||
self.scoping.generate_uid_in_current_scope(name, flags)
|
||||
pub fn generate_uid_in_current_scope(
|
||||
&mut self,
|
||||
name: &str,
|
||||
flags: SymbolFlags,
|
||||
) -> BoundIdentifier<'a> {
|
||||
self.generate_uid(name, self.current_scope_id(), flags)
|
||||
}
|
||||
|
||||
/// Generate UID in root scope.
|
||||
///
|
||||
/// See also comments on [`TraverseScoping::generate_uid_name`] for important information
|
||||
/// on how UIDs are generated. There are some potential "gotchas".
|
||||
///
|
||||
/// This is a shortcut for `ctx.scoping.generate_uid_in_root_scope`.
|
||||
#[inline]
|
||||
pub fn generate_uid_in_root_scope(&mut self, name: &str, flags: SymbolFlags) -> SymbolId {
|
||||
self.scoping.generate_uid_in_root_scope(name, flags)
|
||||
pub fn generate_uid_in_root_scope(
|
||||
&mut self,
|
||||
name: &str,
|
||||
flags: SymbolFlags,
|
||||
) -> BoundIdentifier<'a> {
|
||||
self.generate_uid(name, self.scopes().root_scope_id(), flags)
|
||||
}
|
||||
|
||||
/// Generate UID based on node.
|
||||
///
|
||||
/// See also comments on [`TraverseScoping::generate_uid_name`] for important information
|
||||
/// on how UIDs are generated. There are some potential "gotchas".
|
||||
/// Recursively gathers the identifying names of a node, and joins them with `$`.
|
||||
///
|
||||
/// This is a shortcut for `ctx.scoping.generate_uid_based_on_node`.
|
||||
/// Based on Babel's `scope.generateUidBasedOnNode` logic.
|
||||
/// <https://github.com/babel/babel/blob/419644f27c5c59deb19e71aaabd417a3bc5483ca/packages/babel-traverse/src/scope/index.ts#L543>
|
||||
#[inline]
|
||||
pub fn generate_uid_based_on_node(
|
||||
&mut self,
|
||||
node: &Expression<'a>,
|
||||
scope_id: ScopeId,
|
||||
flags: SymbolFlags,
|
||||
) -> SymbolId {
|
||||
self.scoping.generate_uid_based_on_node(node, scope_id, flags)
|
||||
) -> BoundIdentifier<'a> {
|
||||
let mut parts = String::new();
|
||||
node.gather(&mut |part| {
|
||||
if !parts.is_empty() {
|
||||
parts.push('$');
|
||||
}
|
||||
parts.push_str(part);
|
||||
});
|
||||
let name = if parts.is_empty() { "ref" } else { parts.trim_start_matches('_') };
|
||||
self.generate_uid(&to_identifier(name.get(..20).unwrap_or(name)), scope_id, flags)
|
||||
}
|
||||
|
||||
/// Generate UID in current scope based on node.
|
||||
|
|
@ -355,8 +381,8 @@ impl<'a> TraverseCtx<'a> {
|
|||
&mut self,
|
||||
node: &Expression<'a>,
|
||||
flags: SymbolFlags,
|
||||
) -> SymbolId {
|
||||
self.scoping.generate_uid_in_current_scope_based_on_node(node, flags)
|
||||
) -> BoundIdentifier<'a> {
|
||||
self.generate_uid_based_on_node(node, self.current_scope_id(), flags)
|
||||
}
|
||||
|
||||
/// Create a reference bound to a `SymbolId`.
|
||||
|
|
|
|||
|
|
@ -7,14 +7,13 @@ use rustc_hash::FxHashSet;
|
|||
#[allow(clippy::wildcard_imports)]
|
||||
use oxc_ast::{ast::*, visit::Visit};
|
||||
use oxc_semantic::{NodeId, Reference, ScopeTree, SymbolTable};
|
||||
use oxc_span::{Atom, CompactStr, Span, SPAN};
|
||||
use oxc_span::{Atom, CompactStr, Span};
|
||||
use oxc_syntax::{
|
||||
reference::{ReferenceFlags, ReferenceId},
|
||||
scope::{ScopeFlags, ScopeId},
|
||||
symbol::{SymbolFlags, SymbolId},
|
||||
symbol::SymbolId,
|
||||
};
|
||||
|
||||
use super::{ast_operations::GatherNodeParts, identifier::to_identifier};
|
||||
use crate::scopes_collector::ChildScopeCollector;
|
||||
|
||||
/// Traverse scope context.
|
||||
|
|
@ -229,81 +228,6 @@ impl TraverseScoping {
|
|||
uid
|
||||
}
|
||||
|
||||
/// Generate UID in provided scope.
|
||||
///
|
||||
/// See also comments on [`TraverseScoping::generate_uid_name`] for important information
|
||||
/// on how UIDs are generated. There are some potential "gotchas".
|
||||
pub fn generate_uid(&mut self, name: &str, scope_id: ScopeId, flags: SymbolFlags) -> SymbolId {
|
||||
// Get name for UID
|
||||
let name = self.generate_uid_name(name);
|
||||
|
||||
// Add binding to scope
|
||||
let symbol_id =
|
||||
self.symbols.create_symbol(SPAN, name.clone(), flags, scope_id, NodeId::DUMMY);
|
||||
self.scopes.add_binding(scope_id, name, symbol_id);
|
||||
symbol_id
|
||||
}
|
||||
|
||||
/// Generate UID in current scope.
|
||||
///
|
||||
/// See also comments on [`TraverseScoping::generate_uid_name`] for important information
|
||||
/// on how UIDs are generated. There are some potential "gotchas".
|
||||
pub fn generate_uid_in_current_scope(&mut self, name: &str, flags: SymbolFlags) -> SymbolId {
|
||||
self.generate_uid(name, self.current_scope_id, flags)
|
||||
}
|
||||
|
||||
/// Generate UID in root scope.
|
||||
///
|
||||
/// See also comments on [`TraverseScoping::generate_uid_name`] for important information
|
||||
/// on how UIDs are generated. There are some potential "gotchas".
|
||||
pub fn generate_uid_in_root_scope(&mut self, name: &str, flags: SymbolFlags) -> SymbolId {
|
||||
self.generate_uid(name, self.scopes.root_scope_id(), flags)
|
||||
}
|
||||
|
||||
/// Generate UID based on node.
|
||||
///
|
||||
/// Recursively gathers the identifying names of a node, and joins them with `$`.
|
||||
///
|
||||
/// Based on Babel's `scope.generateUidBasedOnNode` logic.
|
||||
/// <https://github.com/babel/babel/blob/419644f27c5c59deb19e71aaabd417a3bc5483ca/packages/babel-traverse/src/scope/index.ts#L543>
|
||||
///
|
||||
/// See also comments on [`TraverseScoping::generate_uid_name`] for important information
|
||||
/// on how UIDs are generated. There are some potential "gotchas".
|
||||
pub fn generate_uid_based_on_node<'a, T>(
|
||||
&mut self,
|
||||
node: &T,
|
||||
scope_id: ScopeId,
|
||||
flags: SymbolFlags,
|
||||
) -> SymbolId
|
||||
where
|
||||
T: GatherNodeParts<'a>,
|
||||
{
|
||||
let mut parts = String::new();
|
||||
node.gather(&mut |part| {
|
||||
if !parts.is_empty() {
|
||||
parts.push('$');
|
||||
}
|
||||
parts.push_str(part);
|
||||
});
|
||||
let name = if parts.is_empty() { "ref" } else { parts.trim_start_matches('_') };
|
||||
self.generate_uid(&to_identifier(name.get(..20).unwrap_or(name)), scope_id, flags)
|
||||
}
|
||||
|
||||
/// Generate UID in current scope based on node.
|
||||
///
|
||||
/// See also comments on [`TraverseScoping::generate_uid_name`] for important information
|
||||
/// on how UIDs are generated. There are some potential "gotchas".
|
||||
pub fn generate_uid_in_current_scope_based_on_node<'a, T>(
|
||||
&mut self,
|
||||
node: &T,
|
||||
flags: SymbolFlags,
|
||||
) -> SymbolId
|
||||
where
|
||||
T: GatherNodeParts<'a>,
|
||||
{
|
||||
self.generate_uid_based_on_node(node, self.current_scope_id, flags)
|
||||
}
|
||||
|
||||
/// Create a reference bound to a `SymbolId`
|
||||
pub fn create_bound_reference(
|
||||
&mut self,
|
||||
|
|
|
|||
|
|
@ -1645,7 +1645,7 @@ x Output mismatch
|
|||
|
||||
* regression/4403/input.js
|
||||
Reference flags mismatch for "_ref":
|
||||
after transform: ReferenceId(3): ReferenceFlags(Write)
|
||||
after transform: ReferenceId(2): ReferenceFlags(Write)
|
||||
rebuilt : ReferenceId(0): ReferenceFlags(Read | Write)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue