enhance `collapse_vars` (#3621)
authorAlex Lam S.L <alexlamsl@gmail.com>
Mon, 2 Dec 2019 07:25:38 +0000 (15:25 +0800)
committerGitHub <noreply@github.com>
Mon, 2 Dec 2019 07:25:38 +0000 (15:25 +0800)
lib/compress.js
test/compress/collapse_vars.js

index 2c60a9b..e18fd57 100644 (file)
@@ -1124,7 +1124,7 @@ merge(Compressor.prototype, {
                     hit_index++;
                     if (hit_index < hit_stack.length) return handle_custom_scan_order(node);
                     hit = true;
-                    stop_after = find_stop(node, 0);
+                    stop_after = (value_def ? find_stop_value : find_stop)(node, 0);
                     if (stop_after === node) abort = true;
                     return node;
                 }
@@ -1540,46 +1540,95 @@ 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_Array) return node;
+                if (parent instanceof AST_Assign) return node;
+                if (parent instanceof AST_Binary) return node;
+                if (parent instanceof AST_Call) return node;
+                if (parent instanceof AST_Case) return node;
+                if (parent instanceof AST_Conditional) return node;
+                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;
+                if (parent instanceof AST_IterationStatement) return node;
+                if (parent instanceof AST_ObjectKeyVal) return node;
+                if (parent instanceof AST_PropAccess) return node;
+                if (parent instanceof AST_Sequence) {
+                    return (parent.tail_node() === node ? find_stop : find_stop_unused)(parent, level + 1);
+                }
+                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_VarDef) return node;
+                return null;
+            }
+
+            function find_stop_value(node, level) {
+                var parent = scanner.parent(level);
+                if (parent instanceof AST_Array) return find_stop_value(parent, level + 1);
                 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.left instanceof AST_SymbolRef) {
+                        var name = parent.left.name;
+                        if (lhs.name == name) return node;
+                        if (value_def.name == name) return node;
+                    }
+                    return find_stop_value(parent, level + 1);
                 }
                 if (parent instanceof AST_Binary) {
-                    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);
+                    return find_stop_value(parent, level + 1);
+                }
+                if (parent instanceof AST_Call) return parent;
+                if (parent instanceof AST_Case) {
+                    if (parent.expression !== node) return node;
+                    return find_stop_value(parent, level + 1);
                 }
-                if (parent instanceof AST_Call) return value_def ? parent : node;
-                if (parent instanceof AST_Case) return node;
                 if (parent instanceof AST_Conditional) {
-                    if (!value_def || parent.condition !== node) return node;
-                    return find_stop(parent, level + 1);
+                    if (parent.condition !== node) return node;
+                    return find_stop_value(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;
-                if (parent instanceof AST_IterationStatement) return node;
-                if (parent instanceof AST_ObjectKeyVal) {
-                    return value_def ? find_stop(scanner.parent(level + 1), level + 2) : node;
+                if (parent instanceof AST_Do) return node;
+                if (parent instanceof AST_Exit) return find_stop_unused(parent, level + 1);
+                if (parent instanceof AST_For) {
+                    if (parent.init !== node && parent.condition !== node) return node;
+                    return find_stop_value(parent, level + 1);
                 }
-                if (parent instanceof AST_PropAccess) return node;
+                if (parent instanceof AST_ForIn) {
+                    if (parent.init !== node) return node;
+                    return find_stop_value(parent, level + 1);
+                }
+                if (parent instanceof AST_If) {
+                    if (parent.condition !== node) return node;
+                    return find_stop_value(parent, level + 1);
+                }
+                if (parent instanceof AST_ObjectKeyVal) return find_stop_value(scanner.parent(level + 1), level + 2);
+                if (parent instanceof AST_PropAccess) return find_stop_value(parent, level + 1);
                 if (parent instanceof AST_Sequence) {
-                    return (parent.tail_node() === node ? find_stop : find_stop_unused)(parent, level + 1);
+                    return (parent.tail_node() === node ? find_stop_value : find_stop_unused)(parent, level + 1);
                 }
                 if (parent instanceof AST_SimpleStatement) return find_stop_unused(parent, level + 1);
-                if (parent instanceof AST_Switch) return node;
+                if (parent instanceof AST_Switch) {
+                    if (parent.expression !== node) return node;
+                    return find_stop_value(parent, level + 1);
+                }
                 if (parent instanceof AST_Unary) {
                     if (parent.operator == "delete") return node;
-                    return value_def ? find_stop(parent, level + 1) : node;
+                    return find_stop_value(parent, level + 1);
+                }
+                if (parent instanceof AST_VarDef) {
+                    var name = parent.name.name;
+                    if (lhs.name == name) return node;
+                    if (value_def.name == name) return node;
+                    return find_stop_value(parent, level + 1);
+                }
+                if (parent instanceof AST_While) {
+                    if (parent.condition !== node) return node;
+                    return find_stop_value(parent, level + 1);
                 }
-                if (parent instanceof AST_VarDef) return node;
                 return null;
             }
 
index 58325be..cc6c5f9 100644 (file)
@@ -2578,6 +2578,23 @@ chained_3: {
     expect_stdout: "2"
 }
 
+chained_4: {
+    options = {
+        collapse_vars: true,
+    }
+    input: {
+        var a = "foo", b = 42;
+        var b = void (b = a);
+        console.log(a, b);
+    }
+    expect: {
+        var a = "foo", b = 42;
+        var b = void (b = a);
+        console.log(a, b);
+    }
+    expect_stdout: "foo undefined"
+}
+
 boolean_binary_1: {
     options = {
         collapse_vars: true,