enhance dead_code (#5014)
This commit is contained in:
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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');
|
||||
|
||||
Reference in New Issue
Block a user