From b6e493bd78a2f5b49e70ec763ad4734727d50f7c Mon Sep 17 00:00:00 2001 From: Dunqing Date: Mon, 25 Mar 2024 04:50:04 +0800 Subject: [PATCH] fix(semantic): ModuleRecord's indirect_export_entires missing reexported imports (#2792) local_name has `name` and `span`. We can't directly compare ExportEntry's local_name and ImportEntry's local_name. because the span is never equal. --- crates/oxc_semantic/src/builder.rs | 20 +++++++------- .../oxc_semantic/src/module_record/builder.rs | 14 +++++----- crates/oxc_semantic/src/module_record/mod.rs | 27 +++++++++++++++++++ 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index 2ad852552..e43349809 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -7,7 +7,7 @@ use oxc_ast::{ast::*, AstKind, Trivias, Visit}; use oxc_diagnostics::Error; use oxc_span::{CompactStr, SourceType, Span}; use oxc_syntax::{ - module_record::{ExportLocalName, ModuleRecord}, + module_record::{ExportImportName, ExportLocalName, ModuleRecord}, operator::AssignmentOperator, }; @@ -324,18 +324,20 @@ impl<'a> SemanticBuilder<'a> { } fn add_export_flag_for_export_identifier(&mut self) { - self.module_record.local_export_entries.iter().for_each(|entry| match &entry.local_name { - ExportLocalName::Name(name_span) => { + self.module_record.indirect_export_entries.iter().for_each(|entry| { + if let ExportImportName::Name(name) = &entry.import_name { + if let Some(symbol_id) = self.symbols.get_symbol_id_from_name(name.name()) { + self.symbols.union_flag(symbol_id, SymbolFlags::Export); + } + } + }); + + self.module_record.local_export_entries.iter().for_each(|entry| { + if let ExportLocalName::Name(name_span) = &entry.local_name { if let Some(symbol_id) = self.scope.get_root_binding(name_span.name()) { self.symbols.union_flag(symbol_id, SymbolFlags::Export); } } - ExportLocalName::Default(span) => { - if let Some(symbol_id) = self.symbols.get_symbol_id_from_span(span) { - self.symbols.union_flag(symbol_id, SymbolFlags::Export); - } - } - ExportLocalName::Null => {} }); } } diff --git a/crates/oxc_semantic/src/module_record/builder.rs b/crates/oxc_semantic/src/module_record/builder.rs index 9ea66936a..f7cf028b8 100644 --- a/crates/oxc_semantic/src/module_record/builder.rs +++ b/crates/oxc_semantic/src/module_record/builder.rs @@ -85,15 +85,14 @@ impl ModuleRecordBuilder { for ee in export_entries { // a. If ee.[[ModuleRequest]] is null, then if ee.module_request.is_none() { - let local_name = match &ee.local_name { - ExportLocalName::Name(name) => Some(name), + let found_import_entry = match &ee.local_name { + ExportLocalName::Name(name) => self + .module_record + .import_entries + .iter() + .find(|entry| entry.local_name.name() == name.name()), _ => None, }; - let found_import_entry = self - .module_record - .import_entries - .iter() - .find(|import_entry| Some(&import_entry.local_name) == local_name); match found_import_entry { // i. If ee.[[LocalName]] is not an element of importedBoundNames, then None => { @@ -130,6 +129,7 @@ impl ModuleRecordBuilder { ImportImportName::NamespaceObject => unreachable!(), }, export_name: ee.export_name.clone(), + span: ee.span, ..ExportEntry::default() }; self.append_indirect_export_entry(export_entry); diff --git a/crates/oxc_semantic/src/module_record/mod.rs b/crates/oxc_semantic/src/module_record/mod.rs index c9439f31f..719317d09 100644 --- a/crates/oxc_semantic/src/module_record/mod.rs +++ b/crates/oxc_semantic/src/module_record/mod.rs @@ -248,4 +248,31 @@ mod module_record_tests { assert_eq!(module_record.local_export_entries.len(), 1); assert_eq!(module_record.local_export_entries[0], export_entry); } + + #[test] + fn indirect_export_entries() { + let module_record = + build("import { x } from 'mod';export { x };export * as ns from 'mod';"); + assert_eq!(module_record.indirect_export_entries.len(), 2); + assert_eq!( + module_record.indirect_export_entries[0], + ExportEntry { + module_request: Some(NameSpan::new("mod".into(), Span::new(18, 23))), + span: Span::new(33, 34), + import_name: ExportImportName::Name(NameSpan::new("x".into(), Span::new(9, 10))), + export_name: ExportExportName::Name(NameSpan::new("x".into(), Span::new(33, 34))), + local_name: ExportLocalName::Null, + } + ); + assert_eq!( + module_record.indirect_export_entries[1], + ExportEntry { + module_request: Some(NameSpan::new("mod".into(), Span::new(57, 62))), + span: Span::new(0, 0), + import_name: ExportImportName::All, + export_name: ExportExportName::Name(NameSpan::new("ns".into(), Span::new(49, 51))), + local_name: ExportLocalName::Null, + } + ); + } }