From ec851208bbbb1dd98e7c14d7dfedeae02eeee4a4 Mon Sep 17 00:00:00 2001 From: alexlamsl Date: Thu, 21 Dec 2017 17:39:00 +0800 Subject: [PATCH 1/5] make comments output more robust fixes #112 fixes #218 fixes #372 --- lib/output.js | 146 ++++++++++++++++++++++-------------------- lib/utils.js | 2 +- test/mocha/comment.js | 66 +++++++++++++++++++ 3 files changed, 144 insertions(+), 70 deletions(-) diff --git a/lib/output.js b/lib/output.js index a4c41f11ae..a46f7843f0 100644 --- a/lib/output.js +++ b/lib/output.js @@ -52,6 +52,7 @@ function is_some_comments(comment) { function OutputStream(options) { + var readonly = !options; options = defaults(options, { ascii_only : false, beautify : false, @@ -427,6 +428,80 @@ function OutputStream(options) { return OUTPUT; }; + function add_comments(node) { + var self = this; + var start = node.start; + if (!(start.comments_before && start.comments_before._dumped === self)) { + var comments = start.comments_before; + if (!comments) { + comments = start.comments_before = []; + } + comments._dumped = self; + + if (node instanceof AST_Exit && node.value) { + var tw = new TreeWalker(function(node) { + var parent = tw.parent(); + if (parent instanceof AST_Exit + || parent instanceof AST_Binary && parent.left === node + || parent.TYPE == "Call" && parent.expression === node + || parent instanceof AST_Conditional && parent.condition === node + || parent instanceof AST_Dot && parent.expression === node + || parent instanceof AST_Sequence && parent.expressions[0] === node + || parent instanceof AST_Sub && parent.expression === node + || parent instanceof AST_UnaryPostfix) { + var text = node.start.comments_before; + if (text && text._dumped !== self) { + text._dumped = self; + comments = comments.concat(text); + } + } else { + return true; + } + }); + tw.push(node); + node.value.walk(tw); + } + + if (current_pos == 0) { + if (comments.length > 0 && options.shebang && comments[0].type == "comment5") { + print("#!" + comments.shift().value + "\n"); + indent(); + } + var preamble = options.preamble; + if (preamble) { + print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n")); + } + } + + comments = comments.filter(comment_filter, node); + + // Keep single line comments after nlb, after nlb + if (current_col != 0 + && !options.beautify + && comments.length > 0 + && comments[0].nlb + && /comment[134]/.test(comments[0].type)) { + print("\n"); + } + + comments.forEach(function(c){ + if (/comment[134]/.test(c.type)) { + print("//" + c.value + "\n"); + indent(); + } + else if (c.type == "comment2") { + print("/*" + c.value + "*/"); + if (start.nlb) { + print("\n"); + indent(); + } else { + space(); + } + } + }); + } + } + var stack = []; return { get : get, @@ -464,7 +539,7 @@ function OutputStream(options) { with_square : with_square, add_mapping : add_mapping, option : function(opt) { return options[opt] }, - comment_filter : comment_filter, + add_comments : readonly ? noop : add_comments, line : function() { return current_line }, col : function() { return current_col }, pos : function() { return current_pos }, @@ -500,7 +575,7 @@ function OutputStream(options) { use_asm = active_scope; } function doit() { - self.add_comments(stream); + stream.add_comments(self); self.add_source_map(stream); generator(self, stream); } @@ -519,77 +594,10 @@ function OutputStream(options) { AST_Node.DEFMETHOD("print_to_string", function(options){ var s = OutputStream(options); - if (!options) s._readonly = true; this.print(s); return s.get(); }); - /* -----[ comments ]----- */ - - AST_Node.DEFMETHOD("add_comments", function(output){ - if (output._readonly) return; - var self = this; - var start = self.start; - if (start && !start._comments_dumped) { - start._comments_dumped = true; - var comments = start.comments_before || []; - - // XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112 - // and https://github.com/mishoo/UglifyJS2/issues/372 - if (self instanceof AST_Exit && self.value) { - self.value.walk(new TreeWalker(function(node){ - if (node.start && node.start.comments_before) { - comments = comments.concat(node.start.comments_before); - node.start.comments_before = []; - } - if (node instanceof AST_Function || - node instanceof AST_Array || - node instanceof AST_Object) - { - return true; // don't go inside. - } - })); - } - - if (output.pos() == 0) { - if (comments.length > 0 && output.option("shebang") && comments[0].type == "comment5") { - output.print("#!" + comments.shift().value + "\n"); - output.indent(); - } - var preamble = output.option("preamble"); - if (preamble) { - output.print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n")); - } - } - - comments = comments.filter(output.comment_filter, self); - - // Keep single line comments after nlb, after nlb - if (!output.option("beautify") && comments.length > 0 && - /comment[134]/.test(comments[0].type) && - output.col() !== 0 && comments[0].nlb) - { - output.print("\n"); - } - - comments.forEach(function(c){ - if (/comment[134]/.test(c.type)) { - output.print("//" + c.value + "\n"); - output.indent(); - } - else if (c.type == "comment2") { - output.print("/*" + c.value + "*/"); - if (start.nlb) { - output.print("\n"); - output.indent(); - } else { - output.space(); - } - } - }); - } - }); - /* -----[ PARENTHESES ]----- */ function PARENS(nodetype, func) { diff --git a/lib/utils.js b/lib/utils.js index 102c4789f1..dab7f56640 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -324,7 +324,7 @@ function first_in_statement(stack) { if (p instanceof AST_Statement && p.body === node) return true; if ((p instanceof AST_Sequence && p.expressions[0] === node) || - (p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) ) || + (p.TYPE == "Call" && p.expression === node ) || (p instanceof AST_Dot && p.expression === node ) || (p instanceof AST_Sub && p.expression === node ) || (p instanceof AST_Conditional && p.condition === node ) || diff --git a/test/mocha/comment.js b/test/mocha/comment.js index 6b5428d4f3..e8d7a24d34 100644 --- a/test/mocha/comment.js +++ b/test/mocha/comment.js @@ -47,4 +47,70 @@ describe("Comment", function() { }, fail, tests[i]); } }); + + it("Should handle comment within return correctly", function() { + var result = uglify.minify([ + "function unequal(x, y) {", + " return (", + " // Either one", + " x < y", + " ||", + " y < x", + " );", + "}", + ].join("\n"), { + compress: false, + mangle: false, + output: { + beautify: true, + comments: "all", + }, + }); + if (result.error) throw result.error; + assert.strictEqual(result.code, [ + "function unequal(x, y) {", + " // Either one", + " return x < y || y < x;", + "}", + ].join("\n")); + }); + + it("Should handle comment folded into return correctly", function() { + var result = uglify.minify([ + "function f() {", + " /* boo */ x();", + " return y();", + "}", + ].join("\n"), { + mangle: false, + output: { + beautify: true, + comments: "all", + }, + }); + if (result.error) throw result.error; + assert.strictEqual(result.code, [ + "function f() {", + " /* boo */", + " return x(), y();", + "}", + ].join("\n")); + }); + + it("Should not drop comments after first OutputStream", function() { + var code = "/* boo */\nx();"; + var ast = uglify.parse(code); + var out1 = uglify.OutputStream({ + beautify: true, + comments: "all", + }); + ast.print(out1); + var out2 = uglify.OutputStream({ + beautify: true, + comments: "all", + }); + ast.print(out2); + assert.strictEqual(out1.get(), code); + assert.strictEqual(out2.get(), out1.get()); + }); }); From 054330df3fd061ac1c4b41e78c846d3f3a128edf Mon Sep 17 00:00:00 2001 From: alexlamsl Date: Thu, 21 Dec 2017 21:33:16 +0800 Subject: [PATCH 2/5] preserve trailing comments fixes #88 --- lib/ast.js | 2 +- lib/output.js | 108 +++++++++++++++++++++++++---------- lib/parse.js | 6 +- test/mocha/comment-filter.js | 6 +- test/mocha/comment.js | 94 ++++++++++++++++++++++++++++++ 5 files changed, 176 insertions(+), 40 deletions(-) diff --git a/lib/ast.js b/lib/ast.js index 997486c298..65918675a9 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -87,7 +87,7 @@ function DEFNODE(type, props, methods, base) { return ctor; }; -var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before file raw", { +var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before comments_after file raw", { }, null); var AST_Node = DEFNODE("Node", "start end", { diff --git a/lib/output.js b/lib/output.js index a46f7843f0..b0cecf068f 100644 --- a/lib/output.js +++ b/lib/output.js @@ -200,6 +200,7 @@ function OutputStream(options) { var might_need_space = false; var might_need_semicolon = false; var might_add_newline = 0; + var need_newline_indented = false; var last = ""; var mapping_token, mapping_name, mappings = options.source_map && []; @@ -258,6 +259,13 @@ function OutputStream(options) { function print(str) { str = String(str); var ch = str.charAt(0); + if (need_newline_indented && ch) { + need_newline_indented = false; + if (ch != "\n") { + print("\n"); + indent(); + } + } var prev = last.charAt(last.length - 1); if (might_need_semicolon) { might_need_semicolon = false; @@ -428,7 +436,7 @@ function OutputStream(options) { return OUTPUT; }; - function add_comments(node) { + function prepend_comments(node) { var self = this; var start = node.start; if (!(start.comments_before && start.comments_before._dumped === self)) { @@ -474,29 +482,58 @@ function OutputStream(options) { } comments = comments.filter(comment_filter, node); - - // Keep single line comments after nlb, after nlb - if (current_col != 0 - && !options.beautify - && comments.length > 0 - && comments[0].nlb - && /comment[134]/.test(comments[0].type)) { - print("\n"); - } - - comments.forEach(function(c){ + if (comments.length == 0) return; + var last_nlb = /(^|\n) *$/.test(OUTPUT); + comments.forEach(function(c, i) { + if (!last_nlb) { + if (c.nlb) { + print("\n"); + indent(); + last_nlb = true; + } else if (i > 0) { + space(); + } + } if (/comment[134]/.test(c.type)) { print("//" + c.value + "\n"); indent(); + last_nlb = true; + } else if (c.type == "comment2") { + print("/*" + c.value + "*/"); + last_nlb = false; } - else if (c.type == "comment2") { + }); + if (!last_nlb) { + if (start.nlb) { + print("\n"); + indent(); + } else { + space(); + } + } + } + } + + function append_comments(node, tail) { + var self = this; + var token = node.end; + if (!token) return; + var comments = token[tail ? "comments_before" : "comments_after"]; + if (comments && comments._dumped !== self) { + comments._dumped = self; + comments.filter(comment_filter, node).forEach(function(c, i) { + if (need_newline_indented || c.nlb) { + print("\n"); + indent(); + need_newline_indented = false; + } else if (i > 0 || !tail) { + space(); + } + if (/comment[134]/.test(c.type)) { + print("//" + c.value); + need_newline_indented = true; + } else if (c.type == "comment2") { print("/*" + c.value + "*/"); - if (start.nlb) { - print("\n"); - indent(); - } else { - space(); - } } }); } @@ -539,7 +576,8 @@ function OutputStream(options) { with_square : with_square, add_mapping : add_mapping, option : function(opt) { return options[opt] }, - add_comments : readonly ? noop : add_comments, + prepend_comments: readonly ? noop : prepend_comments, + append_comments : readonly ? noop : append_comments, line : function() { return current_line }, col : function() { return current_col }, pos : function() { return current_pos }, @@ -575,9 +613,10 @@ function OutputStream(options) { use_asm = active_scope; } function doit() { - stream.add_comments(self); + stream.prepend_comments(self); self.add_source_map(stream); generator(self, stream); + stream.append_comments(self); } stream.push_node(self); if (force_parens || self.needs_parens(stream)) { @@ -819,14 +858,21 @@ function OutputStream(options) { self.body.print(output); output.semicolon(); }); - function print_bracketed(body, output, allow_directives) { - if (body.length > 0) output.with_block(function(){ - display_body(body, false, output, allow_directives); - }); - else output.print("{}"); + function print_bracketed(self, output, allow_directives) { + if (self.body.length > 0) { + output.with_block(function() { + display_body(self.body, false, output, allow_directives); + }); + } else { + output.print("{"); + output.with_indent(output.next_indent(), function() { + output.append_comments(self, true); + }); + output.print("}"); + } }; DEFPRINT(AST_BlockStatement, function(self, output){ - print_bracketed(self.body, output); + print_bracketed(self, output); }); DEFPRINT(AST_EmptyStatement, function(self, output){ output.semicolon(); @@ -921,7 +967,7 @@ function OutputStream(options) { }); }); output.space(); - print_bracketed(self.body, output, true); + print_bracketed(self, output, true); }); DEFPRINT(AST_Lambda, function(self, output){ self._do_print(output); @@ -1052,7 +1098,7 @@ function OutputStream(options) { DEFPRINT(AST_Try, function(self, output){ output.print("try"); output.space(); - print_bracketed(self.body, output); + print_bracketed(self, output); if (self.bcatch) { output.space(); self.bcatch.print(output); @@ -1069,12 +1115,12 @@ function OutputStream(options) { self.argname.print(output); }); output.space(); - print_bracketed(self.body, output); + print_bracketed(self, output); }); DEFPRINT(AST_Finally, function(self, output){ output.print("finally"); output.space(); - print_bracketed(self.body, output); + print_bracketed(self, output); }); /* -----[ var/const ]----- */ diff --git a/lib/parse.js b/lib/parse.js index f0098c7540..2b1a37141e 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -317,11 +317,7 @@ function tokenizer($TEXT, filename, html5_comments, shebang) { } if (!is_comment) { ret.comments_before = S.comments_before; - S.comments_before = []; - // make note of any newlines in the comments that came before - for (var i = 0, len = ret.comments_before.length; i < len; i++) { - ret.nlb = ret.nlb || ret.comments_before[i].nlb; - } + ret.comments_after = S.comments_before = []; } S.newline_before = false; return new AST_Token(ret); diff --git a/test/mocha/comment-filter.js b/test/mocha/comment-filter.js index 0e4f3dffcb..25233d115d 100644 --- a/test/mocha/comment-filter.js +++ b/test/mocha/comment-filter.js @@ -14,7 +14,7 @@ describe("comment filters", function() { it("Should be able to filter commments with the 'some' option", function() { var ast = UglifyJS.parse("// foo\n/*@preserve*/\n// bar\n/*@license*/\n//@license with the wrong comment type\n/*@cc_on something*/"); - assert.strictEqual(ast.print_to_string({comments: "some"}), "/*@preserve*/\n/*@license*/\n/*@cc_on something*/\n"); + assert.strictEqual(ast.print_to_string({comments: "some"}), "/*@preserve*/\n/*@license*/\n/*@cc_on something*/"); }); it("Should be able to filter comments by passing a function", function() { @@ -55,12 +55,12 @@ describe("comment filters", function() { return true; }; - assert.strictEqual(ast.print_to_string({comments: f}), "#!Random comment\n//test1\n/*test2*/\n"); + assert.strictEqual(ast.print_to_string({comments: f}), "#!Random comment\n//test1\n/*test2*/"); }); it("Should never be able to filter comment5 when using 'some' as filter", function() { var ast = UglifyJS.parse("#!foo\n//foo\n/*@preserve*/\n/* please hide me */"); - assert.strictEqual(ast.print_to_string({comments: "some"}), "#!foo\n/*@preserve*/\n"); + assert.strictEqual(ast.print_to_string({comments: "some"}), "#!foo\n/*@preserve*/"); }); it("Should have no problem on multiple calls", function() { diff --git a/test/mocha/comment.js b/test/mocha/comment.js index e8d7a24d34..fae9ab36b6 100644 --- a/test/mocha/comment.js +++ b/test/mocha/comment.js @@ -113,4 +113,98 @@ describe("Comment", function() { assert.strictEqual(out1.get(), code); assert.strictEqual(out2.get(), out1.get()); }); + + it("Should retain trailing comments", function() { + var code = [ + "if (foo /* lost comment */ && bar /* lost comment */) {", + " // this one is kept", + " {/* lost comment */}", + " !function() {", + " // lost comment", + " }();", + " function baz() {/* lost comment */}", + " // lost comment", + "}", + "// comments right before EOF are lost as well", + ].join("\n"); + var result = uglify.minify(code, { + compress: false, + mangle: false, + output: { + beautify: true, + comments: "all", + }, + }); + if (result.error) throw result.error; + assert.strictEqual(result.code, code); + }); + + it("Should correctly preserve new lines around comments", function() { + var tests = [ + [ + "// foo", + "// bar", + "x();", + ].join("\n"), + [ + "// foo", + "/* bar */", + "x();", + ].join("\n"), + [ + "// foo", + "/* bar */ x();", + ].join("\n"), + [ + "/* foo */", + "// bar", + "x();", + ].join("\n"), + [ + "/* foo */ // bar", + "x();", + ].join("\n"), + [ + "/* foo */", + "/* bar */", + "x();", + ].join("\n"), + [ + "/* foo */", + "/* bar */ x();", + ].join("\n"), + [ + "/* foo */ /* bar */", + "x();", + ].join("\n"), + "/* foo */ /* bar */ x();", + ].forEach(function(code) { + var result = uglify.minify(code, { + compress: false, + mangle: false, + output: { + beautify: true, + comments: "all", + }, + }); + if (result.error) throw result.error; + assert.strictEqual(result.code, code); + }); + }); + + it("Should preserve new line before comment without beautify", function() { + var code = [ + "function f(){", + "/* foo */bar()}", + ].join("\n"); + var result = uglify.minify(code, { + compress: false, + mangle: false, + output: { + comments: "all", + }, + }); + if (result.error) throw result.error; + assert.strictEqual(result.code, code); + }); }); From dd36b1965ace89cd3a5e459b16265d0bd5d0a587 Mon Sep 17 00:00:00 2001 From: alexlamsl Date: Thu, 21 Dec 2017 22:20:27 +0800 Subject: [PATCH 3/5] handle comments around parentheses fixes #2629 --- lib/parse.js | 9 ++++++++- test/compress/pure_funcs.js | 13 +++++++++++++ test/mocha/comment.js | 12 ++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/parse.js b/lib/parse.js index 2b1a37141e..41aa988bed 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -1276,9 +1276,16 @@ function parse($TEXT, options) { case "(": next(); var ex = expression(true); + [].push.apply(start.comments_before, ex.start.comments_before); + ex.start.comments_before = start.comments_before; + start.comments_after = ex.start.comments_after; ex.start = start; - ex.end = S.token; expect(")"); + var end = prev(); + end.comments_before = ex.end.comments_before; + [].push.apply(ex.end.comments_after, end.comments_after); + end.comments_after = ex.end.comments_after; + ex.end = end; return subscripts(ex, allow_calls); case "[": return subscripts(array_(), allow_calls); diff --git a/test/compress/pure_funcs.js b/test/compress/pure_funcs.js index 3cc529a8e5..7acc38abb0 100644 --- a/test/compress/pure_funcs.js +++ b/test/compress/pure_funcs.js @@ -293,3 +293,16 @@ unary: { bar(); } } + +issue_2629: { + options = { + side_effects: true, + } + input: { + /*@__PURE__*/ f1(); + (/*@__PURE__*/ f2)(); + /*@__PURE__*/ (f3()); + (/*@__PURE__*/ f4()); + } + expect: {} +} diff --git a/test/mocha/comment.js b/test/mocha/comment.js index fae9ab36b6..3bad9e01b7 100644 --- a/test/mocha/comment.js +++ b/test/mocha/comment.js @@ -207,4 +207,16 @@ describe("Comment", function() { if (result.error) throw result.error; assert.strictEqual(result.code, code); }); + + it("Should preserve comments around IIFE", function() { + var result = uglify.minify("/*a*/(/*b*/function(){/*c*/}/*d*/)/*e*/();", { + compress: false, + mangle: false, + output: { + comments: "all", + }, + }); + if (result.error) throw result.error; + assert.strictEqual(result.code, "/*a*/ /*b*/(function(){/*c*/}/*d*/ /*e*/)();"); + }); }); From 28b697f6173f09b272c716b1f73e9c20c3e8765d Mon Sep 17 00:00:00 2001 From: alexlamsl Date: Fri, 22 Dec 2017 03:39:13 +0800 Subject: [PATCH 4/5] add tests --- test/compress/pure_funcs.js | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/test/compress/pure_funcs.js b/test/compress/pure_funcs.js index 7acc38abb0..ad7fc861f0 100644 --- a/test/compress/pure_funcs.js +++ b/test/compress/pure_funcs.js @@ -294,7 +294,7 @@ unary: { } } -issue_2629: { +issue_2629_1: { options = { side_effects: true, } @@ -303,6 +303,39 @@ issue_2629: { (/*@__PURE__*/ f2)(); /*@__PURE__*/ (f3()); (/*@__PURE__*/ f4()); + /*@__PURE__*/ f5(1)(2)(3); + (/*@__PURE__*/ f6(1)(2)(3)); + /*@__PURE__*/ f7.x(1).y(2).z(3); + (/*@__PURE__*/ f8.x(1).y(2).z(3)); } expect: {} } + +issue_2629_2: { + options = { + side_effects: true, + } + input: { + (/*@__PURE__*/ x(), y()); + (w(), /*@__PURE__*/ x(), y()); + } + expect: { + y(); + w(), y(); + } +} + +issue_2629_3: { + options = { + side_effects: true, + } + input: { + [ /*@__PURE__*/ x() ]; + [ /*@__PURE__*/ x(), y() ]; + [ w(), /*@__PURE__*/ x(), y() ]; + } + expect: { + y(); + w(), y(); + } +} From fd267ad1a55e586d35497ba72539c2437036767b Mon Sep 17 00:00:00 2001 From: alexlamsl Date: Fri, 22 Dec 2017 03:47:25 +0800 Subject: [PATCH 5/5] add tests --- test/compress/pure_funcs.js | 54 ++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/test/compress/pure_funcs.js b/test/compress/pure_funcs.js index ad7fc861f0..6f3bbb21ff 100644 --- a/test/compress/pure_funcs.js +++ b/test/compress/pure_funcs.js @@ -299,19 +299,55 @@ issue_2629_1: { side_effects: true, } input: { - /*@__PURE__*/ f1(); - (/*@__PURE__*/ f2)(); - /*@__PURE__*/ (f3()); - (/*@__PURE__*/ f4()); - /*@__PURE__*/ f5(1)(2)(3); - (/*@__PURE__*/ f6(1)(2)(3)); - /*@__PURE__*/ f7.x(1).y(2).z(3); - (/*@__PURE__*/ f8.x(1).y(2).z(3)); + /*@__PURE__*/ a(); + /*@__PURE__*/ (b()); + (/*@__PURE__*/ c)(); + (/*@__PURE__*/ d()); } expect: {} } issue_2629_2: { + options = { + side_effects: true, + } + input: { + /*@__PURE__*/ a(1)(2)(3); + /*@__PURE__*/ (b(1))(2)(3); + /*@__PURE__*/ (c(1)(2))(3); + /*@__PURE__*/ (d(1)(2)(3)); + (/*@__PURE__*/ e)(1)(2)(3); + (/*@__PURE__*/ f(1))(2)(3); + (/*@__PURE__*/ g(1)(2))(3); + (/*@__PURE__*/ h(1)(2)(3)); + } + expect: {} +} + +issue_2629_3: { + options = { + side_effects: true, + } + input: { + /*@__PURE__*/ a.x(1).y(2).z(3); + /*@__PURE__*/ (a.x)(1).y(2).z(3); + /*@__PURE__*/ (a.x(1)).y(2).z(3); + /*@__PURE__*/ (a.x(1).y)(2).z(3); + /*@__PURE__*/ (a.x(1).y(2)).z(3); + /*@__PURE__*/ (a.x(1).y(2).z)(3); + /*@__PURE__*/ (a.x(1).y(2).z(3)); + (/*@__PURE__*/ a).x(1).y(2).z(3); + (/*@__PURE__*/ a.x)(1).y(2).z(3); + (/*@__PURE__*/ a.x(1)).y(2).z(3); + (/*@__PURE__*/ a.x(1).y)(2).z(3); + (/*@__PURE__*/ a.x(1).y(2)).z(3); + (/*@__PURE__*/ a.x(1).y(2).z)(3); + (/*@__PURE__*/ a.x(1).y(2).z(3)); + } + expect: {} +} + +issue_2629_4: { options = { side_effects: true, } @@ -325,7 +361,7 @@ issue_2629_2: { } } -issue_2629_3: { +issue_2629_5: { options = { side_effects: true, }