From e918748d88e39c6f2142b01e71c3e580d790d642 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Fri, 24 Mar 2017 02:55:32 +0800 Subject: improve collapsible value detection (#1638) - #1634 bars variables with cross-scope references in between to collapse - but if assigned value is side-effect-free, no states can be modified, so it is safe to move --- lib/compress.js | 4 ++- test/compress/collapse_vars.js | 68 ++++++++++++++++++++++++++++++++++++++++++ test/mocha/glob.js | 4 +-- 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index cfa8f230..e75d7c96 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -592,9 +592,10 @@ merge(Compressor.prototype, { // Restrict var replacement to constants if side effects encountered. if (side_effects_encountered |= lvalues_encountered) continue; + var value_has_side_effects = var_decl.value.has_side_effects(compressor); // Non-constant single use vars can only be replaced in same scope. if (ref.scope !== self) { - side_effects_encountered |= var_decl.value.has_side_effects(compressor); + side_effects_encountered |= value_has_side_effects; continue; } @@ -620,6 +621,7 @@ merge(Compressor.prototype, { || (parent instanceof AST_If && node !== parent.condition) || (parent instanceof AST_Conditional && node !== parent.condition) || (node instanceof AST_SymbolRef + && value_has_side_effects && !are_references_in_scope(node.definition(), self)) || (parent instanceof AST_Binary && (parent.operator == "&&" || parent.operator == "||") diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index 6f273b97..2437ca5f 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -1522,3 +1522,71 @@ issue_1631_3: { } expect_stdout: "6" } + +var_side_effects_1: { + options = { + collapse_vars: true, + } + input: { + var print = console.log.bind(console); + function foo(x) { + var twice = x * 2; + print('Foo:', twice); + } + foo(10); + } + expect: { + var print = console.log.bind(console); + function foo(x) { + print('Foo:', 2 * x); + } + foo(10); + } + expect_stdout: true +} + +var_side_effects_2: { + options = { + collapse_vars: true, + } + input: { + var print = console.log.bind(console); + function foo(x) { + var twice = x.y * 2; + print('Foo:', twice); + } + foo({ y: 10 }); + } + expect: { + var print = console.log.bind(console); + function foo(x) { + var twice = 2 * x.y; + print('Foo:', twice); + } + foo({ y: 10 }); + } + expect_stdout: true +} + +var_side_effects_3: { + options = { + collapse_vars: true, + pure_getters: true, + } + input: { + var print = console.log.bind(console); + function foo(x) { + var twice = x.y * 2; + print('Foo:', twice); + } + foo({ y: 10 }); + } + expect: { + var print = console.log.bind(console); + function foo(x) { + print('Foo:', 2 * x.y); + } + foo({ y: 10 }); + } + expect_stdout: true +} diff --git a/test/mocha/glob.js b/test/mocha/glob.js index e291efc8..e9555a52 100644 --- a/test/mocha/glob.js +++ b/test/mocha/glob.js @@ -5,7 +5,7 @@ var path = require("path"); describe("minify() with input file globs", function() { it("minify() with one input file glob string.", function() { var result = Uglify.minify("test/input/issue-1242/foo.*"); - assert.strictEqual(result.code, 'function foo(o){var n=2*o;print("Foo:",n)}var print=console.log.bind(console);'); + assert.strictEqual(result.code, 'function foo(o){print("Foo:",2*o)}var print=console.log.bind(console);'); }); it("minify() with an array of one input file glob.", function() { var result = Uglify.minify([ @@ -20,7 +20,7 @@ describe("minify() with input file globs", function() { ], { compress: { toplevel: true } }); - assert.strictEqual(result.code, 'var print=console.log.bind(console),a=function(n){return 3*n}(3),b=function(n){return n/2}(12);print("qux",a,b),function(n){var o=2*n;print("Foo:",o)}(11);'); + assert.strictEqual(result.code, 'var print=console.log.bind(console),a=function(n){return 3*n}(3),b=function(n){return n/2}(12);print("qux",a,b),function(n){print("Foo:",2*n)}(11);'); }); it("should throw with non-matching glob string", function() { var glob = "test/input/issue-1242/blah.*"; -- cgit v1.2.3