From 5229cb2b1b345a4cedbdeacb02f114033f4c69b7 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Fri, 14 Jul 2017 00:39:34 +0800 Subject: [PATCH] drop `unused` compound assignments (#2230) fixes #2226 --- lib/compress.js | 45 ++++++++++------- test/compress/collapse_vars.js | 4 +- test/compress/drop-unused.js | 90 +++++++++++++++++++++++++++++++++- 3 files changed, 118 insertions(+), 21 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 9b79a3cb..3a5694fc 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -790,6 +790,7 @@ merge(Compressor.prototype, { right: candidate.value }); } + candidate.write_only = false; return candidate; } // These node types have child nodes that execute sequentially, @@ -2177,7 +2178,12 @@ merge(Compressor.prototype, { var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs; var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars; if (!drop_funcs && !drop_vars) return; - var assign_as_unused = !/keep_assign/.test(compressor.option("unused")); + var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node) { + if (node instanceof AST_Assign && (node.write_only || node.operator == "=")) { + return node.left; + } + if (node instanceof AST_Unary && node.write_only) return node.expression; + }; var in_use = []; var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use if (self instanceof AST_Toplevel && compressor.top_retain) { @@ -2227,12 +2233,8 @@ merge(Compressor.prototype, { }); return true; } - if (assign_as_unused - && node instanceof AST_Assign - && node.operator == "=" - && node.left instanceof AST_SymbolRef - && scope === self) { - node.right.walk(tw); + if (assign_as_unused(node) instanceof AST_SymbolRef && scope === self) { + if (node instanceof AST_Assign) node.right.walk(tw); return true; } if (node instanceof AST_SymbolRef) { @@ -2396,14 +2398,17 @@ merge(Compressor.prototype, { }); } } - if (drop_vars && assign_as_unused - && node instanceof AST_Assign - && node.operator == "=" - && node.left instanceof AST_SymbolRef) { - var def = node.left.definition(); - if (!(def.id in in_use_ids) + if (drop_vars) { + var def = assign_as_unused(node); + if (def instanceof AST_SymbolRef + && !((def = def.definition()).id in in_use_ids) && self.variables.get(def.name) === def) { - return maintain_this_binding(tt.parent(), node, node.right.transform(tt)); + if (node instanceof AST_Assign) { + return maintain_this_binding(tt.parent(), node, node.right.transform(tt)); + } + return make_node(AST_Number, node, { + value: 0 + }); } } // certain combination of unused name + side effect leads to: @@ -2642,7 +2647,10 @@ merge(Compressor.prototype, { return make_sequence(this, [ left, right ]); } }); - def(AST_Assign, return_this); + def(AST_Assign, function(compressor){ + this.write_only = !this.left.has_side_effects(compressor); + return this; + }); def(AST_Conditional, function(compressor){ var consequent = this.consequent.drop_side_effect_free(compressor); var alternative = this.alternative.drop_side_effect_free(compressor); @@ -2663,7 +2671,10 @@ merge(Compressor.prototype, { return node; }); def(AST_Unary, function(compressor, first_in_statement){ - if (unary_side_effects(this.operator)) return this; + if (unary_side_effects(this.operator)) { + this.write_only = !this.expression.has_side_effects(compressor); + return this; + } if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) return null; var expression = this.expression.drop_side_effect_free(compressor, first_in_statement); if (first_in_statement @@ -3485,7 +3496,7 @@ merge(Compressor.prototype, { operator: car.operator, expression: left }); - } + } else car.write_only = false; if (parent) { parent[field] = car; expressions[i] = expressions[j]; diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index 10c403fa..7686addf 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -863,7 +863,7 @@ collapse_vars_unary: { input: { function f0(o, p) { var x = o[p]; - delete x; + return delete x; } function f1(n) { var k = !!n; @@ -893,7 +893,7 @@ collapse_vars_unary: { expect: { function f0(o, p) { var x = o[p]; - delete x; + return delete x; } function f1(n) { return n > +!!n diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js index a44107ae..34d47d0d 100644 --- a/test/compress/drop-unused.js +++ b/test/compress/drop-unused.js @@ -1090,6 +1090,7 @@ var_catch_toplevel: { a--; try { a++; + x(); } catch(a) { if (a) var a; var a = 10; @@ -1099,9 +1100,8 @@ var_catch_toplevel: { } expect: { !function() { - a--; try { - a++; + x(); } catch(a) { var a; } @@ -1153,3 +1153,89 @@ issue_2105: { } expect_stdout: "PASS" } + +issue_2226_1: { + options = { + side_effects: true, + unused: true, + } + input: { + function f1() { + var a = b; + a += c; + } + function f2(a) { + a <<= b; + } + function f3(a) { + --a; + } + function f4() { + var a = b; + return a *= c; + } + function f5(a) { + x(a /= b); + } + } + expect: { + function f1() { + b; + c; + } + function f2(a) { + b; + } + function f3(a) { + 0; + } + function f4() { + var a = b; + return a *= c; + } + function f5(a) { + x(a /= b); + } + } +} + +issue_2226_2: { + options = { + cascade: true, + sequences: true, + side_effects: true, + unused: true, + } + input: { + console.log(function(a, b) { + a += b; + return a; + }(1, 2)); + } + expect: { + console.log(function(a, b) { + return a += b; + }(1, 2)); + } + expect_stdout: "3" +} + +issue_2226_3: { + options = { + collapse_vars: true, + side_effects: true, + unused: true, + } + input: { + console.log(function(a, b) { + a += b; + return a; + }(1, 2)); + } + expect: { + console.log(function(a, b) { + return a += 2; + }(1)); + } + expect_stdout: "3" +} -- 2.34.1