mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
fix(minifier): compute void number as undefined (#6028)
This commit is contained in:
parent
539751cd13
commit
e0a895962d
5 changed files with 41 additions and 22 deletions
|
|
@ -23,11 +23,13 @@ fn main() -> std::io::Result<()> {
|
||||||
let source_text = std::fs::read_to_string(path)?;
|
let source_text = std::fs::read_to_string(path)?;
|
||||||
let source_type = SourceType::from_path(path).unwrap();
|
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}");
|
println!("{printed}");
|
||||||
|
|
||||||
if twice {
|
if twice {
|
||||||
let printed2 = minify(&printed, source_type, mangle);
|
allocator.reset();
|
||||||
|
let printed2 = minify(&allocator, &printed, source_type, mangle);
|
||||||
println!("{printed2}");
|
println!("{printed2}");
|
||||||
println!("same = {}", printed == printed2);
|
println!("same = {}", printed == printed2);
|
||||||
}
|
}
|
||||||
|
|
@ -35,11 +37,15 @@ fn main() -> std::io::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn minify(source_text: &str, source_type: SourceType, mangle: bool) -> String {
|
fn minify(
|
||||||
let allocator = Allocator::default();
|
allocator: &Allocator,
|
||||||
let ret = Parser::new(&allocator, source_text, source_type).parse();
|
source_text: &str,
|
||||||
let program = allocator.alloc(ret.program);
|
source_type: SourceType,
|
||||||
let options = MinifierOptions { mangle, compress: CompressOptions::all_true() };
|
mangle: bool,
|
||||||
let ret = Minifier::new(options).build(&allocator, program);
|
) -> String {
|
||||||
CodeGenerator::new().with_mangler(ret.mangler).build(program).source_text
|
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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{cmp::Ordering, mem};
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use oxc_ast::ast::*;
|
use oxc_ast::ast::*;
|
||||||
|
|
@ -105,12 +105,12 @@ impl<'a> PeepholeFoldConstants {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_fold_unary_expression(
|
fn try_fold_unary_expression(
|
||||||
&self,
|
&mut self,
|
||||||
expr: &mut UnaryExpression<'a>,
|
expr: &mut UnaryExpression<'a>,
|
||||||
ctx: &mut TraverseCtx<'a>,
|
ctx: &mut TraverseCtx<'a>,
|
||||||
) -> Option<Expression<'a>> {
|
) -> Option<Expression<'a>> {
|
||||||
match expr.operator {
|
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),
|
UnaryOperator::Typeof => self.try_fold_type_of(expr, ctx),
|
||||||
#[allow(clippy::float_cmp)]
|
#[allow(clippy::float_cmp)]
|
||||||
UnaryOperator::LogicalNot => {
|
UnaryOperator::LogicalNot => {
|
||||||
|
|
@ -135,13 +135,15 @@ impl<'a> PeepholeFoldConstants {
|
||||||
|
|
||||||
/// `void 1` -> `void 0`
|
/// `void 1` -> `void 0`
|
||||||
fn try_reduce_void(
|
fn try_reduce_void(
|
||||||
|
&mut self,
|
||||||
expr: &mut UnaryExpression<'a>,
|
expr: &mut UnaryExpression<'a>,
|
||||||
ctx: &mut TraverseCtx<'a>,
|
ctx: &mut TraverseCtx<'a>,
|
||||||
) -> Option<Expression<'a>> {
|
) -> Option<Expression<'a>> {
|
||||||
if (!expr.argument.is_number() || !expr.argument.is_number_0())
|
if (!expr.argument.is_number() || !expr.argument.is_number_0())
|
||||||
&& !expr.may_have_side_effects()
|
&& !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
|
None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,10 +46,10 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax {
|
||||||
fn enter_variable_declaration(
|
fn enter_variable_declaration(
|
||||||
&mut self,
|
&mut self,
|
||||||
decl: &mut VariableDeclaration<'a>,
|
decl: &mut VariableDeclaration<'a>,
|
||||||
_ctx: &mut TraverseCtx<'a>,
|
ctx: &mut TraverseCtx<'a>,
|
||||||
) {
|
) {
|
||||||
for declarator in decl.declarations.iter_mut() {
|
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() {
|
if decl.kind.is_const() {
|
||||||
return;
|
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;
|
decl.init = None;
|
||||||
self.changed = true;
|
self.changed = true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,13 @@ pub trait NodeUtil {
|
||||||
fn scopes(&self) -> &ScopeTree;
|
fn scopes(&self) -> &ScopeTree;
|
||||||
|
|
||||||
fn is_expression_undefined(&self, expr: &Expression) -> bool {
|
fn is_expression_undefined(&self, expr: &Expression) -> bool {
|
||||||
if let Expression::Identifier(ident) = expr {
|
match expr {
|
||||||
return self.is_identifier_undefined(ident);
|
Expression::Identifier(ident) if self.is_identifier_undefined(ident) => true,
|
||||||
};
|
Expression::UnaryExpression(e) if e.operator.is_void() && e.argument.is_number() => {
|
||||||
false
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_identifier_undefined(&self, ident: &IdentifierReference) -> bool {
|
fn is_identifier_undefined(&self, ident: &IdentifierReference) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use oxc_allocator::CloneIn;
|
||||||
use oxc_ast_macros::ast;
|
use oxc_ast_macros::ast;
|
||||||
use oxc_span::{cmp::ContentEq, hash::ContentHash};
|
use oxc_span::{cmp::ContentEq, hash::ContentHash};
|
||||||
#[cfg(feature = "serialize")]
|
#[cfg(feature = "serialize")]
|
||||||
use ::{serde::Serialize, tsify::Tsify};
|
use {serde::Serialize, tsify::Tsify};
|
||||||
|
|
||||||
use crate::precedence::{GetPrecedence, Precedence};
|
use crate::precedence::{GetPrecedence, Precedence};
|
||||||
|
|
||||||
|
|
@ -356,6 +356,10 @@ impl UnaryOperator {
|
||||||
matches!(self, Self::BitwiseNot)
|
matches!(self, Self::BitwiseNot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_void(self) -> bool {
|
||||||
|
matches!(self, Self::Void)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_keyword(self) -> bool {
|
pub fn is_keyword(self) -> bool {
|
||||||
matches!(self, Self::Typeof | Self::Void | Self::Delete)
|
matches!(self, Self::Typeof | Self::Void | Self::Delete)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue