diff --git a/crates/oxc_minifier/src/ast_passes/mod.rs b/crates/oxc_minifier/src/ast_passes/mod.rs index 7c0a26ba050fb..f93a038b30e6c 100644 --- a/crates/oxc_minifier/src/ast_passes/mod.rs +++ b/crates/oxc_minifier/src/ast_passes/mod.rs @@ -60,7 +60,7 @@ impl PeepholeOptimizations { x3_collapse_variable_declarations: CollapseVariableDeclarations::new(), x4_peephole_fold_constants: PeepholeFoldConstants::new(), x5_peephole_minimize_conditions: PeepholeMinimizeConditions::new(target), - x6_peephole_remove_dead_code: PeepholeRemoveDeadCode::new(), + x6_peephole_remove_dead_code: PeepholeRemoveDeadCode::new(in_fixed_loop), x7_convert_to_dotted_properties: ConvertToDottedProperties::new(in_fixed_loop), x8_peephole_replace_known_methods: PeepholeReplaceKnownMethods::new(), x9_peephole_substitute_alternate_syntax: PeepholeSubstituteAlternateSyntax::new( @@ -149,6 +149,10 @@ impl<'a> Traverse<'a> for PeepholeOptimizations { self.x1_minimize_exit_points.exit_function_body(body, ctx); } + fn exit_class_body(&mut self, body: &mut ClassBody<'a>, ctx: &mut TraverseCtx<'a>) { + self.x6_peephole_remove_dead_code.exit_class_body(body, ctx); + } + fn exit_variable_declaration( &mut self, decl: &mut VariableDeclaration<'a>, @@ -236,7 +240,7 @@ impl DeadCodeElimination { pub fn new() -> Self { Self { x1_peephole_fold_constants: PeepholeFoldConstants::new(), - x2_peephole_remove_dead_code: PeepholeRemoveDeadCode::new(), + x2_peephole_remove_dead_code: PeepholeRemoveDeadCode::new(false), } } } diff --git a/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs b/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs index 4e9c8c6112a05..4ca3bab28defc 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs @@ -17,6 +17,8 @@ use crate::{ctx::Ctx, keep_var::KeepVar, CompressorPass}; /// pub struct PeepholeRemoveDeadCode { pub(crate) changed: bool, + + in_fixed_loop: bool, } impl<'a> CompressorPass<'a> for PeepholeRemoveDeadCode { @@ -70,11 +72,17 @@ impl<'a> Traverse<'a> for PeepholeRemoveDeadCode { self.changed = true; } } + + fn exit_class_body(&mut self, body: &mut ClassBody<'a>, _ctx: &mut TraverseCtx<'a>) { + if !self.in_fixed_loop { + Self::remove_empty_class_static_block(body); + } + } } impl<'a, 'b> PeepholeRemoveDeadCode { - pub fn new() -> Self { - Self { changed: false } + pub fn new(in_fixed_loop: bool) -> Self { + Self { changed: false, in_fixed_loop } } /// Removes dead code thats comes after `return` statements after inlining `if` statements @@ -562,6 +570,10 @@ impl<'a, 'b> PeepholeRemoveDeadCode { }; (params_empty && body_empty).then(|| ctx.ast.statement_empty(e.span)) } + + fn remove_empty_class_static_block(body: &mut ClassBody<'a>) { + body.body.retain(|e| !matches!(e, ClassElement::StaticBlock(s) if s.body.is_empty())); + } } /// @@ -573,7 +585,7 @@ mod test { fn test(source_text: &str, positive: &str) { let allocator = Allocator::default(); - let mut pass = super::PeepholeRemoveDeadCode::new(); + let mut pass = super::PeepholeRemoveDeadCode::new(false); tester::test(&allocator, source_text, positive, &mut pass); } @@ -791,4 +803,10 @@ mod test { // test("/* @__PURE__ */ (() => x)()", ""); // test("/* @__PURE__ */ (() => x)(y, z)", "y, z;"); } + + #[test] + fn test_remove_empty_static_block() { + test("class Foo { static {}; foo }", "class Foo { foo }"); + test_same("class Foo { static { foo() }"); + } }