enhance `dead_code` (#3811)
authorAlex Lam S.L <alexlamsl@gmail.com>
Wed, 22 Apr 2020 10:22:45 +0000 (11:22 +0100)
committerGitHub <noreply@github.com>
Wed, 22 Apr 2020 10:22:45 +0000 (18:22 +0800)
lib/compress.js
test/compress/dead-code.js

index d055132..6926b35 100644 (file)
@@ -1034,6 +1034,16 @@ merge(Compressor.prototype, {
         return false;
     }
 
+    function has_declarations_only(block) {
+        return all(block.body, function(stat) {
+            return is_empty(stat)
+                || stat instanceof AST_Defun
+                || stat instanceof AST_Var && all(stat.definitions, function(var_def) {
+                    return !var_def.value;
+                });
+        });
+    }
+
     function loop_body(x) {
         if (x instanceof AST_IterationStatement) {
             return x.body instanceof AST_BlockStatement ? x.body : x;
@@ -5493,15 +5503,15 @@ merge(Compressor.prototype, {
             var stat = branch.body[branch.body.length - 1];
             if (is_break(stat, compressor)) branch.body.pop();
             if (branch === default_branch) {
-                if (!is_body_empty(branch)) break;
+                if (!has_declarations_only(branch)) break;
             } else if (branch.expression.has_side_effects(compressor)) {
                 break;
             } else if (default_branch) {
-                if (!is_body_empty(default_branch)) break;
+                if (!has_declarations_only(default_branch)) break;
                 if (body[body.length - 2] !== default_branch) break;
                 default_branch.body = default_branch.body.concat(branch.body);
                 branch.body = [];
-            } else if (!is_body_empty(branch)) break;
+            } else if (!has_declarations_only(branch)) break;
             eliminate_branch(branch);
             if (body.pop() === default_branch) default_branch = null;
         }
@@ -5543,16 +5553,6 @@ merge(Compressor.prototype, {
             return node instanceof AST_Break && tw.loopcontrol_target(node) === self;
         }
 
-        function is_body_empty(branch) {
-            return all(branch.body, function(stat) {
-                return is_empty(stat)
-                    || stat instanceof AST_Defun
-                    || stat instanceof AST_Var && all(stat.definitions, function(var_def) {
-                        return !var_def.value;
-                    });
-            });
-        }
-
         function eliminate_branch(branch, prev) {
             if (prev && !aborts(prev)) {
                 prev.body = prev.body.concat(branch.body);
@@ -5564,25 +5564,35 @@ merge(Compressor.prototype, {
 
     OPT(AST_Try, function(self, compressor) {
         self.body = tighten_body(self.body, compressor);
-        if (self.bcatch && self.bfinally && all(self.bfinally.body, is_empty)) self.bfinally = null;
-        if (compressor.option("dead_code") && all(self.body, is_empty)) {
-            var body = [];
-            if (self.bcatch) {
-                extract_declarations_from_unreachable_code(self.bcatch, body);
-                body.forEach(function(stat) {
-                    if (!(stat instanceof AST_Definitions)) return;
-                    stat.definitions.forEach(function(var_def) {
-                        var def = var_def.name.definition().redefined();
-                        if (!def) return;
-                        var_def.name = var_def.name.clone();
-                        var_def.name.thedef = def;
+        if (compressor.option("dead_code")) {
+            if (has_declarations_only(self)) {
+                var body = [];
+                if (self.bcatch) {
+                    extract_declarations_from_unreachable_code(self.bcatch, body);
+                    body.forEach(function(stat) {
+                        if (!(stat instanceof AST_Definitions)) return;
+                        stat.definitions.forEach(function(var_def) {
+                            var def = var_def.name.definition().redefined();
+                            if (!def) return;
+                            var_def.name = var_def.name.clone();
+                            var_def.name.thedef = def;
+                        });
                     });
-                });
+                }
+                [].unshift.apply(body, self.body);
+                if (self.bfinally) [].push.apply(body, self.bfinally.body);
+                return make_node(AST_BlockStatement, self, {
+                    body: body
+                }).optimize(compressor);
+            }
+            if (self.bfinally && has_declarations_only(self.bfinally)) {
+                var body = self.body.concat(self.bfinally.body);
+                if (!self.bcatch) return make_node(AST_BlockStatement, self, {
+                    body: body
+                }).optimize(compressor);
+                self.body = body;
+                self.bfinally = null;
             }
-            if (self.bfinally) body = body.concat(self.bfinally.body);
-            return make_node(AST_BlockStatement, self, {
-                body: body
-            }).optimize(compressor);
         }
         return self;
     });
index 344e1ff..5de9ad3 100644 (file)
@@ -97,6 +97,66 @@ dead_code_constant_boolean_should_warn_more: {
     node_version: "<=4"
 }
 
+trim_try: {
+    options = {
+        dead_code: true,
+    }
+    input: {
+        try {
+            var a;
+        } catch (e) {
+            console.log("FAIL");
+        } finally {
+            console.log(a);
+        }
+    }
+    expect: {
+        var a;
+        console.log(a);
+    }
+    expect_stdout: "undefined"
+}
+
+trim_finally_1: {
+    options = {
+        dead_code: true,
+    }
+    input: {
+        try {
+            console.log("PASS");
+        } finally {
+            var a;
+        }
+    }
+    expect: {
+        console.log("PASS");
+        var a;
+    }
+    expect_stdout: "PASS"
+}
+
+trim_finally_2: {
+    options = {
+        dead_code: true,
+    }
+    input: {
+        try {
+            console.log("PASS");
+        } catch (e) {
+        } finally {
+            var a;
+        }
+    }
+    expect: {
+        try {
+            console.log("PASS");
+            var a;
+        } catch (e) {
+        }
+    }
+    expect_stdout: "PASS"
+}
+
 try_catch_finally: {
     options = {
         conditionals: true,
@@ -130,10 +190,7 @@ try_catch_finally: {
             a = 3;
             console.log("PASS");
         }();
-        try {
-            console.log(a);
-        } finally {
-        }
+        console.log(a);
     }
     expect_stdout: [
         "PASS",