Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/oxc_ast/src/ast/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1581,7 +1581,7 @@ pub struct YieldExpression<'a> {

/// Class Definitions
#[visited_node]
#[scope(flags(ScopeFlags::StrictMode))]
#[scope(flags(ScopeFlags::StrictMode | ScopeFlags::Class))]
#[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))]
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_ast/src/generated/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2928,7 +2928,7 @@ pub mod walk {
if let Some(id) = &it.id {
visitor.visit_binding_identifier(id);
}
visitor.enter_scope(ScopeFlags::StrictMode, &it.scope_id);
visitor.enter_scope(ScopeFlags::StrictMode | ScopeFlags::Class, &it.scope_id);
if let Some(type_parameters) = &it.type_parameters {
visitor.visit_ts_type_parameter_declaration(type_parameters);
}
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_ast/src/generated/visit_mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3052,7 +3052,7 @@ pub mod walk_mut {
if let Some(id) = &mut it.id {
visitor.visit_binding_identifier(id);
}
visitor.enter_scope(ScopeFlags::StrictMode, &it.scope_id);
visitor.enter_scope(ScopeFlags::StrictMode | ScopeFlags::Class, &it.scope_id);
if let Some(type_parameters) = &mut it.type_parameters {
visitor.visit_ts_type_parameter_declaration(type_parameters);
}
Expand Down
5 changes: 1 addition & 4 deletions crates/oxc_semantic/src/binder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,7 @@ impl<'a> Binder for Class<'a> {
SymbolFlags::ClassExcludes,
)
} else {
let symbol_id = builder.declare_symbol(ident.span, &ident.name, SymbolFlags::Class);
builder.symbols.set_declaration_symbol(symbol_id, builder.current_node_id);
symbol_id
builder.declare_symbol(ident.span, &ident.name, SymbolFlags::Class)
};
ident.symbol_id.set(Some(symbol_id));
}
Expand Down Expand Up @@ -156,7 +154,6 @@ impl<'a> Binder for Function<'a> {
// 5. Perform ! funcEnv.CreateImmutableBinding(name, false).
let symbol_id =
builder.declare_symbol(ident.span, &ident.name, SymbolFlags::Function);
builder.symbols.set_declaration_symbol(symbol_id, builder.current_node_id);
ident.symbol_id.set(Some(symbol_id));
}
}
Expand Down
28 changes: 18 additions & 10 deletions crates/oxc_semantic/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ impl<'a> SemanticBuilder<'a> {
}

