Skip to content

Commit f6e2f29

Browse files
committed
feat(minifier): remove unused class declaration (#12419)
closes #11857 Only implement for simple cases in this PR. Keep if class elements may have side effects.
1 parent c4a2d79 commit f6e2f29

File tree

2 files changed

+75
-8
lines changed

2 files changed

+75
-8
lines changed

crates/oxc_minifier/src/peephole/remove_dead_code.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ impl<'a> PeepholeOptimizations {
3030
Statement::TryStatement(s) => Self::try_fold_try(s, ctx),
3131
Statement::LabeledStatement(s) => Self::try_fold_labeled(s, ctx),
3232
Statement::FunctionDeclaration(f) => Self::remove_unused_function_declaration(f, ctx),
33+
Statement::ClassDeclaration(c) => Self::remove_unused_class_declaration(c, ctx),
3334
_ => None,
3435
} {
3536
*stmt = new_stmt;

crates/oxc_minifier/src/peephole/remove_unused_variable_declaration.rs

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,51 @@ impl<'a> PeepholeOptimizations {
3939
}
4040
let id = f.id.as_ref()?;
4141
let symbol_id = id.symbol_id.get()?;
42-
if ctx.scoping().symbol_is_unused(symbol_id) {
43-
return Some(ctx.ast.statement_empty(f.span));
42+
if !ctx.scoping().symbol_is_unused(symbol_id) {
43+
return None;
44+
}
45+
Some(ctx.ast.statement_empty(f.span))
46+
}
47+
48+
pub fn remove_unused_class_declaration(
49+
c: &Class<'a>,
50+
ctx: &mut Ctx<'a, '_>,
51+
) -> Option<Statement<'a>> {
52+
if ctx.state.options.unused == CompressOptionsUnused::Keep {
53+
return None;
54+
}
55+
if Self::keep_top_level_var_in_script_mode(ctx) {
56+
return None;
57+
}
58+
let id = c.id.as_ref()?;
59+
let symbol_id = id.symbol_id.get()?;
60+
if !ctx.scoping().symbol_is_unused(symbol_id) {
61+
return None;
62+
}
63+
// TODO: keep side effectful expressions and remove the class.
64+
if c.super_class.is_some() {
65+
return None;
66+
}
67+
for e in &c.body.body {
68+
match e {
69+
ClassElement::StaticBlock(e) => {
70+
if !e.body.is_empty() {
71+
return None;
72+
}
73+
}
74+
ClassElement::MethodDefinition(d) => {
75+
if d.computed {
76+
return None;
77+
}
78+
}
79+
ClassElement::PropertyDefinition(_)
80+
| ClassElement::AccessorProperty(_)
81+
| ClassElement::TSIndexSignature(_) => {
82+
return None;
83+
}
84+
}
4485
}
45-
None
86+
Some(ctx.ast.statement_empty(c.span))
4687
}
4788

4889
pub fn remove_unused_assignment_expression(
@@ -119,6 +160,26 @@ mod test {
119160
test_same_options("export function foo() {} foo()", &options);
120161
}
121162

163+
#[test]
164+
fn remove_unused_class_declaration() {
165+
let options = CompressOptions::smallest();
166+
test_options("class C {}", "", &options);
167+
test_same_options("class C extends Foo { }", &options);
168+
169+
test_options("class C { static {} }", "", &options);
170+
test_same_options("class C { static { foo } }", &options);
171+
172+
test_options("class C { foo() {} }", "", &options);
173+
test_same_options("class C { [foo]() {} }", &options);
174+
175+
test_same_options("class C { [foo] }", &options);
176+
test_same_options("class C { foo = bar() }", &options);
177+
test_same_options("class C { foo = 1 }", &options);
178+
test_same_options("class C { static foo = bar }", &options);
179+
180+
test_same_options("class C { accessor foo = 1}", &options);
181+
}
182+
122183
#[test]
123184
#[ignore]
124185
fn remove_unused_assignment_expression() {
@@ -139,21 +200,26 @@ mod test {
139200
"function foo(t) { return x(); } foo();",
140201
&options,
141202
);
142-
}
143203

144-
#[test]
145-
#[ignore]
146-
fn keep_in_script_mode() {
147204
let options = CompressOptions::smallest();
148205
let source_type = SourceType::cjs();
149206
test_same_options_source_type("var x = 1; x = 2;", source_type, &options);
150207
test_same_options_source_type("var x = 1; x = 2, foo(x)", source_type, &options);
151-
152208
test_options_source_type(
153209
"function foo() { var x = 1; x = 2; bar() } foo()",
154210
"function foo() { bar() } foo()",
155211
source_type,
156212
&options,
157213
);
158214
}
215+
216+
#[test]
217+
fn keep_in_script_mode() {
218+
let options = CompressOptions::smallest();
219+
let source_type = SourceType::cjs();
220+
test_same_options_source_type("var x = 1; x = 2;", source_type, &options);
221+
test_same_options_source_type("var x = 1; x = 2, foo(x)", source_type, &options);
222+
223+
test_options_source_type("class C {}", "class C {}", source_type, &options);
224+
}
159225
}

0 commit comments

Comments
 (0)