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
|
||||
var unused_fn_names = [];
|
||||
var calls_to_drop_args = [];
|
||||
var fns_with_marked_args = [];
|
||||
var tt = new TreeTransformer(function(node, descend, in_list) {
|
||||
var parent = tt.parent();
|
||||
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 (node instanceof AST_Function && node.name && drop_fn_name(node.name.definition())) {
|
||||
unused_fn_names.push(node);
|
||||
@@ -4059,6 +4062,7 @@ merge(Compressor.prototype, {
|
||||
trim = false;
|
||||
}
|
||||
}
|
||||
fns_with_marked_args.push(node);
|
||||
}
|
||||
if (drop_funcs && node instanceof AST_Defun && node !== self) {
|
||||
var def = node.name.definition();
|
||||
@@ -4252,6 +4256,9 @@ merge(Compressor.prototype, {
|
||||
unused_fn_names.forEach(function(fn) {
|
||||
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) {
|
||||
AST_Node[sym.unreferenced() ? "warn" : "info"](text, props);
|
||||
@@ -5448,6 +5455,62 @@ merge(Compressor.prototype, {
|
||||
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) {
|
||||
var exp = self.expression;
|
||||
if (compressor.option("sequences")) {
|
||||
@@ -5464,63 +5527,7 @@ merge(Compressor.prototype, {
|
||||
if (seq !== self) return seq.optimize(compressor);
|
||||
}
|
||||
}
|
||||
var fn = exp;
|
||||
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("unused")) drop_unused_call_args(self, compressor);
|
||||
if (compressor.option("unsafe")) {
|
||||
if (is_undeclared_ref(exp)) switch (exp.name) {
|
||||
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 can_inline = compressor.option("inline") && !self.is_expr_pure(compressor);
|
||||
if (exp === fn && can_inline && stat instanceof AST_Return) {
|
||||
|
||||
@@ -1191,10 +1191,10 @@ issue_2105_1: {
|
||||
input: {
|
||||
!function(factory) {
|
||||
factory();
|
||||
}( function() {
|
||||
}(function() {
|
||||
return function(fn) {
|
||||
fn()().prop();
|
||||
}( function() {
|
||||
}(function() {
|
||||
function bar() {
|
||||
var quux = function() {
|
||||
console.log("PASS");
|
||||
@@ -1205,7 +1205,7 @@ issue_2105_1: {
|
||||
return { prop: foo };
|
||||
}
|
||||
return bar;
|
||||
} );
|
||||
});
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
@@ -1235,10 +1235,10 @@ issue_2105_2: {
|
||||
input: {
|
||||
!function(factory) {
|
||||
factory();
|
||||
}( function() {
|
||||
}(function() {
|
||||
return function(fn) {
|
||||
fn()().prop();
|
||||
}( function() {
|
||||
}(function() {
|
||||
function bar() {
|
||||
var quux = function() {
|
||||
console.log("PASS");
|
||||
@@ -1249,7 +1249,7 @@ issue_2105_2: {
|
||||
return { prop: foo };
|
||||
}
|
||||
return bar;
|
||||
} );
|
||||
});
|
||||
});
|
||||
}
|
||||
expect: {
|
||||
@@ -1258,6 +1258,44 @@ issue_2105_2: {
|
||||
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: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
@@ -2330,7 +2368,7 @@ function_parameter_ie8: {
|
||||
(function() {
|
||||
(function f() {
|
||||
console.log("PASS");
|
||||
})(0);
|
||||
})();
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
|
||||
@@ -1276,7 +1276,7 @@ issue_2630_3: {
|
||||
(function() {
|
||||
(function f1(a) {
|
||||
f2();
|
||||
--x >= 0 && f1({});
|
||||
--x >= 0 && f1();
|
||||
})(a++);
|
||||
function f2() {
|
||||
a++;
|
||||
|
||||
@@ -728,7 +728,7 @@ issue_2630_3: {
|
||||
(function() {
|
||||
(function f1() {
|
||||
f2();
|
||||
--x >= 0 && f1({});
|
||||
--x >= 0 && f1();
|
||||
})(a++);
|
||||
function f2() {
|
||||
a++;
|
||||
@@ -1369,7 +1369,7 @@ recursive_iife_1: {
|
||||
}
|
||||
expect: {
|
||||
console.log(function f(a, b) {
|
||||
return b || f("FAIL", "PASS");
|
||||
return b || f(0, "PASS");
|
||||
}());
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
@@ -1388,7 +1388,7 @@ recursive_iife_2: {
|
||||
}
|
||||
expect: {
|
||||
console.log(function f(a, b) {
|
||||
return b || f("FAIL", "PASS");
|
||||
return b || f(0, "PASS");
|
||||
}(0, 0));
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
@@ -1416,7 +1416,7 @@ recursive_iife_3: {
|
||||
var a = 1, c = "PASS";
|
||||
(function() {
|
||||
(function f(b, d, e) {
|
||||
a-- && f(null, 42, 0);
|
||||
a-- && f(0, 42, 0);
|
||||
e && (c = "FAIL");
|
||||
d && d.p;
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user