fix(es/minifier): Don't replace parameters of IIFE if it's recursive (#5852)

**Description:**

While investigating, I found that problem is not the analysis of recursive functions. Instead, it was a problem with the IIFE evaluator, which replaces parameters even if it's recursive.

**Related issue:**

 - Closes https://github.com/swc-project/swc/issues/5846
This commit is contained in:
Donny/강동윤 2022-09-14 14:02:14 +09:00 committed by GitHub
parent 9d5439281a
commit a5f7b6946f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 772 additions and 3 deletions

View File

@ -175,6 +175,16 @@ where
} }
} }
if let Expr::Fn(FnExpr {
ident: Some(ident),
function,
}) = callee
{
if IdentUsageFinder::find(&ident.to_id(), &*function) {
return;
}
}
fn find_body(callee: &mut Expr) -> Option<Either<&mut BlockStmt, &mut Expr>> { fn find_body(callee: &mut Expr) -> Option<Either<&mut BlockStmt, &mut Expr>> {
match callee { match callee {
Expr::Arrow(e) => match &mut e.body { Expr::Arrow(e) => match &mut e.body {

View File

@ -13,7 +13,6 @@
//! `SWC_RUN` to `1`, the minifier will validate the code using node before each //! `SWC_RUN` to `1`, the minifier will validate the code using node before each
//! step. //! step.
#![deny(clippy::all)] #![deny(clippy::all)]
#![deny(unused)]
#![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::blocks_in_if_conditions)]
#![allow(clippy::collapsible_else_if)] #![allow(clippy::collapsible_else_if)]
#![allow(clippy::collapsible_if)] #![allow(clippy::collapsible_if)]

View File

@ -0,0 +1,660 @@
TestSnapshot {
vars: [
(
(
Atom('callback' type=dynamic),
#3,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 1,
cond_init: false,
declared: false,
declared_count: 0,
declared_as_fn_param: false,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 0,
usage_count: 1,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: false,
has_property_access: false,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: true,
is_fn_local: true,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: None,
var_initialized: false,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: true,
used_as_arg: false,
pure_fn: false,
infects: [],
},
),
(
(
Atom('children' type=dynamic),
#2,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 2,
cond_init: false,
declared: true,
declared_count: 1,
declared_as_fn_param: false,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 0,
usage_count: 2,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: false,
has_property_access: true,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: false,
is_fn_local: true,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: Some(
"const",
),
var_initialized: true,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: false,
used_as_arg: false,
pure_fn: false,
infects: [],
},
),
(
(
Atom('connectNodes' type=dynamic),
#2,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 2,
cond_init: false,
declared: true,
declared_count: 1,
declared_as_fn_param: false,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 1,
usage_count: 2,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: true,
has_property_access: false,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: false,
is_fn_local: false,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: Some(
"const",
),
var_initialized: true,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: false,
used_as_arg: true,
pure_fn: false,
infects: [],
},
),
(
(
Atom('data' type=static),
#4,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 1,
cond_init: false,
declared: true,
declared_count: 1,
declared_as_fn_param: false,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 1,
usage_count: 1,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: true,
has_property_access: false,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: false,
is_fn_local: true,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: Some(
"const",
),
var_initialized: true,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: false,
used_as_arg: true,
pure_fn: false,
infects: [],
},
),
(
(
Atom('dataNodes' type=dynamic),
#3,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 1,
cond_init: false,
declared: false,
declared_count: 0,
declared_as_fn_param: false,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 0,
usage_count: 1,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: false,
has_property_access: false,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: true,
is_fn_local: true,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: None,
var_initialized: false,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: false,
used_as_arg: false,
pure_fn: false,
infects: [],
},
),
(
(
Atom('getPosition' type=dynamic),
#3,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 1,
cond_init: false,
declared: false,
declared_count: 0,
declared_as_fn_param: false,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 0,
usage_count: 1,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: false,
has_property_access: false,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: true,
is_fn_local: true,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: None,
var_initialized: false,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: true,
used_as_arg: false,
pure_fn: false,
infects: [],
},
),
(
(
Atom('index' type=inline),
#2,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 2,
cond_init: false,
declared: true,
declared_count: 1,
declared_as_fn_param: true,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 1,
usage_count: 2,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: true,
has_property_access: false,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: false,
is_fn_local: true,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: None,
var_initialized: false,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: false,
used_as_arg: true,
pure_fn: false,
infects: [],
},
),
(
(
Atom('key' type=static),
#4,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 1,
cond_init: false,
declared: true,
declared_count: 1,
declared_as_fn_param: false,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 0,
usage_count: 1,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: false,
has_property_access: false,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: false,
is_fn_local: true,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: Some(
"const",
),
var_initialized: true,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: false,
used_as_arg: false,
pure_fn: false,
infects: [],
},
),
(
(
Atom('mergeChildrenPropName' type=dynamic),
#3,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 1,
cond_init: false,
declared: false,
declared_count: 0,
declared_as_fn_param: false,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 0,
usage_count: 1,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: false,
has_property_access: false,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: true,
is_fn_local: true,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: None,
var_initialized: false,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: false,
used_as_arg: false,
pure_fn: false,
infects: [],
},
),
(
(
Atom('node' type=inline),
#2,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 9,
cond_init: false,
declared: true,
declared_count: 1,
declared_as_fn_param: true,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 2,
usage_count: 9,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: true,
has_property_access: true,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: false,
is_fn_local: false,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: None,
var_initialized: false,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: false,
used_as_arg: true,
pure_fn: false,
infects: [],
},
),
(
(
Atom('parent' type=inline),
#2,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 6,
cond_init: false,
declared: true,
declared_count: 1,
declared_as_fn_param: true,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 0,
usage_count: 6,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: false,
has_property_access: true,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: false,
is_fn_local: false,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: None,
var_initialized: false,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: false,
used_as_arg: false,
pure_fn: false,
infects: [],
},
),
(
(
Atom('pathNodes' type=dynamic),
#2,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 1,
cond_init: false,
declared: true,
declared_count: 1,
declared_as_fn_param: true,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 0,
usage_count: 1,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: false,
has_property_access: false,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: false,
is_fn_local: true,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: None,
var_initialized: false,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: false,
used_as_arg: false,
pure_fn: false,
infects: [],
},
),
(
(
Atom('pos' type=inline),
#2,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 3,
cond_init: false,
declared: true,
declared_count: 1,
declared_as_fn_param: false,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 2,
usage_count: 3,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: true,
has_property_access: false,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: false,
is_fn_local: false,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: Some(
"const",
),
var_initialized: true,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: false,
used_as_arg: true,
pure_fn: false,
infects: [],
},
),
(
(
Atom('processNode' type=dynamic),
#1,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 1,
cond_init: false,
declared: true,
declared_count: 1,
declared_as_fn_param: false,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 0,
usage_count: 1,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: false,
has_property_access: false,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: false,
is_fn_local: false,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: false,
var_kind: None,
var_initialized: true,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: true,
used_as_arg: false,
pure_fn: false,
infects: [],
},
),
(
(
Atom('subIndex' type=dynamic),
#5,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 1,
cond_init: false,
declared: true,
declared_count: 1,
declared_as_fn_param: true,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 1,
usage_count: 1,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: true,
has_property_access: false,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: false,
is_fn_local: true,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: None,
var_initialized: false,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: false,
used_as_arg: true,
pure_fn: false,
infects: [],
},
),
(
(
Atom('subNode' type=inline),
#5,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 1,
cond_init: false,
declared: true,
declared_count: 1,
declared_as_fn_param: true,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 1,
usage_count: 1,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: true,
has_property_access: false,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: false,
is_fn_local: true,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: None,
var_initialized: false,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: false,
used_as_arg: true,
pure_fn: false,
infects: [],
},
),
(
(
Atom('syntheticGetKey' type=dynamic),
#3,
),
VarUsageInfo {
inline_prevented: false,
ref_count: 1,
cond_init: false,
declared: false,
declared_count: 0,
declared_as_fn_param: false,
declared_as_fn_expr: false,
assign_count: 0,
mutation_by_call_count: 0,
usage_count: 1,
reassigned_with_assignment: false,
reassigned_with_var_decl: false,
mutated: false,
has_property_access: false,
has_property_mutation: false,
accessed_props: {},
exported: false,
used_above_decl: true,
is_fn_local: true,
used_by_nested_fn: true,
executed_multiple_time: false,
used_in_cond: true,
var_kind: None,
var_initialized: false,
declared_as_catch_param: false,
no_side_effect_for_member_access: false,
used_as_callee: true,
used_as_arg: false,
pure_fn: false,
infects: [],
},
),
],
}

View File

@ -0,0 +1,44 @@
function processNode(
node,
index,
parent,
pathNodes
) {
const children = node ? node[mergeChildrenPropName] : dataNodes;
const pos = node ? getPosition(parent.pos, index) : '0';
const connectNodes = node ? [...pathNodes, node] : [];
// Process node if is not root
if (node) {
const key = syntheticGetKey(node, pos);
const data = {
node,
index,
pos,
key,
parentPos: parent.node ? parent.pos : null,
level: parent.level + 1,
nodes: connectNodes,
};
callback(data);
}
// Process children node
if (children) {
children.forEach((subNode, subIndex) => {
processNode(
subNode,
subIndex,
{
node,
pos,
level: parent ? parent.level + 1 : -1,
},
connectNodes,
);
});
}
}
processNode(null);

View File

@ -0,0 +1,25 @@
!function processNode(node, index, parent, pathNodes) {
const children = node ? node[mergeChildrenPropName] : dataNodes, pos = node ? getPosition(parent.pos, index) : '0', connectNodes = node ? [
...pathNodes,
node
] : [];
if (node) {
const key = syntheticGetKey(node, pos), data = {
node,
index,
pos,
key,
parentPos: parent.node ? parent.pos : null,
level: parent.level + 1,
nodes: connectNodes
};
callback(data);
}
children && children.forEach((subNode, subIndex)=>{
processNode(subNode, subIndex, {
node,
pos,
level: parent ? parent.level + 1 : -1
}, connectNodes);
});
}(null);

View File

@ -0,0 +1,31 @@
function e(o, l, n, t) {
const s = o ? o[mergeChildrenPropName] : dataNodes;
const c = o ? getPosition(n.pos, l) : '0';
const a = o ? [
...t,
o
] : [];
if (o) {
const i = syntheticGetKey(o, c);
const d = {
node: o,
index: l,
pos: c,
key: i,
parentPos: n.node ? n.pos : null,
level: n.level + 1,
nodes: a
};
callback(d);
}
if (s) {
s.forEach((l, t)=>{
e(l, t, {
node: o,
pos: c,
level: n ? n.level + 1 : -1
}, a);
});
}
}
e(null);

View File

@ -2395,7 +2395,7 @@
!function propagate(doc, skip, sharedHist) { !function propagate(doc, skip, sharedHist) {
if (doc.linked) for(var i = 0; i < doc.linked.length; ++i){ if (doc.linked) for(var i = 0; i < doc.linked.length; ++i){
var rel = doc.linked[i]; var rel = doc.linked[i];
if (null != rel.doc) { if (rel.doc != skip) {
var shared = sharedHist && rel.sharedHist; var shared = sharedHist && rel.sharedHist;
(!sharedHistOnly || shared) && (f(rel.doc, shared), propagate(rel.doc, doc, shared)); (!sharedHistOnly || shared) && (f(rel.doc, shared), propagate(rel.doc, doc, shared));
} }

View File

@ -112,7 +112,7 @@ fn snapshot_compress_fixture(input: PathBuf) {
) )
.expect_module(); .expect_module();
{ if output_path.exists() {
// Compare AST, and mark test as a success if ast is identical. // Compare AST, and mark test as a success if ast is identical.
let mut actual = m.clone(); let mut actual = m.clone();