fix corner case in `mangle` (#4174)
authorAlex Lam S.L <alexlamsl@gmail.com>
Sun, 4 Oct 2020 00:24:41 +0000 (01:24 +0100)
committerGitHub <noreply@github.com>
Sun, 4 Oct 2020 00:24:41 +0000 (08:24 +0800)
lib/scope.js
test/compress/functions.js
test/compress/reduce_vars.js

index 27acf20..359bd88 100644 (file)
@@ -59,13 +59,9 @@ function SymbolDef(id, scope, orig, init) {
 }
 
 SymbolDef.prototype = {
-    unmangleable: function(options) {
-        return this.global && !options.toplevel
-            || this.undeclared
-            || !options.eval && this.scope.pinned()
-            || options.keep_fnames
-                && (this.orig[0] instanceof AST_SymbolLambda
-                    || this.orig[0] instanceof AST_SymbolDefun);
+    forEach: function(fn) {
+        this.orig.forEach(fn);
+        this.references.forEach(fn);
     },
     mangle: function(options) {
         var cache = options.cache && options.cache.props;
@@ -85,7 +81,15 @@ SymbolDef.prototype = {
     },
     redefined: function() {
         return this.defun && this.defun.variables.get(this.name);
-    }
+    },
+    unmangleable: function(options) {
+        return this.global && !options.toplevel
+            || this.undeclared
+            || !options.eval && this.scope.pinned()
+            || options.keep_fnames
+                && (this.orig[0] instanceof AST_SymbolLambda
+                    || this.orig[0] instanceof AST_SymbolDefun);
+    },
 };
 
 AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
@@ -100,15 +104,18 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
     var next_def_id = 0;
     var scope = self.parent_scope = null;
     var tw = new TreeWalker(function(node, descend) {
+        if (node instanceof AST_Defun) {
+            node.name.walk(tw);
+            walk_scope(function() {
+                node.argnames.forEach(function(argname) {
+                    argname.walk(tw);
+                });
+                walk_body(node, tw);
+            });
+            return true;
+        }
         if (node instanceof AST_BlockScope) {
-            node.init_scope_vars(scope);
-            var save_defun = defun;
-            var save_scope = scope;
-            if (node instanceof AST_Scope) defun = node;
-            scope = node;
-            descend();
-            scope = save_scope;
-            defun = save_defun;
+            walk_scope(descend);
             return true;
         }
         if (node instanceof AST_With) {
@@ -122,25 +129,41 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
             node.thedef = node;
             node.references = [];
         }
-        if (node instanceof AST_SymbolDefun) {
-            // This should be defined in the parent scope, as we encounter the
-            // AST_Defun node before getting to its AST_Symbol.
-            (node.scope = defun.parent_scope.resolve()).def_function(node, defun);
+        if (node instanceof AST_SymbolCatch) {
+            scope.def_variable(node).defun = defun;
+        } else if (node instanceof AST_SymbolDefun) {
+            defun.def_function(node, tw.parent());
+            entangle(defun, scope);
+        } else if (node instanceof AST_SymbolFunarg) {
+            defun.def_variable(node);
+            entangle(defun, scope);
         } else if (node instanceof AST_SymbolLambda) {
             var def = defun.def_function(node, node.name == "arguments" ? undefined : defun);
             if (options.ie8) def.defun = defun.parent_scope.resolve();
         } else if (node instanceof AST_SymbolVar) {
-            defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined);
-            if (defun !== scope) {
-                node.mark_enclosed(options);
-                var def = scope.find_variable(node);
-                if (node.thedef !== def) {
-                    node.thedef = def;
-                }
-                node.reference(options);
-            }
-        } else if (node instanceof AST_SymbolCatch) {
-            scope.def_variable(node).defun = defun;
+            defun.def_variable(node, null);
+            entangle(defun, scope);
+        }
+
+        function walk_scope(descend) {
+            node.init_scope_vars(scope);
+            var save_defun = defun;
+            var save_scope = scope;
+            if (node instanceof AST_Scope) defun = node;
+            scope = node;
+            descend();
+            scope = save_scope;
+            defun = save_defun;
+        }
+
+        function entangle(defun, scope) {
+            if (defun === scope) return;
+            node.mark_enclosed(options);
+            var def = scope.find_variable(node);
+            if (node.thedef === def) return;
+            node.thedef = def;
+            def.orig.push(node);
+            node.mark_enclosed(options);
         }
     });
     self.make_def = function(orig, init) {
@@ -227,7 +250,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
             new_def = scope.def_variable(node);
         }
         old_def.defun = new_def.scope;
-        old_def.orig.concat(old_def.references).forEach(function(node) {
+        old_def.forEach(function(node) {
             node.redef = true;
             node.thedef = new_def;
             node.reference(options);
@@ -341,7 +364,7 @@ function next_mangled_name(scope, options, def) {
     var holes = scope.cname_holes;
     var names = Object.create(null);
     var scopes = [ scope ];
-    def.references.forEach(function(sym) {
+    def.forEach(function(sym) {
         var scope = sym.scope;
         do {
             if (scopes.indexOf(scope) < 0) {
@@ -525,7 +548,7 @@ AST_Toplevel.DEFMETHOD("expand_names", function(options) {
         var redef = def.redefined();
         var name = redef ? redef.rename || redef.name : next_name();
         def.rename = name;
-        def.orig.concat(def.references).forEach(function(sym) {
+        def.forEach(function(sym) {
             if (sym.definition() === def) sym.name = name;
         });
     }
index 745de9d..b68a04a 100644 (file)
@@ -4960,3 +4960,30 @@ issue_4171_2: {
     }
     expect_stdout: "undefined"
 }
+
+catch_defun: {
+    mangle = {
+        toplevel: true,
+    }
+    input: {
+        try {
+            throw 42;
+        } catch (a) {
+            function f() {
+                return typeof a;
+            }
+        }
+        console.log(f());
+    }
+    expect: {
+        try {
+            throw 42;
+        } catch (o) {
+            function t() {
+                return typeof o;
+            }
+        }
+        console.log(t());
+    }
+    expect_stdout: true
+}
index a79dd06..414d664 100644 (file)
@@ -5374,11 +5374,11 @@ defun_catch_4: {
         try {
             throw 42;
         } catch (a) {
+            function a() {}
             console.log(a);
         }
     }
-    expect_stdout: "42"
-    node_version: "<=4"
+    expect_stdout: true
 }
 
 defun_catch_5: {
@@ -5400,10 +5400,10 @@ defun_catch_5: {
             throw 42;
         } catch (a) {
             console.log(a);
+            function a() {}
         }
     }
-    expect_stdout: "42"
-    node_version: "<=4"
+    expect_stdout: true
 }
 
 defun_catch_6: {