fix corner case in arguments (#3421)

fixes #3420
This commit is contained in:
Alex Lam S.L
2019-05-19 12:59:40 +08:00
committed by GitHub
parent 04439edcec
commit ae77ebe5a5
3 changed files with 255 additions and 20 deletions

View File

@@ -105,10 +105,10 @@ function Compressor(options, false_by_default) {
} }
if (this.options["inline"] === true) this.options["inline"] = 3; if (this.options["inline"] === true) this.options["inline"] = 3;
var keep_fargs = this.options["keep_fargs"]; var keep_fargs = this.options["keep_fargs"];
this.drop_fargs = keep_fargs == "strict" ? function(lambda) { this.drop_fargs = keep_fargs == "strict" ? function(lambda, parent) {
if (lambda.length_read) return false; if (lambda.length_read) return false;
var name = lambda.name; var name = lambda.name;
if (!name) return true; if (!name) return parent && parent.TYPE == "Call";
if (name.fixed_value() !== lambda) return false; if (name.fixed_value() !== lambda) return false;
var def = name.definition(); var def = name.definition();
if (def.direct_access) return false; if (def.direct_access) return false;
@@ -527,12 +527,9 @@ merge(Compressor.prototype, {
function mark_assignment_to_arguments(node) { function mark_assignment_to_arguments(node) {
if (!(node instanceof AST_Sub)) return; if (!(node instanceof AST_Sub)) return;
var expr = node.expression; var expr = node.expression;
var prop = node.property; if (!(expr instanceof AST_SymbolRef)) return;
if (expr instanceof AST_SymbolRef var def = expr.definition();
&& is_arguments(expr.definition()) if (is_arguments(def) && node.property instanceof AST_Number) def.reassigned = true;
&& prop instanceof AST_Number) {
expr.definition().reassigned = true;
}
} }
var suppressor = new TreeWalker(function(node) { var suppressor = new TreeWalker(function(node) {
@@ -3641,7 +3638,7 @@ merge(Compressor.prototype, {
node.name = null; node.name = null;
} }
if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) { if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
var trim = compressor.drop_fargs(node); var trim = compressor.drop_fargs(node, parent);
for (var a = node.argnames, i = a.length; --i >= 0;) { for (var a = node.argnames, i = a.length; --i >= 0;) {
var sym = a[i]; var sym = a[i];
if (!(sym.definition().id in in_use_ids)) { if (!(sym.definition().id in in_use_ids)) {
@@ -3832,6 +3829,7 @@ merge(Compressor.prototype, {
}; };
} }
}); });
tt.push(compressor.parent());
self.transform(tt); self.transform(tt);
function verify_safe_usage(def, read, modified) { function verify_safe_usage(def, read, modified) {
@@ -6682,23 +6680,30 @@ merge(Compressor.prototype, {
} }
} }
} }
var fn; var parent = compressor.parent();
var def, fn, fn_parent;
if (compressor.option("arguments") if (compressor.option("arguments")
&& expr instanceof AST_SymbolRef && expr instanceof AST_SymbolRef
&& is_arguments(expr.definition()) && is_arguments(def = expr.definition())
&& prop instanceof AST_Number && prop instanceof AST_Number
&& (fn = expr.scope) === compressor.find_parent(AST_Lambda)) { && (fn = expr.scope) === find_lambda()) {
var index = prop.getValue(); var index = prop.getValue();
if (parent instanceof AST_UnaryPrefix && parent.operator == "delete") {
if (!def.deleted) def.deleted = [];
def.deleted[index] = true;
}
var argname = fn.argnames[index]; var argname = fn.argnames[index];
if (argname && compressor.has_directive("use strict")) { if (def.deleted && def.deleted[index]) {
var def = argname.definition(); argname = null;
} else if (argname && compressor.has_directive("use strict")) {
var arg_def = argname.definition();
if (!compressor.option("reduce_vars") if (!compressor.option("reduce_vars")
|| expr.definition().reassigned || def.reassigned
|| def.assignments || arg_def.assignments
|| def.orig.length > 1) { || arg_def.orig.length > 1) {
argname = null; argname = null;
} }
} else if (!argname && compressor.drop_fargs(fn) && index < fn.argnames.length + 5) { } else if (!argname && index < fn.argnames.length + 5 && compressor.drop_fargs(fn, fn_parent)) {
while (index >= fn.argnames.length) { while (index >= fn.argnames.length) {
argname = make_node(AST_SymbolFunarg, fn, { argname = make_node(AST_SymbolFunarg, fn, {
name: fn.make_var_name("argument_" + fn.argnames.length), name: fn.make_var_name("argument_" + fn.argnames.length),
@@ -6711,14 +6716,14 @@ merge(Compressor.prototype, {
if (argname && find_if(function(node) { if (argname && find_if(function(node) {
return node.name === argname.name; return node.name === argname.name;
}, fn.argnames) === argname) { }, fn.argnames) === argname) {
expr.definition().reassigned = false; def.reassigned = false;
var sym = make_node(AST_SymbolRef, self, argname); var sym = make_node(AST_SymbolRef, self, argname);
sym.reference({}); sym.reference({});
delete argname.__unused; delete argname.__unused;
return sym; return sym;
} }
} }
if (is_lhs(compressor.self(), compressor.parent())) return self; if (is_lhs(compressor.self(), parent)) return self;
if (key !== prop) { if (key !== prop) {
var sub = self.flatten_object(property, compressor); var sub = self.flatten_object(property, compressor);
if (sub) { if (sub) {
@@ -6767,6 +6772,16 @@ merge(Compressor.prototype, {
return best_of(compressor, ev, self); return best_of(compressor, ev, self);
} }
return self; return self;
function find_lambda() {
var i = 0, p;
while (p = compressor.parent(i++)) {
if (p instanceof AST_Lambda) {
fn_parent = compressor.parent(i);
return p;
}
}
}
}); });
AST_Scope.DEFMETHOD("contains_this", function() { AST_Scope.DEFMETHOD("contains_this", function() {

View File

@@ -622,3 +622,157 @@ issue_3282_2_passes: {
} }
expect_stdout: true expect_stdout: true
} }
issue_3420_1: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
console.log(function() {
return function() {
return arguments[0];
};
}().length);
}
expect: {
console.log(function() {
return function() {
return arguments[0];
};
}().length);
}
expect_stdout: "0"
}
issue_3420_2: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
var foo = function() {
delete arguments[0];
};
foo();
}
expect: {
var foo = function() {
delete arguments[0];
};
foo();
}
expect_stdout: true
}
issue_3420_3: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
"use strict";
var foo = function() {
delete arguments[0];
};
foo();
}
expect: {
"use strict";
var foo = function() {
delete arguments[0];
};
foo();
}
expect_stdout: true
}
issue_3420_4: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
!function() {
console.log(arguments[0]);
delete arguments[0];
console.log(arguments[0]);
}(42);
}
expect: {
!function(argument_0) {
console.log(argument_0);
delete arguments[0];
console.log(arguments[0]);
}(42);
}
expect_stdout: [
"42",
"undefined",
]
}
issue_3420_5: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
"use strict";
!function() {
console.log(arguments[0]);
delete arguments[0];
console.log(arguments[0]);
}(42);
}
expect: {
"use strict";
!function(argument_0) {
console.log(argument_0);
delete arguments[0];
console.log(arguments[0]);
}(42);
}
expect_stdout: [
"42",
"undefined",
]
}
issue_3420_6: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
console.log(function() {
return delete arguments[0];
}());
}
expect: {
console.log(function() {
return delete arguments[0];
}());
}
expect_stdout: "true"
}
issue_3420_7: {
options = {
arguments: true,
keep_fargs: "strict",
}
input: {
"use strict";
console.log(function() {
return delete arguments[0];
}());
}
expect: {
"use strict";
console.log(function() {
return delete arguments[0];
}());
}
expect_stdout: "true"
}

View File

@@ -1051,3 +1051,69 @@ function_name_mangle_ie8: {
expect_exact: "(function(){console.log(typeof function o(){})})();" expect_exact: "(function(){console.log(typeof function o(){})})();"
expect_stdout: "function" expect_stdout: "function"
} }
issue_3420_1: {
options = {
keep_fargs: "strict",
unused: true,
}
input: {
console.log(function() {
return function(a, b, c, d) {
return a + b;
};
}().length);
}
expect: {
console.log(function() {
return function(a, b, c, d) {
return a + b;
};
}().length);
}
expect_stdout: "4"
}
issue_3420_2: {
options = {
inline: true,
keep_fargs: "strict",
unused: true,
}
input: {
console.log(function() {
return function(a, b, c, d) {
return a + b;
};
}().length);
}
expect: {
console.log(function(a, b, c, d) {
return a + b;
}.length);
}
expect_stdout: "4"
}
issue_3420_3: {
options = {
inline: true,
keep_fargs: "strict",
reduce_vars: true,
unused: true,
}
input: {
console.log(function() {
function f(a, b, c, d) {
return a + b;
}
return f;
}().length);
}
expect: {
console.log(function(a, b, c, d) {
return a + b;
}.length);
}
expect_stdout: "4"
}