Skip to content

Commit 353c001

Browse files
committed
fix(minifier): keep private class members used in nested classes (#14217)
refs #14026, #14209
1 parent b83ffe5 commit 353c001

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

crates/oxc_minifier/src/peephole/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ impl<'a> Traverse<'a, MinifierState<'a>> for PeepholeOptimizations {
372372
let ctx = &mut Ctx::new(ctx);
373373
Self::remove_dead_code_exit_class_body(body, ctx);
374374
Self::remove_unused_private_members(body, ctx);
375-
ctx.state.class_symbols_stack.pop_class_scope();
375+
ctx.state.class_symbols_stack.pop_class_scope(Self::get_declared_private_symbols(body));
376376
}
377377

378378
fn exit_catch_clause(&mut self, catch: &mut CatchClause<'a>, ctx: &mut TraverseCtx<'a>) {

crates/oxc_minifier/src/peephole/remove_unused_private_members.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,33 @@ impl<'a> PeepholeOptimizations {
5656
ctx.state.changed = true;
5757
}
5858
}
59+
60+
pub fn get_declared_private_symbols(body: &ClassBody<'a>) -> impl Iterator<Item = Atom<'a>> {
61+
body.body.iter().filter_map(|element| match element {
62+
ClassElement::PropertyDefinition(prop) => {
63+
let PropertyKey::PrivateIdentifier(private_id) = &prop.key else {
64+
return None;
65+
};
66+
Some(private_id.name)
67+
}
68+
ClassElement::MethodDefinition(method) => {
69+
let PropertyKey::PrivateIdentifier(private_id) = &method.key else {
70+
return None;
71+
};
72+
Some(private_id.name)
73+
}
74+
ClassElement::AccessorProperty(accessor) => {
75+
let PropertyKey::PrivateIdentifier(private_id) = &accessor.key else {
76+
return None;
77+
};
78+
Some(private_id.name)
79+
}
80+
ClassElement::StaticBlock(_) => None,
81+
ClassElement::TSIndexSignature(_) => {
82+
unreachable!("TypeScript syntax should be transformed away")
83+
}
84+
})
85+
}
5986
}
6087

6188
#[cfg(test)]
@@ -153,5 +180,19 @@ mod test {
153180
}
154181
} new Outer();",
155182
);
183+
test_same(
184+
r"class Outer {
185+
#shared = 1;
186+
187+
getInner() {
188+
let self = this;
189+
return class {
190+
method() {
191+
return self.#shared;
192+
}
193+
};
194+
}
195+
} new Outer();",
196+
);
156197
}
157198
}

crates/oxc_minifier/src/state.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,13 @@ impl<'a> ClassSymbolsStack<'a> {
5757
}
5858

5959
/// Exit the current class scope
60-
pub fn pop_class_scope(&mut self) {
61-
self.stack.pop();
60+
pub fn pop_class_scope(&mut self, declared_private_symbols: impl Iterator<Item = Atom<'a>>) {
61+
let mut used_private_symbols = self.stack.pop();
62+
declared_private_symbols.for_each(|name| {
63+
used_private_symbols.remove(&name);
64+
});
65+
// if the symbol was not declared in this class, that is declared in the class outside the current class
66+
self.stack.last_mut().extend(used_private_symbols);
6267
}
6368

6469
/// Add a private member to the current class scope

0 commit comments

Comments
 (0)