diff --git a/crates/oxc_minifier/src/peephole/mod.rs b/crates/oxc_minifier/src/peephole/mod.rs index a8558c03f..87d319ce1 100644 --- a/crates/oxc_minifier/src/peephole/mod.rs +++ b/crates/oxc_minifier/src/peephole/mod.rs @@ -306,6 +306,14 @@ impl<'a> Traverse<'a> for LatePeepholeOptimizations { fn exit_catch_clause(&mut self, catch: &mut CatchClause<'a>, ctx: &mut TraverseCtx<'a>) { self.substitute_catch_clause(catch, Ctx(ctx)); } + + fn exit_call_expression(&mut self, e: &mut CallExpression<'a>, _ctx: &mut TraverseCtx<'a>) { + Self::remove_empty_spread_arguments(&mut e.arguments); + } + + fn exit_new_expression(&mut self, e: &mut NewExpression<'a>, _ctx: &mut TraverseCtx<'a>) { + Self::remove_empty_spread_arguments(&mut e.arguments); + } } pub struct DeadCodeElimination { diff --git a/crates/oxc_minifier/src/peephole/remove_dead_code.rs b/crates/oxc_minifier/src/peephole/remove_dead_code.rs index bd7616311..b9a9e8941 100644 --- a/crates/oxc_minifier/src/peephole/remove_dead_code.rs +++ b/crates/oxc_minifier/src/peephole/remove_dead_code.rs @@ -620,6 +620,17 @@ impl<'a> LatePeepholeOptimizations { pub fn remove_dead_code_exit_class_body(body: &mut ClassBody<'a>, _ctx: Ctx<'a, '_>) { body.body.retain(|e| !matches!(e, ClassElement::StaticBlock(s) if s.body.is_empty())); } + + pub fn remove_empty_spread_arguments(args: &mut Vec<'a, Argument<'a>>) { + if args.len() != 1 { + return; + } + let Argument::SpreadElement(e) = &args[0] else { return }; + let Expression::ArrayExpression(e) = &e.argument else { return }; + if e.elements.is_empty() { + args.drain(..); + } + } } /// @@ -898,4 +909,10 @@ mod test { test_same("throw foo; export let bar"); test_same("throw foo; export default bar"); } + + #[test] + fn remove_empty_spread_arguments() { + test("foo(...[])", "foo()"); + test("new Foo(...[])", "new Foo()"); + } }