fix various corner cases (#3123)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sat, 5 May 2018 05:17:50 +0000 (13:17 +0800)
committerGitHub <noreply@github.com>
Sat, 5 May 2018 05:17:50 +0000 (13:17 +0800)
lib/compress.js
test/compress/collapse_vars.js
test/compress/reduce_vars.js

index 31747c9..bdce24b 100644 (file)
@@ -355,20 +355,18 @@ merge(Compressor.prototype, {
             } else {
                 def.fixed = false;
             }
-            if (def.init instanceof AST_Defun && !all(def.references, same_defun_scope)) {
+            if (def.init instanceof AST_Defun && !all(def.references, function(ref) {
+                var scope = ref.scope;
+                do {
+                    if (def.scope === scope) return true;
+                } while (scope instanceof AST_Function && (scope = scope.parent_scope));
+            })) {
                 tw.defun_ids[def.id] = undefined;
             }
             def.recursive_refs = 0;
             def.references = [];
             def.should_replace = undefined;
             def.single_use = undefined;
-
-            function same_defun_scope(ref) {
-                var scope = ref.scope;
-                do {
-                    if (def.scope === scope) return true;
-                } while (scope instanceof AST_Function && (scope = scope.parent_scope));
-            }
         }
 
         function reset_variables(tw, compressor, scope) {
@@ -384,11 +382,11 @@ merge(Compressor.prototype, {
             });
         }
 
-        function walk_defun(tw, def) {
-            if (def.id in tw.defun_ids) return;
+        function mark_defun(tw, def) {
+            if (def.id in tw.defun_ids) return def.fixed;
             if (!tw.in_loop) {
-                tw.defun_ids[def.id] = true;
-                def.fixed.walk(tw);
+                tw.defun_ids[def.id] = tw.safe_ids;
+                return def.fixed;
             } else if (tw.defun_ids[def.id] !== false) {
                 tw.defun_ids[def.id] = undefined;
             }
@@ -397,7 +395,7 @@ merge(Compressor.prototype, {
         function walk_defuns(tw, scope) {
             scope.functions.each(function(def) {
                 if (def.init instanceof AST_Defun && tw.defun_ids[def.id] === undefined) {
-                    tw.defun_ids[def.id] = true;
+                    tw.defun_ids[def.id] = tw.safe_ids;
                     def.init.walk(tw);
                 }
             });
@@ -536,11 +534,14 @@ merge(Compressor.prototype, {
             return true;
         });
         def(AST_Call, function(tw, descend) {
-            descend();
             var exp = this.expression;
-            if (exp instanceof AST_SymbolRef && exp.fixed_value() instanceof AST_Defun) {
-                walk_defun(tw, exp.definition());
-            }
+            if (!(exp instanceof AST_SymbolRef)) return;
+            var def = exp.definition();
+            if (!(def.fixed instanceof AST_Defun)) return;
+            var defun = mark_defun(tw, def);
+            if (!defun) return;
+            descend();
+            defun.walk(tw);
             return true;
         });
         def(AST_Case, function(tw) {
@@ -570,7 +571,7 @@ merge(Compressor.prototype, {
         });
         def(AST_Defun, function(tw, descend, compressor) {
             var id = this.name.definition().id;
-            if (!tw.defun_ids[id]) return true;
+            if (tw.defun_ids[id] !== tw.safe_ids) return true;
             tw.defun_ids[id] = false;
             this.inlined = false;
             push(tw);
@@ -707,7 +708,8 @@ merge(Compressor.prototype, {
             var parent;
             if (d.fixed instanceof AST_Defun
                 && !((parent = tw.parent()) instanceof AST_Call && parent.expression === this)) {
-                walk_defun(tw, d);
+                var defun = mark_defun(tw, d);
+                if (defun) defun.walk(tw);
             }
         });
         def(AST_Toplevel, function(tw, descend, compressor) {
@@ -1121,7 +1123,7 @@ merge(Compressor.prototype, {
                     if (is_lhs(node, multi_replacer.parent())) return node;
                     def.replaced++;
                     value_def.replaced--;
-                    return candidate.value;
+                    return candidate.value.clone();
                 }
                 // Skip (non-executed) functions and (leading) default case in switch statements
                 if (node instanceof AST_Default || node instanceof AST_Scope) return node;
index 950ebd0..c915041 100644 (file)
@@ -4056,6 +4056,36 @@ replace_all_var: {
     expect_stdout: "PASS"
 }
 
+replace_all_var_scope: {
+    rename = true;
+    options = {
+        collapse_vars: true,
+        unused: true,
+    }
+    mangle = {}
+    input: {
+        var a = 100, b = 10;
+        (function(r, a) {
+            switch (~a) {
+            case (b += a):
+            case a++:
+            }
+        })(--b, a);
+        console.log(a, b);
+    }
+    expect: {
+        var a = 100, b = 10;
+        (function(c, o) {
+            switch (~a) {
+            case (b += a):
+            case o++:
+            }
+        })(--b, a);
+        console.log(a, b);
+    }
+    expect_stdout: "100 109"
+}
+
 cascade_statement: {
     options = {
         collapse_vars: true,
index 1d6d189..14b6a46 100644 (file)
@@ -5998,3 +5998,35 @@ issue_3113_5: {
         "1",
     ]
 }
+
+conditional_nested: {
+    options = {
+        evaluate: true,
+        reduce_vars: true,
+    }
+    input: {
+        var a = 1, b = 0;
+        (function f(c) {
+            function g() {
+                c && (c.a = 0);
+                c && (c.a = 0);
+                c && (c[b++] *= 0);
+            }
+            g(a-- && f(g(c = 42)));
+        })();
+        console.log(b);
+    }
+    expect: {
+        var a = 1, b = 0;
+        (function f(c) {
+            function g() {
+                c && (c.a = 0);
+                c && (c.a = 0);
+                c && (c[b++] *= 0);
+            }
+            g(a-- && f(g(c = 42)));
+        })();
+        console.log(b);
+    }
+    expect_stdout: "2"
+}