mirror of
https://github.com/swc-project/swc.git
synced 2024-10-26 17:13:09 +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 {
|
||||
// TODO: span
|
||||
self.wr.write_symbol(ident.span, &ident.sym)?;
|
||||
if ident.optional {
|
||||
punct!("?");
|
||||
}
|
||||
|
||||
if let Some(ty) = &ident.type_ann {
|
||||
punct!(":");
|
||||
|
@ -17,6 +17,7 @@ use test::{
|
||||
};
|
||||
use testing::{NormalizedOutput, StdErr};
|
||||
|
||||
#[path = "common/mod.rs"]
|
||||
mod common;
|
||||
|
||||
const IGNORED_PASS_TESTS: &[&str] = &[
|
||||
|
@ -21,6 +21,7 @@ use test::{
|
||||
use testing::StdErr;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
#[path = "common/mod.rs"]
|
||||
mod common;
|
||||
|
||||
fn add_test<F: FnOnce() + Send + 'static>(
|
||||
|
@ -539,8 +539,21 @@ impl ClassProperties {
|
||||
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 params = c.params.fold_with(&mut folder);
|
||||
Constructor { body, params, ..c }
|
||||
})
|
||||
|
@ -1,8 +1,9 @@
|
||||
use swc_atoms::JsWord;
|
||||
use swc_common::Mark;
|
||||
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 mark: Mark,
|
||||
pub used_names: &'a [JsWord],
|
||||
@ -11,6 +12,13 @@ pub(super) struct UsedNameRenamer<'a> {
|
||||
noop_fold_type!(UsedNameRenamer<'_>);
|
||||
|
||||
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 {
|
||||
if self.used_names.contains(&ident.sym) {
|
||||
return Ident {
|
||||
@ -20,6 +28,21 @@ impl<'a> Fold for UsedNameRenamer<'a> {
|
||||
}
|
||||
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> {
|
||||
|
@ -289,6 +289,27 @@ impl<'a> Fold for Resolver<'a> {
|
||||
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 {
|
||||
let old = self.ident_type;
|
||||
self.ident_type = IdentType::Binding;
|
||||
|
@ -1,10 +1,13 @@
|
||||
use super::*;
|
||||
use crate::{
|
||||
compat::es2015::{block_scoping, destructuring, Classes},
|
||||
compat::{
|
||||
es2015::{block_scoping, destructuring, Classes},
|
||||
es2020::class_properties,
|
||||
},
|
||||
modules::common_js::common_js,
|
||||
};
|
||||
use swc_common::chain;
|
||||
use swc_ecma_parser::{EsConfig, Syntax};
|
||||
use swc_ecma_parser::{EsConfig, Syntax, TsConfig};
|
||||
|
||||
fn tr() -> impl Fold {
|
||||
chain!(resolver(), block_scoping())
|
||||
@ -17,6 +20,13 @@ fn syntax() -> Syntax {
|
||||
})
|
||||
}
|
||||
|
||||
fn ts() -> Syntax {
|
||||
Syntax::Typescript(TsConfig {
|
||||
decorators: true,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! identical {
|
||||
($name:ident, $src:literal) => {
|
||||
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