enhance loops & unused (#4074)
- extend `ufuzz` generation of for-in loops
This commit is contained in:
@@ -4456,7 +4456,7 @@ merge(Compressor.prototype, {
|
|||||||
if (drop_funcs && node !== self && node instanceof AST_Defun) {
|
if (drop_funcs && node !== self && node instanceof AST_Defun) {
|
||||||
var def = node.name.definition();
|
var def = node.name.definition();
|
||||||
if (!(def.id in in_use_ids)) {
|
if (!(def.id in in_use_ids)) {
|
||||||
log(node.name, "Dropping unused function {name} [{file}:{line},{col}]", template(node.name));
|
log(node.name, "Dropping unused function {name}");
|
||||||
def.eliminated++;
|
def.eliminated++;
|
||||||
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
||||||
}
|
}
|
||||||
@@ -4471,7 +4471,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!(sym.definition().id in in_use_ids)) {
|
if (!(sym.definition().id in in_use_ids)) {
|
||||||
sym.__unused = true;
|
sym.__unused = true;
|
||||||
if (trim) {
|
if (trim) {
|
||||||
log(sym, "Dropping unused function argument {name} [{file}:{line},{col}]", template(sym));
|
log(sym, "Dropping unused function argument {name}");
|
||||||
a.pop();
|
a.pop();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -4574,7 +4574,7 @@ merge(Compressor.prototype, {
|
|||||||
AST_Node.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", template(def.name));
|
AST_Node.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", template(def.name));
|
||||||
side_effects.push(value);
|
side_effects.push(value);
|
||||||
} else {
|
} else {
|
||||||
log(def.name, "Dropping unused variable {name} [{file}:{line},{col}]", template(def.name));
|
log(def.name, "Dropping unused variable {name}");
|
||||||
}
|
}
|
||||||
sym.eliminated++;
|
sym.eliminated++;
|
||||||
}
|
}
|
||||||
@@ -4669,19 +4669,22 @@ merge(Compressor.prototype, {
|
|||||||
return !block ? node : in_list ? List.splice(block.body) : block;
|
return !block ? node : in_list ? List.splice(block.body) : block;
|
||||||
} else if (node instanceof AST_ForIn) {
|
} else if (node instanceof AST_ForIn) {
|
||||||
if (!drop_vars || !compressor.option("loops")) return;
|
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;
|
if (!is_empty(node.body)) return;
|
||||||
log(sym, "Dropping unused loop variable {name} [{file}:{line},{col}]", template(sym));
|
var sym = node.init;
|
||||||
var value = node.object.drop_side_effect_free(compressor);
|
if (sym instanceof AST_Definitions) {
|
||||||
if (value) {
|
sym = sym.definitions[0].name;
|
||||||
AST_Node.warn("Side effects in object of for-in loop [{file}:{line},{col}]", template(sym));
|
} else while (sym instanceof AST_PropAccess) {
|
||||||
return make_node(AST_SimpleStatement, node, {
|
sym = sym.expression.tail_node();
|
||||||
body: value
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
var def = sym.definition();
|
||||||
|
if (!def || def.id in in_use_ids) return;
|
||||||
|
log(sym, "Dropping unused loop variable {name}");
|
||||||
|
var value = node.object.drop_side_effect_free(compressor);
|
||||||
|
if (!value) return in_list ? List.skip : make_node(AST_EmptyStatement, node);
|
||||||
|
AST_Node.warn("Side effects in object of for-in loop [{file}:{line},{col}]", value.start);
|
||||||
|
return make_node(AST_SimpleStatement, node, {
|
||||||
|
body: value
|
||||||
|
});
|
||||||
} else if (node instanceof AST_Sequence) {
|
} else if (node instanceof AST_Sequence) {
|
||||||
if (node.expressions.length == 1) return node.expressions[0];
|
if (node.expressions.length == 1) return node.expressions[0];
|
||||||
}
|
}
|
||||||
@@ -4701,8 +4704,8 @@ merge(Compressor.prototype, {
|
|||||||
drop_unused_call_args(call, compressor, fns_with_marked_args);
|
drop_unused_call_args(call, compressor, fns_with_marked_args);
|
||||||
});
|
});
|
||||||
|
|
||||||
function log(sym, text, props) {
|
function log(sym, text) {
|
||||||
AST_Node[sym.definition().references.length > 0 ? "info" : "warn"](text, props);
|
AST_Node[sym.definition().references.length > 0 ? "info" : "warn"](text + " [{file}:{line},{col}]", template(sym));
|
||||||
}
|
}
|
||||||
|
|
||||||
function template(sym) {
|
function template(sym) {
|
||||||
@@ -4790,6 +4793,13 @@ merge(Compressor.prototype, {
|
|||||||
if (track_assigns(node_def, sym) && is_lhs(sym, node) !== sym) add_assigns(node_def, sym);
|
if (track_assigns(node_def, sym) && is_lhs(sym, node) !== sym) add_assigns(node_def, sym);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_ForIn) {
|
||||||
|
if (!compressor.option("loops")) return;
|
||||||
|
if (!is_empty(node.body)) return;
|
||||||
|
if (node.init.has_side_effects(compressor)) return;
|
||||||
|
node.object.walk(tw);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
node_def = node.definition();
|
node_def = node.definition();
|
||||||
if (!(node_def.id in in_use_ids)) {
|
if (!(node_def.id in in_use_ids)) {
|
||||||
|
|||||||
@@ -756,7 +756,37 @@ empty_for_in_side_effects: {
|
|||||||
expect_warnings: [
|
expect_warnings: [
|
||||||
"WARN: Dropping unused variable b [test/compress/loops.js:4,16]",
|
"WARN: Dropping unused variable b [test/compress/loops.js:4,16]",
|
||||||
"INFO: Dropping unused loop variable a [test/compress/loops.js:1,17]",
|
"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]",
|
"WARN: Side effects in object of for-in loop [test/compress/loops.js:2,17]",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
empty_for_in_prop_init: {
|
||||||
|
options = {
|
||||||
|
loops: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function f() {
|
||||||
|
var a = "bar";
|
||||||
|
for ((a, f)[a] in console.log("foo"));
|
||||||
|
return a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
var a = "bar";
|
||||||
|
console.log("foo");
|
||||||
|
return a;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"foo",
|
||||||
|
"bar",
|
||||||
|
]
|
||||||
|
expect_warnings: [
|
||||||
|
"INFO: Dropping unused loop variable f [test/compress/loops.js:3,21]",
|
||||||
|
"WARN: Side effects in object of for-in loop [test/compress/loops.js:3,30]",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -496,11 +496,16 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
|||||||
var label = createLabel(canBreak, canContinue);
|
var label = createLabel(canBreak, canContinue);
|
||||||
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
||||||
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
||||||
var optElementVar = "";
|
var key = rng(10) ? "key" + loop : getVarName();
|
||||||
if (rng(5) > 1) {
|
return [
|
||||||
optElementVar = "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[key" + loop + "]; ";
|
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
||||||
}
|
label.target + " for (",
|
||||||
return "{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; " + label.target + " for (var key" + loop + " in expr" + loop + ") {" + optElementVar + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "}}";
|
/^key/.test(key) ? "var " : "",
|
||||||
|
key + " in expr" + loop + ") {",
|
||||||
|
rng(5) > 1 ? "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[" + key + "]; " : "",
|
||||||
|
createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
||||||
|
"}}",
|
||||||
|
].join("");
|
||||||
case STMT_SEMI:
|
case STMT_SEMI:
|
||||||
return use_strict && rng(20) === 0 ? '"use strict";' : ";";
|
return use_strict && rng(20) === 0 ? '"use strict";' : ";";
|
||||||
case STMT_EXPR:
|
case STMT_EXPR:
|
||||||
|
|||||||
Reference in New Issue
Block a user