From: Alex Lam S.L Date: Sat, 30 Nov 2019 18:31:04 +0000 (+0800) Subject: enhance `collapse_vars` (#3616) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=0593892d6efeee15b54bc91bdd0ef1224a466541;p=UglifyJS.git enhance `collapse_vars` (#3616) --- diff --git a/lib/compress.js b/lib/compress.js index 34700d4a..6a76fc32 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -1147,7 +1147,7 @@ merge(Compressor.prototype, { && (scan_lhs && lhs.equivalent_to(node) || scan_rhs && (hit_rhs = scan_rhs(node, this)))) { if (stop_if_hit && (hit_rhs || !lhs_local || !replace_all)) { - abort = true; + if (!hit_rhs || !value_def) abort = true; return node; } if (is_lhs(node, parent)) { @@ -1541,14 +1541,27 @@ merge(Compressor.prototype, { function find_stop(node, level) { var parent = scanner.parent(level); if (parent instanceof AST_Array) return value_def ? find_stop(parent, level + 1) : node; - if (parent instanceof AST_Assign) return node; + if (parent instanceof AST_Assign) { + if (!value_def) return node; + if (lhs.equivalent_to(parent.left)) return node; + if (get_rvalue(candidate).equivalent_to(parent.left)) return node; + return find_stop(parent, level + 1); + } if (parent instanceof AST_Binary) { - if (!value_def || parent.left !== node) return node; + if (!value_def) return node; + if (lazy_op[parent.operator] && parent.left !== node) { + var grandparent = scanner.parent(level + 1); + if (!(grandparent instanceof AST_Binary)) return node; + if (grandparent.operator != parent.operator) return node; + } return find_stop(parent, level + 1); } - if (parent instanceof AST_Call) return node; + if (parent instanceof AST_Call) return value_def ? parent : node; if (parent instanceof AST_Case) return node; - if (parent instanceof AST_Conditional) return node; + if (parent instanceof AST_Conditional) { + if (!value_def || parent.condition !== node) return node; + return find_stop(parent, level + 1); + } if (parent instanceof AST_Definitions) return find_stop_unused(parent, level + 1); if (parent instanceof AST_Exit) return node; if (parent instanceof AST_If) return node; @@ -1562,7 +1575,10 @@ merge(Compressor.prototype, { } if (parent instanceof AST_SimpleStatement) return find_stop_unused(parent, level + 1); if (parent instanceof AST_Switch) return node; - if (parent instanceof AST_Unary) return node; + if (parent instanceof AST_Unary) { + if (parent.operator == "delete") return node; + return value_def ? find_stop(parent, level + 1) : node; + } if (parent instanceof AST_VarDef) return node; return null; } diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index 20bbfea2..75dddb02 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -6965,3 +6965,330 @@ setter_side_effect: { } expect_stdout: "PASS" } + +substitution_assign: { + options = { + collapse_vars: true, + } + input: { + function f1(a, b) { + f1 = b = a; + console.log(a, b); + } + function f2(a, b) { + a = 1 + (b = a); + console.log(a, b); + } + function f3(a, b) { + b = 1 + (b = a); + console.log(a, b); + } + f1(42, "foo"); + f2(42, "foo"); + f3(42, "foo"); + } + expect: { + function f1(a, b) { + f1 = a; + console.log(a, a); + } + function f2(a, b) { + a = 1 + (b = a); + console.log(a, b); + } + function f3(a, b) { + b = 1 + (b = a); + console.log(a, b); + } + f1(42, "foo"); + f2(42, "foo"); + f3(42, "foo"); + } + expect_stdout: [ + "42 42", + "43 42", + "42 43", + ] +} + +substitution_arithmetic: { + options = { + collapse_vars: true, + } + input: { + function f1(a, b) { + console.log((b = a) + a, b); + } + function f2(a, b) { + console.log(a - (b = a), b); + } + function f3(a, b) { + console.log(a / (b = a) + b, b); + } + f1(42, "foo"); + f2(42, "foo"); + f3(42, "foo"); + } + expect: { + function f1(a, b) { + console.log(a + a, a); + } + function f2(a, b) { + console.log(a - a, a); + } + function f3(a, b) { + console.log(a / a + a, a); + } + f1(42, "foo"); + f2(42, "foo"); + f3(42, "foo"); + } + expect_stdout: [ + "84 42", + "0 42", + "43 42", + ] +} + +substitution_logical_1: { + options = { + collapse_vars: true, + } + input: { + function f1(a, b) { + console.log((b = a) && a, b); + } + function f2(a, b) { + console.log(a && (b = a), b); + } + f1(42, "foo"); + f1(null, true); + f2(42, "foo"); + f2(null, true); + } + expect: { + function f1(a, b) { + console.log(a && a, a); + } + function f2(a, b) { + console.log(a && (b = a), b); + } + f1(42, "foo"); + f1(null, true); + f2(42, "foo"); + f2(null, true); + } + expect_stdout: [ + "42 42", + "null null", + "42 42", + "null true" + ] +} + +substitution_logical_2: { + options = { + collapse_vars: true, + } + input: { + function f1(a, b) { + console.log((b = a) && a && b); + } + function f2(a, b) { + console.log((b = a) && a || b); + } + function f3(a, b) { + console.log((b = a) || a && b); + } + function f4(a, b) { + console.log((b = a) || a || b); + } + f1(42, "foo"); + f1(null, true); + f2(42, "foo"); + f2(null, true); + f3(42, "foo"); + f3(null, true); + f4(42, "foo"); + f4(null, true); + } + expect: { + function f1(a, b) { + console.log(a && a && a); + } + function f2(a, b) { + console.log(a && a || a); + } + function f3(a, b) { + console.log(a || a && a); + } + function f4(a, b) { + console.log(a || a || a); + } + f1(42, "foo"); + f1(null, true); + f2(42, "foo"); + f2(null, true); + f3(42, "foo"); + f3(null, true); + f4(42, "foo"); + f4(null, true); + } + expect_stdout: [ + "42", + "null", + "42", + "null", + "42", + "null", + "42", + "null", + ] +} + +substitution_logical_3: { + options = { + collapse_vars: true, + } + input: { + function f1(a, b) { + console.log(a && (b = a) && b); + } + function f2(a, b) { + console.log(a && (b = a) || b); + } + function f3(a, b) { + console.log(a || (b = a) && b); + } + function f4(a, b) { + console.log(a || (b = a) || b); + } + f1(42, "foo"); + f1(null, true); + f2(42, "foo"); + f2(null, true); + f3(42, "foo"); + f3(null, true); + f4(42, "foo"); + f4(null, true); + } + expect: { + function f1(a, b) { + console.log(a && a && a); + } + function f2(a, b) { + console.log(a && (b = a) || b); + } + function f3(a, b) { + console.log(a || a && a); + } + function f4(a, b) { + console.log(a || a || a); + } + f1(42, "foo"); + f1(null, true); + f2(42, "foo"); + f2(null, true); + f3(42, "foo"); + f3(null, true); + f4(42, "foo"); + f4(null, true); + } + expect_stdout: [ + "42", + "null", + "42", + "true", + "42", + "null", + "42", + "null", + ] +} + +substitution_conditional: { + options = { + collapse_vars: true, + } + input: { + function f1(a, b) { + console.log((b = a) ? a : b, a, b); + } + function f2(a, b) { + console.log(a ? b = a : b, a, b); + } + function f3(a, b) { + console.log(a ? a : b = a, a, b); + } + f1("foo", "bar"); + f1(null, true); + f2("foo", "bar"); + f2(null, true); + f3("foo", "bar"); + f3(null, true); + } + expect: { + function f1(a, b) { + console.log(a ? a : a, a, a); + } + function f2(a, b) { + console.log(a ? b = a : b, a, b); + } + function f3(a, b) { + console.log(a ? a : b = a, a, b); + } + f1("foo", "bar"); + f1(null, true); + f2("foo", "bar"); + f2(null, true); + f3("foo", "bar"); + f3(null, true); + } + expect_stdout: [ + "foo foo foo", + "null null null", + "foo foo foo", + "true null true", + "foo foo bar", + "null null null", + ] +} + +substitution_unary: { + options = { + collapse_vars: true, + } + input: { + function f1(a, b) { + console.log(typeof (b = a), a, b); + } + function f2(a, b) { + console.log(void (b = a), a, b); + } + function f3(a, b) { + console.log(delete (b = a), a, b); + } + f1(42, "foo"); + f2(42, "foo"); + f3(42, "foo"); + } + expect: { + function f1(a, b) { + console.log(typeof a, a, a); + } + function f2(a, b) { + console.log(void a, a, a); + } + function f3(a, b) { + console.log(delete (b = a), a, b); + } + f1(42, "foo"); + f2(42, "foo"); + f3(42, "foo"); + } + expect_stdout: [ + "number 42 42", + "undefined 42 42", + "true 42 42", + ] +}