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:
166
lib/compress.js
166
lib/compress.js
@@ -1955,12 +1955,7 @@ merge(Compressor.prototype, {
|
|||||||
sym.__unused = true;
|
sym.__unused = true;
|
||||||
if (trim) {
|
if (trim) {
|
||||||
a.pop();
|
a.pop();
|
||||||
compressor[sym.unreferenced() ? "warn" : "info"]("Dropping unused function argument {name} [{file}:{line},{col}]", {
|
compressor[sym.unreferenced() ? "warn" : "info"]("Dropping unused function argument {name} [{file}:{line},{col}]", template(sym));
|
||||||
name : sym.name,
|
|
||||||
file : sym.start.file,
|
|
||||||
line : sym.start.line,
|
|
||||||
col : sym.start.col
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1970,115 +1965,93 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (drop_funcs && node instanceof AST_Defun && node !== self) {
|
if (drop_funcs && node instanceof AST_Defun && node !== self) {
|
||||||
if (!(node.name.definition().id in in_use_ids)) {
|
if (!(node.name.definition().id in in_use_ids)) {
|
||||||
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", {
|
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
|
||||||
name : node.name.name,
|
|
||||||
file : node.name.start.file,
|
|
||||||
line : node.name.start.line,
|
|
||||||
col : node.name.start.col
|
|
||||||
});
|
|
||||||
return make_node(AST_EmptyStatement, node);
|
return make_node(AST_EmptyStatement, node);
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
if (drop_vars && node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn)) {
|
if (drop_vars && node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn)) {
|
||||||
var def = node.definitions.filter(function(def){
|
// place uninitialized names at the start
|
||||||
var w = {
|
var body = [], head = [], tail = [];
|
||||||
name : def.name.name,
|
// for unused names whose initialization has
|
||||||
file : def.name.start.file,
|
// side effects, we can cascade the init. code
|
||||||
line : def.name.start.line,
|
// into the next one, or next statement.
|
||||||
col : def.name.start.col
|
var side_effects = [];
|
||||||
};
|
node.definitions.forEach(function(def) {
|
||||||
if (def.value) def.value = def.value.transform(tt);
|
if (def.value) def.value = def.value.transform(tt);
|
||||||
var sym = def.name.definition();
|
var sym = def.name.definition();
|
||||||
if (sym.id in in_use_ids) {
|
if (sym.id in in_use_ids) {
|
||||||
if (def.name instanceof AST_SymbolVar) {
|
if (def.name instanceof AST_SymbolVar) {
|
||||||
var var_defs = var_defs_by_id.get(sym.id);
|
var var_defs = var_defs_by_id.get(sym.id);
|
||||||
if (var_defs.length > 1 && !def.value) {
|
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);
|
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
|
if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) {
|
||||||
&& def[0].value
|
var var_defs = var_defs_by_id.get(tail[0].name.definition().id);
|
||||||
&& !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 (var_defs.length > 1) {
|
if (var_defs.length > 1) {
|
||||||
compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", {
|
var def = tail.pop();
|
||||||
name : def[0].name.name,
|
compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name));
|
||||||
file : def[0].name.start.file,
|
var_defs.splice(var_defs.indexOf(def), 1);
|
||||||
line : def[0].name.start.line,
|
side_effects.unshift(make_node(AST_Assign, def, {
|
||||||
col : def[0].name.start.col
|
operator: "=",
|
||||||
});
|
left: make_node(AST_SymbolRef, def.name, def.name),
|
||||||
var_defs.splice(var_defs.indexOf(def[0]), 1);
|
right: def.value
|
||||||
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
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// place uninitialized names at the start
|
if (head.length > 0 || tail.length > 0) {
|
||||||
def = mergeSort(def, function(a, b){
|
node.definitions = head.concat(tail);
|
||||||
if (!a.value && b.value) return -1;
|
body.push(node);
|
||||||
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 (side_effects.length > 0) {
|
if (side_effects.length > 0) {
|
||||||
side_effects = make_node(AST_BlockStatement, node, {
|
body.push(make_node(AST_SimpleStatement, node, {
|
||||||
body: [ make_node(AST_SimpleStatement, node, {
|
body: make_sequence(node, side_effects)
|
||||||
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
|
if (drop_vars && assign_as_unused
|
||||||
&& node instanceof AST_Assign
|
&& node instanceof AST_Assign
|
||||||
@@ -2119,6 +2092,15 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_Scope && node !== self)
|
if (node instanceof AST_Scope && node !== self)
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
|
function template(sym) {
|
||||||
|
return {
|
||||||
|
name : sym.name,
|
||||||
|
file : sym.start.file,
|
||||||
|
line : sym.start.line,
|
||||||
|
col : sym.start.col
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
self.transform(tt);
|
self.transform(tt);
|
||||||
|
|||||||
@@ -701,10 +701,10 @@ collapse_vars_lvalues_drop_assign: {
|
|||||||
function f2(x) { var z = x, a = ++z; return z += a; }
|
function f2(x) { var z = x, a = ++z; return z += a; }
|
||||||
function f3(x) { var a = (x -= 3); return x + a; }
|
function f3(x) { var a = (x -= 3); return x + a; }
|
||||||
function f4(x) { var a = (x -= 3); return x + a; }
|
function f4(x) { var a = (x -= 3); return x + a; }
|
||||||
function f5(x) { var v = (e1(), e2()), c = v = --x; return x - c; }
|
function f5(x) { e1(); var v = e2(), c = v = --x; return x - c; }
|
||||||
function f6(x) { e1(), e2(); return --x - x; }
|
function f6(x) { e1(), e2(); return --x - x; }
|
||||||
function f7(x) { var c = (e1(), e2() - x); return x - c; }
|
function f7(x) { e1(); var c = e2() - x; return x - c; }
|
||||||
function f8(x) { var v = (e1(), e2()); return x - (v - x); }
|
function f8(x) { e1(); var v = e2(); return x - (v - x); }
|
||||||
function f9(x) { e1(); return e2() - x - x; }
|
function f9(x) { e1(); return e2() - x - x; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -935,7 +935,8 @@ issue_1715_3: {
|
|||||||
try {
|
try {
|
||||||
console;
|
console;
|
||||||
} catch (a) {
|
} catch (a) {
|
||||||
var a = x();
|
var a;
|
||||||
|
x();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f();
|
f();
|
||||||
|
|||||||
@@ -53,9 +53,7 @@ reduce_vars: {
|
|||||||
console.log(-3);
|
console.log(-3);
|
||||||
eval("console.log(a);");
|
eval("console.log(a);");
|
||||||
})(eval);
|
})(eval);
|
||||||
(function() {
|
"yes";
|
||||||
return "yes";
|
|
||||||
})();
|
|
||||||
console.log(2);
|
console.log(2);
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
@@ -1699,9 +1697,7 @@ redefine_arguments_2: {
|
|||||||
console.log(function() {
|
console.log(function() {
|
||||||
var arguments;
|
var arguments;
|
||||||
return typeof arguments;
|
return typeof arguments;
|
||||||
}(), function() {
|
}(), "number", function(x) {
|
||||||
return"number";
|
|
||||||
}(), function(x) {
|
|
||||||
var arguments = x;
|
var arguments = x;
|
||||||
return typeof arguments;
|
return typeof arguments;
|
||||||
}());
|
}());
|
||||||
@@ -1810,9 +1806,7 @@ redefine_farg_2: {
|
|||||||
console.log(function(a) {
|
console.log(function(a) {
|
||||||
var a;
|
var a;
|
||||||
return typeof a;
|
return typeof a;
|
||||||
}([]), function() {
|
}([]), "number",function(a, b) {
|
||||||
return "number";
|
|
||||||
}(),function(a, b) {
|
|
||||||
var a = b;
|
var a = b;
|
||||||
return typeof a;
|
return typeof a;
|
||||||
}([]));
|
}([]));
|
||||||
|
|||||||
Reference in New Issue
Block a user