Skip to content

Commit

Permalink
fix(minifier): remove expression statement void 0 (#8602)
Browse files Browse the repository at this point in the history
  • Loading branch information
Boshen committed Jan 19, 2025
1 parent 1a99d35 commit 4ff6e85
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ pub fn is_immutable_value(expr: &Expression<'_>) -> bool {
Expression::Identifier(ident) => {
matches!(ident.name.as_str(), "undefined" | "Infinity" | "NaN")
}
Expression::UnaryExpression(e)
if matches!(
e.operator,
UnaryOperator::Void | UnaryOperator::LogicalNot | UnaryOperator::UnaryNegation
) =>
{
is_immutable_value(&e.argument)
}
// Operations on bigint can result type error.
// Expression::BigIntLiteral(_) => false,
_ => false,
Expand Down
107 changes: 55 additions & 52 deletions crates/oxc_minifier/src/ast_passes/peephole_remove_dead_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,60 +326,55 @@ impl<'a, 'b> PeepholeRemoveDeadCode {
}
}

stmt.expression
.is_literal_value(false)
.then(|| Some(ctx.ast.statement_empty(stmt.span)))
.unwrap_or_else(|| match &mut stmt.expression {
Expression::ArrayExpression(expr) => Self::try_fold_array_expression(expr, ctx),
Expression::ObjectExpression(object_expr) => {
Self::try_fold_object_expression(object_expr, ctx)
}
Expression::TemplateLiteral(template_lit) => {
if !template_lit.expressions.is_empty() {
return None;
}
let mut expressions = ctx.ast.move_vec(&mut template_lit.expressions);
if expressions.len() == 0 {
return Some(ctx.ast.statement_empty(stmt.span));
} else if expressions.len() == 1 {
return Some(
ctx.ast.statement_expression(
template_lit.span,
expressions.pop().unwrap(),
),
);
}
Some(ctx.ast.statement_expression(
template_lit.span,
ctx.ast.expression_sequence(template_lit.span, expressions),
))
}
Expression::FunctionExpression(function_expr) if function_expr.id.is_none() => {
Some(ctx.ast.statement_empty(stmt.span))
}
Expression::ArrowFunctionExpression(_) => Some(ctx.ast.statement_empty(stmt.span)),
// `typeof x` -> ``
Expression::UnaryExpression(unary_expr)
if unary_expr.operator.is_typeof()
&& unary_expr.argument.is_identifier_reference() =>
{
Some(ctx.ast.statement_empty(stmt.span))
if stmt.expression.is_literal_value(false) {
return Some(ctx.ast.statement_empty(stmt.span));
}

match &mut stmt.expression {
Expression::ArrayExpression(expr) => Self::try_fold_array_expression(expr, ctx),
Expression::ObjectExpression(object_expr) => {
Self::try_fold_object_expression(object_expr, ctx)
}
Expression::TemplateLiteral(template_lit) => {
if !template_lit.expressions.is_empty() {
return None;
}
// `typeof x.y` -> `x.y`, `void x` -> `x`
// `+0n` -> `Uncaught TypeError: Cannot convert a BigInt value to a number`
Expression::UnaryExpression(unary_expr)
if matches!(
unary_expr.operator,
UnaryOperator::Typeof | UnaryOperator::Void
) =>
{
Some(ctx.ast.statement_expression(
unary_expr.span,
ctx.ast.move_expression(&mut unary_expr.argument),
))
let mut expressions = ctx.ast.move_vec(&mut template_lit.expressions);
if expressions.len() == 0 {
return Some(ctx.ast.statement_empty(stmt.span));
} else if expressions.len() == 1 {
return Some(
ctx.ast.statement_expression(template_lit.span, expressions.pop().unwrap()),
);
}
_ => None,
})
Some(ctx.ast.statement_expression(
template_lit.span,
ctx.ast.expression_sequence(template_lit.span, expressions),
))
}
Expression::FunctionExpression(function_expr) if function_expr.id.is_none() => {
Some(ctx.ast.statement_empty(stmt.span))
}
Expression::ArrowFunctionExpression(_) => Some(ctx.ast.statement_empty(stmt.span)),
// `typeof x` -> ``
Expression::UnaryExpression(unary_expr)
if unary_expr.operator.is_typeof()
&& unary_expr.argument.is_identifier_reference() =>
{
Some(ctx.ast.statement_empty(stmt.span))
}
// `typeof x.y` -> `x.y`, `void x` -> `x`
// `+0n` -> `Uncaught TypeError: Cannot convert a BigInt value to a number`
Expression::UnaryExpression(unary_expr)
if matches!(unary_expr.operator, UnaryOperator::Typeof | UnaryOperator::Void) =>
{
Some(ctx.ast.statement_expression(
unary_expr.span,
ctx.ast.move_expression(&mut unary_expr.argument),
))
}
_ => None,
}
}

fn try_fold_try(s: &mut TryStatement<'a>, ctx: Ctx<'a, 'b>) -> Option<Statement<'a>> {
Expand Down Expand Up @@ -837,4 +832,12 @@ mod test {
test("class Foo { static {}; foo }", "class Foo { foo }");
test_same("class Foo { static { foo() }");
}

#[test]
fn remove_expression_statement() {
test("void 0", "");
test("-1", "");
test("!1", "");
test("1", "");
}
}

0 comments on commit 4ff6e85

Please sign in to comment.