Skip to content

Commit 572bd52

Browse files
committed
fix(mangler): avoid reusing same mangled names in the outer class
1 parent 1171718 commit 572bd52

File tree

3 files changed

+55
-7
lines changed

3 files changed

+55
-7
lines changed

crates/oxc_mangler/src/lib.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -564,11 +564,40 @@ impl<'t> Mangler<'t> {
564564
semantic: &Semantic<'_>,
565565
) -> IndexVec<ClassId, FxHashMap<String, CompactStr>> {
566566
let classes = semantic.classes();
567-
classes
567+
568+
let private_member_count: IndexVec<ClassId, usize> = classes
568569
.elements
569570
.iter()
570571
.map(|class_elements| {
571-
assert!(u32::try_from(class_elements.len()).is_ok(), "too many class elements");
572+
class_elements
573+
.iter()
574+
.filter_map(|element| {
575+
if element.is_private { Some(element.name.to_string()) } else { None }
576+
})
577+
.count()
578+
})
579+
.collect();
580+
let parent_private_member_count: IndexVec<ClassId, usize> = classes
581+
.declarations
582+
.iter_enumerated()
583+
.map(|(class_id, _)| {
584+
classes
585+
.ancestors(class_id)
586+
.skip(1)
587+
.map(|id| private_member_count[id])
588+
.sum::<usize>()
589+
})
590+
.collect();
591+
592+
classes
593+
.elements
594+
.iter_enumerated()
595+
.map(|(class_id, class_elements)| {
596+
let parent_private_member_count = parent_private_member_count[class_id];
597+
assert!(
598+
u32::try_from(class_elements.len() + parent_private_member_count).is_ok(),
599+
"too many class elements"
600+
);
572601
class_elements
573602
.iter()
574603
.filter_map(|element| {
@@ -580,7 +609,13 @@ impl<'t> Mangler<'t> {
580609
clippy::cast_possible_truncation,
581610
reason = "checked above with assert"
582611
)]
583-
let mangled = CompactStr::new(base54(i as u32).as_str());
612+
let mangled = CompactStr::new(
613+
// Avoid reusing the same mangled name in parent classes.
614+
// We can improve this by reusing names that are not used in child classes,
615+
// but nesting a class inside another class is not common
616+
// and that would require liveness analysis.
617+
base54((parent_private_member_count + i) as u32).as_str(),
618+
);
584619
(name, mangled)
585620
})
586621
.collect::<FxHashMap<_, _>>()

crates/oxc_minifier/tests/mangler/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ fn private_member_mangling() {
125125
// Test same names across different classes should reuse mangled names
126126
"class A { #field = 1; #method() { return this.#field; } } class B { #field = 2; #method() { return this.#field; } }",
127127
"class A { #field = 1; #method() { return this.#field; } } class B { #field2 = 2; #method2() { return this.#field2; } }",
128+
"class Outer { #shared = 1; #getInner() { return class { #method() { return this.#shared; } }; } }",
128129
];
129130

130131
let mut snapshot = String::new();

crates/oxc_minifier/tests/mangler/snapshots/private_member_mangling.snap

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ class Outer {
5252
#e = 1;
5353
inner() {
5454
return class e {
55-
#e = 2;
55+
#t = 2;
5656
get() {
57-
return this.#e;
57+
return this.#t;
5858
}
5959
};
6060
}
@@ -78,9 +78,9 @@ class Outer {
7878
#e = 1;
7979
getInner() {
8080
return class {
81-
#e = 2;
81+
#t = 2;
8282
method() {
83-
return this.#e;
83+
return this.#t;
8484
}
8585
};
8686
}
@@ -122,3 +122,15 @@ class B {
122122
return this.#e;
123123
}
124124
}
125+
126+
class Outer { #shared = 1; #getInner() { return class { #method() { return this.#shared; } }; } }
127+
class Outer {
128+
#e = 1;
129+
#t() {
130+
return class {
131+
#n() {
132+
return this.#e;
133+
}
134+
};
135+
}
136+
}

0 commit comments

Comments
 (0)