From ae28a24c7f7919d8de1c3044f28571ebe2036850 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Thu, 16 Nov 2017 10:04:30 +0800 Subject: [PATCH] fix cross-scope inlining of `AST_Function`s (#2486) fixes #2485 --- bin/uglifyjs | 2 +- lib/ast.js | 4 +-- lib/compress.js | 13 +++++++--- test/compress/reduce_vars.js | 48 ++++++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/bin/uglifyjs b/bin/uglifyjs index 8cbb3cad..04c402d3 100755 --- a/bin/uglifyjs +++ b/bin/uglifyjs @@ -15,7 +15,7 @@ var path = require("path"); var program = require("commander"); var UglifyJS = require("../tools/node"); -var skip_keys = [ "cname", "enclosed", "parent_scope", "scope", "thedef", "uses_eval", "uses_with" ]; +var skip_keys = [ "cname", "enclosed", "inlined", "parent_scope", "scope", "thedef", "uses_eval", "uses_with" ]; var files = {}; var options = { compress: false, diff --git a/lib/ast.js b/lib/ast.js index 9b243f16..a2aa2b40 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -352,11 +352,11 @@ var AST_Accessor = DEFNODE("Accessor", null, { $documentation: "A setter/getter function. The `name` property is always null." }, AST_Lambda); -var AST_Function = DEFNODE("Function", null, { +var AST_Function = DEFNODE("Function", "inlined", { $documentation: "A function expression" }, AST_Lambda); -var AST_Defun = DEFNODE("Defun", null, { +var AST_Defun = DEFNODE("Defun", "inlined", { $documentation: "A function definition" }, AST_Lambda); diff --git a/lib/compress.js b/lib/compress.js index 0f72404f..2577643b 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -373,6 +373,7 @@ merge(Compressor.prototype, { } } if (node instanceof AST_Defun) { + node.inlined = false; var d = node.name.definition(); if (compressor.exposed(d) || safe_to_read(d)) { d.fixed = false; @@ -389,6 +390,7 @@ merge(Compressor.prototype, { return true; } if (node instanceof AST_Function) { + node.inlined = false; push(); var iife; if (!node.name @@ -4329,16 +4331,21 @@ merge(Compressor.prototype, { d.fixed = fixed = make_node(AST_Function, fixed, fixed); } if (d.single_use && fixed instanceof AST_Function) { - if (!compressor.option("reduce_funcs") && d.scope !== self.scope) { + if (d.scope !== self.scope + && (!compressor.option("reduce_funcs") + || d.escaped + || fixed.inlined)) { d.single_use = false; - } else if (d.escaped && d.scope !== self.scope || recursive_ref(compressor, d)) { + } else if (recursive_ref(compressor, d)) { d.single_use = false; } else if (d.scope !== self.scope || d.orig[0] instanceof AST_SymbolFunarg) { d.single_use = fixed.is_constant_expression(self.scope); if (d.single_use == "f") { var scope = self.scope; do { - if (scope.name) scope.name.definition().single_use = false; + if (scope instanceof AST_Defun || scope instanceof AST_Function) { + scope.inlined = true; + } } while (scope = scope.parent_scope); } } diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index e7189492..02ff5e43 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -4477,3 +4477,51 @@ perf_8: { } expect_stdout: "348150" } + +issue_2485: { + options = { + reduce_funcs: true, + reduce_vars: true, + unused: true, + } + input: { + var foo = function(bar) { + var n = function(a, b) { + return a + b; + }; + var sumAll = function(arg) { + return arg.reduce(n, 0); + }; + var runSumAll = function(arg) { + return sumAll(arg); + }; + bar.baz = function(arg) { + var n = runSumAll(arg); + return (n.get = 1), n; + }; + return bar; + }; + var bar = foo({}); + console.log(bar.baz([1, 2, 3])); + } + expect: { + var foo = function(bar) { + var n = function(a, b) { + return a + b; + }; + var runSumAll = function(arg) { + return function(arg) { + return arg.reduce(n, 0); + }(arg); + }; + bar.baz = function(arg) { + var n = runSumAll(arg); + return (n.get = 1), n; + }; + return bar; + }; + var bar = foo({}); + console.log(bar.baz([1, 2, 3])); + } + expect_stdout: "6" +} -- 2.34.1