fn resolve_references_for_current_scope(&mut self) {
let current_scope_flags = self.current_scope_flags();
// `iter_mut` to get mut references to 2 entries of `unresolved_references` simultaneously
let mut iter = self.unresolved_references.iter_mut();
let parent_refs = iter.nth(self.current_scope_depth - 1).unwrap();
Expand All @@ -391,18 +392,24 @@ impl<'a> SemanticBuilder<'a> {
// Try to resolve a reference.
// If unresolved, transfer it to parent scope's unresolved references.
if let Some(symbol_id) = bindings.get(&name).copied().or_else(|| {
self.symbols.get_symbol_id_from_declaration(self.current_node_id).and_then(
|symbol_id| {
let flag = self.symbols.get_flag(symbol_id);
if (flag.is_class() || flag.is_function())
&& self.symbols.get_name(symbol_id) == name
// If the current node is a class or function expression,
// Try to get the symbol by binding name
// and check if it's the same name with the reference.
if current_scope_flags.is_class() || current_scope_flags.is_function() {
let kind = self.nodes.kind(self.current_node_id);
if matches!(kind, AstKind::Function(func) if func.id.is_some() && func.is_expression())
|| matches!(kind, AstKind::Class(class) if class.id.is_some() && class.is_expression())
{
if let Some(symbol_id) =
self.symbols.get_symbol_id_from_declaration(self.current_node_id)
{
Some(symbol_id)
} else {
None
if self.symbols.get_name(symbol_id) == name {
return Some(symbol_id);
}
}
},
)
}
}
None
}) {
for reference_id in &reference_ids {
self.symbols.references[*reference_id].set_symbol_id(symbol_id);
Expand Down Expand Up @@ -1598,6 +1605,7 @@ impl<'a> SemanticBuilder<'a> {
self.current_node_flags |= NodeFlags::Class;
class.bind(self);
self.current_symbol_flags -= SymbolFlags::Export;
self.add_current_node_id_to_current_scope();
self.make_all_namespaces_valuelike();
}
AstKind::ClassBody(body) => {
Expand Down
20 changes: 10 additions & 10 deletions crates/oxc_semantic/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ pub use oxc_syntax::{
scope::ScopeId,
symbol::{SymbolFlags, SymbolId},
};
use rustc_hash::FxHashMap;

#[cfg(feature = "serialize")]
use serde::Serialize;
Expand Down Expand Up @@ -37,7 +36,6 @@ pub struct SymbolTable {
pub scope_ids: IndexVec<SymbolId, Option<ScopeId>>,
/// Pointer to the AST Node where this symbol is declared
pub declarations: IndexVec<SymbolId, AstNodeId>,
pub declaration_symbol: FxHashMap<AstNodeId, SymbolId>,
pub resolved_references: IndexVec<SymbolId, Vec<ReferenceId>>,
pub references: IndexVec<ReferenceId, Reference>,
pub redeclare_variables: IndexVec<SymbolId, Vec<Span>>,
Expand Down Expand Up @@ -66,10 +64,6 @@ impl SymbolTable {
.find_map(|(symbol, inner_span)| if inner_span == span { Some(symbol) } else { None })
}

pub fn get_symbol_id_from_declaration(&self, declaration: AstNodeId) -> Option<SymbolId> {
self.declaration_symbol.get(&declaration).copied()
}

pub fn get_symbol_id_from_name(&self, name: &str) -> Option<SymbolId> {
self.names.iter_enumerated().find_map(|(symbol, inner_name)| {
if inner_name.as_str() == name {
Expand All @@ -80,6 +74,16 @@ impl SymbolTable {
})
}

pub fn get_symbol_id_from_declaration(&self, declaration: AstNodeId) -> Option<SymbolId> {
self.declarations.iter_enumerated().find_map(|(symbol, inner_declaration)| {
if *inner_declaration == declaration {
Some(symbol)
} else {
None
}
})
}

pub fn get_span(&self, symbol_id: SymbolId) -> Span {
self.spans[symbol_id]
}
Expand Down Expand Up @@ -178,10 +182,6 @@ impl SymbolTable {
.map(|reference_id| &self.references[*reference_id])
}

pub fn set_declaration_symbol(&mut self, symbol_id: SymbolId, declaration: AstNodeId) {
self.declaration_symbol.insert(declaration, symbol_id);
}

/// Determine whether evaluating the specific input `node` is a consequenceless reference. ie.
/// evaluating it won't result in potentially arbitrary code from being ran. The following are
/// allowed and determined not to cause side effects:
Expand Down
5 changes: 5 additions & 0 deletions crates/oxc_syntax/src/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ bitflags! {
const GetAccessor = 1 << 7;
const SetAccessor = 1 << 8;
const CatchClause = 1 << 9;
const Class = 1 << 10;
const Var = Self::Top.bits() | Self::Function.bits() | Self::ClassStaticBlock.bits() | Self::TsModuleBlock.bits();
const Modifiers = Self::Constructor.bits() | Self::GetAccessor.bits() | Self::SetAccessor.bits();
}
Expand Down Expand Up @@ -86,4 +87,8 @@ impl ScopeFlags {
pub fn is_catch_clause(&self) -> bool {
self.contains(Self::CatchClause)
}

pub fn is_class(&self) -> bool {
self.contains(Self::Class)
}
}