Skip to content

Commit

Permalink
feat(minifier): add constant folding to remove dead code (#4058)
Browse files Browse the repository at this point in the history
  • Loading branch information
Boshen authored Jul 5, 2024
1 parent edb557c commit 0da9dfb
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 11 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/oxc_minifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ num-traits = { workspace = true }
oxc_parser = { workspace = true }
oxc_codegen = { workspace = true }

# insta = { workspace = true }
# walkdir = { workspace = true }
insta = { workspace = true }
walkdir = { workspace = true }
pico-args = { workspace = true }
15 changes: 12 additions & 3 deletions crates/oxc_minifier/src/ast_passes/remove_dead_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,34 @@ use oxc_allocator::Allocator;
use oxc_ast::{ast::*, visit::walk_mut, AstBuilder, VisitMut};
use oxc_span::SPAN;

use crate::{compressor::ast_util::get_boolean_value, folder::Folder};

/// Remove Dead Code from the AST.
///
/// Terser option: `dead_code: true`.
pub struct RemoveDeadCode<'a> {
ast: AstBuilder<'a>,
folder: Folder<'a>,
}

impl<'a> RemoveDeadCode<'a> {
pub fn new(allocator: &'a Allocator) -> Self {
Self { ast: AstBuilder::new(allocator) }
let ast = AstBuilder::new(allocator);
Self { ast, folder: Folder::new(ast) }
}

pub fn build(&mut self, program: &mut Program<'a>) {
self.visit_program(program);
}

fn test_expression(&mut self, expr: &mut Expression<'a>) -> Option<bool> {
self.folder.fold_expression(expr);
get_boolean_value(expr)
}

pub fn remove_if(&mut self, stmt: &mut Statement<'a>) {
let Statement::IfStatement(if_stmt) = stmt else { return };
match if_stmt.test.get_boolean_value() {
match self.test_expression(&mut if_stmt.test) {
Some(true) => {
*stmt = self.ast.move_statement(&mut if_stmt.consequent);
}
Expand All @@ -41,7 +50,7 @@ impl<'a> RemoveDeadCode<'a> {
else {
return;
};
match conditional_expr.test.get_boolean_value() {
match self.test_expression(&mut conditional_expr.test) {
Some(true) => {
expression_stmt.expression =
self.ast.move_expression(&mut conditional_expr.consequent);
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_minifier/src/folder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl<'a> Folder<'a> {
self
}

pub(crate) fn fold_expression<'b>(&mut self, expr: &'b mut Expression<'a>) {
pub fn fold_expression<'b>(&mut self, expr: &'b mut Expression<'a>) {
let folded_expr = match expr {
Expression::BinaryExpression(binary_expr) => match binary_expr.operator {
BinaryOperator::Equality
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
mod closure;
mod esbuild;
#![allow(unused)]
// mod closure;
// mod esbuild;
mod oxc;
mod tdewolff;
mod terser;
// mod tdewolff;
// mod terser;

use oxc_allocator::Allocator;
use oxc_codegen::WhitespaceRemover;
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_minifier/tests/oxc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mod code_removal;
mod folding;
mod precedence;
// mod precedence;
mod remove_dead_code;
mod replace_global_defines;
15 changes: 15 additions & 0 deletions crates/oxc_minifier/tests/oxc/remove_dead_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,21 @@ fn remove_dead_code() {
test("if (true) { foo } else { bar }", "{foo}");
test("if (false) { foo } else { bar }", "{bar}");

test("if (!false) { foo }", "{foo}");
test("if (!true) { foo } else { bar }", "{bar}");

test("if ('production' == 'production') { foo } else { bar }", "{foo}");
test("if ('development' == 'production') { foo } else { bar }", "{bar}");

test("if ('production' === 'production') { foo } else { bar }", "{foo}");
test("if ('development' === 'production') { foo } else { bar }", "{bar}");

test("false ? foo : bar;", "bar");
test("true ? foo : bar;", "foo");

test("!true ? foo : bar;", "bar");
test("!false ? foo : bar;", "foo");

test("!!false ? foo : bar;", "bar");
test("!!true ? foo : bar;", "foo");
}

0 comments on commit 0da9dfb

Please sign in to comment.