diff options
author | Alex Lam S.L <alexlamsl@gmail.com> | 2021-06-20 08:30:04 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-20 15:30:04 +0800 |
commit | fd8dec61ad0e83caa72691b56e1d36b6f29203a8 (patch) | |
tree | 6cd5e0ba7d136c4c0365983d8ea4c18dea98cc6d | |
parent | 7880568d157fcd1c15c0f392e4646e01de363afd (diff) | |
download | tracifyjs-fd8dec61ad0e83caa72691b56e1d36b6f29203a8.tar.gz tracifyjs-fd8dec61ad0e83caa72691b56e1d36b6f29203a8.zip |
enhance `dead_code` (#5014)
-rw-r--r-- | lib/compress.js | 91 | ||||
-rw-r--r-- | test/compress/dead-code.js | 164 | ||||
-rwxr-xr-x | test/release/rollup-ts.sh | 3 |
3 files changed, 231 insertions, 27 deletions
diff --git a/lib/compress.js b/lib/compress.js index 22434f62..5a7461a8 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -1714,6 +1714,15 @@ merge(Compressor.prototype, { return stat instanceof AST_LambdaDefinition; } + function is_last_statement(body, stat) { + var index = body.lastIndexOf(stat); + if (index < 0) return false; + while (++index < body.length) { + if (!is_declaration(body[index], true)) return false; + } + return true; + } + function tighten_body(statements, compressor) { var in_loop, in_try, scope; find_loop_scope_try(); @@ -3168,15 +3177,6 @@ merge(Compressor.prototype, { return !value || value instanceof AST_UnaryPrefix && value.operator == "void"; } - function is_last_statement(body, stat) { - var index = body.lastIndexOf(stat); - if (index < 0) return false; - while (++index < body.length) { - if (!is_declaration(body[index], true)) return false; - } - return true; - } - function last_of(predicate) { var block = self, stat, level = 0; do { @@ -11140,28 +11140,36 @@ merge(Compressor.prototype, { if (node instanceof AST_PropAccess) return true; if (!found && node instanceof AST_SymbolRef && node.definition() === def) { if (in_try(level, parent)) return true; - def.fixed = false; found = true; } })) break; - if (found) return strip_assignment(); - } else if (parent instanceof AST_Exit) { + if (!found) continue; + return strip_assignment(def); + } + if (parent instanceof AST_Exit) { if (!local) break; if (in_try(level, parent)) break; if (is_reachable(scope, [ def ])) break; - def.fixed = false; - return strip_assignment(); - } else if (parent instanceof AST_VarDef) { + return strip_assignment(def); + } + if (parent instanceof AST_SimpleStatement) { + if (!local) break; + if (is_reachable(scope, [ def ])) break; + var stat; + do { + stat = parent; + parent = compressor.parent(level++); + if (parent === scope && is_last_statement(parent.body, stat)) return strip_assignment(def); + } while (is_tail_block(stat, parent)); + break; + } + if (parent instanceof AST_VarDef) { if (!(parent.name instanceof AST_SymbolDeclaration)) continue; if (parent.name.definition() !== def) continue; if (in_try(level, parent)) break; - def.fixed = false; - return strip_assignment(); + return strip_assignment(def); } - } while (parent instanceof AST_Binary && parent.right === node - || parent instanceof AST_Conditional && parent.condition !== node - || parent instanceof AST_Sequence && parent.tail_node() === node - || parent instanceof AST_UnaryPrefix); + } while (is_tail(node, parent)); } } if (compressor.option("sequences")) { @@ -11206,26 +11214,55 @@ merge(Compressor.prototype, { } return try_evaluate(compressor, self); + function is_tail(node, parent) { + if (parent instanceof AST_Binary) { + return parent.right === node || parent.right.is_constant_expression(scope); + } + if (parent instanceof AST_Conditional) { + return parent.condition !== node + || parent.consequent.is_constant_expression(scope) + && parent.alternative.is_constant_expression(scope); + } + if (parent instanceof AST_Sequence) { + var exprs = parent.expressions; + var stop = exprs.indexOf(node); + if (stop < 0) return false; + for (var i = exprs.length; --i > stop;) { + if (!exprs[i].is_constant_expression(scope)) return false; + } + return true; + } + if (parent instanceof AST_UnaryPrefix) return true; + } + + function is_tail_block(stat, parent) { + if (parent instanceof AST_BlockStatement) return is_last_statement(parent.body, stat); + if (parent instanceof AST_Catch) return is_last_statement(parent.body, stat); + if (parent instanceof AST_Finally) return is_last_statement(parent.body, stat); + if (parent instanceof AST_If) return parent.body === stat || parent.alternative === stat; + if (parent instanceof AST_Try) return parent.bfinally ? parent.bfinally === stat : parent.bcatch === stat; + } + function in_try(level, node) { var right = self.right; self.right = make_node(AST_Null, right); var may_throw = node.may_throw(compressor); self.right = right; - var parent; - while (parent = compressor.parent(level++)) { + for (var parent; parent = compressor.parent(level++); node = parent) { if (parent === scope) return false; if (parent instanceof AST_Try) { - if (parent.bfinally) return true; - if (may_throw && parent.bcatch) return true; + if (parent.bfinally && parent.bfinally !== node) return true; + if (may_throw && parent.bcatch && parent.bcatch !== node) return true; } } } - function strip_assignment() { + function strip_assignment(def) { + if (def) def.fixed = false; return (self.operator != "=" ? make_node(AST_Binary, self, { operator: self.operator.slice(0, -1), left: self.left, - right: self.right + right: self.right, }) : maintain_this_binding(compressor, compressor.parent(), self, self.right)).optimize(compressor); } }); diff --git a/test/compress/dead-code.js b/test/compress/dead-code.js index 9101869d..4493deb0 100644 --- a/test/compress/dead-code.js +++ b/test/compress/dead-code.js @@ -939,6 +939,170 @@ catch_return_assign: { expect_stdout: "PASS" } +catch_return_assign_may_throw: { + options = { + dead_code: true, + } + input: { + function f() { + try { + throw "FAIL"; + } catch (e) { + return e = console.log("PASS"); + } + } + f(); + } + expect: { + function f() { + try { + throw "FAIL"; + } catch (e) { + return console.log("PASS"); + } + } + f(); + } + expect_stdout: "PASS" +} + +finally_return_assign: { + options = { + dead_code: true, + } + input: { + console.log(function(a) { + try { + throw "FAIL"; + } finally { + return a = "PASS"; + } + }()); + } + expect: { + console.log(function(a) { + try { + throw "FAIL"; + } finally { + return "PASS"; + } + }()); + } + expect_stdout: "PASS" +} + +last_assign_statement: { + options = { + dead_code: true, + } + input: { + function f(a) { + a = a("PASS"); + } + f(console.log); + } + expect: { + function f(a) { + a("PASS"); + } + f(console.log); + } + expect_stdout: "PASS" +} + +last_assign_if_else: { + options = { + dead_code: true, + } + input: { + function f(a) { + if (a) + a = console.log("foo"); + else { + console.log("bar"); + a = console.log("baz"); + } + } + f(42); + f(null); + } + expect: { + function f(a) { + if (a) + console.log("foo"); + else { + console.log("bar"); + console.log("baz"); + } + } + f(42); + f(null); + } + expect_stdout: [ + "foo", + "bar", + "baz", + ] +} + +last_assign_catch: { + options = { + dead_code: true, + } + input: { + function f() { + try { + throw "FAIL"; + } catch (e) { + e = console.log("PASS"); + } + } + f(); + } + expect: { + function f() { + try { + throw "FAIL"; + } catch (e) { + console.log("PASS"); + } + } + f(); + } + expect_stdout: "PASS" +} + +last_assign_finally: { + options = { + dead_code: true, + } + input: { + function f(a) { + try { + throw a.log; + } catch (e) { + a = e; + } finally { + a = a("PASS"); + } + } + f(console); + } + expect: { + function f(a) { + try { + throw a.log; + } catch (e) { + a = e; + } finally { + a("PASS"); + } + } + f(console); + } + expect_stdout: "PASS" +} + issue_3578: { options = { dead_code: true, diff --git a/test/release/rollup-ts.sh b/test/release/rollup-ts.sh index 503aeadf..4763911d 100755 --- a/test/release/rollup-ts.sh +++ b/test/release/rollup-ts.sh @@ -43,6 +43,9 @@ rm -rf tmp/rollup \ - "postpublish": "pinst --enable", - "prepare": "npm run build", - "prepublishOnly": "pinst --disable && npm ci && npm run lint:nofix && npm run security && npm run build:bootstrap && npm run test:all", +@@ -93 +89 @@ +- "is-reference": "lukastaegert/is-reference#update-class-features", ++ "is-reference": "3.0.0", --- a/test/cli/index.js +++ b/test/cli/index.js @@ -13,0 +14,3 @@ sander.rimrafSync(__dirname, 'node_modules'); |