From 4e10d94d8558267353dff40d172853a36b10d934 Mon Sep 17 00:00:00 2001 From: alexlamsl Date: Thu, 16 May 2019 23:42:35 +0800 Subject: [PATCH] enhance `unsafe` `comparisons` --- lib/compress.js | 40 +++++++++++++++++++--------- test/compress/comparisons.js | 51 +++++++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 16 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 5d6567f74d..b7e5b3d2e1 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -5969,11 +5969,10 @@ merge(Compressor.prototype, { } } } - if (compressor.option("unsafe") - && self.right instanceof AST_Call - && self.right.expression instanceof AST_Dot - && indexFns[self.right.expression.property]) { + if (compressor.option("unsafe")) { + var indexRight = is_indexFn(self.right); if (compressor.option("booleans") + && indexRight && (self.operator == "==" || self.operator == "!=") && self.left instanceof AST_Number && self.left.getValue() == 0 @@ -5983,18 +5982,26 @@ merge(Compressor.prototype, { expression: self.right }) : self.right).optimize(compressor); } + var indexLeft = is_indexFn(self.left); if (compressor.option("comparisons") && is_indexOf_match_pattern()) { var node = make_node(AST_UnaryPrefix, self, { operator: "!", expression: make_node(AST_UnaryPrefix, self, { operator: "~", - expression: self.right + expression: indexLeft ? self.left : self.right }) }); - if (self.operator == "!=" || self.operator == "<=") node = make_node(AST_UnaryPrefix, self, { - operator: "!", - expression: node - }); + switch (self.operator) { + case "<": + if (indexLeft) break; + case "<=": + case "!=": + node = make_node(AST_UnaryPrefix, self, { + operator: "!", + expression: node + }); + break; + } return node.optimize(compressor); } } @@ -6032,17 +6039,26 @@ merge(Compressor.prototype, { return node.evaluate(compressor); } + function is_indexFn(node) { + return node instanceof AST_Call + && node.expression instanceof AST_Dot + && indexFns[node.expression.property]; + } + function is_indexOf_match_pattern() { switch (self.operator) { - case ">": case "<=": - // 0 > array.indexOf(string) => !~array.indexOf(string) // 0 <= array.indexOf(string) => !!~array.indexOf(string) - return self.left instanceof AST_Number && self.left.getValue() == 0; + return indexRight && self.left instanceof AST_Number && self.left.getValue() == 0; + case "<": + // array.indexOf(string) < 0 => !~array.indexOf(string) + if (indexLeft && self.right instanceof AST_Number && self.right.getValue() == 0) return true; + // -1 < array.indexOf(string) => !!~array.indexOf(string) case "==": case "!=": // -1 == array.indexOf(string) => !~array.indexOf(string) // -1 != array.indexOf(string) => !!~array.indexOf(string) + if (!indexRight) return false; return self.left instanceof AST_Number && self.left.getValue() == -1 || self.left instanceof AST_UnaryPrefix && self.left.operator == "-" && self.left.expression instanceof AST_Number && self.left.expression.getValue() == 1; diff --git a/test/compress/comparisons.js b/test/compress/comparisons.js index 461f415cb9..bb140fd8ac 100644 --- a/test/compress/comparisons.js +++ b/test/compress/comparisons.js @@ -373,12 +373,55 @@ unsafe_indexOf: { unsafe: true, } input: { - if (Object.keys({ foo: 42 }).indexOf("foo") >= 0) console.log("PASS"); + var a = Object.keys({ foo: 42 }); + if (a.indexOf("bar") < 0) console.log("PASS"); + if (0 > a.indexOf("bar")) console.log("PASS"); + if (a.indexOf("foo") >= 0) console.log("PASS"); + if (0 <= a.indexOf("foo")) console.log("PASS"); + if (a.indexOf("foo") > -1) console.log("PASS"); + if (-1 < a.indexOf("foo")) console.log("PASS"); + if (a.indexOf("bar") == -1) console.log("PASS"); + if (-1 == a.indexOf("bar")) console.log("PASS"); + if (a.indexOf("bar") === -1) console.log("PASS"); + if (-1 === a.indexOf("bar")) console.log("PASS"); + if (a.indexOf("foo") != -1) console.log("PASS"); + if (-1 != a.indexOf("foo")) console.log("PASS"); + if (a.indexOf("foo") !== -1) console.log("PASS"); + if (-1 !== a.indexOf("foo")) console.log("PASS"); } expect: { - if (~Object.keys({ foo: 42 }).indexOf("foo")) console.log("PASS"); - } - expect_stdout: "PASS" + var a = Object.keys({ foo: 42 }); + if (!~a.indexOf("bar")) console.log("PASS"); + if (!~a.indexOf("bar")) console.log("PASS"); + if (~a.indexOf("foo")) console.log("PASS"); + if (~a.indexOf("foo")) console.log("PASS"); + if (~a.indexOf("foo")) console.log("PASS"); + if (~a.indexOf("foo")) console.log("PASS"); + if (!~a.indexOf("bar")) console.log("PASS"); + if (!~a.indexOf("bar")) console.log("PASS"); + if (!~a.indexOf("bar")) console.log("PASS"); + if (!~a.indexOf("bar")) console.log("PASS"); + if (~a.indexOf("foo")) console.log("PASS"); + if (~a.indexOf("foo")) console.log("PASS"); + if (~a.indexOf("foo")) console.log("PASS"); + if (~a.indexOf("foo")) console.log("PASS"); + } + expect_stdout: [ + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + "PASS", + ] } issue_3413: {