Compare commits

...

4 Commits

Author SHA1 Message Date
Alex Lam S.L
7ccdf3337b v3.5.7 2019-04-24 14:05:07 +08:00
Alex Lam S.L
dafed54764 fix corner case in reduce_vars (#3378)
fixes #3377
2019-04-24 14:01:01 +08:00
Alex Lam S.L
a84beafd1b fix corner case in assignments (#3376)
fixes #3375
2019-04-24 02:50:15 +08:00
Alex Lam S.L
f01cc1e413 unwind IIFE class patterns (#3373)
fixes #2332
2019-04-21 09:49:07 +08:00
8 changed files with 158 additions and 38 deletions

View File

@@ -773,7 +773,7 @@ var AST_Label = DEFNODE("Label", "references", {
} }
}, AST_Symbol); }, AST_Symbol);
var AST_SymbolRef = DEFNODE("SymbolRef", null, { var AST_SymbolRef = DEFNODE("SymbolRef", "fixed", {
$documentation: "Reference to some symbol (not definition/declaration)", $documentation: "Reference to some symbol (not definition/declaration)",
}, AST_Symbol); }, AST_Symbol);

View File

@@ -551,6 +551,7 @@ merge(Compressor.prototype, {
mark_assignment_to_arguments(sym); mark_assignment_to_arguments(sym);
return; return;
} }
if (sym.fixed) delete sym.fixed;
var d = sym.definition(); var d = sym.definition();
var safe = safe_to_assign(tw, d, sym.scope, node.right); var safe = safe_to_assign(tw, d, sym.scope, node.right);
d.assignments++; d.assignments++;
@@ -560,7 +561,7 @@ merge(Compressor.prototype, {
var value = eq ? node.right : node; var value = eq ? node.right : node;
if (is_modified(compressor, tw, node, value, 0)) return; if (is_modified(compressor, tw, node, value, 0)) return;
if (!eq) d.chained = true; if (!eq) d.chained = true;
d.fixed = eq ? function() { sym.fixed = d.fixed = eq ? function() {
return node.right; return node.right;
} : function() { } : function() {
return make_node(AST_Binary, node, { return make_node(AST_Binary, node, {
@@ -574,7 +575,7 @@ merge(Compressor.prototype, {
mark(tw, d, false); mark(tw, d, false);
node.right.walk(tw); node.right.walk(tw);
mark(tw, d, true); mark(tw, d, true);
mark_escaped(tw, d, sym.scope, node, value, 0, 1); if (eq) mark_escaped(tw, d, sym.scope, node, value, 0, 1);
return true; return true;
}); });
def(AST_Binary, function(tw) { def(AST_Binary, function(tw) {
@@ -730,6 +731,7 @@ merge(Compressor.prototype, {
this.definition().fixed = false; this.definition().fixed = false;
}); });
def(AST_SymbolRef, function(tw, descend, compressor) { def(AST_SymbolRef, function(tw, descend, compressor) {
if (this.fixed) delete this.fixed;
var d = this.definition(); var d = this.definition();
d.references.push(this); d.references.push(this);
if (d.references.length == 1 if (d.references.length == 1
@@ -742,7 +744,7 @@ merge(Compressor.prototype, {
d.fixed = false; d.fixed = false;
} else if (d.fixed) { } else if (d.fixed) {
value = this.fixed_value(); value = this.fixed_value();
if (value instanceof AST_Lambda && recursive_ref(tw, d)) { if (recursive_ref(tw, d)) {
d.recursive_refs++; d.recursive_refs++;
} else if (value && ref_once(tw, compressor, d)) { } else if (value && ref_once(tw, compressor, d)) {
d.single_use = value instanceof AST_Lambda && !value.pinned() d.single_use = value instanceof AST_Lambda && !value.pinned()
@@ -797,13 +799,14 @@ merge(Compressor.prototype, {
mark_assignment_to_arguments(exp); mark_assignment_to_arguments(exp);
return; return;
} }
if (exp.fixed) delete exp.fixed;
var d = exp.definition(); var d = exp.definition();
var safe = safe_to_assign(tw, d, exp.scope, true); var safe = safe_to_assign(tw, d, exp.scope, true);
d.assignments++; d.assignments++;
var fixed = d.fixed; var fixed = d.fixed;
if (!fixed) return; if (!fixed) return;
d.chained = true; d.chained = true;
d.fixed = function() { exp.fixed = d.fixed = function() {
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_node(AST_UnaryPrefix, node, { left: make_node(AST_UnaryPrefix, node, {
@@ -874,10 +877,11 @@ merge(Compressor.prototype, {
this.walk(tw); this.walk(tw);
}); });
AST_Symbol.DEFMETHOD("fixed_value", function() { AST_Symbol.DEFMETHOD("fixed_value", function(final) {
var fixed = this.definition().fixed; var fixed = this.definition().fixed;
if (!fixed || fixed instanceof AST_Node) return fixed; if (!fixed) return fixed;
return fixed(); if (!final && this.fixed) fixed = this.fixed;
return fixed instanceof AST_Node ? fixed : fixed();
}); });
AST_SymbolRef.DEFMETHOD("is_immutable", function() { AST_SymbolRef.DEFMETHOD("is_immutable", function() {
@@ -1287,7 +1291,9 @@ merge(Compressor.prototype, {
if (node instanceof AST_Try) return true; if (node instanceof AST_Try) return true;
if (node instanceof AST_With) return true; if (node instanceof AST_With) return true;
if (replace_all) return false; if (replace_all) return false;
return node instanceof AST_SymbolRef && !node.is_declared(compressor); return node instanceof AST_SymbolRef
&& !node.is_declared(compressor)
&& !(parent instanceof AST_Assign && parent.left === node);
} }
function in_conditional(node, parent) { function in_conditional(node, parent) {
@@ -2597,9 +2603,9 @@ merge(Compressor.prototype, {
} }
function convert_to_predicate(obj) { function convert_to_predicate(obj) {
for (var key in obj) { Object.keys(obj).forEach(function(key) {
obj[key] = makePredicate(obj[key]); obj[key] = makePredicate(obj[key]);
} });
} }
var object_fns = [ var object_fns = [
@@ -3512,7 +3518,7 @@ merge(Compressor.prototype, {
if (def.value.has_side_effects(compressor)) { if (def.value.has_side_effects(compressor)) {
def.value.walk(tw); def.value.walk(tw);
} }
if (!node_def.chained && def.name.fixed_value() === def.value) { if (!node_def.chained && def.name.fixed_value(true) === def.value) {
fixed_ids[node_def.id] = def; fixed_ids[node_def.id] = def;
} }
} }
@@ -3783,7 +3789,7 @@ merge(Compressor.prototype, {
if (node instanceof AST_Assign) { if (node instanceof AST_Assign) {
node.right.walk(tw); node.right.walk(tw);
if (node.left === sym) { if (node.left === sym) {
if (!node_def.chained && sym.fixed_value() === node.right) { if (!node_def.chained && sym.fixed_value(true) === node.right) {
fixed_ids[node_def.id] = node; fixed_ids[node_def.id] = node;
} }
if (!node.write_only) { if (!node.write_only) {
@@ -5102,7 +5108,7 @@ merge(Compressor.prototype, {
})) { })) {
return false; return false;
} }
} else if (line instanceof AST_EmptyStatement) { } else if (line instanceof AST_Defun || line instanceof AST_EmptyStatement) {
continue; continue;
} else if (stat) { } else if (stat) {
return false; return false;
@@ -5113,16 +5119,15 @@ merge(Compressor.prototype, {
return return_value(stat); return return_value(stat);
} }
function var_exists(catches, name) {
return catches[name] || identifier_atom[name] || scope.var_names()[name];
}
function can_inject_args(catches, safe_to_inject) { function can_inject_args(catches, safe_to_inject) {
for (var i = 0; i < fn.argnames.length; i++) { for (var i = 0; i < fn.argnames.length; i++) {
var arg = fn.argnames[i]; var arg = fn.argnames[i];
if (arg.__unused) continue; if (arg.__unused) continue;
if (!safe_to_inject if (!safe_to_inject || var_exists(catches, arg.name)) return false;
|| catches[arg.name]
|| identifier_atom[arg.name]
|| scope.var_names()[arg.name]) {
return false;
}
if (in_loop) in_loop.push(arg.definition()); if (in_loop) in_loop.push(arg.definition());
} }
return true; return true;
@@ -5131,15 +5136,15 @@ merge(Compressor.prototype, {
function can_inject_vars(catches, safe_to_inject) { function can_inject_vars(catches, safe_to_inject) {
for (var i = 0; i < fn.body.length; i++) { for (var i = 0; i < fn.body.length; i++) {
var stat = fn.body[i]; var stat = fn.body[i];
if (stat instanceof AST_Defun) {
if (!safe_to_inject || var_exists(catches, stat.name.name)) return false;
continue;
}
if (!(stat instanceof AST_Var)) continue; if (!(stat instanceof AST_Var)) continue;
if (!safe_to_inject) return false; if (!safe_to_inject) return false;
for (var j = stat.definitions.length; --j >= 0;) { for (var j = stat.definitions.length; --j >= 0;) {
var name = stat.definitions[j].name; var name = stat.definitions[j].name;
if (catches[name.name] if (var_exists(catches, name.name)) return false;
|| identifier_atom[name.name]
|| scope.var_names()[name.name]) {
return false;
}
if (in_loop) in_loop.push(name.definition()); if (in_loop) in_loop.push(name.definition());
} }
} }
@@ -5243,12 +5248,21 @@ merge(Compressor.prototype, {
flatten_args(decls, expressions); flatten_args(decls, expressions);
flatten_vars(decls, expressions); flatten_vars(decls, expressions);
expressions.push(value); expressions.push(value);
if (decls.length) { var args = fn.body.filter(function(stat) {
i = scope.body.indexOf(compressor.parent(level - 1)) + 1; if (stat instanceof AST_Defun) {
scope.body.splice(i, 0, make_node(AST_Var, fn, { var def = stat.name.definition();
definitions: decls scope.functions.set(def.name, def);
})); scope.variables.set(def.name, def);
} scope.enclosed.push(def);
scope.var_names()[def.name] = true;
return true;
}
});
args.unshift(scope.body.indexOf(compressor.parent(level - 1)) + 1, 0);
if (decls.length) args.push(make_node(AST_Var, fn, {
definitions: decls
}));
[].splice.apply(scope.body, args);
return expressions; return expressions;
} }
}); });

View File

@@ -3,7 +3,7 @@
"description": "JavaScript parser, mangler/compressor and beautifier toolkit", "description": "JavaScript parser, mangler/compressor and beautifier toolkit",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)", "author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause", "license": "BSD-2-Clause",
"version": "3.5.6", "version": "3.5.7",
"engines": { "engines": {
"node": ">=0.8.0" "node": ">=0.8.0"
}, },

View File

@@ -289,3 +289,25 @@ increment_decrement_2: {
} }
expect_stdout: "42" expect_stdout: "42"
} }
issue_3375: {
options = {
assignments: true,
reduce_vars: true,
}
input: {
console.log(typeof function(b) {
var a = b += 1;
--b;
return a;
}("object"));
}
expect: {
console.log(typeof function(b) {
var a = b += 1;
--b;
return a;
}("object"));
}
expect_stdout: "string"
}

View File

@@ -6157,3 +6157,24 @@ sub_property: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
assign_undeclared: {
options = {
collapse_vars: true,
toplevel: true,
unused: true,
}
input: {
var A = (console.log(42), function() {});
B = new A();
console.log(typeof B);
}
expect: {
B = new (console.log(42), function() {})();
console.log(typeof B);
}
expect_stdout: [
"42",
"object",
]
}

View File

@@ -2005,3 +2005,24 @@ issue_3233: {
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
issue_3375: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
var b = 1;
var a = c = [], c = --b + ("function" == typeof f && f());
var a = c && c[a];
console.log(a, b);
}
expect: {
var b = 1;
var a = [], c = --b + ("function" == typeof f && f());
a = c && c[a];
console.log(a, b);
}
expect_stdout: "0 0"
}

View File

@@ -3003,12 +3003,10 @@ issue_3366: {
f(); f();
} }
expect: { expect: {
(function() { void function() {
function a() {} this && a && console.log("PASS");
(function() { }();
this && a && console.log("PASS"); function a() {}
})();
})();
} }
expect_stdout: "PASS" expect_stdout: "PASS"
} }
@@ -3041,3 +3039,29 @@ issue_3371: {
} }
expect_stdout: "function" expect_stdout: "function"
} }
class_iife: {
options = {
inline: true,
sequences: true,
toplevel: true,
}
input: {
var A = function() {
function B() {}
B.prototype.m = function() {
console.log("PASS");
};
return B;
}();
new A().m();
}
expect: {
var A = (B.prototype.m = function() {
console.log("PASS");
}, B);
function B() {}
new A().m();
}
expect_stdout: "PASS"
}

View File

@@ -6737,3 +6737,21 @@ drop_side_effect_free: {
} }
expect_stdout: "123" expect_stdout: "123"
} }
issue_3377: {
options = {
reduce_vars: true,
unused: true,
}
input: {
console.log(function f() {
return f[0], (f = 42);
}());
}
expect: {
console.log(function f() {
return f[0], (f = 42);
}());
}
expect_stdout: "42"
}