mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
fix(semantic): incorrect resolve references for ExportSpecifier (#4320)
```ts
type A = any;
const B = 0;
export { A, B }
^^^^^^^^ ExportSpecifiers
export { A }
^^^^^ type-only ExportSpecifiers
```
non-type-only `ExportSpecifier` can reference value and type symbols. but currently, `IdentifierReference` in ExportSpecifier only has a `ReferenceFlags::Read`
This commit is contained in:
parent
a88d588a07
commit
95e15b6dc5
6 changed files with 45 additions and 23 deletions
|
|
@ -399,9 +399,15 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
resolved_references.reserve(references.len());
|
resolved_references.reserve(references.len());
|
||||||
|
|
||||||
references.retain(|(id, flag)| {
|
references.retain(|(id, flag)| {
|
||||||
if flag.is_type() && symbol_flag.is_type()
|
if flag.is_type() && symbol_flag.is_can_be_referenced_by_type()
|
||||||
|| flag.is_value() && symbol_flag.is_value()
|
|| flag.is_value() && symbol_flag.is_value()
|
||||||
{
|
{
|
||||||
|
// The non type-only ExportSpecifier can reference a type,
|
||||||
|
// If the reference is not a type, remove the type flag from the reference
|
||||||
|
if !symbol_flag.is_type() && !flag.is_type_only() {
|
||||||
|
*self.symbols.references[*id].flag_mut() -= ReferenceFlag::Type;
|
||||||
|
}
|
||||||
|
|
||||||
self.symbols.references[*id].set_symbol_id(symbol_id);
|
self.symbols.references[*id].set_symbol_id(symbol_id);
|
||||||
resolved_references.push(*id);
|
resolved_references.push(*id);
|
||||||
false
|
false
|
||||||
|
|
@ -1619,11 +1625,12 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
self.current_reference_flag = ReferenceFlag::Type;
|
self.current_reference_flag = ReferenceFlag::Type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AstKind::ExportAllDeclaration(s) if s.export_kind.is_type() => {
|
AstKind::ExportSpecifier(s) => {
|
||||||
|
if self.current_reference_flag.is_type() || s.export_kind.is_type() {
|
||||||
self.current_reference_flag = ReferenceFlag::Type;
|
self.current_reference_flag = ReferenceFlag::Type;
|
||||||
|
} else {
|
||||||
|
self.current_reference_flag = ReferenceFlag::Read | ReferenceFlag::Type;
|
||||||
}
|
}
|
||||||
AstKind::ExportSpecifier(s) if s.export_kind.is_type() => {
|
|
||||||
self.current_reference_flag = ReferenceFlag::Type;
|
|
||||||
}
|
}
|
||||||
AstKind::ImportSpecifier(specifier) => {
|
AstKind::ImportSpecifier(specifier) => {
|
||||||
specifier.bind(self);
|
specifier.bind(self);
|
||||||
|
|
@ -1709,9 +1716,6 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
AstKind::TSTypeParameter(type_parameter) => {
|
AstKind::TSTypeParameter(type_parameter) => {
|
||||||
type_parameter.bind(self);
|
type_parameter.bind(self);
|
||||||
}
|
}
|
||||||
AstKind::ExportSpecifier(s) if s.export_kind.is_type() => {
|
|
||||||
self.current_reference_flag = ReferenceFlag::Type;
|
|
||||||
}
|
|
||||||
AstKind::TSInterfaceHeritage(_) => {
|
AstKind::TSInterfaceHeritage(_) => {
|
||||||
self.current_reference_flag = ReferenceFlag::Type;
|
self.current_reference_flag = ReferenceFlag::Type;
|
||||||
}
|
}
|
||||||
|
|
@ -1798,17 +1802,11 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
AstKind::BindingIdentifier(_) => {
|
AstKind::BindingIdentifier(_) => {
|
||||||
self.current_symbol_flags -= SymbolFlags::Export;
|
self.current_symbol_flags -= SymbolFlags::Export;
|
||||||
}
|
}
|
||||||
AstKind::ExportNamedDeclaration(decl) => {
|
AstKind::ExportSpecifier(_) => {
|
||||||
if decl.export_kind.is_type() {
|
if !self.current_reference_flag.is_type_only() {
|
||||||
self.current_reference_flag -= ReferenceFlag::Type;
|
self.current_reference_flag = ReferenceFlag::empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AstKind::ExportAllDeclaration(s) if s.export_kind.is_type() => {
|
|
||||||
self.current_reference_flag -= ReferenceFlag::Type;
|
|
||||||
}
|
|
||||||
AstKind::ExportSpecifier(s) if s.export_kind.is_type() => {
|
|
||||||
self.current_reference_flag -= ReferenceFlag::Type;
|
|
||||||
}
|
|
||||||
AstKind::LabeledStatement(_) => self.label_builder.leave(),
|
AstKind::LabeledStatement(_) => self.label_builder.leave(),
|
||||||
AstKind::StaticBlock(_) => {
|
AstKind::StaticBlock(_) => {
|
||||||
self.label_builder.leave_function_or_static_block();
|
self.label_builder.leave_function_or_static_block();
|
||||||
|
|
@ -1851,7 +1849,9 @@ impl<'a> SemanticBuilder<'a> {
|
||||||
self.current_reference_flag -= ReferenceFlag::Read;
|
self.current_reference_flag -= ReferenceFlag::Read;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AstKind::MemberExpression(_) | AstKind::TSTypeQuery(_) => {
|
AstKind::MemberExpression(_)
|
||||||
|
| AstKind::TSTypeQuery(_)
|
||||||
|
| AstKind::ExportNamedDeclaration(_) => {
|
||||||
self.current_reference_flag = ReferenceFlag::empty();
|
self.current_reference_flag = ReferenceFlag::empty();
|
||||||
}
|
}
|
||||||
AstKind::AssignmentTarget(_) => self.current_reference_flag -= ReferenceFlag::Write,
|
AstKind::AssignmentTarget(_) => self.current_reference_flag -= ReferenceFlag::Write,
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/export/named-du
|
||||||
"node": "VariableDeclarator",
|
"node": "VariableDeclarator",
|
||||||
"references": [
|
"references": [
|
||||||
{
|
{
|
||||||
"flag": "ReferenceFlag(Read)",
|
"flag": "ReferenceFlag(Read | Type)",
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "T",
|
"name": "T",
|
||||||
"node_id": 12
|
"node_id": 12
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,14 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/export/named2-t
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "A",
|
"name": "A",
|
||||||
"node": "TSTypeAliasDeclaration",
|
"node": "TSTypeAliasDeclaration",
|
||||||
"references": []
|
"references": [
|
||||||
|
{
|
||||||
|
"flag": "ReferenceFlag(Read | Type)",
|
||||||
|
"id": 0,
|
||||||
|
"name": "A",
|
||||||
|
"node_id": 8
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,14 @@ input_file: crates/oxc_semantic/tests/fixtures/typescript-eslint/export/named3-t
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"name": "V",
|
"name": "V",
|
||||||
"node": "TSTypeAliasDeclaration",
|
"node": "TSTypeAliasDeclaration",
|
||||||
"references": []
|
"references": [
|
||||||
|
{
|
||||||
|
"flag": "ReferenceFlag(Read | Type)",
|
||||||
|
"id": 0,
|
||||||
|
"name": "V",
|
||||||
|
"node_id": 8
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,10 @@ impl ReferenceFlag {
|
||||||
self.contains(Self::Type)
|
self.contains(Self::Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const fn is_type_only(self) -> bool {
|
||||||
|
matches!(self, Self::Type)
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn is_value(&self) -> bool {
|
pub const fn is_value(&self) -> bool {
|
||||||
self.intersects(Self::Value)
|
self.intersects(Self::Value)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,11 @@ impl SymbolFlags {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_type(&self) -> bool {
|
pub fn is_type(&self) -> bool {
|
||||||
self.intersects(Self::Type | Self::TypeImport | Self::Import)
|
self.intersects(Self::Type | Self::TypeImport)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_can_be_referenced_by_type(&self) -> bool {
|
||||||
|
self.is_type() || self.contains(Self::Import)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_value(&self) -> bool {
|
pub fn is_value(&self) -> bool {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue