improve unused (#1832)

- extract leading value with side-effects out of `var` statement
- reduce scanning of `AST_Definitions` from 3 passes to just once
This commit is contained in:
Alex Lam S.L
2017-04-20 13:06:14 +08:00
committed by GitHub
parent 88e7a542cd
commit f05d4f7af3
4 changed files with 82 additions and 105 deletions

View File

@@ -1955,12 +1955,7 @@ merge(Compressor.prototype, {
sym.__unused = true;
if (trim) {
a.pop();
compressor[sym.unreferenced() ? "warn" : "info"]("Dropping unused function argument {name} [{file}:{line},{col}]", {
name : sym.name,
file : sym.start.file,
line : sym.start.line,
col : sym.start.col
});
compressor[sym.unreferenced() ? "warn" : "info"]("Dropping unused function argument {name} [{file}:{line},{col}]", template(sym));
}
}
else {
@@ -1970,115 +1965,93 @@ merge(Compressor.prototype, {
}
if (drop_funcs && node instanceof AST_Defun && node !== self) {
if (!(node.name.definition().id in in_use_ids)) {
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", {
name : node.name.name,
file : node.name.start.file,
line : node.name.start.line,
col : node.name.start.col
});
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
return make_node(AST_EmptyStatement, node);
}
return node;
}
if (drop_vars && node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn)) {
var def = node.definitions.filter(function(def){
var w = {
name : def.name.name,
file : def.name.start.file,
line : def.name.start.line,
col : def.name.start.col
};
// place uninitialized names at the start
var body = [], head = [], tail = [];
// for unused names whose initialization has
// side effects, we can cascade the init. code
// into the next one, or next statement.
var side_effects = [];
node.definitions.forEach(function(def) {
if (def.value) def.value = def.value.transform(tt);
var sym = def.name.definition();
if (sym.id in in_use_ids) {
if (def.name instanceof AST_SymbolVar) {
var var_defs = var_defs_by_id.get(sym.id);
if (var_defs.length > 1 && !def.value) {
compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", w);
compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
var_defs.splice(var_defs.indexOf(def), 1);
return false;
return;
}
}
return true;
if (def.value) {
if (side_effects.length > 0) {
if (tail.length > 0) {
merge_sequence(side_effects, def.value);
def.value = make_sequence(def.value, side_effects);
} else {
body.push(make_node(AST_SimpleStatement, node, {
body: make_sequence(node, side_effects)
}));
}
side_effects = [];
}
tail.push(def);
} else {
head.push(def);
}
} else if (sym.orig[0] instanceof AST_SymbolCatch) {
var value = def.value && def.value.drop_side_effect_free(compressor);
if (value) merge_sequence(side_effects, value);
def.value = null;
head.push(def);
} else {
var value = def.value && def.value.drop_side_effect_free(compressor);
if (value) {
compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", template(def.name));
merge_sequence(side_effects, value);
} else {
compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", template(def.name));
}
}
if (sym.orig[0] instanceof AST_SymbolCatch) {
def.value = def.value && def.value.drop_side_effect_free(compressor);
return true;
}
if (def.value && (def._unused_side_effects = def.value.drop_side_effect_free(compressor))) {
compressor.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", w);
return true;
}
compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", w);
return false;
});
if (def.length == 1
&& def[0].value
&& !def[0]._unused_side_effects
&& def[0].name instanceof AST_SymbolVar) {
var var_defs = var_defs_by_id.get(def[0].name.definition().id);
if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) {
var var_defs = var_defs_by_id.get(tail[0].name.definition().id);
if (var_defs.length > 1) {
compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", {
name : def[0].name.name,
file : def[0].name.start.file,
line : def[0].name.start.line,
col : def[0].name.start.col
});
var_defs.splice(var_defs.indexOf(def[0]), 1);
return make_node(AST_SimpleStatement, node, {
body: make_node(AST_Assign, def[0], {
operator: "=",
left: make_node(AST_SymbolRef, def[0].name, def[0].name),
right: def[0].value
})
});
var def = tail.pop();
compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name));
var_defs.splice(var_defs.indexOf(def), 1);
side_effects.unshift(make_node(AST_Assign, def, {
operator: "=",
left: make_node(AST_SymbolRef, def.name, def.name),
right: def.value
}));
}
}
// place uninitialized names at the start
def = mergeSort(def, function(a, b){
if (!a.value && b.value) return -1;
if (!b.value && a.value) return 1;
return 0;
});
// for unused names whose initialization has
// side effects, we can cascade the init. code
// into the next one, or next statement.
var side_effects = [];
for (var i = 0; i < def.length;) {
var x = def[i];
if (x._unused_side_effects) {
merge_sequence(side_effects, x._unused_side_effects);
def.splice(i, 1);
} else {
if (side_effects.length > 0) {
merge_sequence(side_effects, x.value);
x.value = make_sequence(x.value, side_effects);
side_effects = [];
}
++i;
}
if (head.length > 0 || tail.length > 0) {
node.definitions = head.concat(tail);
body.push(node);
}
if (side_effects.length > 0) {
side_effects = make_node(AST_BlockStatement, node, {
body: [ make_node(AST_SimpleStatement, node, {
body: make_sequence(node, side_effects)
}) ]
body.push(make_node(AST_SimpleStatement, node, {
body: make_sequence(node, side_effects)
}));
}
switch (body.length) {
case 0:
return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
case 1:
return body[0];
default:
return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
body: body
});
} else {
side_effects = null;
}
if (def.length == 0 && !side_effects) {
return make_node(AST_EmptyStatement, node);
}
if (def.length == 0) {
return in_list ? MAP.splice(side_effects.body) : side_effects;
}
node.definitions = def;
if (side_effects) {
side_effects.body.unshift(node);
return in_list ? MAP.splice(side_effects.body) : side_effects;
}
return node;
}
if (drop_vars && assign_as_unused
&& node instanceof AST_Assign
@@ -2119,6 +2092,15 @@ merge(Compressor.prototype, {
}
if (node instanceof AST_Scope && node !== self)
return node;
function template(sym) {
return {
name : sym.name,
file : sym.start.file,
line : sym.start.line,
col : sym.start.col
};
}
}
);
self.transform(tt);