@@ -167,7 +167,7 @@ merge(Compressor.prototype, {
|
|||||||
if (def.global) for (var i = 0; i < def.orig.length; i++)
|
if (def.global) for (var i = 0; i < def.orig.length; i++)
|
||||||
if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"])
|
if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"])
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return def.undeclared;
|
||||||
},
|
},
|
||||||
compress: function(node) {
|
compress: function(node) {
|
||||||
node = node.resolve_defines(this);
|
node = node.resolve_defines(this);
|
||||||
@@ -1386,6 +1386,7 @@ merge(Compressor.prototype, {
|
|||||||
var scan_lhs = lhs && !side_effects && !is_lhs_read_only(lhs, compressor);
|
var scan_lhs = lhs && !side_effects && !is_lhs_read_only(lhs, compressor);
|
||||||
var scan_rhs = foldable(candidate);
|
var scan_rhs = foldable(candidate);
|
||||||
if (!scan_lhs && !scan_rhs) continue;
|
if (!scan_lhs && !scan_rhs) continue;
|
||||||
|
var read_toplevel = false;
|
||||||
var modify_toplevel = false;
|
var modify_toplevel = false;
|
||||||
// Locate symbols which may execute code outside of scanning range
|
// Locate symbols which may execute code outside of scanning range
|
||||||
var lvalues = get_lvalues(candidate);
|
var lvalues = get_lvalues(candidate);
|
||||||
@@ -1548,8 +1549,10 @@ merge(Compressor.prototype, {
|
|||||||
return lvalues.has(node.name.name) || side_effects && may_modify(node.name);
|
return lvalues.has(node.name.name) || side_effects && may_modify(node.name);
|
||||||
}
|
}
|
||||||
var sym = is_lhs(node.left, node);
|
var sym = is_lhs(node.left, node);
|
||||||
if (sym && lvalues.has(sym.name)) return true;
|
if (!sym) return false;
|
||||||
if (sym instanceof AST_PropAccess) return true;
|
return lvalues.has(sym.name)
|
||||||
|
|| sym instanceof AST_PropAccess
|
||||||
|
|| read_toplevel && compressor.exposed(sym.definition());
|
||||||
}
|
}
|
||||||
|
|
||||||
function extract_args() {
|
function extract_args() {
|
||||||
@@ -1936,26 +1939,43 @@ merge(Compressor.prototype, {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function may_be_global(node) {
|
||||||
|
if (node instanceof AST_SymbolRef) {
|
||||||
|
node = node.fixed_value();
|
||||||
|
if (!node) return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_Assign) return node.operator == "=" && may_be_global(node.right);
|
||||||
|
return node instanceof AST_PropAccess || node instanceof AST_This;
|
||||||
|
}
|
||||||
|
|
||||||
function get_lvalues(expr) {
|
function get_lvalues(expr) {
|
||||||
var lvalues = new Dictionary();
|
var lvalues = new Dictionary();
|
||||||
if (candidate instanceof AST_VarDef) lvalues.add(candidate.name.name, lhs);
|
if (expr instanceof AST_VarDef) lvalues.add(expr.name.name, lhs);
|
||||||
var scan_iife = scope instanceof AST_Toplevel;
|
var scan_toplevel = scope instanceof AST_Toplevel;
|
||||||
var tw = new TreeWalker(function(node) {
|
var tw = new TreeWalker(function(node) {
|
||||||
if (scan_iife && node.TYPE == "Call") {
|
|
||||||
var exp = node.expression;
|
|
||||||
if (exp instanceof AST_PropAccess) return;
|
|
||||||
if (exp instanceof AST_Function && !exp.contains_this()) return;
|
|
||||||
modify_toplevel = true;
|
|
||||||
scan_iife = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var value;
|
var value;
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
value = node.fixed_value() || node;
|
value = node.fixed_value() || node;
|
||||||
} else if (node instanceof AST_This) {
|
} else if (node instanceof AST_This) {
|
||||||
value = node;
|
value = node;
|
||||||
}
|
}
|
||||||
if (value) lvalues.add(node.name, is_modified(compressor, tw, node, value, 0));
|
if (value) {
|
||||||
|
lvalues.add(node.name, is_modified(compressor, tw, node, value, 0));
|
||||||
|
} else if (scan_toplevel) {
|
||||||
|
if (node.TYPE == "Call") {
|
||||||
|
if (modify_toplevel) return;
|
||||||
|
var exp = node.expression;
|
||||||
|
if (exp instanceof AST_PropAccess) return;
|
||||||
|
if (exp instanceof AST_Function && !exp.contains_this()) return;
|
||||||
|
modify_toplevel = true;
|
||||||
|
} else if (node instanceof AST_PropAccess && may_be_global(node.expression)) {
|
||||||
|
if (node === lhs && !(expr instanceof AST_Unary)) {
|
||||||
|
modify_toplevel = true;
|
||||||
|
} else {
|
||||||
|
read_toplevel = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
expr.walk(tw);
|
expr.walk(tw);
|
||||||
return lvalues;
|
return lvalues;
|
||||||
|
|||||||
@@ -8317,3 +8317,61 @@ issue_4012: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
global_assign: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
this.A = "FAIL";
|
||||||
|
A = "PASS";
|
||||||
|
B = "FAIL";
|
||||||
|
console.log(A);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
this.A = "FAIL";
|
||||||
|
A = "PASS";
|
||||||
|
B = "FAIL";
|
||||||
|
console.log(A);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
global_read: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0;
|
||||||
|
a = this.A;
|
||||||
|
A = 1;
|
||||||
|
a ? console.log("FAIL") : console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0;
|
||||||
|
a = this.A;
|
||||||
|
A = 1;
|
||||||
|
a ? console.log("FAIL") : console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_4038: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0;
|
||||||
|
a = this;
|
||||||
|
a = a.A;
|
||||||
|
A = 1;
|
||||||
|
a ? console.log("FAIL") : console.log("PASS");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0;
|
||||||
|
a = (a = this).A;
|
||||||
|
A = 1;
|
||||||
|
a ? console.log("FAIL") : console.log("PASS");
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|||||||
@@ -7402,7 +7402,27 @@ issue_4030: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
A = "PASS";
|
A = "PASS";
|
||||||
console.log("PASS");
|
console.log(A);
|
||||||
|
}
|
||||||
|
expect_stdout: "PASS"
|
||||||
|
}
|
||||||
|
|
||||||
|
global_assign: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
A = "FAIL";
|
||||||
|
this.A = "PASS";
|
||||||
|
console.log(A);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
A = "FAIL";
|
||||||
|
this.A = "PASS";
|
||||||
|
console.log(A);
|
||||||
}
|
}
|
||||||
expect_stdout: "PASS"
|
expect_stdout: "PASS"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1175,7 +1175,8 @@ function log(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sort_globals(code) {
|
function sort_globals(code) {
|
||||||
return "var " + sandbox.run_code("throw Object.keys(this).sort();" + code).join(",") + ";" + code;
|
var globals = sandbox.run_code("throw Object.keys(this).sort();" + code);
|
||||||
|
return globals.length ? "var " + globals.join(",") + ";" + code : code;
|
||||||
}
|
}
|
||||||
|
|
||||||
function fuzzy_match(original, uglified) {
|
function fuzzy_match(original, uglified) {
|
||||||
|
|||||||
Reference in New Issue
Block a user