enhance unsafe (#3382)
This commit is contained in:
116
lib/compress.js
116
lib/compress.js
@@ -2532,6 +2532,20 @@ merge(Compressor.prototype, {
|
|||||||
return this.operator == "+" &&
|
return this.operator == "+" &&
|
||||||
(this.left.is_string(compressor) || this.right.is_string(compressor));
|
(this.left.is_string(compressor) || this.right.is_string(compressor));
|
||||||
});
|
});
|
||||||
|
var fn = makePredicate([
|
||||||
|
"charAt",
|
||||||
|
"substr",
|
||||||
|
"substring",
|
||||||
|
"toLowerCase",
|
||||||
|
"toString",
|
||||||
|
"toUpperCase",
|
||||||
|
"trim",
|
||||||
|
]);
|
||||||
|
def(AST_Call, function(compressor) {
|
||||||
|
if (!compressor.option("unsafe")) return false;
|
||||||
|
var exp = this.expression;
|
||||||
|
return exp instanceof AST_Dot && fn[exp.property];
|
||||||
|
});
|
||||||
def(AST_Conditional, function(compressor) {
|
def(AST_Conditional, function(compressor) {
|
||||||
return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
|
return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
|
||||||
});
|
});
|
||||||
@@ -2539,6 +2553,9 @@ merge(Compressor.prototype, {
|
|||||||
return this.tail_node().is_string(compressor);
|
return this.tail_node().is_string(compressor);
|
||||||
});
|
});
|
||||||
def(AST_String, return_true);
|
def(AST_String, return_true);
|
||||||
|
def(AST_Sub, function(compressor) {
|
||||||
|
return this.expression.is_string(compressor) && this.property instanceof AST_Number;
|
||||||
|
});
|
||||||
def(AST_SymbolRef, function(compressor) {
|
def(AST_SymbolRef, function(compressor) {
|
||||||
var fixed = this.fixed_value();
|
var fixed = this.fixed_value();
|
||||||
if (!fixed) return false;
|
if (!fixed) return false;
|
||||||
@@ -3127,25 +3144,31 @@ merge(Compressor.prototype, {
|
|||||||
return this.pure || !compressor.pure_funcs(this);
|
return this.pure || !compressor.pure_funcs(this);
|
||||||
});
|
});
|
||||||
AST_Node.DEFMETHOD("is_call_pure", return_false);
|
AST_Node.DEFMETHOD("is_call_pure", return_false);
|
||||||
AST_Dot.DEFMETHOD("is_call_pure", function(compressor) {
|
AST_Call.DEFMETHOD("is_call_pure", function(compressor) {
|
||||||
if (!compressor.option("unsafe")) return;
|
if (!compressor.option("unsafe")) return false;
|
||||||
var expr = this.expression;
|
var dot = this.expression;
|
||||||
|
if (!(dot instanceof AST_Dot)) return false;
|
||||||
|
var exp = dot.expression;
|
||||||
var map;
|
var map;
|
||||||
if (expr instanceof AST_Array) {
|
var prop = dot.property;
|
||||||
|
if (exp instanceof AST_Array) {
|
||||||
map = native_fns.Array;
|
map = native_fns.Array;
|
||||||
} else if (expr.is_boolean(compressor)) {
|
} else if (exp.is_boolean(compressor)) {
|
||||||
map = native_fns.Boolean;
|
map = native_fns.Boolean;
|
||||||
} else if (expr.is_number(compressor)) {
|
} else if (exp.is_number(compressor)) {
|
||||||
map = native_fns.Number;
|
map = native_fns.Number;
|
||||||
} else if (expr instanceof AST_RegExp) {
|
} else if (exp instanceof AST_RegExp) {
|
||||||
map = native_fns.RegExp;
|
map = native_fns.RegExp;
|
||||||
} else if (expr.is_string(compressor)) {
|
} else if (exp.is_string(compressor)) {
|
||||||
if (this.property == "replace") return false;
|
|
||||||
map = native_fns.String;
|
map = native_fns.String;
|
||||||
} else if (!this.may_throw_on_access(compressor)) {
|
if (prop == "replace") {
|
||||||
|
var arg = this.args[1];
|
||||||
|
if (arg && !arg.is_string(compressor)) return false;
|
||||||
|
}
|
||||||
|
} else if (!dot.may_throw_on_access(compressor)) {
|
||||||
map = native_fns.Object;
|
map = native_fns.Object;
|
||||||
}
|
}
|
||||||
return map && map[this.property];
|
return map && map[prop];
|
||||||
});
|
});
|
||||||
|
|
||||||
// determine if expression has side effects
|
// determine if expression has side effects
|
||||||
@@ -3170,8 +3193,7 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_Call, function(compressor) {
|
def(AST_Call, function(compressor) {
|
||||||
if (!this.is_expr_pure(compressor)
|
if (!this.is_expr_pure(compressor)
|
||||||
&& (!this.expression.is_call_pure(compressor)
|
&& (!this.is_call_pure(compressor) || this.expression.has_side_effects(compressor))) {
|
||||||
|| this.expression.has_side_effects(compressor))) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return any(this.args, compressor);
|
return any(this.args, compressor);
|
||||||
@@ -4162,16 +4184,15 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_Call, function(compressor, first_in_statement) {
|
def(AST_Call, function(compressor, first_in_statement) {
|
||||||
if (!this.is_expr_pure(compressor)) {
|
if (!this.is_expr_pure(compressor)) {
|
||||||
if (this.expression.is_call_pure(compressor)) {
|
var exp = this.expression;
|
||||||
|
if (this.is_call_pure(compressor)) {
|
||||||
var exprs = this.args.slice();
|
var exprs = this.args.slice();
|
||||||
exprs.unshift(this.expression.expression);
|
exprs.unshift(exp.expression);
|
||||||
exprs = trim(exprs, compressor, first_in_statement);
|
exprs = trim(exprs, compressor, first_in_statement);
|
||||||
return exprs && make_sequence(this, exprs);
|
return exprs && make_sequence(this, exprs);
|
||||||
}
|
}
|
||||||
if (this.expression instanceof AST_Function
|
if (exp instanceof AST_Function && (!exp.name || !exp.name.definition().references.length)) {
|
||||||
&& (!this.expression.name || !this.expression.name.definition().references.length)) {
|
|
||||||
var node = this.clone();
|
var node = this.clone();
|
||||||
var exp = node.expression;
|
|
||||||
exp.process_expression(false, compressor);
|
exp.process_expression(false, compressor);
|
||||||
exp.walk(new TreeWalker(function(node) {
|
exp.walk(new TreeWalker(function(node) {
|
||||||
if (node instanceof AST_Return && node.value) {
|
if (node instanceof AST_Return && node.value) {
|
||||||
@@ -4963,15 +4984,21 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "charAt":
|
case "charAt":
|
||||||
if (exp.expression.is_string(compressor)) {
|
if (self.args.length < 2) {
|
||||||
var arg = self.args[0];
|
var node = make_node(AST_Sub, self, {
|
||||||
var index = arg ? arg.evaluate(compressor) : 0;
|
expression: exp.expression,
|
||||||
if (index !== arg) {
|
property: self.args.length ? make_node(AST_Binary, self.args[0], {
|
||||||
return make_node(AST_Sub, exp, {
|
operator: "|",
|
||||||
expression: exp.expression,
|
left: make_node(AST_Number, self, {
|
||||||
property: make_node_from_constant(index | 0, arg || exp)
|
value: 0
|
||||||
}).optimize(compressor);
|
}),
|
||||||
}
|
right: self.args[0]
|
||||||
|
}) : make_node(AST_Number, self, {
|
||||||
|
value: 0
|
||||||
|
})
|
||||||
|
});
|
||||||
|
node.is_string = return_true;
|
||||||
|
return node.optimize(compressor);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "apply":
|
case "apply":
|
||||||
@@ -5610,7 +5637,8 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (compressor.option("booleans") && self.operator == "+" && compressor.in_boolean_context()) {
|
if (compressor.option("booleans") && compressor.in_boolean_context()) switch (self.operator) {
|
||||||
|
case "+":
|
||||||
var ll = self.left.evaluate(compressor);
|
var ll = self.left.evaluate(compressor);
|
||||||
var rr = self.right.evaluate(compressor);
|
var rr = self.right.evaluate(compressor);
|
||||||
if (ll && typeof ll == "string") {
|
if (ll && typeof ll == "string") {
|
||||||
@@ -5627,6 +5655,20 @@ merge(Compressor.prototype, {
|
|||||||
make_node(AST_True, self)
|
make_node(AST_True, self)
|
||||||
]).optimize(compressor);
|
]).optimize(compressor);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case "==":
|
||||||
|
if (self.left instanceof AST_String && self.left.getValue() == "" && self.right.is_string(compressor)) {
|
||||||
|
return make_node(AST_UnaryPrefix, self, {
|
||||||
|
operator: "!",
|
||||||
|
expression: self.right
|
||||||
|
}).optimize(compressor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "!=":
|
||||||
|
if (self.left instanceof AST_String && self.left.getValue() == "" && self.right.is_string(compressor)) {
|
||||||
|
return self.right.optimize(compressor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (compressor.option("comparisons") && self.is_boolean(compressor)) {
|
if (compressor.option("comparisons") && self.is_boolean(compressor)) {
|
||||||
if (!(compressor.parent() instanceof AST_Binary)
|
if (!(compressor.parent() instanceof AST_Binary)
|
||||||
@@ -5646,12 +5688,12 @@ merge(Compressor.prototype, {
|
|||||||
if (self.right instanceof AST_String
|
if (self.right instanceof AST_String
|
||||||
&& self.right.getValue() == ""
|
&& self.right.getValue() == ""
|
||||||
&& self.left.is_string(compressor)) {
|
&& self.left.is_string(compressor)) {
|
||||||
return self.left;
|
return self.left.optimize(compressor);
|
||||||
}
|
}
|
||||||
if (self.left instanceof AST_String
|
if (self.left instanceof AST_String
|
||||||
&& self.left.getValue() == ""
|
&& self.left.getValue() == ""
|
||||||
&& self.right.is_string(compressor)) {
|
&& self.right.is_string(compressor)) {
|
||||||
return self.right;
|
return self.right.optimize(compressor);
|
||||||
}
|
}
|
||||||
if (self.left instanceof AST_Binary
|
if (self.left instanceof AST_Binary
|
||||||
&& self.left.operator == "+"
|
&& self.left.operator == "+"
|
||||||
@@ -5659,7 +5701,7 @@ merge(Compressor.prototype, {
|
|||||||
&& self.left.left.getValue() == ""
|
&& self.left.left.getValue() == ""
|
||||||
&& self.right.is_string(compressor)) {
|
&& self.right.is_string(compressor)) {
|
||||||
self.left = self.left.right;
|
self.left = self.left.right;
|
||||||
return self.transform(compressor);
|
return self.optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("evaluate")) {
|
if (compressor.option("evaluate")) {
|
||||||
@@ -5918,6 +5960,16 @@ merge(Compressor.prototype, {
|
|||||||
&& self.right instanceof AST_Call
|
&& self.right instanceof AST_Call
|
||||||
&& self.right.expression instanceof AST_Dot
|
&& self.right.expression instanceof AST_Dot
|
||||||
&& indexFns[self.right.expression.property]) {
|
&& indexFns[self.right.expression.property]) {
|
||||||
|
if (compressor.option("booleans")
|
||||||
|
&& (self.operator == "==" || self.operator == "!=")
|
||||||
|
&& self.left instanceof AST_Number
|
||||||
|
&& self.left.getValue() == 0
|
||||||
|
&& compressor.in_boolean_context()) {
|
||||||
|
return (self.operator == "==" ? make_node(AST_UnaryPrefix, self, {
|
||||||
|
operator: "!",
|
||||||
|
expression: self.right
|
||||||
|
}) : self.right).optimize(compressor);
|
||||||
|
}
|
||||||
if (compressor.option("comparisons") && is_indexOf_match_pattern()) {
|
if (compressor.option("comparisons") && is_indexOf_match_pattern()) {
|
||||||
var node = make_node(AST_UnaryPrefix, self, {
|
var node = make_node(AST_UnaryPrefix, self, {
|
||||||
operator: "!",
|
operator: "!",
|
||||||
@@ -6229,7 +6281,7 @@ merge(Compressor.prototype, {
|
|||||||
if (parent instanceof AST_Exit) {
|
if (parent instanceof AST_Exit) {
|
||||||
if (in_try(level, parent)) break;
|
if (in_try(level, parent)) break;
|
||||||
if (is_reachable(def.scope, [ def ])) break;
|
if (is_reachable(def.scope, [ def ])) break;
|
||||||
if (self.operator == "=") return self.right;
|
if (self.operator == "=") return self.right.optimize(compressor);
|
||||||
def.fixed = false;
|
def.fixed = false;
|
||||||
return make_node(AST_Binary, self, {
|
return make_node(AST_Binary, self, {
|
||||||
operator: self.operator.slice(0, -1),
|
operator: self.operator.slice(0, -1),
|
||||||
|
|||||||
@@ -820,8 +820,8 @@ unsafe_charAt_noop: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(
|
console.log(
|
||||||
s.charAt(0),
|
s[0],
|
||||||
"string".charAt(x),
|
"string"[0 | x],
|
||||||
(typeof x)[0]
|
(typeof x)[0]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user