fix label-related bugs (#1835)

- deep cloning of `AST_LabeledStatement`
- `L:do{...}while(false)`
- empty statement with label within block

extend `test/ufuzz.js`
- generate labels for blocks & loops
- generate for-in statements
- skip suspicious option search if `minify()` errs

fixes #1833
This commit is contained in:
Alex Lam S.L
2017-04-22 22:15:04 +08:00
committed by alexlamsl
parent dda4eb96e1
commit d8106b6c63
4 changed files with 148 additions and 16 deletions

View File

@@ -214,12 +214,13 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
clone: function(deep) { clone: function(deep) {
var node = this._clone(deep); var node = this._clone(deep);
if (deep) { if (deep) {
var refs = node.label.references; var label = node.label;
var label = this.label; var def = this.label;
node.walk(new TreeWalker(function(node) { node.walk(new TreeWalker(function(node) {
if (node instanceof AST_LoopControl if (node instanceof AST_LoopControl
&& node.label && node.label.thedef === label) { && node.label && node.label.thedef === def) {
refs.push(node); node.label.thedef = label;
label.references.push(node);
} }
})); }));
} }

View File

@@ -2404,7 +2404,7 @@ merge(Compressor.prototype, {
if (compressor.option("dead_code") && self instanceof AST_While) { if (compressor.option("dead_code") && self instanceof AST_While) {
var a = []; var a = [];
extract_declarations_from_unreachable_code(compressor, self.body, a); extract_declarations_from_unreachable_code(compressor, self.body, a);
return make_node(AST_BlockStatement, self, { body: a }); return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor);
} }
if (self instanceof AST_Do) { if (self instanceof AST_Do) {
var has_loop_control = false; var has_loop_control = false;
@@ -2413,7 +2413,8 @@ merge(Compressor.prototype, {
if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === self) if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === self)
return has_loop_control = true; return has_loop_control = true;
}); });
self.walk(tw); var parent = compressor.parent();
(parent instanceof AST_LabeledStatement ? parent : self).walk(tw);
if (!has_loop_control) return self.body; if (!has_loop_control) return self.body;
} }
} }
@@ -2483,7 +2484,7 @@ merge(Compressor.prototype, {
})); }));
} }
extract_declarations_from_unreachable_code(compressor, self.body, a); extract_declarations_from_unreachable_code(compressor, self.body, a);
return make_node(AST_BlockStatement, self, { body: a }); return make_node(AST_BlockStatement, self, { body: a }).optimize(compressor);
} }
if (cond !== self.condition) { if (cond !== self.condition) {
cond = make_node_from_constant(cond, self.condition).transform(compressor); cond = make_node_from_constant(cond, self.condition).transform(compressor);
@@ -2735,9 +2736,9 @@ merge(Compressor.prototype, {
var body = []; var body = [];
if (self.bcatch) extract_declarations_from_unreachable_code(compressor, self.bcatch, body); if (self.bcatch) extract_declarations_from_unreachable_code(compressor, self.bcatch, body);
if (self.bfinally) body = body.concat(self.bfinally.body); if (self.bfinally) body = body.concat(self.bfinally.body);
return body.length > 0 ? make_node(AST_BlockStatement, self, { return make_node(AST_BlockStatement, self, {
body: body body: body
}).optimize(compressor) : make_node(AST_EmptyStatement, self); }).optimize(compressor);
} }
return self; return self;
}); });

View File

@@ -190,11 +190,7 @@ function OutputStream(options) {
var might_need_space = false; var might_need_space = false;
var might_need_semicolon = false; var might_need_semicolon = false;
var might_add_newline = 0; var might_add_newline = 0;
var last = null; var last = "";
function last_char() {
return last.charAt(last.length - 1);
};
var ensure_line_len = options.max_line_len ? function() { var ensure_line_len = options.max_line_len ? function() {
if (current_col > options.max_line_len) { if (current_col > options.max_line_len) {
@@ -218,10 +214,11 @@ function OutputStream(options) {
function print(str) { function print(str) {
str = String(str); str = String(str);
var ch = str.charAt(0); var ch = str.charAt(0);
var prev = last.charAt(last.length - 1);
if (might_need_semicolon) { if (might_need_semicolon) {
might_need_semicolon = false; might_need_semicolon = false;
if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) { if (prev == ":" && ch == "}" || (!ch || ";}".indexOf(ch) < 0) && prev != ";") {
if (options.semicolons || requireSemicolonChars(ch)) { if (options.semicolons || requireSemicolonChars(ch)) {
OUTPUT += ";"; OUTPUT += ";";
current_col++; current_col++;
@@ -258,7 +255,6 @@ function OutputStream(options) {
} }
if (might_need_space) { if (might_need_space) {
var prev = last_char();
if ((is_identifier_char(prev) if ((is_identifier_char(prev)
&& (is_identifier_char(ch) || ch == "\\")) && (is_identifier_char(ch) || ch == "\\"))
|| (ch == "/" && ch == prev) || (ch == "/" && ch == prev)

134
test/compress/issue-1833.js Normal file
View File

@@ -0,0 +1,134 @@
iife_for: {
options = {
negate_iife: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
function g() {
L: for (;;) break L;
}
g();
}
f();
}
expect: {
!function() {
!function() {
L: for (;;) break L;
}();
}();
}
}
iife_for_in: {
options = {
negate_iife: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
function g() {
L: for (var a in x) break L;
}
g();
}
f();
}
expect: {
!function() {
!function() {
L: for (var a in x) break L;
}();
}();
}
}
iife_do: {
options = {
negate_iife: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
function g() {
L: do {
break L;
} while (1);
}
g();
}
f();
}
expect: {
!function() {
!function() {
L: do {
break L;
} while (1);
}();
}();
}
}
iife_while: {
options = {
negate_iife: true,
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
function g() {
L: while (1) break L;
}
g();
}
f();
}
expect: {
!function() {
!function() {
L: while (1) break L;
}();
}();
}
}
label_do: {
options = {
evaluate: true,
loops: true,
}
input: {
L: do {
continue L;
} while (0);
}
expect: {
L: do {
continue L;
} while (0);
}
}
label_while: {
options = {
evaluate: true,
dead_code: true,
loops: true,
}
input: {
function f() {
L: while (0) continue L;
}
}
expect_exact: "function f(){L:;}"
}