mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
fix(minifier): Preserve init variable declarations when removing for statements during DCE (#6551)
- Closes: #6547 --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
2e4c793a78
commit
a71e8a00bf
3 changed files with 58 additions and 17 deletions
|
|
@ -112,6 +112,20 @@ impl<'a> AstBuilder<'a> {
|
||||||
mem::replace(decl, empty_decl)
|
mem::replace(decl, empty_decl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn move_variable_declaration(
|
||||||
|
self,
|
||||||
|
decl: &mut VariableDeclaration<'a>,
|
||||||
|
) -> VariableDeclaration<'a> {
|
||||||
|
let empty_decl = self.variable_declaration(
|
||||||
|
Span::default(),
|
||||||
|
VariableDeclarationKind::Var,
|
||||||
|
self.vec(),
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
mem::replace(decl, empty_decl)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn move_vec<T>(self, vec: &mut Vec<'a, T>) -> Vec<'a, T> {
|
pub fn move_vec<T>(self, vec: &mut Vec<'a, T>) -> Vec<'a, T> {
|
||||||
mem::replace(vec, self.vec())
|
mem::replace(vec, self.vec())
|
||||||
|
|
|
||||||
|
|
@ -203,11 +203,26 @@ impl<'a, 'b> PeepholeRemoveDeadCode {
|
||||||
// Check vars in statement
|
// Check vars in statement
|
||||||
let mut keep_var = KeepVar::new(ctx.ast);
|
let mut keep_var = KeepVar::new(ctx.ast);
|
||||||
keep_var.visit_statement(&for_stmt.body);
|
keep_var.visit_statement(&for_stmt.body);
|
||||||
Some(
|
|
||||||
keep_var
|
let mut var_decl = keep_var.get_variable_declaration();
|
||||||
.get_variable_declaration_statement()
|
|
||||||
.unwrap_or_else(|| ctx.ast.statement_empty(SPAN)),
|
if let Some(ForStatementInit::VariableDeclaration(var_init)) = &mut for_stmt.init {
|
||||||
)
|
if var_init.kind.is_var() {
|
||||||
|
if let Some(var_decl) = &mut var_decl {
|
||||||
|
var_decl
|
||||||
|
.declarations
|
||||||
|
.splice(0..0, ctx.ast.move_vec(&mut var_init.declarations));
|
||||||
|
} else {
|
||||||
|
var_decl = Some(ctx.ast.move_variable_declaration(var_init));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var_decl
|
||||||
|
.map(|var_decl| {
|
||||||
|
ctx.ast.statement_declaration(ctx.ast.declaration_from_variable(var_decl))
|
||||||
|
})
|
||||||
|
.or_else(|| Some(ctx.ast.statement_empty(SPAN)))
|
||||||
}
|
}
|
||||||
Some(true) => {
|
Some(true) => {
|
||||||
// Remove the test expression.
|
// Remove the test expression.
|
||||||
|
|
@ -350,6 +365,10 @@ mod test {
|
||||||
// Make sure it plays nice with minimizing
|
// Make sure it plays nice with minimizing
|
||||||
fold("for(;false;) { foo(); continue }", "");
|
fold("for(;false;) { foo(); continue }", "");
|
||||||
|
|
||||||
|
fold("for (var { c, x: [d] } = {}; 0;);", "var { c, x: [d] } = {};");
|
||||||
|
fold("for (var se = [1, 2]; false;);", "var se = [1, 2];");
|
||||||
|
fold("for (var se = [1, 2]; false;) { var a = 0; }", "var se = [1, 2], a;");
|
||||||
|
|
||||||
// fold("l1:for(;false;) { }", "");
|
// fold("l1:for(;false;) { }", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,19 +34,21 @@ impl<'a> Visit<'a> for KeepVar<'a> {
|
||||||
// match_module_declaration!(Statement) => {
|
// match_module_declaration!(Statement) => {
|
||||||
// visitor.visit_module_declaration(it.to_module_declaration())
|
// visitor.visit_module_declaration(it.to_module_declaration())
|
||||||
// }
|
// }
|
||||||
Statement::VariableDeclaration(decl) => {
|
Statement::VariableDeclaration(decl) => self.visit_variable_declaration(decl),
|
||||||
if decl.kind.is_var() {
|
_ => {}
|
||||||
decl.bound_names(&mut |ident| {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_variable_declaration(&mut self, it: &VariableDeclaration<'a>) {
|
||||||
|
if it.kind.is_var() {
|
||||||
|
it.bound_names(&mut |ident| {
|
||||||
self.vars.push((ident.name.clone(), ident.span));
|
self.vars.push((ident.name.clone(), ident.span));
|
||||||
});
|
});
|
||||||
if decl.has_init() {
|
if it.has_init() {
|
||||||
self.all_hoisted = false;
|
self.all_hoisted = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> KeepVar<'a> {
|
impl<'a> KeepVar<'a> {
|
||||||
|
|
@ -58,7 +60,7 @@ impl<'a> KeepVar<'a> {
|
||||||
self.all_hoisted
|
self.all_hoisted
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_variable_declaration_statement(self) -> Option<Statement<'a>> {
|
pub fn get_variable_declaration(self) -> Option<VariableDeclaration<'a>> {
|
||||||
if self.vars.is_empty() {
|
if self.vars.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
@ -71,7 +73,13 @@ impl<'a> KeepVar<'a> {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let decl = self.ast.variable_declaration(SPAN, kind, decls, false);
|
let decl = self.ast.variable_declaration(SPAN, kind, decls, false);
|
||||||
let stmt = self.ast.statement_declaration(self.ast.declaration_from_variable(decl));
|
Some(decl)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_variable_declaration_statement(self) -> Option<Statement<'a>> {
|
||||||
|
let stmt = self.ast.statement_declaration(
|
||||||
|
self.ast.declaration_from_variable(self.get_variable_declaration()?),
|
||||||
|
);
|
||||||
Some(stmt)
|
Some(stmt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue