From e24b2553508d70386924532f18dfeb35de4aef08 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Thu, 20 Jan 2022 21:13:26 +0000 Subject: [PATCH] implement `keep_fargs` for `mangle` (#5307) closes #4657 --- README.md | 7 + bin/uglifyjs | 5 + lib/compress.js | 75 +++--- lib/minify.js | 3 + lib/scope.js | 34 ++- test/compress/awaits.js | 14 +- test/compress/const.js | 26 ++ test/compress/destructured.js | 10 +- test/compress/functions.js | 6 +- test/compress/hoist_props.js | 8 +- test/compress/ie.js | 8 +- test/compress/keep_fargs.js | 22 ++ test/compress/let.js | 32 +++ test/compress/merge_vars.js | 439 +++++++++++++++++++------------ test/compress/optional-chains.js | 8 +- test/compress/rests.js | 18 +- test/compress/varify.js | 16 +- test/compress/yields.js | 14 +- test/mocha/cli.js | 28 +- test/ufuzz/options.json | 1 + 20 files changed, 507 insertions(+), 267 deletions(-) diff --git a/README.md b/README.md index 048de63b777..22842e3f008 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ a double dash to prevent input files being used as option arguments: Equivalent to setting `ie: true` in `minify()` for `compress`, `mangle` and `output` options. By default UglifyJS will not try to be IE-proof. + --keep-fargs Do not mangle/drop function arguments. --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name. --name-cache File to hold mangled name mappings. @@ -504,6 +505,9 @@ if (result.error) throw result.error; - `ie` (default: `false`) — enable workarounds for Internet Explorer bugs. +- `keep_fargs` (default: `false`) — pass `true` to prevent discarding or mangling + of function arguments. + - `keep_fnames` (default: `false`) — pass `true` to prevent discarding or mangling of function names. Useful for code relying on `Function.prototype.name`. @@ -868,6 +872,9 @@ UglifyJS.minify(code, { mangle: { toplevel: true } }).code; - `debug` (default: `false`) — Mangle names with the original name still present. Pass an empty string `""` to enable, or a non-empty string to set the debug suffix. +- `keep_fargs` (default: `false`) — Use `true` to prevent mangling of function + arguments. + - `keep_quoted` (default: `false`) — Only mangle unquoted property names. - `regex` (default: `null`) — Pass a RegExp literal to only mangle property diff --git a/bin/uglifyjs b/bin/uglifyjs index 8e679977456..d7a6498efb4 100755 --- a/bin/uglifyjs +++ b/bin/uglifyjs @@ -72,6 +72,7 @@ function process_option(name, no_value) { } else { if (padding.length < name.length) padding = Array(name.length + 1).join(" "); toplevels.push([ { + keep_fargs: "keep-fargs", keep_fnames: "keep-fnames", nameCache: "name-cache", }[name] || name, option ]); @@ -104,6 +105,7 @@ function process_option(name, no_value) { " -d, --define [=value] Global definitions.", " -e, --enclose [arg[,...][:value[,...]]] Embed everything in a big function, with configurable argument(s) & value(s).", " --ie Support non-standard Internet Explorer.", + " --keep-fargs Do not mangle/drop function arguments.", " --keep-fnames Do not mangle/drop function names. Useful for code relying on Function.prototype.name.", " --name-cache File to hold mangled name mappings.", " --rename Force symbol expansion.", @@ -160,6 +162,9 @@ function process_option(name, no_value) { case "no-annotations": options.annotations = false; break; + case "keep-fargs": + options.keep_fargs = true; + break; case "keep-fnames": options.keep_fnames = true; break; diff --git a/lib/compress.js b/lib/compress.js index 404c0621155..0d4370b9b7d 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -443,10 +443,6 @@ Compressor.prototype.compress = function(node) { return def.name == "arguments" && def.scope.uses_arguments; } - function is_funarg(def) { - return def.orig[0] instanceof AST_SymbolFunarg || def.orig[1] instanceof AST_SymbolFunarg; - } - function cross_scope(def, sym) { do { if (def === sym) return false; @@ -2053,7 +2049,7 @@ Compressor.prototype.compress = function(node) { } return make_node(AST_Assign, candidate, { operator: "=", - left: make_node(AST_SymbolRef, candidate.name, candidate.name), + left: node, right: rvalue, }); } @@ -6229,51 +6225,46 @@ Compressor.prototype.compress = function(node) { var changed = false; var merged = Object.create(null); while (first.length && last.length) { - var head = first.pop(); - var def = head.definition; - if (!(def.id in prev)) continue; - if (!references[def.id]) continue; - var head_refs = { - start: references[def.id].start, - }; + var tail = last.shift(); + if (!tail) continue; + var def = tail.definition; + var tail_refs = references[def.id]; + if (!tail_refs) continue; + tail_refs = { end: tail_refs.end }; while (def.id in merged) def = merged[def.id]; - head_refs.end = references[def.id].end; + tail_refs.start = references[def.id].start; var skipped = []; do { - var tail = last.pop(); - if (!tail) continue; + var head = first.shift(); if (tail.index > head.index) continue; - var id = tail.definition.id; - var tail_refs = references[id]; - if (!tail_refs) continue; + var id = head.definition.id; + if (!(id in prev)) continue; + var head_refs = references[id]; + if (!head_refs) continue; if (head_refs.start.block !== tail_refs.start.block || !mergeable(head_refs, tail_refs) || (head_refs.start.loop || !same_scope(def)) && !mergeable(tail_refs, head_refs) - || compressor.option("webkit") && is_funarg(def) !== is_funarg(tail.definition) - || !all(tail_refs, function(sym) { - return sym.scope.find_variable(def.name) === def; - })) { - skipped.unshift(tail); + || compressor.option("webkit") && is_funarg(def) !== is_funarg(head.definition) + || !safe_to_rename(head_refs, def) + || !safe_to_rename(references[def.id], head.definition)) { + skipped.push(head); continue; } - var orig = [], refs = []; - tail_refs.forEach(function(sym) { + head_refs.forEach(function(sym) { sym.thedef = def; sym.name = def.name; if (sym instanceof AST_SymbolRef) { - refs.push(sym); + def.references.push(sym); } else { - orig.push(sym); + def.orig.push(sym); } }); - def.orig = orig.concat(def.orig); - def.references = refs.concat(def.references); - def.fixed = tail.definition.fixed && def.fixed; + if (!head.definition.fixed) def.fixed = false; merged[id] = def; changed = true; break; - } while (last.length); - if (skipped.length) last = last.concat(skipped); + } while (first.length); + if (skipped.length) first = skipped.concat(first); } return changed; @@ -6357,6 +6348,12 @@ Compressor.prototype.compress = function(node) { function mergeable(head, tail) { return must_visit(head.start, head.end) || must_visit(head.start, tail.start); } + + function safe_to_rename(refs, def) { + return all(refs, function(sym) { + return sym.scope.find_variable(def.name) === def; + }); + } }); function fill_holes(orig, elements) { @@ -8072,9 +8069,7 @@ Compressor.prototype.compress = function(node) { return exp.drop_side_effect_free(compressor, first_in_statement); } function convert_spread(node) { - return node instanceof AST_Spread ? make_node(AST_Array, node, { - elements: [ node ] - }) : node; + return node instanceof AST_Spread ? make_node(AST_Array, node, { elements: [ node ] }) : node; } def(AST_Node, return_this); def(AST_Accessor, return_null); @@ -8396,20 +8391,20 @@ Compressor.prototype.compress = function(node) { node = alternative ? make_node(AST_Binary, this, { operator: "||", left: this.condition, - right: alternative + right: alternative, }) : this.condition.drop_side_effect_free(compressor); } else if (!alternative) { node = make_node(AST_Binary, this, { operator: "&&", left: this.condition, - right: consequent + right: consequent, }); } else { node = this.clone(); node.consequent = consequent; node.alternative = alternative; } - if (!compressor.option("ie")) return node; + if (!exprs) return node; if (node) exprs.push(node); return exprs.length == 0 ? null : make_sequence(this, exprs); }); @@ -8442,9 +8437,7 @@ Compressor.prototype.compress = function(node) { return !(node instanceof AST_Spread); })) return this; return make_sequence(this, values.map(function(node) { - return node instanceof AST_Spread ? make_node(AST_Object, node, { - properties: [ node ], - }) : node; + return node instanceof AST_Spread ? make_node(AST_Object, node, { properties: [ node ] }) : node; })); }); def(AST_ObjectIdentity, return_null); diff --git a/lib/minify.js b/lib/minify.js index b8f020408f8..aca7f5fdf25 100644 --- a/lib/minify.js +++ b/lib/minify.js @@ -78,6 +78,7 @@ function minify(files, options) { enclose: false, ie: false, ie8: false, + keep_fargs: false, keep_fnames: false, mangle: {}, nameCache: null, @@ -99,6 +100,7 @@ function minify(files, options) { if (options.annotations !== undefined) set_shorthand("annotations", options, [ "compress", "output" ]); if (options.ie8) options.ie = options.ie || options.ie8; if (options.ie) set_shorthand("ie", options, [ "compress", "mangle", "output" ]); + if (options.keep_fargs) set_shorthand("keep_fargs", options, [ "compress", "mangle" ]); if (options.keep_fnames) set_shorthand("keep_fnames", options, [ "compress", "mangle" ]); if (options.toplevel) set_shorthand("toplevel", options, [ "compress", "mangle" ]); if (options.v8) set_shorthand("v8", options, [ "mangle", "output" ]); @@ -109,6 +111,7 @@ function minify(files, options) { cache: options.nameCache && (options.nameCache.vars || {}), eval: false, ie: false, + keep_fargs: false, keep_fnames: false, properties: false, reserved: [], diff --git a/lib/scope.js b/lib/scope.js index 17665e8835d..8aa38160f70 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -92,15 +92,19 @@ SymbolDef.prototype = { if (def && def !== self) return def.redefined() || def; }, unmangleable: function(options) { - return this.global && !options.toplevel - || this.exported - || this.undeclared - || !options.eval && this.scope.pinned() - || options.keep_fnames - && (this.orig[0] instanceof AST_SymbolClass - || this.orig[0] instanceof AST_SymbolDefClass - || this.orig[0] instanceof AST_SymbolDefun - || this.orig[0] instanceof AST_SymbolLambda); + if (this.exported) return true; + if (this.undeclared) return true; + if (!options.eval && this.scope.pinned()) return true; + if (options.keep_fargs && is_funarg(this)) return true; + if (options.keep_fnames) { + var sym = this.orig[0]; + if (sym instanceof AST_SymbolClass) return true; + if (sym instanceof AST_SymbolDefClass) return true; + if (sym instanceof AST_SymbolDefun) return true; + if (sym instanceof AST_SymbolLambda) return true; + } + if (!options.toplevel && this.global) return true; + return false; }, }; @@ -113,6 +117,10 @@ DEF_BITPROPS(SymbolDef, [ "undeclared", ]); +function is_funarg(def) { + return def.orig[0] instanceof AST_SymbolFunarg || def.orig[1] instanceof AST_SymbolFunarg; +} + var unary_side_effects = makePredicate("delete ++ --"); function is_lhs(node, parent) { @@ -473,8 +481,11 @@ AST_Symbol.DEFMETHOD("mark_enclosed", function(options) { push_uniq(s.enclosed, def); if (!options) { s._var_names = undefined; - } else if (options.keep_fnames) { - s.functions.each(function(d) { + } else { + if (options.keep_fargs && s instanceof AST_Lambda) s.each_argname(function(arg) { + push_uniq(def.scope.enclosed, arg.definition()); + }); + if (options.keep_fnames) s.functions.each(function(d) { push_uniq(def.scope.enclosed, d); }); } @@ -579,6 +590,7 @@ function _default_mangler_options(options) { options = defaults(options, { eval : false, ie : false, + keep_fargs : false, keep_fnames : false, reserved : [], toplevel : false, diff --git a/test/compress/awaits.js b/test/compress/awaits.js index 5f65e3e1138..55951fa4b25 100644 --- a/test/compress/awaits.js +++ b/test/compress/awaits.js @@ -1746,10 +1746,10 @@ issue_4454_2: { f("PASS"); } expect: { - function f(b) { - (async function(c = console.log(b)) {})(); - var b = 42..toString(); - console.log(b); + function f(a) { + (async function(c = console.log(a)) {})(); + var a = 42..toString(); + console.log(a); } f("PASS"); } @@ -2449,9 +2449,9 @@ issue_5032_normal: { console.log(value); return value; } - async function f(c) { - var b = log(c), c = b; - log(b); + async function f(a) { + var a = log(a), c = a; + log(a); log(c); } f("PASS"); diff --git a/test/compress/const.js b/test/compress/const.js index 1beccfcde11..92071056abb 100644 --- a/test/compress/const.js +++ b/test/compress/const.js @@ -220,6 +220,32 @@ merge_vars_3: { expect_stdout: true } +merge_vars_4: { + options = { + merge_vars: true, + toplevel: true, + } + input: { + var a = 1; + console.log(typeof a); + { + var b = console; + console.log(typeof b); + const a = 0; + } + } + expect: { + var a = 1; + console.log(typeof a); + { + var b = console; + console.log(typeof b); + const a = 0; + } + } + expect_stdout: true +} + use_before_init_1: { options = { reduce_vars: true, diff --git a/test/compress/destructured.js b/test/compress/destructured.js index 825ac5a5beb..712083915d2 100644 --- a/test/compress/destructured.js +++ b/test/compress/destructured.js @@ -1845,13 +1845,13 @@ issue_4294: { expect: { A = "PASS"; (function() { - var b = function({ - [b]: {}, + var a = function({ + [a]: {}, }) {}({ - [b]: 0, + [a]: 0, }); - var b = A; - console.log(b); + var a = A; + console.log(a); })(); } expect_stdout: "PASS" diff --git a/test/compress/functions.js b/test/compress/functions.js index 50982230627..863f990dbea 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -7605,11 +7605,11 @@ issue_5230: { }()); } expect: { - while (void (f = function(c) { + while (void (f = function(a) { var b = 42; console; - var c; - for (var k in c = [ c ]) + var a; + for (var k in a = [ a ]) console.log(b++); })(f)); var f; diff --git a/test/compress/hoist_props.js b/test/compress/hoist_props.js index ab9a16f3c83..31c8439a686 100644 --- a/test/compress/hoist_props.js +++ b/test/compress/hoist_props.js @@ -1163,13 +1163,13 @@ issue_5182: { log(o.p(42)); } expect: { - var o_p = console; - log = o_p.log; - o_p = function(a) { + var o = console; + log = o.log; + o = function(a) { console.log(a ? "PASS" : "FAIL"); return a; }; - log(o_p(42)); + log(o(42)); } expect_stdout: [ "PASS", diff --git a/test/compress/ie.js b/test/compress/ie.js index 284a8cccd79..e346a086966 100644 --- a/test/compress/ie.js +++ b/test/compress/ie.js @@ -3109,9 +3109,9 @@ issue_5081_call: { })); } expect: { - function f(b) { + function f(a) { // IE5-10: TypeError: Function expected - return b(b = "A") + (b += "SS"); + return a(a = "A") + (a += "SS"); } console.log(f(function() { return "P"; @@ -3161,8 +3161,8 @@ issue_5081_property_access: { console.log(f({ A: "P" })); } expect: { - function f(b) { - return b[b = "A"] + (b += "SS"); + function f(a) { + return a[a = "A"] + (a += "SS"); } // IE9-11: undefinedASS console.log(f({ A: "P" })); diff --git a/test/compress/keep_fargs.js b/test/compress/keep_fargs.js index 7c78ad20aab..93c431b9118 100644 --- a/test/compress/keep_fargs.js +++ b/test/compress/keep_fargs.js @@ -925,6 +925,28 @@ duplicate_lambda_defun_name_2: { expect_stdout: "0" } +function_argument_mangle: { + mangle = { + keep_fargs: true, + toplevel: true, + } + input: { + A = "PASS"; + var a = A; + (function(o) { + console.log(a); + })("FAIL"); + } + expect: { + A = "PASS"; + var n = A; + (function(o) { + console.log(n); + })("FAIL"); + } + expect_stdout: "PASS" +} + function_name_mangle: { options = { keep_fargs: false, diff --git a/test/compress/let.js b/test/compress/let.js index 1942fdec8df..6e9cdb63876 100644 --- a/test/compress/let.js +++ b/test/compress/let.js @@ -280,6 +280,38 @@ merge_vars_3: { node_version: ">=4" } +merge_vars_4: { + options = { + merge_vars: true, + toplevel: true, + } + input: { + "use strict"; + var a = 1; + console.log(typeof a); + { + var b = console; + console.log(typeof b); + let a = 0; + } + } + expect: { + "use strict"; + var a = 1; + console.log(typeof a); + { + var b = console; + console.log(typeof b); + let a = 0; + } + } + expect_stdout: [ + "number", + "object", + ] + node_version: ">=4" +} + use_before_init_1: { options = { evaluate: true, diff --git a/test/compress/merge_vars.js b/test/compress/merge_vars.js index a0ece252c0e..d5a636c9e18 100644 --- a/test/compress/merge_vars.js +++ b/test/compress/merge_vars.js @@ -19,11 +19,11 @@ merge: { expect: { var a = "foo"; console.log(a); - function f(c) { - var c; - console.log(c); - c = "bar"; - console.log(c); + function f(b) { + var b; + console.log(b); + b = "bar"; + console.log(b); } f("baz"); var d = "moo"; @@ -56,17 +56,17 @@ merge_toplevel: { console.log(d); } expect: { - var d = "foo"; - console.log(d); - function f(c) { - var c; - console.log(c); - c = "bar"; - console.log(c); + var a = "foo"; + console.log(a); + function f(b) { + var b; + console.log(b); + b = "bar"; + console.log(b); } f("baz"); - var d = "moo"; - console.log(d); + var a = "moo"; + console.log(a); } expect_stdout: [ "foo", @@ -94,16 +94,16 @@ segment: { console.log(d); } expect: { - var d = "foo"; - console.log(d); - for (var c, i = 0; i < 1; i++) { - var c = "bar"; - console.log(c); - c = "baz"; - console.log(c); + var a = "foo"; + console.log(a); + for (var b, i = 0; i < 1; i++) { + var b = "bar"; + console.log(b); + b = "baz"; + console.log(b); } - var d = "moo"; - console.log(d); + var a = "moo"; + console.log(a); } expect_stdout: [ "foo", @@ -298,6 +298,89 @@ read_before_assign_2: { expect_stdout: "PASS" } +collapse_vars_1: { + options = { + collapse_vars: true, + merge_vars: true, + toplevel: true, + } + input: { + var a = a && a.p; + var b = "PASS"; + var b = b && console.log(b); + } + expect: { + var a = a && a.p; + var a; + var a = (a = "PASS") && console.log(a); + } + expect_stdout: "PASS" +} + +collapse_vars_2: { + options = { + collapse_vars: true, + merge_vars: true, + } + input: { + "use strict"; + var log = console.log; + (function g(a) { + var b = a; + var c = Math.random(); + var c = b; + log(c); + return c; + })("PASS"); + } + expect: { + "use strict"; + var log = console.log; + (function g(a) { + var a = a; + var c = Math.random(); + var c; + log(c = a); + return c; + })("PASS"); + } + expect_stdout: "PASS" +} + +not_redefined: { + options = { + inline: true, + join_vars: true, + merge_vars: true, + reduce_vars: true, + unused: true, + varify: true, + } + input: { + var log = console.log; + (function() { + return f("PASS"); + function f(a) { + const b = a; + const c = log(b); + const d = log; + c && log(d); + } + })(); + } + expect: { + var log = console.log; + (function() { + return a = "PASS", + a = log(a), + d = log, + void (a && log(d)); + var a, d; + })(); + } + expect_stdout: "PASS" +} + issue_4103: { options = { merge_vars: true, @@ -325,7 +408,7 @@ issue_4103: { ] } -issue_4107: { +issue_4107_1: { options = { keep_fargs: false, merge_vars: true, @@ -342,6 +425,38 @@ issue_4107: { })(); console.log(typeof a); } + expect: { + (function() { + (function(c) { + c = console || c; + console.log(typeof c); + })(); + })(); + console.log(typeof a); + } + expect_stdout: [ + "object", + "undefined", + ] +} + +issue_4107_2: { + options = { + keep_fargs: false, + merge_vars: true, + reduce_vars: true, + unused: true, + } + input: { + (function() { + function f(b, b, a) { + var d = 1 && c, c = console || a; + console.log(typeof c); + } + f(); + })(); + console.log(typeof a); + } expect: { (function() { (function(a) { @@ -538,12 +653,12 @@ cross_branch_1_1: { expect: { var a; function f() { - var y, y; + var x, x; if (a) - y = "foo"; - console.log(y); - y = "bar"; - console.log(y); + x = "foo"; + console.log(x); + x = "bar"; + console.log(x); } a = 0; f(); @@ -581,13 +696,13 @@ cross_branch_1_2: { expect: { var a; function f() { - var y, y; + var x, x; if (a) { - y = "foo"; - console.log(y); + x = "foo"; + console.log(x); } - y = "bar"; - console.log(y); + x = "bar"; + console.log(x); } a = 0; f(); @@ -624,13 +739,13 @@ cross_branch_1_3: { expect: { var a; function f() { - var y, y; + var x, x; if (a) { - y = "foo"; - console.log(y); - y = "bar"; + x = "foo"; + console.log(x); + x = "bar"; } - console.log(y); + console.log(x); } a = 0; f(); @@ -666,12 +781,12 @@ cross_branch_1_4: { expect: { var a; function f() { - var y, y; - y = "foo"; + var x, x; + x = "foo"; if (a) - console.log(y); - y = "bar"; - console.log(y); + console.log(x); + x = "bar"; + console.log(x); } a = 0; f(); @@ -751,12 +866,12 @@ cross_branch_1_6: { expect: { var a; function f() { - var y, y; - y = "foo"; + var x, x; + x = "foo"; if (a) { - console.log(y); - y = "bar"; - console.log(y); + console.log(x); + x = "bar"; + console.log(x); } } a = 0; @@ -835,12 +950,12 @@ cross_branch_1_8: { expect: { var a; function f() { - var y, y; - y = "foo"; - console.log(y); + var x, x; + x = "foo"; + console.log(x); if (a) { - y = "bar"; - console.log(y); + x = "bar"; + console.log(x); } } a = 0; @@ -877,12 +992,12 @@ cross_branch_1_9: { expect: { var a; function f() { - var y, y; - y = "foo"; - console.log(y); - y = "bar"; + var x, x; + x = "foo"; + console.log(x); + x = "bar"; if (a) - console.log(y); + console.log(x); } a = 0; f(); @@ -924,14 +1039,14 @@ cross_branch_2a_1: { expect: { var a, b; function f() { - var y, y; + var x, x; if (a) { if (b) - y = "foo"; - console.log(y); + x = "foo"; + console.log(x); } - y = "bar"; - console.log(y); + x = "bar"; + console.log(x); } a = 0, b = 0; f(); @@ -980,14 +1095,14 @@ cross_branch_2a_2: { expect: { var a, b; function f() { - var y, y; + var x, x; if (a) { - y = "foo"; + x = "foo"; if (b) - console.log(y); + console.log(x); } - y = "bar"; - console.log(y); + x = "bar"; + console.log(x); } a = 0, b = 0; f(); @@ -1035,14 +1150,14 @@ cross_branch_2a_3: { expect: { var a, b; function f() { - var y, y; + var x, x; if (a) { if (b) - y = "foo"; - console.log(y); - y = "bar"; + x = "foo"; + console.log(x); + x = "bar"; } - console.log(y); + console.log(x); } a = 0, b = 0; f(); @@ -1092,15 +1207,15 @@ cross_branch_2a_4: { expect: { var a, b; function f() { - var y, y; + var x, x; if (a) { if (b) { - y = "foo"; - console.log(y); + x = "foo"; + console.log(x); } - y = "bar"; + x = "bar"; } - console.log(y); + console.log(x); } a = 0, b = 0; f(); @@ -1148,14 +1263,14 @@ cross_branch_2a_5: { expect: { var a, b; function f() { - var y, y; + var x, x; if (a) { - y = "foo"; + x = "foo"; if (b) - console.log(y); - y = "bar"; + console.log(x); + x = "bar"; } - console.log(y); + console.log(x); } a = 0, b = 0; f(); @@ -1427,13 +1542,13 @@ cross_branch_2a_10: { expect: { var a, b; function f() { - var y, y; - y = "foo"; + var x, x; + x = "foo"; if (a) { if (b) - console.log(y); - y = "bar"; - console.log(y); + console.log(x); + x = "bar"; + console.log(x); } } a = 0, b = 0; @@ -1590,13 +1705,13 @@ cross_branch_2a_13: { expect: { var a, b; function f() { - var y, y; - y = "foo"; + var x, x; + x = "foo"; if (a) { - console.log(y); + console.log(x); if (b) { - y = "bar"; - console.log(y); + x = "bar"; + console.log(x); } } } @@ -1644,13 +1759,13 @@ cross_branch_2a_14: { expect: { var a, b; function f() { - var y, y; - y = "foo"; + var x, x; + x = "foo"; if (a) { - console.log(y); - y = "bar"; + console.log(x); + x = "bar"; if (b) - console.log(y); + console.log(x); } } a = 0, b = 0; @@ -1753,13 +1868,13 @@ cross_branch_2a_16: { expect: { var a, b; function f() { - var y, y; - y = "foo"; - console.log(y); + var x, x; + x = "foo"; + console.log(x); if (a) { - y = "bar"; + x = "bar"; if (b) - console.log(y); + console.log(x); } } a = 0, b = 0; @@ -1807,13 +1922,13 @@ cross_branch_2b_1: { expect: { var a, b; function f() { - var y, y; + var x, x; if (a) - y = "foo"; + x = "foo"; if (b) - console.log(y); - y = "bar"; - console.log(y); + console.log(x); + x = "bar"; + console.log(x); } a = 0, b = 0; f(); @@ -1918,13 +2033,13 @@ cross_branch_2b_3: { expect: { var a, b; function f() { - var y, y; + var x, x; if (a) - y = "foo"; + x = "foo"; if (b) { - console.log(y); - y = "bar"; - console.log(y); + console.log(x); + x = "bar"; + console.log(x); } } a = 0, b = 0; @@ -2028,13 +2143,13 @@ cross_branch_2b_5: { expect: { var a, b; function f() { - var y, y; + var x, x; if (a) - y = "foo"; - console.log(y); + x = "foo"; + console.log(x); if (b) { - y = "bar"; - console.log(y); + x = "bar"; + console.log(x); } } a = 0, b = 0; @@ -2141,14 +2256,14 @@ cross_branch_2b_7: { expect: { var a, b; function f() { - var y, y; + var x, x; if (a) { - y = "foo"; - console.log(y); + x = "foo"; + console.log(x); } if (b) { - y = "bar"; - console.log(y); + x = "bar"; + console.log(x); } } a = 0, b = 0; @@ -2195,13 +2310,13 @@ cross_branch_2b_8: { expect: { var a, b; function f() { - var y, y; + var x, x; if (a) - y = "foo"; - console.log(y); - y = "bar"; + x = "foo"; + console.log(x); + x = "bar"; if (b) - console.log(y); + console.log(x); } a = 0, b = 0; f(); @@ -2250,14 +2365,14 @@ cross_branch_2b_9: { expect: { var a, b; function f() { - var y, y; + var x, x; if (a) { - y = "foo"; - console.log(y); + x = "foo"; + console.log(x); } - y = "bar"; + x = "bar"; if (b) - console.log(y); + console.log(x); } a = 0, b = 0; f(); @@ -2304,14 +2419,14 @@ cross_branch_2b_10: { expect: { var a, b; function f() { - var y, y; + var x, x; if (a) { - y = "foo"; - console.log(y); - y = "bar"; + x = "foo"; + console.log(x); + x = "bar"; } if (b) - console.log(y); + console.log(x); } a = 0, b = 0; f(); @@ -2412,13 +2527,13 @@ cross_branch_2b_12: { expect: { var a, b; function f() { - var y, y; - y = "foo"; + var x, x; + x = "foo"; if (a) - console.log(y); + console.log(x); if (b) { - y = "bar"; - console.log(y); + x = "bar"; + console.log(x); } } a = 0, b = 0; @@ -2465,13 +2580,13 @@ cross_branch_2b_13: { expect: { var a, b; function f() { - var y, y; - y = "foo"; + var x, x; + x = "foo"; if (a) - console.log(y); - y = "bar"; + console.log(x); + x = "bar"; if (b) - console.log(y); + console.log(x); } a = 0, b = 0; f(); @@ -2620,11 +2735,11 @@ issue_4126_1: { try { console.log("PASS"); } catch (e) { - var c = a; + var b = a; } finally { - var c = c; + var a = b; } - console.log(c); + console.log(a); } f("FAIL"); } @@ -2816,11 +2931,11 @@ conditional_write: { console.log(b); } expect: { - var b = "FAIL", b; + var a = "FAIL", a; if (console) - b = "PASS"; - b = [b, 42].join(); - console.log(b); + a = "PASS"; + a = [a, 42].join(); + console.log(a); } expect_stdout: "PASS,42" } @@ -2994,13 +3109,13 @@ issue_4168_use_strict: { expect: { "use strict"; var o = { - f: function(d, e, f) { - var d = d.d; - var e = e.e; - var f = f.f; + f: function(a, b, c) { + var a = a.d; + var b = b.e; + var c = c.f; this.g(arguments); - if (d) - console.log(e, f); + if (a) + console.log(b, c); }, g: function(args) { console.log(args[0], args[1], args[2]); diff --git a/test/compress/optional-chains.js b/test/compress/optional-chains.js index b6ffc22f11f..fcff9a8a94d 100644 --- a/test/compress/optional-chains.js +++ b/test/compress/optional-chains.js @@ -457,11 +457,11 @@ issue_5091: { console.log(f("FAIL 1") || "PASS"); } expect: { - function f(b) { - var b = b.p; + function f(a) { + var a = a.p; var c; - b?.[c = "FAIL 2"]; - return b || c; + a?.[c = "FAIL 2"]; + return a || c; } console.log(f("FAIL 1") || "PASS"); } diff --git a/test/compress/rests.js b/test/compress/rests.js index 33584216044..9a32bccef7e 100644 --- a/test/compress/rests.js +++ b/test/compress/rests.js @@ -436,9 +436,9 @@ merge_funarg: { })(); } expect: { - (function(...b) { - var b = b.length; - console.log(b); + (function(...a) { + var a = a.length; + console.log(a); })(); } expect_stdout: "0" @@ -456,9 +456,9 @@ merge_funarg_destructured_array: { })([]); } expect: { - (function([ ...b ]) { - var b = b.length; - console.log(b); + (function([ ...a ]) { + var a = a.length; + console.log(a); })([]); } expect_stdout: "0" @@ -476,9 +476,9 @@ merge_funarg_destructured_object: { })([ "PASS" ]); } expect: { - (function({ ...b }) { - var b = b[0]; - console.log(b); + (function({ ...a }) { + var a = a[0]; + console.log(a); })([ "PASS" ]); } expect_stdout: "PASS" diff --git a/test/compress/varify.js b/test/compress/varify.js index 4a90a955fd0..0bc9ada2563 100644 --- a/test/compress/varify.js +++ b/test/compress/varify.js @@ -13,10 +13,10 @@ reduce_merge_const: { console.log(b); } expect: { - var b = console; - console.log(typeof b); - b = typeof b; - console.log(b); + var a = console; + console.log(typeof a); + a = typeof a; + console.log(a); } expect_stdout: [ "object", @@ -41,10 +41,10 @@ reduce_merge_let: { } expect: { "use strict"; - var b = console; - console.log(typeof b); - b = typeof b; - console.log(b); + var a = console; + console.log(typeof a); + a = typeof a; + console.log(a); } expect_stdout: [ "object", diff --git a/test/compress/yields.js b/test/compress/yields.js index 0b90a5f7e49..39a4eca9dc8 100644 --- a/test/compress/yields.js +++ b/test/compress/yields.js @@ -976,10 +976,10 @@ issue_4454_2: { f("PASS"); } expect: { - function f(b) { - (function*(c = console.log(b)) {})(); - var b = 42..toString(); - console.log(b); + function f(a) { + (function*(c = console.log(a)) {})(); + var a = 42..toString(); + console.log(a); } f("PASS"); } @@ -1289,9 +1289,9 @@ issue_5032_normal: { console.log(value); return value; } - function *f(c) { - var b = log(c), c = b; - log(b); + function *f(a) { + var a = log(a), c = a; + log(a); log(c); } f("PASS").next(); diff --git a/test/mocha/cli.js b/test/mocha/cli.js index 66fe3a4f8dd..6e9f124a9f6 100644 --- a/test/mocha/cli.js +++ b/test/mocha/cli.js @@ -188,6 +188,30 @@ describe("bin/uglifyjs", function() { child.stdin.end(read("test/input/issue-3040/input.js")); }, 1000); }); + it("Should work with --keep-fargs (mangle only)", function(done) { + var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fargs -m'; + exec(command, function(err, stdout) { + if (err) throw err; + assert.strictEqual(stdout, "function f(x){return function(){function n(a){return a*a}return x(n)}}function g(op){return op(1)+op(2)}console.log(f(g)()==5);\n"); + done(); + }); + }); + it("Should work with --keep-fargs (mangle & compress)", function(done) { + var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fargs -m -c'; + exec(command, function(err, stdout) { + if (err) throw err; + assert.strictEqual(stdout, "function f(x){return function(){return x(function(a){return a*a})}}function g(op){return op(1)+op(2)}console.log(5==f(g)());\n"); + done(); + }); + }); + it("Should work with keep_fargs under mangler options", function(done) { + var command = uglifyjscmd + ' test/input/issue-1431/sample.js -m keep_fargs=true'; + exec(command, function(err, stdout) { + if (err) throw err; + assert.strictEqual(stdout, "function f(x){return function(){function n(a){return a*a}return x(n)}}function g(op){return op(1)+op(2)}console.log(f(g)()==5);\n"); + done(); + }); + }); it("Should work with --keep-fnames (mangle only)", function(done) { var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m'; exec(command, function(err, stdout) { @@ -197,10 +221,10 @@ describe("bin/uglifyjs", function() { }); }); it("Should work with --keep-fnames (mangle & compress)", function(done) { - var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c unused=false'; + var command = uglifyjscmd + ' test/input/issue-1431/sample.js --keep-fnames -m -c'; exec(command, function(err, stdout) { if (err) throw err; - assert.strictEqual(stdout, "function f(r){return function(){function n(n){return n*n}return r(n)}}function g(n){return n(1)+n(2)}console.log(5==f(g)());\n"); + assert.strictEqual(stdout, "function f(n){return function(){return n(function n(r){return r*r})}}function g(n){return n(1)+n(2)}console.log(5==f(g)());\n"); done(); }); }); diff --git a/test/ufuzz/options.json b/test/ufuzz/options.json index ba84029b48d..521ba00e292 100644 --- a/test/ufuzz/options.json +++ b/test/ufuzz/options.json @@ -26,6 +26,7 @@ "passes": 1e6, "unsafe": true }, + "keep_fargs": true, "keep_fnames": true, "toplevel": true },