From a6a0319f1c758013e8f1be9632fa30b031144835 Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Sun, 17 Nov 2019 02:36:42 +0800 Subject: [PATCH] compress empty for-in loops (#3590) --- lib/compress.js | 41 ++++++++++++++++++--------- test/compress/loops.js | 64 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 13 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 9366091c..e85cf5d3 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -3912,19 +3912,6 @@ merge(Compressor.prototype, { scope = save_scope; return node; } - - function log(sym, text, props) { - AST_Node[sym.unreferenced() ? "warn" : "info"](text, props); - } - - function template(sym) { - return { - name : sym.name, - file : sym.start.file, - line : sym.start.line, - col : sym.start.col - }; - } }, function(node, in_list) { if (node instanceof AST_For) { // Certain combination of unused name + side effect leads to invalid AST: @@ -3952,6 +3939,21 @@ merge(Compressor.prototype, { node.init = null; } return !block ? node : in_list ? MAP.splice(block.body) : block; + } else if (node instanceof AST_ForIn) { + if (!drop_vars || !compressor.option("loops")) return; + if (!(node.init instanceof AST_Definitions)) return; + var sym = node.init.definitions[0].name; + if (sym.definition().id in in_use_ids) return; + if (!is_empty(node.body)) return; + log(sym, "Dropping unused loop variable {name} [{file}:{line},{col}]", template(sym)); + var value = node.object.drop_side_effect_free(compressor); + if (value) { + AST_Node.warn("Side effects in object of for-in loop [{file}:{line},{col}]", template(sym)); + return make_node(AST_SimpleStatement, node, { + body: value + }); + } + return in_list ? MAP.skip : make_node(AST_EmptyStatement, node); } else if (node instanceof AST_Sequence) { if (node.expressions.length == 1) return node.expressions[0]; } @@ -3962,6 +3964,19 @@ merge(Compressor.prototype, { fn.name = null; }); + function log(sym, text, props) { + AST_Node[sym.unreferenced() ? "warn" : "info"](text, props); + } + + function template(sym) { + return { + name: sym.name, + file: sym.start.file, + line: sym.start.line, + col : sym.start.col + }; + } + function verify_safe_usage(def, read, modified) { if (def.id in in_use_ids) return; if (read && modified) { diff --git a/test/compress/loops.js b/test/compress/loops.js index d835080d..7b6002a2 100644 --- a/test/compress/loops.js +++ b/test/compress/loops.js @@ -689,3 +689,67 @@ step: { } expect_stdout: "42" } + +empty_for_in: { + options = { + loops: true, + toplevel: true, + unused: true, + } + input: { + for (var a in [ 1, 2, 3 ]) { + var b = a + 1; + } + } + expect: {} + expect_warnings: [ + "WARN: Dropping unused variable b [test/compress/loops.js:2,16]", + "INFO: Dropping unused loop variable a [test/compress/loops.js:1,17]", + ] +} + +empty_for_in_used: { + options = { + loops: true, + toplevel: true, + unused: true, + } + input: { + for (var a in [ 1, 2, 3 ]) { + var b = a + 1; + } + console.log(a); + } + expect: { + for (var a in [ 1, 2, 3 ]); + console.log(a); + } + expect_stdout: "2" + expect_warnings: [ + "WARN: Dropping unused variable b [test/compress/loops.js:2,16]", + ] +} + +empty_for_in_side_effects: { + options = { + loops: true, + toplevel: true, + unused: true, + } + input: { + for (var a in { + foo: console.log("PASS") + }) { + var b = a + "bar"; + } + } + expect: { + console.log("PASS"); + } + expect_stdout: "PASS" + expect_warnings: [ + "WARN: Dropping unused variable b [test/compress/loops.js:4,16]", + "INFO: Dropping unused loop variable a [test/compress/loops.js:1,17]", + "WARN: Side effects in object of for-in loop [test/compress/loops.js:1,17]", + ] +} -- 2.34.1