type: typeof val
}));
}
- };
+ }
+
+ function needs_unbinding(compressor, val) {
+ return val instanceof AST_PropAccess
+ || compressor.has_directive("use strict")
+ && is_undeclared_ref(val)
+ && val.name == "eval";
+ }
// 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_this_binding(parent, orig, val) {
+ function maintain_this_binding(compressor, parent, orig, val) {
if (parent instanceof AST_UnaryPrefix && parent.operator == "delete"
- || parent.TYPE == "Call" && parent.expression === orig
- && (val instanceof AST_PropAccess || val instanceof AST_SymbolRef && val.name == "eval")) {
+ || parent.TYPE == "Call" && parent.expression === orig && needs_unbinding(compressor, val)) {
return make_sequence(orig, [ make_node(AST_Number, orig, { value: 0 }), val ]);
}
return val;
var def = candidate.name.definition();
if (def.references.length - def.replaced == 1 && !compressor.exposed(def)) {
def.replaced++;
- return maintain_this_binding(parent, node, candidate.value);
+ return maintain_this_binding(compressor, parent, node, candidate.value);
}
return make_node(AST_Assign, candidate, {
operator: "=",
}
if (value) {
props.push(value);
- return maintain_this_binding(parent, node, make_sequence(node, props.map(function(prop) {
+ return maintain_this_binding(compressor, parent, node, make_sequence(node, props.map(function(prop) {
return prop.transform(tt);
})));
}
var exp = this.expression;
if (!(exp instanceof AST_Sequence)) return this;
var tail = exp.tail_node();
- if (tail instanceof AST_PropAccess && !(this instanceof AST_New)) return this;
+ if (needs_unbinding(compressor, tail) && !(this instanceof AST_New)) return this;
var expressions = exp.expressions.slice(0, -1);
var node = this.clone();
node.expression = tail;
var end = expressions.length - 1;
trim_right_for_undefined();
if (end == 0) {
- self = maintain_this_binding(compressor.parent(), compressor.self(), expressions[0]);
+ self = maintain_this_binding(compressor, compressor.parent(), compressor.self(), expressions[0]);
if (!(self instanceof AST_Sequence)) self = self.optimize(compressor);
return self;
}
var ll = fuzzy_eval(self.left);
if (!ll) {
compressor.warn("Condition left of && always false [{file}:{line},{col}]", self.start);
- return maintain_this_binding(compressor.parent(), compressor.self(), self.left).optimize(compressor);
+ return maintain_this_binding(compressor, compressor.parent(), compressor.self(), self.left).optimize(compressor);
} else if (!(ll instanceof AST_Node)) {
compressor.warn("Condition left of && always true [{file}:{line},{col}]", self.start);
return make_sequence(self, [ self.left, self.right ]).optimize(compressor);
return make_sequence(self, [ self.left, self.right ]).optimize(compressor);
} else if (!(ll instanceof AST_Node)) {
compressor.warn("Condition left of || always true [{file}:{line},{col}]", self.start);
- return maintain_this_binding(compressor.parent(), compressor.self(), self.left).optimize(compressor);
+ return maintain_this_binding(compressor, compressor.parent(), compressor.self(), self.left).optimize(compressor);
}
var rr = self.right.evaluate(compressor);
if (!rr) {
conditionals: true,
evaluate: true,
side_effects: true,
- };
+ }
input: {
+ "use strict";
(1 && a)();
(0 || a)();
(0 || 1 && a)();
(1 ? eval : 0)();
}
expect: {
+ "use strict";
a();
a();
a();
collapse_vars: true,
toplevel: true,
unused: true,
- };
+ }
input: {
+ "use strict";
var c = a; c();
var d = a.b; d();
var e = eval; e();
}
expect: {
+ "use strict";
a();
(0, a.b)();
(0, eval)();
this_binding_side_effects: {
options = {
side_effects : true
- };
+ }
input: {
- (function (foo) {
+ (function(foo) {
+ (0, foo)();
+ (0, foo.bar)();
+ (0, eval)("console.log(foo);");
+ }());
+ (function(foo) {
+ "use strict";
(0, foo)();
(0, foo.bar)();
- (0, eval)('console.log(foo);');
+ (0, eval)("console.log(foo);");
}());
- (function (foo) {
+ (function(foo) {
var eval = console;
(0, foo)();
(0, foo.bar)();
- (0, eval)('console.log(foo);');
+ (0, eval)("console.log(foo);");
}());
}
expect: {
- (function (foo) {
+ (function(foo) {
foo();
(0, foo.bar)();
- (0, eval)('console.log(foo);');
+ eval("console.log(foo);");
}());
- (function (foo) {
+ (function(foo) {
+ "use strict";
+ foo();
+ (0, foo.bar)();
+ (0, eval)("console.log(foo);");
+ }());
+ (function(foo) {
var eval = console;
foo();
(0, foo.bar)();
- (0, eval)('console.log(foo);');
+ eval("console.log(foo);");
+ }());
+ }
+}
+
+this_binding_sequences: {
+ options = {
+ sequences: true,
+ side_effects: true,
+ }
+ input: {
+ console.log(typeof function() {
+ return eval("this");
+ }());
+ console.log(typeof function() {
+ "use strict";
+ return eval("this");
+ }());
+ console.log(typeof function() {
+ return (0, eval)("this");
+ }());
+ console.log(typeof function() {
+ "use strict";
+ return (0, eval)("this");
+ }());
+ }
+ expect: {
+ console.log(typeof function() {
+ return eval("this");
+ }()),
+ console.log(typeof function() {
+ "use strict";
+ return eval("this");
+ }()),
+ console.log(typeof function() {
+ return eval("this");
+ }()),
+ console.log(typeof function() {
+ "use strict";
+ return (0, eval)("this");
}());
}
-}
\ No newline at end of file
+ expect_stdout: [
+ "object",
+ "undefined",
+ "object",
+ "object",
+ ]
+}