mirror of
https://github.com/swc-project/swc.git
synced 2024-10-27 01:22:05 +03:00
Fix class hygiene issue related to class properties (#892)
swc_ecma_transforms: - fixed hygiene bug of class_properties pass
This commit is contained in:
parent
5fe625ea7a
commit
c7a5d5fef9
@ -1354,6 +1354,9 @@ impl<'a> Emitter<'a> {
|
|||||||
} else {
|
} else {
|
||||||
// TODO: span
|
// TODO: span
|
||||||
self.wr.write_symbol(ident.span, &ident.sym)?;
|
self.wr.write_symbol(ident.span, &ident.sym)?;
|
||||||
|
if ident.optional {
|
||||||
|
punct!("?");
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(ty) = &ident.type_ann {
|
if let Some(ty) = &ident.type_ann {
|
||||||
punct!(":");
|
punct!(":");
|
||||||
|
@ -17,6 +17,7 @@ use test::{
|
|||||||
};
|
};
|
||||||
use testing::{NormalizedOutput, StdErr};
|
use testing::{NormalizedOutput, StdErr};
|
||||||
|
|
||||||
|
#[path = "common/mod.rs"]
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
const IGNORED_PASS_TESTS: &[&str] = &[
|
const IGNORED_PASS_TESTS: &[&str] = &[
|
||||||
|
@ -21,6 +21,7 @@ use test::{
|
|||||||
use testing::StdErr;
|
use testing::StdErr;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
#[path = "common/mod.rs"]
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
fn add_test<F: FnOnce() + Send + 'static>(
|
fn add_test<F: FnOnce() + Send + 'static>(
|
||||||
|
@ -539,8 +539,21 @@ impl ClassProperties {
|
|||||||
used_names,
|
used_names,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle collisions
|
// Handle collisions like
|
||||||
|
//
|
||||||
|
// var foo = "bar";
|
||||||
|
//
|
||||||
|
// class Foo {
|
||||||
|
// bar = foo;
|
||||||
|
// static bar = baz;
|
||||||
|
//
|
||||||
|
// constructor() {
|
||||||
|
// var foo = "foo";
|
||||||
|
// var baz = "baz";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
let body = c.body.fold_with(&mut folder);
|
let body = c.body.fold_with(&mut folder);
|
||||||
|
|
||||||
let params = c.params.fold_with(&mut folder);
|
let params = c.params.fold_with(&mut folder);
|
||||||
Constructor { body, params, ..c }
|
Constructor { body, params, ..c }
|
||||||
})
|
})
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
use swc_atoms::JsWord;
|
use swc_atoms::JsWord;
|
||||||
use swc_common::Mark;
|
use swc_common::Mark;
|
||||||
use swc_ecma_ast::*;
|
use swc_ecma_ast::*;
|
||||||
use swc_ecma_visit::{Fold, Node, Visit, VisitWith};
|
use swc_ecma_visit::{Fold, FoldWith, Node, Visit, VisitWith};
|
||||||
|
|
||||||
|
/// Used to rename **binding** identifiers in constructor.
|
||||||
pub(super) struct UsedNameRenamer<'a> {
|
pub(super) struct UsedNameRenamer<'a> {
|
||||||
pub mark: Mark,
|
pub mark: Mark,
|
||||||
pub used_names: &'a [JsWord],
|
pub used_names: &'a [JsWord],
|
||||||
@ -11,6 +12,13 @@ pub(super) struct UsedNameRenamer<'a> {
|
|||||||
noop_fold_type!(UsedNameRenamer<'_>);
|
noop_fold_type!(UsedNameRenamer<'_>);
|
||||||
|
|
||||||
impl<'a> Fold for UsedNameRenamer<'a> {
|
impl<'a> Fold for UsedNameRenamer<'a> {
|
||||||
|
fn fold_expr(&mut self, e: Expr) -> Expr {
|
||||||
|
match e {
|
||||||
|
Expr::Ident(..) => e,
|
||||||
|
_ => e.fold_children_with(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn fold_ident(&mut self, ident: Ident) -> Ident {
|
fn fold_ident(&mut self, ident: Ident) -> Ident {
|
||||||
if self.used_names.contains(&ident.sym) {
|
if self.used_names.contains(&ident.sym) {
|
||||||
return Ident {
|
return Ident {
|
||||||
@ -20,6 +28,21 @@ impl<'a> Fold for UsedNameRenamer<'a> {
|
|||||||
}
|
}
|
||||||
ident
|
ident
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fold_member_expr(&mut self, e: MemberExpr) -> MemberExpr {
|
||||||
|
if e.computed {
|
||||||
|
MemberExpr {
|
||||||
|
obj: e.obj.fold_with(self),
|
||||||
|
prop: e.prop.fold_with(self),
|
||||||
|
..e
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MemberExpr {
|
||||||
|
obj: e.obj.fold_with(self),
|
||||||
|
..e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct UsedNameCollector<'a> {
|
pub(super) struct UsedNameCollector<'a> {
|
||||||
|
@ -289,6 +289,27 @@ impl<'a> Fold for Resolver<'a> {
|
|||||||
ClassMethod { key, function, ..m }
|
ClassMethod { key, function, ..m }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fold_class_prop(&mut self, p: ClassProp) -> ClassProp {
|
||||||
|
let decorators = p.decorators.fold_with(self);
|
||||||
|
|
||||||
|
let old = self.ident_type;
|
||||||
|
self.ident_type = IdentType::Binding;
|
||||||
|
let key = p.key.fold_with(self);
|
||||||
|
self.ident_type = old;
|
||||||
|
|
||||||
|
let old = self.ident_type;
|
||||||
|
self.ident_type = IdentType::Ref;
|
||||||
|
let value = p.value.fold_with(self);
|
||||||
|
self.ident_type = old;
|
||||||
|
|
||||||
|
ClassProp {
|
||||||
|
decorators,
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
..p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn fold_constructor(&mut self, c: Constructor) -> Constructor {
|
fn fold_constructor(&mut self, c: Constructor) -> Constructor {
|
||||||
let old = self.ident_type;
|
let old = self.ident_type;
|
||||||
self.ident_type = IdentType::Binding;
|
self.ident_type = IdentType::Binding;
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
compat::es2015::{block_scoping, destructuring, Classes},
|
compat::{
|
||||||
|
es2015::{block_scoping, destructuring, Classes},
|
||||||
|
es2020::class_properties,
|
||||||
|
},
|
||||||
modules::common_js::common_js,
|
modules::common_js::common_js,
|
||||||
};
|
};
|
||||||
use swc_common::chain;
|
use swc_common::chain;
|
||||||
use swc_ecma_parser::{EsConfig, Syntax};
|
use swc_ecma_parser::{EsConfig, Syntax, TsConfig};
|
||||||
|
|
||||||
fn tr() -> impl Fold {
|
fn tr() -> impl Fold {
|
||||||
chain!(resolver(), block_scoping())
|
chain!(resolver(), block_scoping())
|
||||||
@ -17,6 +20,13 @@ fn syntax() -> Syntax {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ts() -> Syntax {
|
||||||
|
Syntax::Typescript(TsConfig {
|
||||||
|
decorators: true,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! identical {
|
macro_rules! identical {
|
||||||
($name:ident, $src:literal) => {
|
($name:ident, $src:literal) => {
|
||||||
test!(syntax(), |_| tr(), $name, $src, $src);
|
test!(syntax(), |_| tr(), $name, $src, $src);
|
||||||
@ -1127,3 +1137,32 @@ identical!(
|
|||||||
}
|
}
|
||||||
});"
|
});"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test!(
|
||||||
|
ts(),
|
||||||
|
|_| chain!(resolver(), class_properties()),
|
||||||
|
issue_890_1,
|
||||||
|
"const DURATION = 1000
|
||||||
|
|
||||||
|
export class HygieneTest {
|
||||||
|
private readonly duration: number = DURATION
|
||||||
|
|
||||||
|
constructor(duration?: number) {
|
||||||
|
this.duration = duration ?? DURATION
|
||||||
|
}
|
||||||
|
|
||||||
|
getDuration() {
|
||||||
|
return this.duration
|
||||||
|
}
|
||||||
|
}",
|
||||||
|
"const DURATION = 1000;
|
||||||
|
export class HygieneTest {
|
||||||
|
getDuration() {
|
||||||
|
return this.duration;
|
||||||
|
}
|
||||||
|
constructor(duration?: number){
|
||||||
|
_defineProperty(this, 'duration', DURATION);
|
||||||
|
this.duration = duration ?? DURATION;
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user