From 95ef4d5377efc159c7102f134d844ba617b28996 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Sun, 4 Oct 2020 01:24:41 +0100 Subject: [PATCH] fix corner case in `mangle` (#4174) --- lib/scope.js | 91 ++++++++++++++++++++++-------------- test/compress/functions.js | 27 +++++++++++ test/compress/reduce_vars.js | 8 ++-- 3 files changed, 88 insertions(+), 38 deletions(-) diff --git a/lib/scope.js b/lib/scope.js index 27acf20f..359bd883 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -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; }); } diff --git a/test/compress/functions.js b/test/compress/functions.js index 745de9db..b68a04aa 100644 --- a/test/compress/functions.js +++ b/test/compress/functions.js @@ -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 +} diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index a79dd068..414d6646 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -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: { -- 2.34.1