fix corner case in unused (#3716)
This commit is contained in:
123
lib/compress.js
123
lib/compress.js
@@ -4001,6 +4001,8 @@ merge(Compressor.prototype, {
|
|||||||
};
|
};
|
||||||
// pass 3: we should drop declarations not in_use
|
// pass 3: we should drop declarations not in_use
|
||||||
var unused_fn_names = [];
|
var unused_fn_names = [];
|
||||||
|
var calls_to_drop_args = [];
|
||||||
|
var fns_with_marked_args = [];
|
||||||
var tt = new TreeTransformer(function(node, descend, in_list) {
|
var tt = new TreeTransformer(function(node, descend, in_list) {
|
||||||
var parent = tt.parent();
|
var parent = tt.parent();
|
||||||
if (drop_vars) {
|
if (drop_vars) {
|
||||||
@@ -4041,6 +4043,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_Call) calls_to_drop_args.push(node);
|
||||||
if (scope !== self) return;
|
if (scope !== self) return;
|
||||||
if (node instanceof AST_Function && node.name && drop_fn_name(node.name.definition())) {
|
if (node instanceof AST_Function && node.name && drop_fn_name(node.name.definition())) {
|
||||||
unused_fn_names.push(node);
|
unused_fn_names.push(node);
|
||||||
@@ -4059,6 +4062,7 @@ merge(Compressor.prototype, {
|
|||||||
trim = false;
|
trim = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fns_with_marked_args.push(node);
|
||||||
}
|
}
|
||||||
if (drop_funcs && node instanceof AST_Defun && node !== self) {
|
if (drop_funcs && node instanceof AST_Defun && node !== self) {
|
||||||
var def = node.name.definition();
|
var def = node.name.definition();
|
||||||
@@ -4252,6 +4256,9 @@ merge(Compressor.prototype, {
|
|||||||
unused_fn_names.forEach(function(fn) {
|
unused_fn_names.forEach(function(fn) {
|
||||||
fn.name = null;
|
fn.name = null;
|
||||||
});
|
});
|
||||||
|
calls_to_drop_args.forEach(function(call) {
|
||||||
|
drop_unused_call_args(call, compressor, fns_with_marked_args);
|
||||||
|
});
|
||||||
|
|
||||||
function log(sym, text, props) {
|
function log(sym, text, props) {
|
||||||
AST_Node[sym.unreferenced() ? "warn" : "info"](text, props);
|
AST_Node[sym.unreferenced() ? "warn" : "info"](text, props);
|
||||||
@@ -5448,6 +5455,62 @@ merge(Compressor.prototype, {
|
|||||||
return make_sequence(node, x);
|
return make_sequence(node, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function drop_unused_call_args(call, compressor, fns_with_marked_args) {
|
||||||
|
var exp = call.expression;
|
||||||
|
var fn = exp instanceof AST_SymbolRef ? exp.fixed_value() : exp;
|
||||||
|
if (!(fn instanceof AST_Lambda)) return;
|
||||||
|
if (fn.uses_arguments) return;
|
||||||
|
if (fn.pinned()) return;
|
||||||
|
if (fns_with_marked_args && fns_with_marked_args.indexOf(fn) < 0) return;
|
||||||
|
var args = call.args;
|
||||||
|
var pos = 0, last = 0;
|
||||||
|
var drop_fargs = fn === exp && !fn.name && compressor.drop_fargs(fn, call);
|
||||||
|
var side_effects = [];
|
||||||
|
for (var i = 0; i < args.length; i++) {
|
||||||
|
var trim = i >= fn.argnames.length;
|
||||||
|
if (trim || fn.argnames[i].__unused) {
|
||||||
|
var node = args[i].drop_side_effect_free(compressor);
|
||||||
|
if (drop_fargs) {
|
||||||
|
fn.argnames.splice(i, 1);
|
||||||
|
args.splice(i, 1);
|
||||||
|
if (node) side_effects.push(node);
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
} else if (node) {
|
||||||
|
side_effects.push(node);
|
||||||
|
args[pos++] = make_sequence(call, side_effects);
|
||||||
|
side_effects = [];
|
||||||
|
} else if (!trim) {
|
||||||
|
if (side_effects.length) {
|
||||||
|
node = make_sequence(call, side_effects);
|
||||||
|
side_effects = [];
|
||||||
|
} else {
|
||||||
|
node = make_node(AST_Number, args[i], {
|
||||||
|
value: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
args[pos++] = node;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
side_effects.push(args[i]);
|
||||||
|
args[pos++] = make_sequence(call, side_effects);
|
||||||
|
side_effects = [];
|
||||||
|
}
|
||||||
|
last = pos;
|
||||||
|
}
|
||||||
|
if (drop_fargs) for (; i < fn.argnames.length; i++) {
|
||||||
|
if (fn.argnames[i].__unused) fn.argnames.splice(i--, 1);
|
||||||
|
}
|
||||||
|
args.length = last;
|
||||||
|
if (!side_effects.length) return;
|
||||||
|
var arg = make_sequence(call, side_effects);
|
||||||
|
args.push(args.length < fn.argnames.length ? make_node(AST_UnaryPrefix, call, {
|
||||||
|
operator: "void",
|
||||||
|
expression: arg
|
||||||
|
}) : arg);
|
||||||
|
}
|
||||||
|
|
||||||
OPT(AST_Call, function(self, compressor) {
|
OPT(AST_Call, function(self, compressor) {
|
||||||
var exp = self.expression;
|
var exp = self.expression;
|
||||||
if (compressor.option("sequences")) {
|
if (compressor.option("sequences")) {
|
||||||
@@ -5464,63 +5527,7 @@ merge(Compressor.prototype, {
|
|||||||
if (seq !== self) return seq.optimize(compressor);
|
if (seq !== self) return seq.optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var fn = exp;
|
if (compressor.option("unused")) drop_unused_call_args(self, compressor);
|
||||||
if (compressor.option("reduce_vars") && fn instanceof AST_SymbolRef) {
|
|
||||||
fn = fn.fixed_value();
|
|
||||||
}
|
|
||||||
var is_func = fn instanceof AST_Lambda;
|
|
||||||
if (compressor.option("unused")
|
|
||||||
&& is_func
|
|
||||||
&& !fn.uses_arguments
|
|
||||||
&& !fn.pinned()) {
|
|
||||||
var pos = 0, last = 0;
|
|
||||||
var drop_fargs = exp === fn && !fn.name && compressor.drop_fargs(fn, self);
|
|
||||||
var side_effects = [];
|
|
||||||
for (var i = 0; i < self.args.length; i++) {
|
|
||||||
var trim = i >= fn.argnames.length;
|
|
||||||
if (trim || fn.argnames[i].__unused) {
|
|
||||||
var node = self.args[i].drop_side_effect_free(compressor);
|
|
||||||
if (drop_fargs) {
|
|
||||||
fn.argnames.splice(i, 1);
|
|
||||||
self.args.splice(i, 1);
|
|
||||||
if (node) side_effects.push(node);
|
|
||||||
i--;
|
|
||||||
continue;
|
|
||||||
} else if (node) {
|
|
||||||
side_effects.push(node);
|
|
||||||
self.args[pos++] = make_sequence(self, side_effects);
|
|
||||||
side_effects = [];
|
|
||||||
} else if (!trim) {
|
|
||||||
if (side_effects.length) {
|
|
||||||
node = make_sequence(self, side_effects);
|
|
||||||
side_effects = [];
|
|
||||||
} else {
|
|
||||||
node = make_node(AST_Number, self.args[i], {
|
|
||||||
value: 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
self.args[pos++] = node;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
side_effects.push(self.args[i]);
|
|
||||||
self.args[pos++] = make_sequence(self, side_effects);
|
|
||||||
side_effects = [];
|
|
||||||
}
|
|
||||||
last = pos;
|
|
||||||
}
|
|
||||||
if (drop_fargs) for (; i < fn.argnames.length; i++) {
|
|
||||||
if (fn.argnames[i].__unused) fn.argnames.splice(i--, 1);
|
|
||||||
}
|
|
||||||
self.args.length = last;
|
|
||||||
if (side_effects.length) {
|
|
||||||
var arg = make_sequence(self, side_effects);
|
|
||||||
self.args.push(self.args.length < fn.argnames.length ? make_node(AST_UnaryPrefix, self, {
|
|
||||||
operator: "void",
|
|
||||||
expression: arg
|
|
||||||
}) : arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
if (is_undeclared_ref(exp)) switch (exp.name) {
|
if (is_undeclared_ref(exp)) switch (exp.name) {
|
||||||
case "Array":
|
case "Array":
|
||||||
@@ -5786,6 +5793,8 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var fn = exp instanceof AST_SymbolRef ? exp.fixed_value() : exp;
|
||||||
|
var is_func = fn instanceof AST_Lambda;
|
||||||
var stat = is_func && fn.first_statement();
|
var stat = is_func && fn.first_statement();
|
||||||
var can_inline = compressor.option("inline") && !self.is_expr_pure(compressor);
|
var can_inline = compressor.option("inline") && !self.is_expr_pure(compressor);
|
||||||
if (exp === fn && can_inline && stat instanceof AST_Return) {
|
if (exp === fn && can_inline && stat instanceof AST_Return) {
|
||||||
|
|||||||
@@ -1191,10 +1191,10 @@ issue_2105_1: {
|
|||||||
input: {
|
input: {
|
||||||
!function(factory) {
|
!function(factory) {
|
||||||
factory();
|
factory();
|
||||||
}( function() {
|
}(function() {
|
||||||
return function(fn) {
|
return function(fn) {
|
||||||
fn()().prop();
|
fn()().prop();
|
||||||
}( function() {
|
}(function() {
|
||||||
function bar() {
|
function bar() {
|
||||||
var quux = function() {
|
var quux = function() {
|
||||||
console.log("PASS");
|
console.log("PASS");
|
||||||
@@ -1205,7 +1205,7 @@ issue_2105_1: {
|
|||||||
return { prop: foo };
|
return { prop: foo };
|
||||||
}
|
}
|
||||||
return bar;
|
return bar;
|
||||||
} );
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
@@ -1235,10 +1235,10 @@ issue_2105_2: {
|
|||||||
input: {
|
input: {
|
||||||
!function(factory) {
|
!function(factory) {
|
||||||
factory();
|
factory();
|
||||||
}( function() {
|
}(function() {
|
||||||
return function(fn) {
|
return function(fn) {
|
||||||
fn()().prop();
|
fn()().prop();
|
||||||
}( function() {
|
}(function() {
|
||||||
function bar() {
|
function bar() {
|
||||||
var quux = function() {
|
var quux = function() {
|
||||||
console.log("PASS");
|
console.log("PASS");
|
||||||
@@ -1249,7 +1249,7 @@ issue_2105_2: {
|
|||||||
return { prop: foo };
|
return { prop: foo };
|
||||||
}
|
}
|
||||||
return bar;
|
return bar;
|
||||||
} );
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
@@ -1258,6 +1258,44 @@ issue_2105_2: {
|
|||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2105_3: {
|
||||||
|
options = {
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
!function(factory) {
|
||||||
|
factory();
|
||||||
|
}(function() {
|
||||||
|
return function(fn) {
|
||||||
|
fn()().prop();
|
||||||
|
}(function() {
|
||||||
|
function bar() {
|
||||||
|
var quux = function() {
|
||||||
|
console.log("PASS");
|
||||||
|
}, foo = function() {
|
||||||
|
console.log;
|
||||||
|
quux();
|
||||||
|
};
|
||||||
|
return { prop: foo };
|
||||||
|
}
|
||||||
|
return bar;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
!void void {
|
||||||
|
prop: function() {
|
||||||
|
console.log;
|
||||||
|
void console.log("PASS");
|
||||||
|
}
|
||||||
|
}.prop();
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
issue_2226_1: {
|
issue_2226_1: {
|
||||||
options = {
|
options = {
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
@@ -2330,7 +2368,7 @@ function_parameter_ie8: {
|
|||||||
(function() {
|
(function() {
|
||||||
(function f() {
|
(function f() {
|
||||||
console.log("PASS");
|
console.log("PASS");
|
||||||
})(0);
|
})();
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
|
|||||||
@@ -1276,7 +1276,7 @@ issue_2630_3: {
|
|||||||
(function() {
|
(function() {
|
||||||
(function f1(a) {
|
(function f1(a) {
|
||||||
f2();
|
f2();
|
||||||
--x >= 0 && f1({});
|
--x >= 0 && f1();
|
||||||
})(a++);
|
})(a++);
|
||||||
function f2() {
|
function f2() {
|
||||||
a++;
|
a++;
|
||||||
|
|||||||
@@ -728,7 +728,7 @@ issue_2630_3: {
|
|||||||
(function() {
|
(function() {
|
||||||
(function f1() {
|
(function f1() {
|
||||||
f2();
|
f2();
|
||||||
--x >= 0 && f1({});
|
--x >= 0 && f1();
|
||||||
})(a++);
|
})(a++);
|
||||||
function f2() {
|
function f2() {
|
||||||
a++;
|
a++;
|
||||||
@@ -1369,7 +1369,7 @@ recursive_iife_1: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function f(a, b) {
|
console.log(function f(a, b) {
|
||||||
return b || f("FAIL", "PASS");
|
return b || f(0, "PASS");
|
||||||
}());
|
}());
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
@@ -1388,7 +1388,7 @@ recursive_iife_2: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function f(a, b) {
|
console.log(function f(a, b) {
|
||||||
return b || f("FAIL", "PASS");
|
return b || f(0, "PASS");
|
||||||
}(0, 0));
|
}(0, 0));
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
@@ -1416,7 +1416,7 @@ recursive_iife_3: {
|
|||||||
var a = 1, c = "PASS";
|
var a = 1, c = "PASS";
|
||||||
(function() {
|
(function() {
|
||||||
(function f(b, d, e) {
|
(function f(b, d, e) {
|
||||||
a-- && f(null, 42, 0);
|
a-- && f(0, 42, 0);
|
||||||
e && (c = "FAIL");
|
e && (c = "FAIL");
|
||||||
d && d.p;
|
d && d.p;
|
||||||
})();
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user