consolidate & enhance unused (#2439)
- defer declaration removal in `collapse_vars` - account for `AST_SymbolFunarg` in deduplication - private accounting for `collapse_vars` - avoid issues with identity reference due to deep cloning fixes #2437
This commit is contained in:
@@ -788,6 +788,14 @@ merge(Compressor.prototype, {
|
|||||||
|| compressor.option("unsafe") && global_names(this.name);
|
|| compressor.option("unsafe") && global_names(this.name);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function drop_decl(def) {
|
||||||
|
def._eliminiated = (def._eliminiated || 0) + 1;
|
||||||
|
if (def.orig.length == def._eliminiated) {
|
||||||
|
def.scope.functions.del(def.name);
|
||||||
|
def.scope.variables.del(def.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function tighten_body(statements, compressor) {
|
function tighten_body(statements, compressor) {
|
||||||
var CHANGED, max_iter = 10;
|
var CHANGED, max_iter = 10;
|
||||||
do {
|
do {
|
||||||
@@ -1000,7 +1008,8 @@ merge(Compressor.prototype, {
|
|||||||
function get_lhs(expr) {
|
function get_lhs(expr) {
|
||||||
if (expr instanceof AST_VarDef) {
|
if (expr instanceof AST_VarDef) {
|
||||||
var def = expr.name.definition();
|
var def = expr.name.definition();
|
||||||
if (def.orig.length > 1 && !(expr.name instanceof AST_SymbolFunarg)
|
if (def.orig.length - (def._eliminiated || 0) > 1
|
||||||
|
&& !(expr.name instanceof AST_SymbolFunarg)
|
||||||
|| def.references.length == 1 && !compressor.exposed(def)) {
|
|| def.references.length == 1 && !compressor.exposed(def)) {
|
||||||
return make_node(AST_SymbolRef, expr.name, expr.name);
|
return make_node(AST_SymbolRef, expr.name, expr.name);
|
||||||
}
|
}
|
||||||
@@ -1009,6 +1018,10 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function get_rvalue(expr) {
|
||||||
|
return expr[expr instanceof AST_Assign ? "right" : "value"];
|
||||||
|
}
|
||||||
|
|
||||||
function get_lvalues(expr) {
|
function get_lvalues(expr) {
|
||||||
var lvalues = Object.create(null);
|
var lvalues = Object.create(null);
|
||||||
if (expr instanceof AST_Unary) return lvalues;
|
if (expr instanceof AST_Unary) return lvalues;
|
||||||
@@ -1019,7 +1032,7 @@ merge(Compressor.prototype, {
|
|||||||
lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent());
|
lvalues[sym.name] = lvalues[sym.name] || is_lhs(node, tw.parent());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
expr[expr instanceof AST_Assign ? "right" : "value"].walk(tw);
|
get_rvalue(expr).walk(tw);
|
||||||
return lvalues;
|
return lvalues;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1043,7 +1056,9 @@ merge(Compressor.prototype, {
|
|||||||
if (node === expr) {
|
if (node === expr) {
|
||||||
found = true;
|
found = true;
|
||||||
if (node instanceof AST_VarDef) {
|
if (node instanceof AST_VarDef) {
|
||||||
remove(node.name.definition().orig, node.name);
|
drop_decl(node.name.definition());
|
||||||
|
node.value = null;
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
return in_list ? MAP.skip : null;
|
return in_list ? MAP.skip : null;
|
||||||
}
|
}
|
||||||
@@ -1052,16 +1067,13 @@ merge(Compressor.prototype, {
|
|||||||
case 0: return null;
|
case 0: return null;
|
||||||
case 1: return node.expressions[0];
|
case 1: return node.expressions[0];
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Definitions && node.definitions.length == 0
|
if (node instanceof AST_SimpleStatement && !node.body) return null;
|
||||||
|| node instanceof AST_SimpleStatement && !node.body) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function value_has_side_effects(expr) {
|
function value_has_side_effects(expr) {
|
||||||
if (expr instanceof AST_Unary) return false;
|
if (expr instanceof AST_Unary) return false;
|
||||||
return expr[expr instanceof AST_Assign ? "right" : "value"].has_side_effects(compressor);
|
return get_rvalue(expr).has_side_effects(compressor);
|
||||||
}
|
}
|
||||||
|
|
||||||
function references_in_scope(def) {
|
function references_in_scope(def) {
|
||||||
@@ -2303,7 +2315,7 @@ merge(Compressor.prototype, {
|
|||||||
// this scope (not in nested scopes).
|
// this scope (not in nested scopes).
|
||||||
var scope = this;
|
var scope = this;
|
||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
if (node !== self) {
|
if (node === self) return;
|
||||||
if (node instanceof AST_Defun) {
|
if (node instanceof AST_Defun) {
|
||||||
if (!drop_funcs && scope === self) {
|
if (!drop_funcs && scope === self) {
|
||||||
var node_def = node.name.definition();
|
var node_def = node.name.definition();
|
||||||
@@ -2315,6 +2327,9 @@ merge(Compressor.prototype, {
|
|||||||
initializations.add(node.name.name, node);
|
initializations.add(node.name.name, node);
|
||||||
return true; // don't go in nested scopes
|
return true; // don't go in nested scopes
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_SymbolFunarg && scope === self) {
|
||||||
|
var_defs_by_id.add(node.definition().id, node);
|
||||||
|
}
|
||||||
if (node instanceof AST_Definitions && scope === self) {
|
if (node instanceof AST_Definitions && scope === self) {
|
||||||
node.definitions.forEach(function(def){
|
node.definitions.forEach(function(def){
|
||||||
var node_def = def.name.definition();
|
var node_def = def.name.definition();
|
||||||
@@ -2358,7 +2373,6 @@ merge(Compressor.prototype, {
|
|||||||
scope = save_scope;
|
scope = save_scope;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
// pass 2: for every used symbol we need to walk its
|
// pass 2: for every used symbol we need to walk its
|
||||||
@@ -2415,7 +2429,7 @@ merge(Compressor.prototype, {
|
|||||||
var def = node.name.definition();
|
var def = node.name.definition();
|
||||||
if (!(def.id in in_use_ids)) {
|
if (!(def.id in in_use_ids)) {
|
||||||
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
|
compressor[node.name.unreferenced() ? "warn" : "info"]("Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
|
||||||
drop_decl(def, node.name);
|
drop_decl(def);
|
||||||
return make_node(AST_EmptyStatement, node);
|
return make_node(AST_EmptyStatement, node);
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
@@ -2437,7 +2451,7 @@ merge(Compressor.prototype, {
|
|||||||
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}]", template(def.name));
|
compressor.warn("Dropping duplicated definition of variable {name} [{file}:{line},{col}]", template(def.name));
|
||||||
remove(var_defs, def);
|
remove(var_defs, def);
|
||||||
drop_decl(sym, def.name);
|
drop_decl(sym);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2470,7 +2484,7 @@ merge(Compressor.prototype, {
|
|||||||
} else {
|
} else {
|
||||||
compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", template(def.name));
|
compressor[def.name.unreferenced() ? "warn" : "info"]("Dropping unused variable {name} [{file}:{line},{col}]", template(def.name));
|
||||||
}
|
}
|
||||||
drop_decl(sym, def.name);
|
drop_decl(sym);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) {
|
if (head.length == 0 && tail.length == 1 && tail[0].name instanceof AST_SymbolVar) {
|
||||||
@@ -2479,7 +2493,7 @@ merge(Compressor.prototype, {
|
|||||||
var def = tail.pop();
|
var def = tail.pop();
|
||||||
compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name));
|
compressor.warn("Converting duplicated definition of variable {name} to assignment [{file}:{line},{col}]", template(def.name));
|
||||||
remove(var_defs, def);
|
remove(var_defs, def);
|
||||||
drop_decl(def.name.definition(), def.name);
|
drop_decl(def.name.definition());
|
||||||
side_effects.unshift(make_node(AST_Assign, def, {
|
side_effects.unshift(make_node(AST_Assign, def, {
|
||||||
operator: "=",
|
operator: "=",
|
||||||
left: make_node(AST_SymbolRef, def.name, def.name),
|
left: make_node(AST_SymbolRef, def.name, def.name),
|
||||||
@@ -2561,14 +2575,6 @@ merge(Compressor.prototype, {
|
|||||||
col : sym.start.col
|
col : sym.start.col
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function drop_decl(def, decl) {
|
|
||||||
remove(def.orig, decl);
|
|
||||||
if (!def.orig.length) {
|
|
||||||
def.scope.functions.del(def.name);
|
|
||||||
def.scope.variables.del(def.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
self.transform(tt);
|
self.transform(tt);
|
||||||
@@ -3288,7 +3294,7 @@ merge(Compressor.prototype, {
|
|||||||
}));
|
}));
|
||||||
if (reduce_vars) name.definition().fixed = false;
|
if (reduce_vars) name.definition().fixed = false;
|
||||||
}
|
}
|
||||||
remove(def.name.definition().orig, def.name);
|
drop_decl(def.name.definition());
|
||||||
return a;
|
return a;
|
||||||
}, []);
|
}, []);
|
||||||
if (assignments.length == 0) return null;
|
if (assignments.length == 0) return null;
|
||||||
|
|||||||
@@ -1388,6 +1388,7 @@ issue_1605_1: {
|
|||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
toplevel: false,
|
toplevel: false,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function foo(x) {
|
function foo(x) {
|
||||||
@@ -1410,6 +1411,7 @@ issue_1605_2: {
|
|||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
toplevel: "vars",
|
toplevel: "vars",
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function foo(x) {
|
function foo(x) {
|
||||||
@@ -1537,6 +1539,7 @@ issue_1631_3: {
|
|||||||
var_side_effects_1: {
|
var_side_effects_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var print = console.log.bind(console);
|
var print = console.log.bind(console);
|
||||||
@@ -1559,6 +1562,7 @@ var_side_effects_1: {
|
|||||||
var_side_effects_2: {
|
var_side_effects_2: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var print = console.log.bind(console);
|
var print = console.log.bind(console);
|
||||||
@@ -1584,6 +1588,7 @@ var_side_effects_3: {
|
|||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
pure_getters: true,
|
pure_getters: true,
|
||||||
unsafe: true,
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var print = console.log.bind(console);
|
var print = console.log.bind(console);
|
||||||
@@ -1659,6 +1664,7 @@ iife_2: {
|
|||||||
}(foo);
|
}(foo);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var foo;
|
||||||
!function(x) {
|
!function(x) {
|
||||||
console.log(x);
|
console.log(x);
|
||||||
}(bar());
|
}(bar());
|
||||||
@@ -1945,6 +1951,7 @@ ref_scope: {
|
|||||||
chained_1: {
|
chained_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a = 2;
|
var a = 2;
|
||||||
@@ -1961,6 +1968,7 @@ chained_1: {
|
|||||||
chained_2: {
|
chained_2: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a;
|
var a;
|
||||||
@@ -2061,6 +2069,7 @@ inner_lvalues: {
|
|||||||
double_def: {
|
double_def: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a = x, a = a && y;
|
var a = x, a = a && y;
|
||||||
@@ -2075,6 +2084,7 @@ double_def: {
|
|||||||
toplevel_single_reference: {
|
toplevel_single_reference: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
var a;
|
var a;
|
||||||
@@ -2084,10 +2094,11 @@ toplevel_single_reference: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
for (var b in x) {
|
||||||
var a;
|
var a;
|
||||||
for (var b in x)
|
|
||||||
b(a = b);
|
b(a = b);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unused_orig: {
|
unused_orig: {
|
||||||
@@ -2889,6 +2900,7 @@ pure_getters_chain: {
|
|||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
pure_getters: true,
|
pure_getters: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function o(t, r) {
|
function o(t, r) {
|
||||||
@@ -2909,6 +2921,7 @@ pure_getters_chain: {
|
|||||||
conditional_1: {
|
conditional_1: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function f(a, b) {
|
function f(a, b) {
|
||||||
@@ -2933,6 +2946,7 @@ conditional_1: {
|
|||||||
conditional_2: {
|
conditional_2: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function f(a, b) {
|
function f(a, b) {
|
||||||
@@ -3015,3 +3029,51 @@ issue_2425_3: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "15"
|
expect_stdout: "15"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2437: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
conditionals: true,
|
||||||
|
inline: true,
|
||||||
|
join_vars: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
sequences: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function foo() {
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
function bar() {
|
||||||
|
if (xhrDesc) {
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
var result = !!req.onreadystatechange;
|
||||||
|
Object.defineProperty(XMLHttpRequest.prototype, 'onreadystatechange', xhrDesc || {});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var req = new XMLHttpRequest();
|
||||||
|
var detectFunc = function () { };
|
||||||
|
req.onreadystatechange = detectFunc;
|
||||||
|
var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
|
||||||
|
req.onreadystatechange = null;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foo();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!function() {
|
||||||
|
if (xhrDesc)
|
||||||
|
return result = !!(req = new XMLHttpRequest()).onreadystatechange,
|
||||||
|
Object.defineProperty(XMLHttpRequest.prototype, "onreadystatechange", xhrDesc || {}),
|
||||||
|
result;
|
||||||
|
var req = new XMLHttpRequest(), detectFunc = function() {};
|
||||||
|
req.onreadystatechange = detectFunc;
|
||||||
|
var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc;
|
||||||
|
req.onreadystatechange = null;
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ this_binding_collapse_vars: {
|
|||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
collapse_vars: true,
|
||||||
toplevel: true,
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
var c = a; c();
|
var c = a; c();
|
||||||
|
|||||||
@@ -2131,14 +2131,13 @@ redefine_farg_1: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f(a) {
|
function f(a) {
|
||||||
var a;
|
|
||||||
return typeof a;
|
return typeof a;
|
||||||
}
|
}
|
||||||
function g() {
|
function g() {
|
||||||
return"number";
|
return "number";
|
||||||
}
|
}
|
||||||
function h(a, b) {
|
function h(a, b) {
|
||||||
var a = b;
|
a = b;
|
||||||
return typeof a;
|
return typeof a;
|
||||||
}
|
}
|
||||||
console.log(f([]), g([]), h([]));
|
console.log(f([]), g([]), h([]));
|
||||||
@@ -2173,10 +2172,9 @@ redefine_farg_2: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function(a) {
|
console.log(function(a) {
|
||||||
var a;
|
|
||||||
return typeof a;
|
return typeof a;
|
||||||
}([]), "number",function(a, b) {
|
}([]), "number",function(a, b) {
|
||||||
var a = b;
|
a = b;
|
||||||
return typeof a;
|
return typeof a;
|
||||||
}([]));
|
}([]));
|
||||||
}
|
}
|
||||||
@@ -2185,11 +2183,13 @@ redefine_farg_2: {
|
|||||||
|
|
||||||
redefine_farg_3: {
|
redefine_farg_3: {
|
||||||
options = {
|
options = {
|
||||||
|
cascade: true,
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
inline: true,
|
inline: true,
|
||||||
keep_fargs: false,
|
keep_fargs: false,
|
||||||
passes: 3,
|
passes: 2,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
toplevel: true,
|
toplevel: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user