fix(minifier): compute void number as undefined (#6028)

This commit is contained in:
Boshen 2024-09-24 14:39:44 +00:00
parent 539751cd13
commit e0a895962d
5 changed files with 41 additions and 22 deletions

View file

@ -23,11 +23,13 @@ fn main() -> std::io::Result<()> {
let source_text = std::fs::read_to_string(path)?;
let source_type = SourceType::from_path(path).unwrap();
let printed = minify(&source_text, source_type, mangle);
let mut allocator = Allocator::default();
let printed = minify(&allocator, &source_text, source_type, mangle);
println!("{printed}");
if twice {
let printed2 = minify(&printed, source_type, mangle);
allocator.reset();
let printed2 = minify(&allocator, &printed, source_type, mangle);
println!("{printed2}");
println!("same = {}", printed == printed2);
}
@ -35,11 +37,15 @@ fn main() -> std::io::Result<()> {
Ok(())
}
fn minify(source_text: &str, source_type: SourceType, mangle: bool) -> String {
let allocator = Allocator::default();
let ret = Parser::new(&allocator, source_text, source_type).parse();
let program = allocator.alloc(ret.program);
let options = MinifierOptions { mangle, compress: CompressOptions::all_true() };
let ret = Minifier::new(options).build(&allocator, program);
CodeGenerator::new().with_mangler(ret.mangler).build(program).source_text
fn minify(
allocator: &Allocator,
source_text: &str,
source_type: SourceType,
mangle: bool,
) -> String {
let ret = Parser::new(allocator, source_text, source_type).parse();
let mut program = ret.program;
let options = MinifierOptions { mangle, compress: CompressOptions::default() };
let ret = Minifier::new(options).build(allocator, &mut program);
CodeGenerator::new().with_mangler(ret.mangler).build(&program).source_text
}

View file

@ -1,4 +1,4 @@
use std::{cmp::Ordering, mem};
use std::cmp::Ordering;
use num_bigint::BigInt;
use oxc_ast::ast::*;
@ -105,12 +105,12 @@ impl<'a> PeepholeFoldConstants {
}
fn try_fold_unary_expression(
&self,
&mut self,
expr: &mut UnaryExpression<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Option<Expression<'a>> {
match expr.operator {
UnaryOperator::Void => Self::try_reduce_void(expr, ctx),
UnaryOperator::Void => self.try_reduce_void(expr, ctx),
UnaryOperator::Typeof => self.try_fold_type_of(expr, ctx),
#[allow(clippy::float_cmp)]
UnaryOperator::LogicalNot => {
@ -135,13 +135,15 @@ impl<'a> PeepholeFoldConstants {
/// `void 1` -> `void 0`
fn try_reduce_void(
&mut self,
expr: &mut UnaryExpression<'a>,
ctx: &mut TraverseCtx<'a>,
) -> Option<Expression<'a>> {
if (!expr.argument.is_number() || !expr.argument.is_number_0())
&& !expr.may_have_side_effects()
{
let _ = mem::replace(&mut expr.argument, ctx.ast.number_0());
expr.argument = ctx.ast.number_0();
self.changed = true;
}
None
}

View file

@ -46,10 +46,10 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
fn enter_variable_declaration(
&mut self,
decl: &mut VariableDeclaration<'a>,
_ctx: &mut TraverseCtx<'a>,
ctx: &mut TraverseCtx<'a>,
) {
for declarator in decl.declarations.iter_mut() {
self.compress_variable_declarator(declarator);
self.compress_variable_declarator(declarator, ctx);
}
}
@ -247,11 +247,15 @@ impl<'a> PeepholeSubstituteAlternateSyntax {
}
}
fn compress_variable_declarator(&mut self, decl: &mut VariableDeclarator<'a>) {
fn compress_variable_declarator(
&mut self,
decl: &mut VariableDeclarator<'a>,
ctx: &mut TraverseCtx<'a>,
) {
if decl.kind.is_const() {
return;
}
if decl.init.as_ref().is_some_and(|init| init.is_undefined() || init.is_void_0()) {
if decl.init.as_ref().is_some_and(|init| ctx.is_expression_undefined(init)) {
decl.init = None;
self.changed = true;
}

View file

@ -41,10 +41,13 @@ pub trait NodeUtil {
fn scopes(&self) -> &ScopeTree;
fn is_expression_undefined(&self, expr: &Expression) -> bool {
if let Expression::Identifier(ident) = expr {
return self.is_identifier_undefined(ident);
};
false
match expr {
Expression::Identifier(ident) if self.is_identifier_undefined(ident) => true,
Expression::UnaryExpression(e) if e.operator.is_void() && e.argument.is_number() => {
true
}
_ => false,
}
}
fn is_identifier_undefined(&self, ident: &IdentifierReference) -> bool {

View file

@ -5,7 +5,7 @@ use oxc_allocator::CloneIn;
use oxc_ast_macros::ast;
use oxc_span::{cmp::ContentEq, hash::ContentHash};
#[cfg(feature = "serialize")]
use ::{serde::Serialize, tsify::Tsify};
use {serde::Serialize, tsify::Tsify};
use crate::precedence::{GetPrecedence, Precedence};
@ -356,6 +356,10 @@ impl UnaryOperator {
matches!(self, Self::BitwiseNot)
}
pub fn is_void(self) -> bool {
matches!(self, Self::Void)
}
pub fn is_keyword(self) -> bool {
matches!(self, Self::Typeof | Self::Void | Self::Delete)
}