diff options
-rw-r--r-- | lib/compress.js | 48 | ||||
-rw-r--r-- | test/compress/collapse_vars.js | 23 | ||||
-rw-r--r-- | test/compress/drop-unused.js | 66 | ||||
-rw-r--r-- | test/mocha/release.js | 2 |
4 files changed, 124 insertions, 15 deletions
diff --git a/lib/compress.js b/lib/compress.js index 63830d09..08248309 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -2004,7 +2004,7 @@ merge(Compressor.prototype, { if (this.properties[i].value instanceof AST_Accessor) return true; return false; }); - def(AST_Function, return_false); + def(AST_Lambda, return_false); def(AST_UnaryPostfix, return_false); def(AST_UnaryPrefix, function() { return this.operator == "void"; @@ -2023,8 +2023,9 @@ merge(Compressor.prototype, { }) def(AST_Dot, function(compressor) { if (!is_strict(compressor)) return false; - if (this.expression instanceof AST_Function && this.property == "prototype") return false; - return true; + var exp = this.expression; + if (exp instanceof AST_SymbolRef) exp = exp.fixed_value(); + return !(exp instanceof AST_Lambda && this.property == "prototype"); }); def(AST_Sequence, function(compressor) { return this.tail_node()._dot_throw(compressor); @@ -3009,11 +3010,18 @@ merge(Compressor.prototype, { if (self.uses_eval || self.uses_with) return; var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs; var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars; - var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node) { + var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node, props) { + var sym; if (node instanceof AST_Assign && (node.write_only || node.operator == "=")) { - return node.left; + sym = node.left; + } else if (node instanceof AST_Unary && node.write_only) { + sym = node.expression; } - if (node instanceof AST_Unary && node.write_only) return node.expression; + while (sym instanceof AST_PropAccess && !sym.expression.may_throw_on_access(compressor)) { + if (sym instanceof AST_Sub) props.unshift(sym.property); + sym = sym.expression; + } + return sym; }; var in_use = []; var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use @@ -3089,17 +3097,26 @@ merge(Compressor.prototype, { function before(node, descend, in_list) { var parent = tt.parent(); if (drop_vars) { - var sym = assign_as_unused(node); + var props = [], sym = assign_as_unused(node, props); if (sym instanceof AST_SymbolRef) { var def = sym.definition(); var in_use = def.id in in_use_ids; + var value = null; if (node instanceof AST_Assign) { - if (!in_use || def.id in fixed_ids && fixed_ids[def.id] !== node) { - return maintain_this_binding(parent, node, node.right.transform(tt)); + if (!in_use || node.left === sym && def.id in fixed_ids && fixed_ids[def.id] !== node) { + value = node.right; } - } else if (!in_use) return make_node(AST_Number, node, { - value: 0 - }); + } else if (!in_use) { + value = make_node(AST_Number, node, { + value: 0 + }); + } + if (value) { + props.push(value); + return maintain_this_binding(parent, node, make_sequence(node, props.map(function(prop) { + return prop.transform(tt); + }))); + } } } if (scope !== self) return; @@ -3277,12 +3294,15 @@ merge(Compressor.prototype, { self.transform(tt); function scan_ref_scoped(node, descend) { - var node_def, sym = assign_as_unused(node); + var node_def, props = [], sym = assign_as_unused(node, props); if (sym instanceof AST_SymbolRef && self.variables.get(sym.name) === (node_def = sym.definition())) { + props.forEach(function(prop) { + prop.walk(tw); + }); if (node instanceof AST_Assign) { node.right.walk(tw); - if (!node_def.chained && node.left.fixed_value() === node.right) { + if (node.left === sym && !node_def.chained && sym.fixed_value() === node.right) { fixed_ids[node_def.id] = node; } } diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index bcb9cb91..d0a5df85 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -4619,3 +4619,26 @@ issue_2914_2: { } expect_stdout: "0" } + +issue_805: { + options = { + collapse_vars: true, + pure_getters: "strict", + reduce_vars: true, + } + input: { + function f() { + function Foo(){} + Foo.prototype = {}; + Foo.prototype.bar = 42; + return Foo; + } + } + expect: { + function f() { + function Foo(){} + (Foo.prototype = {}).bar = 42; + return Foo; + } + } +} diff --git a/test/compress/drop-unused.js b/test/compress/drop-unused.js index e99d7ab1..ee8e6c0c 100644 --- a/test/compress/drop-unused.js +++ b/test/compress/drop-unused.js @@ -1719,3 +1719,69 @@ issue_2846: { } expect_stdout: "0" } + +issue_805_1: { + options = { + inline: true, + passes: 2, + pure_getters: "strict", + reduce_vars: true, + sequences: true, + side_effects: true, + unused: true, + } + input: { + (function(a) { + var unused = function() {}; + unused.prototype[a()] = 42; + (unused.prototype.bar = function() { + console.log("bar"); + })(); + return unused; + })(function() { + console.log("foo"); + return "foo"; + }); + } + expect: { + console.log("foo"), + console.log("bar"); + } + expect_stdout: [ + "foo", + "bar", + ] +} + +issue_805_2: { + options = { + inline: true, + passes: 2, + pure_getters: "strict", + reduce_vars: true, + sequences: true, + side_effects: true, + unused: true, + } + input: { + (function(a) { + function unused() {} + unused.prototype[a()] = 42; + (unused.prototype.bar = function() { + console.log("bar"); + })(); + return unused; + })(function() { + console.log("foo"); + return "foo"; + }); + } + expect: { + console.log("foo"), + console.log("bar"); + } + expect_stdout: [ + "foo", + "bar", + ] +} diff --git a/test/mocha/release.js b/test/mocha/release.js index 063d0fc7..656ade8d 100644 --- a/test/mocha/release.js +++ b/test/mocha/release.js @@ -38,7 +38,7 @@ describe("test/jetstream.js", function() { this.timeout(20 * 60 * 1000); [ "-mc", - "-mc keep_fargs=false,passes=3,pure_getters,unsafe,unsafe_comps,unsafe_math,unsafe_proto", + "-mc keep_fargs=false,passes=3,unsafe,unsafe_comps,unsafe_math,unsafe_proto", ].forEach(function(options) { it("Should pass with options " + options, function(done) { var args = options.split(/ /); |