preserve ThisBinding for side_effects
This commit is contained in:
committed by
Richard van Velzen
parent
9662228f6a
commit
6547437725
@@ -179,9 +179,9 @@ merge(Compressor.prototype, {
|
||||
// we shouldn't compress (1,func)(something) to
|
||||
// func(something) because that changes the meaning of
|
||||
// the func (becomes lexical instead of global).
|
||||
function maintain_call_binding(parent, orig, val) {
|
||||
function maintain_this_binding(parent, orig, val) {
|
||||
if (parent instanceof AST_Call && parent.expression === orig) {
|
||||
if (val instanceof AST_PropAccess || (val instanceof AST_Symbol && val.name === "eval")) {
|
||||
if (val instanceof AST_PropAccess || val instanceof AST_SymbolRef && val.name === "eval") {
|
||||
return make_node(AST_Seq, orig, {
|
||||
car: make_node(AST_Number, orig, {
|
||||
value: 0
|
||||
@@ -383,7 +383,7 @@ merge(Compressor.prototype, {
|
||||
if (is_lvalue(node, parent)) return node;
|
||||
|
||||
// Remove var definition and return its value to the TreeTransformer to replace.
|
||||
var value = maintain_call_binding(parent, node, var_decl.value);
|
||||
var value = maintain_this_binding(parent, node, var_decl.value);
|
||||
var_decl.value = null;
|
||||
|
||||
var_defs.splice(var_defs_index, 1);
|
||||
@@ -2125,7 +2125,7 @@ merge(Compressor.prototype, {
|
||||
if (!compressor.option("side_effects"))
|
||||
return self;
|
||||
if (!self.car.has_side_effects(compressor)) {
|
||||
return maintain_call_binding(compressor.parent(), self, self.cdr);
|
||||
return maintain_this_binding(compressor.parent(), self, self.cdr);
|
||||
}
|
||||
if (compressor.option("cascade")) {
|
||||
if (self.car instanceof AST_Assign
|
||||
@@ -2315,10 +2315,10 @@ merge(Compressor.prototype, {
|
||||
if (ll.length > 1) {
|
||||
if (ll[1]) {
|
||||
compressor.warn("Condition left of && always true [{file}:{line},{col}]", self.start);
|
||||
return maintain_call_binding(compressor.parent(), self, self.right.evaluate(compressor)[0]);
|
||||
return maintain_this_binding(compressor.parent(), self, self.right.evaluate(compressor)[0]);
|
||||
} else {
|
||||
compressor.warn("Condition left of && always false [{file}:{line},{col}]", self.start);
|
||||
return maintain_call_binding(compressor.parent(), self, ll[0]);
|
||||
return maintain_this_binding(compressor.parent(), self, ll[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2327,10 +2327,10 @@ merge(Compressor.prototype, {
|
||||
if (ll.length > 1) {
|
||||
if (ll[1]) {
|
||||
compressor.warn("Condition left of || always true [{file}:{line},{col}]", self.start);
|
||||
return maintain_call_binding(compressor.parent(), self, ll[0]);
|
||||
return maintain_this_binding(compressor.parent(), self, ll[0]);
|
||||
} else {
|
||||
compressor.warn("Condition left of || always false [{file}:{line},{col}]", self.start);
|
||||
return maintain_call_binding(compressor.parent(), self, self.right.evaluate(compressor)[0]);
|
||||
return maintain_this_binding(compressor.parent(), self, self.right.evaluate(compressor)[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2555,10 +2555,10 @@ merge(Compressor.prototype, {
|
||||
if (cond.length > 1) {
|
||||
if (cond[1]) {
|
||||
compressor.warn("Condition always true [{file}:{line},{col}]", self.start);
|
||||
return maintain_call_binding(compressor.parent(), self, self.consequent);
|
||||
return maintain_this_binding(compressor.parent(), self, self.consequent);
|
||||
} else {
|
||||
compressor.warn("Condition always false [{file}:{line},{col}]", self.start);
|
||||
return maintain_call_binding(compressor.parent(), self, self.alternative);
|
||||
return maintain_this_binding(compressor.parent(), self, self.alternative);
|
||||
}
|
||||
}
|
||||
var negated = cond[0].negate(compressor);
|
||||
|
||||
@@ -194,6 +194,11 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
}
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
var name = node.name;
|
||||
if (name == "eval" && tw.parent() instanceof AST_Call) {
|
||||
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
|
||||
s.uses_eval = true;
|
||||
}
|
||||
}
|
||||
var sym = node.scope.find_variable(name);
|
||||
if (!sym) {
|
||||
var g;
|
||||
@@ -206,10 +211,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||
globals.set(name, g);
|
||||
}
|
||||
node.thedef = g;
|
||||
if (name == "eval" && tw.parent() instanceof AST_Call) {
|
||||
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope)
|
||||
s.uses_eval = true;
|
||||
}
|
||||
if (func && name == "arguments") {
|
||||
func.uses_arguments = true;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
remove_redundant_sequence_items: {
|
||||
options = { side_effects: true };
|
||||
input: {
|
||||
(0, 1, eval)();
|
||||
(0, 1, logThis)();
|
||||
(0, 1, _decorators.logThis)();
|
||||
}
|
||||
expect: {
|
||||
(0, eval)();
|
||||
logThis();
|
||||
(0, _decorators.logThis)();
|
||||
}
|
||||
@@ -13,10 +15,12 @@ remove_redundant_sequence_items: {
|
||||
dont_remove_this_binding_sequence: {
|
||||
options = { side_effects: true };
|
||||
input: {
|
||||
(0, eval)();
|
||||
(0, logThis)();
|
||||
(0, _decorators.logThis)();
|
||||
}
|
||||
expect: {
|
||||
(0, eval)();
|
||||
logThis();
|
||||
(0, _decorators.logThis)();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,11 @@ this_binding_conditionals: {
|
||||
(0 || a[b])();
|
||||
(0 || 1 && a[b])();
|
||||
(1 ? a[b] : 0)();
|
||||
|
||||
(1 && eval)();
|
||||
(0 || eval)();
|
||||
(0 || 1 && eval)();
|
||||
(1 ? eval : 0)();
|
||||
}
|
||||
expect: {
|
||||
a();
|
||||
@@ -34,6 +39,11 @@ this_binding_conditionals: {
|
||||
(0, a[b])();
|
||||
(0, a[b])();
|
||||
(0, a[b])();
|
||||
|
||||
(0, eval)();
|
||||
(0, eval)();
|
||||
(0, eval)();
|
||||
(0, eval)();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,26 +54,43 @@ this_binding_collapse_vars: {
|
||||
input: {
|
||||
var c = a; c();
|
||||
var d = a.b; d();
|
||||
var e = eval; e();
|
||||
}
|
||||
expect: {
|
||||
a();
|
||||
(0, a.b)();
|
||||
(0, eval)();
|
||||
}
|
||||
}
|
||||
|
||||
eval_direct_calls: {
|
||||
this_binding_side_effects: {
|
||||
options = {
|
||||
side_effects: true,
|
||||
collapse_vars: true
|
||||
}
|
||||
side_effects : true
|
||||
};
|
||||
input: {
|
||||
(0, eval)('');
|
||||
|
||||
var fn = eval;
|
||||
fn('');
|
||||
(function (foo) {
|
||||
(0, foo)();
|
||||
(0, foo.bar)();
|
||||
(0, eval)('console.log(foo);');
|
||||
}());
|
||||
(function (foo) {
|
||||
var eval = console;
|
||||
(0, foo)();
|
||||
(0, foo.bar)();
|
||||
(0, eval)('console.log(foo);');
|
||||
}());
|
||||
}
|
||||
expect: {
|
||||
(0, eval)('');
|
||||
(0, eval)('');
|
||||
(function (foo) {
|
||||
foo();
|
||||
(0, foo.bar)();
|
||||
(0, eval)('console.log(foo);');
|
||||
}());
|
||||
(function (foo) {
|
||||
var eval = console;
|
||||
foo();
|
||||
(0, foo.bar)();
|
||||
(0, eval)('console.log(foo);');
|
||||
}());
|
||||
}
|
||||
}
|
||||
88
test/compress/issue-976.js
Normal file
88
test/compress/issue-976.js
Normal file
@@ -0,0 +1,88 @@
|
||||
eval_collapse_vars: {
|
||||
options = {
|
||||
collapse_vars:true, sequences:false, properties:true, dead_code:true, conditionals:true,
|
||||
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
|
||||
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
|
||||
};
|
||||
input: {
|
||||
function f1() {
|
||||
var e = 7;
|
||||
var s = "abcdef";
|
||||
var i = 2;
|
||||
var eval = console.log.bind(console);
|
||||
var x = s.charAt(i++);
|
||||
var y = s.charAt(i++);
|
||||
var z = s.charAt(i++);
|
||||
eval(x, y, z, e);
|
||||
}
|
||||
function p1() { var a = foo(), b = bar(), eval = baz(); return a + b + eval; }
|
||||
function p2() { var a = foo(), b = bar(), eval = baz; return a + b + eval(); }
|
||||
(function f2(eval) {
|
||||
var a = 2;
|
||||
console.log(a - 5);
|
||||
eval("console.log(a);");
|
||||
})(eval);
|
||||
}
|
||||
expect: {
|
||||
function f1() {
|
||||
var e = 7,
|
||||
s = "abcdef",
|
||||
i = 2,
|
||||
eval = console.log.bind(console),
|
||||
x = s.charAt(i++),
|
||||
y = s.charAt(i++),
|
||||
z = s.charAt(i++);
|
||||
eval(x, y, z, e);
|
||||
}
|
||||
function p1() { return foo() + bar() + baz(); }
|
||||
function p2() { var a = foo(), b = bar(), eval = baz; return a + b + eval(); }
|
||||
(function f2(eval) {
|
||||
var a = 2;
|
||||
console.log(a - 5);
|
||||
eval("console.log(a);");
|
||||
})(eval);
|
||||
}
|
||||
}
|
||||
|
||||
eval_unused: {
|
||||
options = { unused: true, keep_fargs: false };
|
||||
input: {
|
||||
function f1(a, eval, c, d, e) {
|
||||
return a('c') + eval;
|
||||
}
|
||||
function f2(a, b, c, d, e) {
|
||||
return a + eval('c');
|
||||
}
|
||||
function f3(a, eval, c, d, e) {
|
||||
return a + eval('c');
|
||||
}
|
||||
}
|
||||
expect: {
|
||||
function f1(a, eval) {
|
||||
return a('c') + eval;
|
||||
}
|
||||
function f2(a, b, c, d, e) {
|
||||
return a + eval('c');
|
||||
}
|
||||
function f3(a, eval, c, d, e) {
|
||||
return a + eval('c');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eval_mangle: {
|
||||
mangle = {
|
||||
};
|
||||
input: {
|
||||
function f1(a, eval, c, d, e) {
|
||||
return a('c') + eval;
|
||||
}
|
||||
function f2(a, b, c, d, e) {
|
||||
return a + eval('c');
|
||||
}
|
||||
function f3(a, eval, c, d, e) {
|
||||
return a + eval('c');
|
||||
}
|
||||
}
|
||||
expect_exact: 'function f1(n,c,e,a,o){return n("c")+c}function f2(a,b,c,d,e){return a+eval("c")}function f3(a,eval,c,d,e){return a+eval("c")}'
|
||||
}
|
||||
Reference in New Issue
Block a user