From: Alex Lam S.L Date: Sat, 18 Mar 2017 18:17:15 +0000 (+0800) Subject: transform String.charAt() to index access (#1620) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=274331d0ea05197ea7cb531ccd1d78e0c7b8662c;p=UglifyJS.git transform String.charAt() to index access (#1620) Guarded by `unsafe` as `charAt()` can be overridden. --- diff --git a/lib/compress.js b/lib/compress.js index c3f12549..66a4120e 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -2656,7 +2656,7 @@ merge(Compressor.prototype, { if (self.args.length != 1) { return make_node(AST_Array, self, { elements: self.args - }).transform(compressor); + }).optimize(compressor); } break; case "Object": @@ -2674,7 +2674,7 @@ merge(Compressor.prototype, { left: self.args[0], operator: "+", right: make_node(AST_String, self, { value: "" }) - }).transform(compressor); + }).optimize(compressor); break; case "Number": if (self.args.length == 0) return make_node(AST_Number, self, { @@ -2683,7 +2683,7 @@ merge(Compressor.prototype, { if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, { expression: self.args[0], operator: "+" - }).transform(compressor); + }).optimize(compressor); case "Boolean": if (self.args.length == 0) return make_node(AST_False, self); if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, { @@ -2692,7 +2692,7 @@ merge(Compressor.prototype, { operator: "!" }), operator: "!" - }).transform(compressor); + }).optimize(compressor); break; case "Function": // new Function() => function(){} @@ -2757,7 +2757,7 @@ merge(Compressor.prototype, { left: make_node(AST_String, self, { value: "" }), operator: "+", right: exp.expression - }).transform(compressor); + }).optimize(compressor); } else if (exp instanceof AST_Dot && exp.expression instanceof AST_Array && exp.property == "join") EXIT: { var separator; @@ -2811,7 +2811,7 @@ merge(Compressor.prototype, { left : prev, right : el }); - }, first).transform(compressor); + }, first).optimize(compressor); } // need this awkward cloning to not affect original element // best_of will decide which one to get through. @@ -2821,6 +2821,16 @@ merge(Compressor.prototype, { node.expression.expression.elements = elements; return best_of(compressor, self, node); } + else if (exp instanceof AST_Dot && exp.expression.is_string(compressor) && exp.property == "charAt") { + var arg = self.args[0]; + var index = arg ? arg.evaluate(compressor) : 0; + if (index !== arg) { + return make_node(AST_Sub, exp, { + expression: exp.expression, + property: make_node_from_constant(index | 0, arg || exp) + }).optimize(compressor); + } + } } if (exp instanceof AST_Function) { if (exp.body[0] instanceof AST_Return) { diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js index 68739503..3d0d8869 100644 --- a/test/compress/evaluate.js +++ b/test/compress/evaluate.js @@ -200,6 +200,7 @@ negative_zero: { 1 / (-0) ); } + expect_stdout: true } positive_zero: { @@ -220,6 +221,7 @@ positive_zero: { 1 / (0) ); } + expect_stdout: true } unsafe_constant: { @@ -411,6 +413,7 @@ unsafe_integer_key: { 1["1"] + 1 ); } + expect_stdout: true } unsafe_integer_key_complex: { @@ -438,6 +441,7 @@ unsafe_integer_key_complex: { 2 ); } + expect_stdout: true } unsafe_float_key: { @@ -465,6 +469,7 @@ unsafe_float_key: { 1["3.14"] + 1 ); } + expect_stdout: true } unsafe_float_key_complex: { @@ -492,6 +497,7 @@ unsafe_float_key_complex: { 2 ); } + expect_stdout: true } unsafe_array: { @@ -554,6 +560,7 @@ unsafe_string: { "11" ); } + expect_stdout: true } unsafe_array_bad_index: { @@ -575,6 +582,7 @@ unsafe_array_bad_index: { [1, 2, 3, 4][3.14] + 1 ); } + expect_stdout: true } unsafe_string_bad_index: { @@ -596,6 +604,7 @@ unsafe_string_bad_index: { "1234"[3.14] + 1 ); } + expect_stdout: true } unsafe_prototype_function: { @@ -701,3 +710,72 @@ in_boolean_context: { ); } } + +unsafe_charAt: { + options = { + evaluate : true, + unsafe : true + } + input: { + console.log( + "1234" + 1, + "1234".charAt(0) + 1, + "1234".charAt(6 - 5) + 1, + ("12" + "34").charAt(0) + 1, + ("12" + "34").charAt(6 - 5) + 1, + [1, 2, 3, 4].join("").charAt(0) + 1 + ); + } + expect: { + console.log( + "12341", + "11", + "21", + "11", + "21", + "11" + ); + } + expect_stdout: true +} + +unsafe_charAt_bad_index: { + options = { + evaluate : true, + unsafe : true + } + input: { + console.log( + "1234".charAt() + 1, + "1234".charAt("a") + 1, + "1234".charAt(3.14) + 1 + ); + } + expect: { + console.log( + "11", + "11", + "41" + ); + } + expect_stdout: true +} + +unsafe_charAt_noop: { + options = { + evaluate : true, + unsafe : true + } + input: { + console.log( + s.charAt(0), + "string".charAt(x) + ); + } + expect: { + console.log( + s.charAt(0), + "string".charAt(x) + ); + } +}