improve unsafe comparisons (#3200)

This commit is contained in:
Alex Lam S.L
2018-06-28 03:46:19 +08:00
committed by GitHub
parent 88c8f4e363
commit 957d5537a8
4 changed files with 128 additions and 45 deletions

View File

@@ -2264,29 +2264,35 @@ merge(Compressor.prototype, {
// methods to determine whether an expression has a boolean result type
(function(def) {
var unary_bool = makePredicate("! delete");
var binary_bool = makePredicate("in instanceof == != === !== < <= >= >");
def(AST_Node, return_false);
def(AST_Assign, function(compressor) {
return this.operator == "=" && this.right.is_boolean(compressor);
});
var binary = makePredicate("in instanceof == != === !== < <= >= >");
def(AST_Binary, function(compressor) {
return binary[this.operator] || lazy_op[this.operator]
&& this.left.is_boolean(compressor)
&& this.right.is_boolean(compressor);
});
def(AST_Boolean, return_true);
var fn = makePredicate("every hasOwnProperty isPrototypeOf propertyIsEnumerable some");
def(AST_Call, function(compressor) {
if (!compressor.option("unsafe")) return false;
var exp = this.expression;
return exp instanceof AST_Dot && (fn[exp.property]
|| exp.property == "test" && exp.expression instanceof AST_RegExp);
});
def(AST_Conditional, function(compressor) {
return this.consequent.is_boolean(compressor) && this.alternative.is_boolean(compressor);
});
def(AST_New, return_false);
def(AST_Sequence, function(compressor) {
return this.tail_node().is_boolean(compressor);
});
var unary = makePredicate("! delete");
def(AST_UnaryPrefix, function() {
return unary_bool[this.operator];
return unary[this.operator];
});
def(AST_Binary, function() {
return binary_bool[this.operator]
|| lazy_op[this.operator]
&& this.left.is_boolean()
&& this.right.is_boolean();
});
def(AST_Conditional, function() {
return this.consequent.is_boolean() && this.alternative.is_boolean();
});
def(AST_Assign, function() {
return this.operator == "=" && this.right.is_boolean();
});
def(AST_Sequence, function() {
return this.tail_node().is_boolean();
});
def(AST_True, return_true);
def(AST_False, return_true);
})(function(node, func) {
node.DEFMETHOD("is_boolean", func);
});
@@ -2294,27 +2300,80 @@ merge(Compressor.prototype, {
// methods to determine if an expression has a numeric result type
(function(def) {
def(AST_Node, return_false);
def(AST_Number, return_true);
var unary = makePredicate("+ - ~ ++ --");
def(AST_Unary, function() {
return unary[this.operator];
});
var binary = makePredicate("- * / % & | ^ << >> >>>");
def(AST_Assign, function(compressor) {
return binary[this.operator.slice(0, -1)]
|| this.operator == "=" && this.right.is_number(compressor);
});
def(AST_Binary, function(compressor) {
return binary[this.operator] || this.operator == "+"
&& this.left.is_number(compressor)
&& this.right.is_number(compressor);
});
def(AST_Assign, function(compressor) {
return binary[this.operator.slice(0, -1)]
|| this.operator == "=" && this.right.is_number(compressor);
});
def(AST_Sequence, function(compressor) {
return this.tail_node().is_number(compressor);
var fn = makePredicate([
"charCodeAt",
"getDate",
"getDay",
"getFullYear",
"getHours",
"getMilliseconds",
"getMinutes",
"getMonth",
"getSeconds",
"getTime",
"getTimezoneOffset",
"getUTCDate",
"getUTCDay",
"getUTCFullYear",
"getUTCHours",
"getUTCMilliseconds",
"getUTCMinutes",
"getUTCMonth",
"getUTCSeconds",
"getYear",
"indexOf",
"lastIndexOf",
"localeCompare",
"push",
"search",
"setDate",
"setFullYear",
"setHours",
"setMilliseconds",
"setMinutes",
"setMonth",
"setSeconds",
"setTime",
"setUTCDate",
"setUTCFullYear",
"setUTCHours",
"setUTCMilliseconds",
"setUTCMinutes",
"setUTCMonth",
"setUTCSeconds",
"setYear",
"toExponential",
"toFixed",
"toPrecision",
]);
def(AST_Call, function(compressor) {
if (!compressor.option("unsafe")) return false;
var exp = this.expression;
return exp instanceof AST_Dot && (fn[exp.property]
|| is_undeclared_ref(exp.expression) && exp.expression.name == "Math");
});
def(AST_Conditional, function(compressor) {
return this.consequent.is_number(compressor) && this.alternative.is_number(compressor);
});
def(AST_New, return_false);
def(AST_Number, return_true);
def(AST_Sequence, function(compressor) {
return this.tail_node().is_number(compressor);
});
var unary = makePredicate("+ - ~ ++ --");
def(AST_Unary, function() {
return unary[this.operator];
});
})(function(node, func) {
node.DEFMETHOD("is_number", func);
});
@@ -2902,7 +2961,7 @@ merge(Compressor.prototype, {
var map;
if (expr instanceof AST_Array) {
map = native_fns.Array;
} else if (expr.is_boolean()) {
} else if (expr.is_boolean(compressor)) {
map = native_fns.Boolean;
} else if (expr.is_number(compressor)) {
map = native_fns.Number;
@@ -5247,7 +5306,7 @@ merge(Compressor.prototype, {
var is_strict_comparison = true;
if ((self.left.is_string(compressor) && self.right.is_string(compressor)) ||
(self.left.is_number(compressor) && self.right.is_number(compressor)) ||
(self.left.is_boolean() && self.right.is_boolean()) ||
(self.left.is_boolean(compressor) && self.right.is_boolean(compressor)) ||
self.left.equivalent_to(self.right)) {
self.operator = self.operator.substr(0, 2);
}
@@ -5328,7 +5387,7 @@ merge(Compressor.prototype, {
]).optimize(compressor);
}
}
if (compressor.option("comparisons") && self.is_boolean()) {
if (compressor.option("comparisons") && self.is_boolean(compressor)) {
if (!(compressor.parent() instanceof AST_Binary)
|| compressor.parent() instanceof AST_Assign) {
var negated = make_node(AST_UnaryPrefix, self, {
@@ -6102,7 +6161,7 @@ merge(Compressor.prototype, {
return self;
function booleanize(node) {
if (node.is_boolean()) return node;
if (node.is_boolean(compressor)) return node;
// !!expression
return make_node(AST_UnaryPrefix, node, {
operator: "!",