From: Alex Lam S.L Date: Thu, 11 Jun 2020 18:16:13 +0000 (+0100) Subject: enhance `dead_code` (#3990) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=e9465717abb77fed206455881a983f313d2b894c;p=UglifyJS.git enhance `dead_code` (#3990) --- diff --git a/lib/compress.js b/lib/compress.js index 8d8dffa2..2a1399d5 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -571,7 +571,14 @@ merge(Compressor.prototype, { }); def(AST_Assign, function(tw, descend, compressor) { var node = this; + var eq = node.operator == "="; var sym = node.left; + if (eq && sym.equivalent_to(node.right) && !sym.has_side_effects(compressor)) { + node.right.walk(tw); + walk_prop(sym); + node.__drop = true; + return true; + } if (!(sym instanceof AST_SymbolRef)) { mark_assignment_to_arguments(sym); return; @@ -579,7 +586,6 @@ merge(Compressor.prototype, { var d = sym.definition(); d.assignments++; var fixed = d.fixed; - var eq = node.operator == "="; var value = eq ? node.right : node; if (is_modified(compressor, tw, node, value, 0)) return; var safe = eq || safe_to_read(tw, d); @@ -609,6 +615,21 @@ merge(Compressor.prototype, { d.fixed = false; } return true; + + function walk_prop(node) { + if (node instanceof AST_Dot) { + walk_prop(node.expression); + } else if (node instanceof AST_Sub) { + walk_prop(node.expression); + node.property.walk(tw); + } else if (node instanceof AST_SymbolRef) { + var d = node.definition(); + push_ref(d, node); + node.fixed = d.fixed; + } else { + node.walk(tw); + } + } }); def(AST_Binary, function(tw) { if (!lazy_op[this.operator]) return; @@ -7843,8 +7864,15 @@ merge(Compressor.prototype, { if (compressor.option("dead_code")) { if (self.left instanceof AST_PropAccess) { if (self.operator == "=") { - if (self.left.equivalent_to(self.right) - && (self.left instanceof AST_Dot || !self.left.property.has_side_effects(compressor))) { + if (self.__drop) { + var props = []; + flatten(self.left, props); + flatten(self.right, props); + return props.length == 0 ? make_node(AST_Number, self, { + value: 0 + }) : make_sequence(self, props).optimize(compressor); + } + if (self.left.equivalent_to(self.right) && !self.left.has_side_effects(compressor)) { return self.right; } var exp = self.left.expression; @@ -7934,6 +7962,11 @@ merge(Compressor.prototype, { } return try_evaluate(compressor, self); + function flatten(node, props) { + if (!(node.expression instanceof AST_SymbolRef)) props.push(node.expression); + if (node instanceof AST_Sub) props.push(node.property); + } + function in_try(level, node) { var right = self.right; self.right = make_node(AST_Null, right); diff --git a/test/compress/dead-code.js b/test/compress/dead-code.js index 5506b95a..a2ebf37a 100644 --- a/test/compress/dead-code.js +++ b/test/compress/dead-code.js @@ -1169,29 +1169,131 @@ redundant_assignments: { expect_stdout: "PASS PASS" } -self_assignments: { +self_assignments_1: { options = { dead_code: true, } input: { - var a = "PASS", b = 0, l = [ "FAIL", "PASS" ], o = { p: "PASS" }; + var a = "PASS"; a = a; - l[0] = l[0]; - l[b] = l[b]; - l[b++] = l[b++]; - o.p = o.p; - console.log(a, b, l[0], o.p); + console.log(a); } expect: { - var a = "PASS", b = 0, l = [ "FAIL", "PASS" ], o = { p: "PASS" }; + var a = "PASS"; a; - l[0]; - l[b]; - l[b++] = l[b++]; - o.p; - console.log(a, b, l[0], o.p); + console.log(a); + } + expect_stdout: "PASS" +} + +self_assignments_2: { + options = { + dead_code: true, + pure_getters: "strict", + reduce_vars: true, + side_effects: true, + toplevel: true, + } + input: { + var a = "q", o = { + p: "PASS", + }; + o.p = o.p; + o[a] = o[a]; + console.log(o.p, o[a]); + } + expect: { + var a = "q", o = { + p: "PASS", + }; + console.log(o.p, o[a]); + } + expect_stdout: "PASS undefined" +} + +self_assignments_3: { + options = { + dead_code: true, + pure_getters: "strict", + reduce_vars: true, + side_effects: true, + toplevel: true, + } + input: { + var a = "q", o = { + p: "FAIL", + get q() { + return "PASS"; + }, + set q(v) { + this.p = v; + }, + }; + o.p = o.p; + o[a] = o[a]; + console.log(o.p, o[a]); + } + expect: { + var a = "q", o = { + p: "FAIL", + get q() { + return "PASS"; + }, + set q(v) { + this.p = v; + }, + }; + o.p = o.p; + o[a] = o[a]; + console.log(o.p, o[a]); + } + expect_stdout: "PASS PASS" +} + +self_assignments_4: { + options = { + dead_code: true, + pure_getters: "strict", + reduce_vars: true, + side_effects: true, + toplevel: true, + } + input: { + var i = 0, l = [ "PASS" ]; + l[0] = l[0]; + l[i] = l[i]; + console.log(l[0], i); + } + expect: { + var i = 0, l = [ "PASS" ]; + console.log(l[0], i); + } + expect_stdout: "PASS 0" +} + +self_assignments_5: { + options = { + dead_code: true, + evaluate: true, + passes: 3, + pure_getters: "strict", + reduce_vars: true, + side_effects: true, + toplevel: true, + } + input: { + var i = 0, l = [ "FAIL", "PASS" ]; + l[0] = l[0]; + l[i] = l[i]; + l[i++] = l[i++]; + console.log(l[0], i); + } + expect: { + var i = 0, l = [ "FAIL", "PASS" ]; + l[0] = l[1]; + console.log(l[0], 2); } - expect_stdout: "PASS 2 PASS PASS" + expect_stdout: "PASS 2" } issue_3967: {