From 7cf72b8d66ea3a504648f42a2142728d520f3141 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Thu, 19 Jul 2018 18:14:36 +0800 Subject: [PATCH] fix corner case in `global_defs` (#3218) fixes #3217 --- lib/compress.js | 77 +++++++++++++++--------------------- lib/output.js | 2 +- test/compress/global_defs.js | 21 +++++++++- 3 files changed, 53 insertions(+), 47 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 364bd362..ca868a92 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -59,7 +59,7 @@ function Compressor(options, false_by_default) { drop_debugger : !false_by_default, evaluate : !false_by_default, expression : false, - global_defs : {}, + global_defs : false, hoist_funs : false, hoist_props : !false_by_default, hoist_vars : false, @@ -149,6 +149,7 @@ merge(Compressor.prototype, { return false; }, compress: function(node) { + node = node.resolve_defines(this); if (this.option("expression")) { node.process_expression(true); } @@ -2410,22 +2411,6 @@ merge(Compressor.prototype, { } (function(def) { - AST_Node.DEFMETHOD("resolve_defines", function(compressor) { - if (!compressor.option("global_defs")) return; - var def = this._find_defs(compressor, ""); - if (def) { - var node, parent = this, level = 0; - do { - node = parent; - parent = compressor.parent(level++); - } while (parent instanceof AST_PropAccess && parent.expression === node); - if (is_lhs(node, parent)) { - compressor.warn('global_defs ' + this.print_to_string() + ' redefined [{file}:{line},{col}]', this.start); - } else { - return def; - } - } - }); function to_node(value, orig) { if (value instanceof AST_Node) return make_node(value.CTOR, orig, value); if (Array.isArray(value)) return make_node(AST_Array, orig, { @@ -2447,25 +2432,43 @@ merge(Compressor.prototype, { } return make_node_from_constant(value, orig); } + + function warn(compressor, node) { + compressor.warn("global_defs " + node.print_to_string() + " redefined [{file}:{line},{col}]", node.start); + } + + AST_Toplevel.DEFMETHOD("resolve_defines", function(compressor) { + if (!compressor.option("global_defs")) return this; + this.figure_out_scope({ ie8: compressor.option("ie8") }); + return this.transform(new TreeTransformer(function(node) { + var def = node._find_defs(compressor, ""); + if (!def) return; + var level = 0, child = node, parent; + while (parent = this.parent(level++)) { + if (!(parent instanceof AST_PropAccess)) break; + if (parent.expression !== child) break; + child = parent; + } + if (is_lhs(child, parent)) { + warn(compressor, node); + return; + } + return def; + })); + }); def(AST_Node, noop); def(AST_Dot, function(compressor, suffix) { return this.expression._find_defs(compressor, "." + this.property + suffix); }); + def(AST_SymbolDeclaration, function(compressor) { + if (!this.global()) return; + if (HOP(compressor.option("global_defs"), this.name)) warn(compressor, this); + }); def(AST_SymbolRef, function(compressor, suffix) { if (!this.global()) return; - var name; var defines = compressor.option("global_defs"); - if (defines && HOP(defines, (name = this.name + suffix))) { - var node = to_node(defines[name], this); - var top = compressor.find_parent(AST_Toplevel); - node.walk(new TreeWalker(function(node) { - if (node instanceof AST_SymbolRef) { - node.scope = top; - node.thedef = top.def_global(node); - } - })); - return node; - } + var name = this.name + suffix; + if (HOP(defines, name)) return to_node(defines[name], this); }); })(function(node, func) { node.DEFMETHOD("_find_defs", func); @@ -5718,10 +5721,6 @@ merge(Compressor.prototype, { } OPT(AST_SymbolRef, function(self, compressor) { - var def = self.resolve_defines(compressor); - if (def) { - return def.optimize(compressor); - } if (!compressor.option("ie8") && is_undeclared_ref(self) // testing against `self.scope.uses_with` is an optimization @@ -6405,10 +6404,6 @@ merge(Compressor.prototype, { col: self.start.col }); } - var def = self.resolve_defines(compressor); - if (def) { - return def.optimize(compressor); - } if (is_lhs(self, compressor.parent())) return self; if (compressor.option("unsafe_proto") && self.expression instanceof AST_Dot @@ -6464,14 +6459,6 @@ merge(Compressor.prototype, { } return self; }); - - OPT(AST_VarDef, function(self, compressor) { - var defines = compressor.option("global_defs"); - if (defines && HOP(defines, self.name.name)) { - compressor.warn('global_defs ' + self.name.name + ' redefined [{file}:{line},{col}]', self.start); - } - return self; - }); })(function(node, optimizer) { node.DEFMETHOD("optimize", function(compressor) { var self = this; diff --git a/lib/output.js b/lib/output.js index 37536c06..f3feabec 100644 --- a/lib/output.js +++ b/lib/output.js @@ -1161,7 +1161,7 @@ function OutputStream(options) { def.print(output); }); var p = output.parent(); - if (p.init !== self || !(p instanceof AST_For || p instanceof AST_ForIn)) output.semicolon(); + if (p && p.init !== self || !(p instanceof AST_For || p instanceof AST_ForIn)) output.semicolon(); }); function parenthesize_for_noin(node, output, noin) { diff --git a/test/compress/global_defs.js b/test/compress/global_defs.js index 98fa3e9f..f1ef81d9 100644 --- a/test/compress/global_defs.js +++ b/test/compress/global_defs.js @@ -142,7 +142,6 @@ mixed: { } expect_warnings: [ "WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:4,22]", - "WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:5,22]", "WARN: global_defs CONFIG.VALUE redefined [test/compress/global_defs.js:7,8]", ] } @@ -197,3 +196,23 @@ issue_2167: { doWork(); } } + +issue_3217: { + options = { + collapse_vars: true, + global_defs: { + "@o": "{fn:function(){var a=42;console.log(a)}}", + }, + inline: true, + properties: true, + reduce_vars: true, + side_effects: true, + unused: true, + } + input: { + o.fn(); + } + expect: { + console.log(42); + } +} -- 2.34.1