fix corner cases in `functions` (#3372)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sat, 20 Apr 2019 18:16:05 +0000 (02:16 +0800)
committerGitHub <noreply@github.com>
Sat, 20 Apr 2019 18:16:05 +0000 (02:16 +0800)
fixes #3371

lib/compress.js
test/compress/functions.js
test/compress/loops.js

index b0f1bfb..2fd3609 100644 (file)
@@ -114,7 +114,7 @@ function Compressor(options, false_by_default) {
         };
     } else if (Array.isArray(pure_funcs)) {
         this.pure_funcs = function(node) {
-            return pure_funcs.indexOf(node.expression.print_to_string()) < 0;
+            return !member(node.expression.print_to_string(), pure_funcs);
         };
     } else {
         this.pure_funcs = return_true;
@@ -131,7 +131,7 @@ function Compressor(options, false_by_default) {
             top_retain = top_retain.split(/,/);
         }
         this.top_retain = function(def) {
-            return top_retain.indexOf(def.name) >= 0;
+            return member(def.name, top_retain);
         };
     }
     var toplevel = this.options["toplevel"];
@@ -1711,7 +1711,7 @@ merge(Compressor.prototype, {
                     CHANGED = true;
                     statements.splice(i, 1);
                 } else if (stat instanceof AST_Directive) {
-                    if (seen_dirs.indexOf(stat.value) < 0) {
+                    if (!member(stat.value, seen_dirs)) {
                         i++;
                         seen_dirs.push(stat.value);
                     } else {
@@ -2853,7 +2853,7 @@ merge(Compressor.prototype, {
             var fixed = this.fixed_value();
             if (!fixed) return this;
             var value;
-            if (cached.indexOf(fixed) >= 0) {
+            if (member(fixed, cached)) {
                 value = fixed._eval();
             } else {
                 this._eval = return_this;
@@ -3638,11 +3638,16 @@ merge(Compressor.prototype, {
                             var defun = make_node(AST_Defun, def, def.value);
                             defun.name = make_node(AST_SymbolDefun, def.name, def.name);
                             var name_def = def.name.scope.resolve().def_function(defun.name);
-                            if (def.value.name) def.value.name.definition().references.forEach(function(ref) {
-                                ref.name = name_def.name;
-                                ref.thedef = name_def;
-                                ref.reference({});
-                            });
+                            if (def.value.name) {
+                                var old_def = def.value.name.definition();
+                                def.value.walk(new TreeWalker(function(node) {
+                                    if (node instanceof AST_SymbolRef && node.definition() === old_def) {
+                                        node.name = name_def.name;
+                                        node.thedef = name_def;
+                                        node.reference({});
+                                    }
+                                }));
+                            }
                             body.push(defun);
                         } else {
                             if (side_effects.length > 0) {
@@ -3703,6 +3708,7 @@ merge(Compressor.prototype, {
             //    https://github.com/mishoo/UglifyJS2/issues/44
             //    https://github.com/mishoo/UglifyJS2/issues/1830
             //    https://github.com/mishoo/UglifyJS2/issues/1838
+            //    https://github.com/mishoo/UglifyJS2/issues/3371
             // that's an invalid AST.
             // We fix it at this stage by moving the `var` outside the `for`.
             if (node instanceof AST_For) {
@@ -3713,7 +3719,15 @@ merge(Compressor.prototype, {
                     node.init = block.body.pop();
                     block.body.push(node);
                 }
-                if (node.init instanceof AST_SimpleStatement) {
+                if (node.init instanceof AST_Defun) {
+                    if (!block) {
+                        block = make_node(AST_BlockStatement, node, {
+                            body: [ node ]
+                        });
+                    }
+                    block.body.splice(-1, 0, node.init);
+                    node.init = null;
+                } else if (node.init instanceof AST_SimpleStatement) {
                     node.init = node.init.body;
                 } else if (is_empty(node.init)) {
                     node.init = null;
index 64f3bbc..983d706 100644 (file)
@@ -3012,3 +3012,32 @@ issue_3366: {
     }
     expect_stdout: "PASS"
 }
+
+issue_3371: {
+    options = {
+        functions: true,
+        inline: true,
+        reduce_vars: true,
+        side_effects: true,
+        unused: true,
+    }
+    input: {
+        (function() {
+            var a = function f() {
+                (function() {
+                    console.log(typeof f);
+                })();
+            };
+            while (a());
+        })();
+    }
+    expect: {
+        (function() {
+            function a() {
+                console.log(typeof a);
+            }
+            while (a());
+        })();
+    }
+    expect_stdout: "function"
+}
index 3fa7833..137fd9d 100644 (file)
@@ -646,3 +646,30 @@ issue_2904: {
     }
     expect_stdout: "1"
 }
+
+issue_3371: {
+    options = {
+        functions: true,
+        join_vars: true,
+        loops: true,
+        reduce_vars: true,
+        unused: true,
+    }
+    input: {
+        (function() {
+            var a = function() {
+                console.log("PASS");
+            };
+            while (a());
+        })();
+    }
+    expect: {
+        (function() {
+            function a() {
+                console.log("PASS");
+            }
+            for (; a(); );
+        })();
+    }
+    expect_stdout: "PASS"
+}