Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(minifier): add skeleton for RemoveDeadCode ast pass #3802

Merged
merged 1 commit into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/oxc_minifier/src/ast_passes/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#![allow(clippy::wildcard_imports)]

mod remove_dead_code;
mod remove_parens;

pub use remove_dead_code::RemoveDeadCode;
pub use remove_parens::RemoveParens;
45 changes: 45 additions & 0 deletions crates/oxc_minifier/src/ast_passes/remove_dead_code.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use oxc_allocator::Allocator;
use oxc_ast::{ast::*, visit::walk_mut, AstBuilder, VisitMut};
use oxc_span::SPAN;

/// Remove Dead Code from the AST.
///
/// Terser option: `dead_code: true`.
#[derive(Clone, Copy)]
pub struct RemoveDeadCode<'a> {
ast: AstBuilder<'a>,
}

impl<'a> RemoveDeadCode<'a> {
pub fn new(allocator: &'a Allocator) -> Self {
Self { ast: AstBuilder::new(allocator) }
}

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

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() {
Some(true) => {
*stmt = self.ast.move_statement(&mut if_stmt.consequent);
}
Some(false) => {
*stmt = if let Some(alternate) = &mut if_stmt.alternate {
self.ast.move_statement(alternate)
} else {
self.ast.empty_statement(SPAN)
};
}
_ => {}
}
}
}

impl<'a> VisitMut<'a> for RemoveDeadCode<'a> {
fn visit_statement(&mut self, stmt: &mut Statement<'a>) {
self.remove_if(stmt);
walk_mut::walk_statement_mut(self, stmt);
}
}
8 changes: 5 additions & 3 deletions crates/oxc_minifier/src/ast_passes/remove_parens.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use oxc_allocator::{Allocator, Vec};
use oxc_ast::visit::walk_mut::{walk_expression_mut, walk_statements_mut};
#[allow(clippy::wildcard_imports)]
use oxc_ast::{ast::*, AstBuilder, VisitMut};
use oxc_ast::{
ast::*,
visit::walk_mut::{walk_expression_mut, walk_statements_mut},
AstBuilder, VisitMut,
};

/// Remove Parenthesized Expression from the AST.
#[derive(Clone, Copy)]
Expand Down
2 changes: 1 addition & 1 deletion crates/oxc_minifier/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use oxc_allocator::Allocator;
use oxc_ast::ast::Program;

pub use crate::{
ast_passes::RemoveParens,
ast_passes::{RemoveDeadCode, RemoveParens},
compressor::{CompressOptions, Compressor},
mangler::ManglerBuilder,
};
Expand Down
1 change: 1 addition & 0 deletions crates/oxc_minifier/tests/oxc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod code_removal;
mod folding;
mod precedence;
mod remove_dead_code;
26 changes: 26 additions & 0 deletions crates/oxc_minifier/tests/oxc/remove_dead_code.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use oxc_allocator::Allocator;
use oxc_codegen::WhitespaceRemover;
use oxc_minifier::RemoveDeadCode;
use oxc_parser::Parser;
use oxc_span::SourceType;

fn minify(source_text: &str) -> String {
let source_type = SourceType::default();
let allocator = Allocator::default();
let ret = Parser::new(&allocator, source_text, source_type).parse();
let program = allocator.alloc(ret.program);
RemoveDeadCode::new(&allocator).build(program);
WhitespaceRemover::new().build(program).source_text
}

pub(crate) fn test(source_text: &str, expected: &str) {
let minified = minify(source_text);
assert_eq!(minified, expected, "for source {source_text}");
}

#[test]
fn remove_dead_code() {
test("if (true) { foo }", "{foo}");
test("if (true) { foo } else { bar }", "{foo}");
test("if (false) { foo } else { bar }", "{bar}");
}
Loading