enhance pure_getters, reduce_vars & unused (#4863)
This commit is contained in:
@@ -814,11 +814,12 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Assign, function(tw, descend, compressor) {
|
def(AST_Assign, function(tw, descend, compressor) {
|
||||||
var node = this;
|
var node = this;
|
||||||
var left = node.left;
|
var left = node.left;
|
||||||
|
var right = node.right;
|
||||||
var scan = left instanceof AST_Destructured || left instanceof AST_SymbolRef;
|
var scan = left instanceof AST_Destructured || left instanceof AST_SymbolRef;
|
||||||
switch (node.operator) {
|
switch (node.operator) {
|
||||||
case "=":
|
case "=":
|
||||||
if (left.equivalent_to(node.right) && !left.has_side_effects(compressor)) {
|
if (left.equivalent_to(right) && !left.has_side_effects(compressor)) {
|
||||||
node.right.walk(tw);
|
right.walk(tw);
|
||||||
walk_prop(left);
|
walk_prop(left);
|
||||||
node.__drop = true;
|
node.__drop = true;
|
||||||
return true;
|
return true;
|
||||||
@@ -838,7 +839,7 @@ merge(Compressor.prototype, {
|
|||||||
walk_assign();
|
walk_assign();
|
||||||
} else {
|
} else {
|
||||||
mark_assignment_to_arguments(left);
|
mark_assignment_to_arguments(left);
|
||||||
node.right.walk(tw);
|
right.walk(tw);
|
||||||
}
|
}
|
||||||
pop(tw);
|
pop(tw);
|
||||||
return true;
|
return true;
|
||||||
@@ -855,7 +856,7 @@ merge(Compressor.prototype, {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var safe = safe_to_read(tw, d);
|
var safe = safe_to_read(tw, d);
|
||||||
node.right.walk(tw);
|
right.walk(tw);
|
||||||
if (safe && !left.in_arg && safe_to_assign(tw, d)) {
|
if (safe && !left.in_arg && safe_to_assign(tw, d)) {
|
||||||
push_ref(d, left);
|
push_ref(d, left);
|
||||||
mark(tw, d);
|
mark(tw, d);
|
||||||
@@ -864,7 +865,7 @@ merge(Compressor.prototype, {
|
|||||||
return make_node(AST_Binary, node, {
|
return make_node(AST_Binary, node, {
|
||||||
operator: node.operator.slice(0, -1),
|
operator: node.operator.slice(0, -1),
|
||||||
left: make_ref(left, fixed),
|
left: make_ref(left, fixed),
|
||||||
right: node.right
|
right: node.right,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
left.fixed.assigns = !fixed || !fixed.assigns ? [] : fixed.assigns.slice();
|
left.fixed.assigns = !fixed || !fixed.assigns ? [] : fixed.assigns.slice();
|
||||||
@@ -899,7 +900,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function walk_assign() {
|
function walk_assign() {
|
||||||
node.right.walk(tw);
|
right.walk(tw);
|
||||||
scan_declaration(tw, compressor, left, function() {
|
scan_declaration(tw, compressor, left, function() {
|
||||||
return node.right;
|
return node.right;
|
||||||
}, function(sym, fixed, walk) {
|
}, function(sym, fixed, walk) {
|
||||||
@@ -911,14 +912,14 @@ merge(Compressor.prototype, {
|
|||||||
var d = sym.definition();
|
var d = sym.definition();
|
||||||
d.assignments++;
|
d.assignments++;
|
||||||
if (fixed
|
if (fixed
|
||||||
&& !is_modified(compressor, tw, node, node.right, 0)
|
&& !is_modified(compressor, tw, node, right, 0, is_immutable(right), recursive_ref(tw, d))
|
||||||
&& !sym.in_arg
|
&& !sym.in_arg
|
||||||
&& safe_to_assign(tw, d)) {
|
&& safe_to_assign(tw, d)) {
|
||||||
push_ref(d, sym);
|
push_ref(d, sym);
|
||||||
mark(tw, d);
|
mark(tw, d);
|
||||||
if (d.single_use && left instanceof AST_Destructured) d.single_use = false;
|
if (d.single_use && left instanceof AST_Destructured) d.single_use = false;
|
||||||
tw.loop_ids[d.id] = tw.in_loop;
|
tw.loop_ids[d.id] = tw.in_loop;
|
||||||
mark_escaped(tw, d, sym.scope, node, node.right, 0, 1);
|
mark_escaped(tw, d, sym.scope, node, right, 0, 1);
|
||||||
sym.fixed = d.fixed = fixed;
|
sym.fixed = d.fixed = fixed;
|
||||||
sym.fixed.assigns = [ node ];
|
sym.fixed.assigns = [ node ];
|
||||||
} else {
|
} else {
|
||||||
@@ -3656,11 +3657,11 @@ merge(Compressor.prototype, {
|
|||||||
// may_throw_on_access()
|
// may_throw_on_access()
|
||||||
// returns true if this node may be null, undefined or contain `AST_Accessor`
|
// returns true if this node may be null, undefined or contain `AST_Accessor`
|
||||||
(function(def) {
|
(function(def) {
|
||||||
AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
|
AST_Node.DEFMETHOD("may_throw_on_access", function(compressor, force) {
|
||||||
return !compressor.option("pure_getters") || this._dot_throw(compressor);
|
return !compressor.option("pure_getters") || this._dot_throw(compressor, force);
|
||||||
});
|
});
|
||||||
function is_strict(compressor) {
|
function is_strict(compressor, force) {
|
||||||
return /strict/.test(compressor.option("pure_getters"));
|
return force || /strict/.test(compressor.option("pure_getters"));
|
||||||
}
|
}
|
||||||
def(AST_Node, is_strict);
|
def(AST_Node, is_strict);
|
||||||
def(AST_Array, return_false);
|
def(AST_Array, return_false);
|
||||||
@@ -3683,28 +3684,28 @@ merge(Compressor.prototype, {
|
|||||||
return this.consequent._dot_throw(compressor) || this.alternative._dot_throw(compressor);
|
return this.consequent._dot_throw(compressor) || this.alternative._dot_throw(compressor);
|
||||||
});
|
});
|
||||||
def(AST_Constant, return_false);
|
def(AST_Constant, return_false);
|
||||||
def(AST_Dot, function(compressor) {
|
def(AST_Dot, function(compressor, force) {
|
||||||
if (!is_strict(compressor)) return false;
|
if (!is_strict(compressor, force)) return false;
|
||||||
var exp = this.expression;
|
var exp = this.expression;
|
||||||
if (exp instanceof AST_SymbolRef) exp = exp.fixed_value();
|
if (exp instanceof AST_SymbolRef) exp = exp.fixed_value();
|
||||||
return !(this.property == "prototype" && is_lambda(exp));
|
return !(this.property == "prototype" && is_lambda(exp));
|
||||||
});
|
});
|
||||||
def(AST_Lambda, return_false);
|
def(AST_Lambda, return_false);
|
||||||
def(AST_Null, return_true);
|
def(AST_Null, return_true);
|
||||||
def(AST_Object, function(compressor) {
|
def(AST_Object, function(compressor, force) {
|
||||||
return is_strict(compressor) && !all(this.properties, function(prop) {
|
return is_strict(compressor, force) && !all(this.properties, function(prop) {
|
||||||
return prop instanceof AST_ObjectKeyVal;
|
return prop instanceof AST_ObjectKeyVal;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
def(AST_ObjectIdentity, function(compressor) {
|
def(AST_ObjectIdentity, function(compressor, force) {
|
||||||
return is_strict(compressor) && !this.scope.new;
|
return is_strict(compressor, force) && !this.scope.new;
|
||||||
});
|
});
|
||||||
def(AST_Sequence, function(compressor) {
|
def(AST_Sequence, function(compressor) {
|
||||||
return this.tail_node()._dot_throw(compressor);
|
return this.tail_node()._dot_throw(compressor);
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(compressor) {
|
def(AST_SymbolRef, function(compressor, force) {
|
||||||
if (this.is_undefined) return true;
|
if (this.is_undefined) return true;
|
||||||
if (!is_strict(compressor)) return false;
|
if (!is_strict(compressor, force)) return false;
|
||||||
if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
|
if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
|
||||||
if (this.is_immutable()) return false;
|
if (this.is_immutable()) return false;
|
||||||
var def = this.definition();
|
var def = this.definition();
|
||||||
@@ -5817,11 +5818,10 @@ merge(Compressor.prototype, {
|
|||||||
var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node, props) {
|
var assign_as_unused = /keep_assign/.test(compressor.option("unused")) ? return_false : function(node, props) {
|
||||||
var sym, nested = false;
|
var sym, nested = false;
|
||||||
if (node instanceof AST_Assign) {
|
if (node instanceof AST_Assign) {
|
||||||
if (node.write_only || node.operator == "=") sym = node.left;
|
if (node.write_only || node.operator == "=") sym = extract_reference(node.left, props);
|
||||||
} else if (node instanceof AST_Unary) {
|
} else if (node instanceof AST_Unary) {
|
||||||
if (node.write_only) sym = node.expression;
|
if (node.write_only) sym = extract_reference(node.expression, props);
|
||||||
}
|
}
|
||||||
if (/strict/.test(compressor.option("pure_getters"))) sym = extract_reference(sym, props);
|
|
||||||
if (!(sym instanceof AST_SymbolRef)) return;
|
if (!(sym instanceof AST_SymbolRef)) return;
|
||||||
var def = sym.definition();
|
var def = sym.definition();
|
||||||
if (export_defaults[def.id]) return;
|
if (export_defaults[def.id]) return;
|
||||||
@@ -5832,15 +5832,17 @@ merge(Compressor.prototype, {
|
|||||||
function extract_reference(node, props) {
|
function extract_reference(node, props) {
|
||||||
if (node instanceof AST_PropAccess) {
|
if (node instanceof AST_PropAccess) {
|
||||||
var expr = node.expression;
|
var expr = node.expression;
|
||||||
if (!expr.may_throw_on_access(compressor)) {
|
if (!expr.may_throw_on_access(compressor, true)) {
|
||||||
nested = true;
|
nested = true;
|
||||||
if (props && node instanceof AST_Sub) props.unshift(node.property);
|
if (props && node instanceof AST_Sub) props.unshift(node.property);
|
||||||
return extract_reference(expr, props);
|
return extract_reference(expr, props);
|
||||||
}
|
}
|
||||||
} else if (node instanceof AST_Assign && node.operator == "=") {
|
} else if (node instanceof AST_Assign && node.operator == "=") {
|
||||||
|
node.write_only = "p";
|
||||||
var ref = extract_reference(node.right);
|
var ref = extract_reference(node.right);
|
||||||
if (props) props.assign = node;
|
if (!props) return ref;
|
||||||
return ref;
|
props.assign = node;
|
||||||
|
return ref instanceof AST_SymbolRef ? ref : node.left;
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@@ -6125,6 +6127,10 @@ merge(Compressor.prototype, {
|
|||||||
value = make_node(AST_Number, node, { value: 0 });
|
value = make_node(AST_Number, node, { value: 0 });
|
||||||
}
|
}
|
||||||
if (value) {
|
if (value) {
|
||||||
|
if (props.assign) {
|
||||||
|
var assign = props.assign.drop_side_effect_free(compressor);
|
||||||
|
if (assign) props.unshift(assign);
|
||||||
|
}
|
||||||
if (parent instanceof AST_Sequence && parent.tail_node() !== node) {
|
if (parent instanceof AST_Sequence && parent.tail_node() !== node) {
|
||||||
value = value.drop_side_effect_free(compressor);
|
value = value.drop_side_effect_free(compressor);
|
||||||
}
|
}
|
||||||
@@ -6662,16 +6668,17 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}, true);
|
}, true);
|
||||||
}))) {
|
}))) {
|
||||||
if (props.assign) {
|
if (node.write_only === "p" && node.right.may_throw_on_access(compressor, true)) return;
|
||||||
props.assign.write_only = true;
|
var assign = props.assign;
|
||||||
props.assign.walk(tw);
|
if (assign) {
|
||||||
delete props.assign.write_only;
|
assign.write_only = true;
|
||||||
|
assign.walk(tw);
|
||||||
|
assign.write_only = "p";
|
||||||
}
|
}
|
||||||
props.forEach(function(prop) {
|
props.forEach(function(prop) {
|
||||||
prop.walk(tw);
|
prop.walk(tw);
|
||||||
});
|
});
|
||||||
if (node instanceof AST_Assign) {
|
if (node instanceof AST_Assign) {
|
||||||
if (node.write_only === "p" && node.right.may_throw_on_access(compressor)) return;
|
|
||||||
var right = get_rhs(node);
|
var right = get_rhs(node);
|
||||||
if (init && node.write_only === true && node_def.scope === self && !right.has_side_effects(compressor)) {
|
if (init && node.write_only === true && node_def.scope === self && !right.has_side_effects(compressor)) {
|
||||||
initializations.add(node_def.id, right);
|
initializations.add(node_def.id, right);
|
||||||
@@ -7312,11 +7319,8 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Assign, function(compressor) {
|
def(AST_Assign, function(compressor) {
|
||||||
var left = this.left;
|
var left = this.left;
|
||||||
if (left instanceof AST_PropAccess) {
|
if (left instanceof AST_PropAccess) {
|
||||||
var expr = left.expression;
|
if (left.expression.may_throw_on_access(compressor, true)) return this;
|
||||||
if (expr instanceof AST_Assign && expr.operator == "=" && !expr.may_throw_on_access(compressor)) {
|
if (compressor.has_directive("use strict") && left.expression.is_constant()) return this;
|
||||||
expr.write_only = "p";
|
|
||||||
}
|
|
||||||
if (compressor.has_directive("use strict") && expr.is_constant()) return this;
|
|
||||||
}
|
}
|
||||||
if (left.has_side_effects(compressor)) return this;
|
if (left.has_side_effects(compressor)) return this;
|
||||||
var right = this.right;
|
var right = this.right;
|
||||||
|
|||||||
@@ -1546,6 +1546,8 @@ drop_unused_self_reference: {
|
|||||||
options = {
|
options = {
|
||||||
pure_getters: "strict",
|
pure_getters: "strict",
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
toplevel: true,
|
toplevel: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2371,6 +2371,7 @@ function_parameter_ie8: {
|
|||||||
issue_3664: {
|
issue_3664: {
|
||||||
options = {
|
options = {
|
||||||
pure_getters: "strict",
|
pure_getters: "strict",
|
||||||
|
side_effects: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
@@ -2381,7 +2382,7 @@ issue_3664: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function() {
|
console.log(function() {
|
||||||
var b = ([ b && console.log("FAIL") ].p = 0, 0);
|
var b = (b && console.log("FAIL"), 0, 0);
|
||||||
return "PASS";
|
return "PASS";
|
||||||
}());
|
}());
|
||||||
}
|
}
|
||||||
@@ -2391,6 +2392,7 @@ issue_3664: {
|
|||||||
issue_3673: {
|
issue_3673: {
|
||||||
options = {
|
options = {
|
||||||
pure_getters: "strict",
|
pure_getters: "strict",
|
||||||
|
sequences: true,
|
||||||
side_effects: true,
|
side_effects: true,
|
||||||
toplevel: true,
|
toplevel: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
@@ -2401,8 +2403,6 @@ issue_3673: {
|
|||||||
console.log("PASS");
|
console.log("PASS");
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a;
|
|
||||||
(a = [ a ]).p = 42;
|
|
||||||
console.log("PASS");
|
console.log("PASS");
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
|
|||||||
@@ -6026,6 +6026,8 @@ drop_unused_self_reference: {
|
|||||||
options = {
|
options = {
|
||||||
pure_getters: "strict",
|
pure_getters: "strict",
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
toplevel: true,
|
toplevel: true,
|
||||||
unused: true,
|
unused: true,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1564,3 +1564,77 @@ issue_4803: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nested_property_assignments_1: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var f;
|
||||||
|
((f = function() {
|
||||||
|
console.log("FAIL");
|
||||||
|
}).p = f).q = console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
nested_property_assignments_2: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {};
|
||||||
|
(function() {
|
||||||
|
var a;
|
||||||
|
(o.p = a = {}).q = "PASS";
|
||||||
|
})();
|
||||||
|
console.log(o.p.q);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {};
|
||||||
|
(function() {
|
||||||
|
(o.p = {}).q = "PASS";
|
||||||
|
})();
|
||||||
|
console.log(o.p.q);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
nested_property_assignments_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
pure_getters: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = { p: {} };
|
||||||
|
(function(a) {
|
||||||
|
console && a;
|
||||||
|
if (console) {
|
||||||
|
a = a.p;
|
||||||
|
a.q = a;
|
||||||
|
}
|
||||||
|
})(o);
|
||||||
|
console.log(o.p.q === o.p ? "PASS" : "FAIL");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = { p: {} };
|
||||||
|
(function(a) {
|
||||||
|
console;
|
||||||
|
if (console)
|
||||||
|
(a = a.p).q = a;
|
||||||
|
})(o);
|
||||||
|
console.log(o.p.q === o.p ? "PASS" : "FAIL");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -445,9 +445,9 @@ function addTrailingComma(list) {
|
|||||||
|
|
||||||
function createParams(was_async, was_generator, noDuplicate) {
|
function createParams(was_async, was_generator, noDuplicate) {
|
||||||
var save_async = async;
|
var save_async = async;
|
||||||
if (was_async) async = true;
|
if (!async) async = was_async;
|
||||||
var save_generator = generator;
|
var save_generator = generator;
|
||||||
if (was_generator) generator = true;
|
if (!generator) generator = was_generator;
|
||||||
var len = unique_vars.length;
|
var len = unique_vars.length;
|
||||||
var params = [];
|
var params = [];
|
||||||
for (var n = rng(4); --n >= 0;) {
|
for (var n = rng(4); --n >= 0;) {
|
||||||
@@ -569,9 +569,9 @@ function createAssignmentPairs(recurmax, stmtDepth, canThrow, nameLenBefore, was
|
|||||||
function createName() {
|
function createName() {
|
||||||
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity");
|
||||||
var save_async = async;
|
var save_async = async;
|
||||||
if (was_async) async = true;
|
if (!async) async = was_async;
|
||||||
var save_generator = generator;
|
var save_generator = generator;
|
||||||
if (was_generator) generator = true;
|
if (!generator) generator = was_generator;
|
||||||
var name = createVarName(MANDATORY);
|
var name = createVarName(MANDATORY);
|
||||||
generator = save_generator;
|
generator = save_generator;
|
||||||
async = save_async;
|
async = save_async;
|
||||||
|
|||||||
Reference in New Issue
Block a user