enforce toplevel on other compress options (#1855)

Respect "funcs" and "vars" properly.

fixes #1850
This commit is contained in:
Alex Lam S.L
2017-04-30 22:52:36 +08:00
committed by GitHub
parent bbb5f2a89c
commit 2cb55b2ad0
2 changed files with 362 additions and 265 deletions

View File

@@ -109,6 +109,14 @@ function Compressor(options, false_by_default) {
return top_retain.indexOf(def.name) >= 0;
};
}
var toplevel = this.options["toplevel"];
if (typeof toplevel == "string") {
this.toplevel.funcs = /funcs/.test(toplevel);
this.toplevel.vars = /vars/.test(toplevel);
} else {
this.toplevel = toplevel ? return_true : return_false;
this.toplevel.funcs = this.toplevel.vars = toplevel;
}
var sequences = this.options["sequences"];
this.sequences_limit = sequences == 1 ? 800 : sequences | 0;
this.warnings_produced = {};
@@ -117,6 +125,12 @@ function Compressor(options, false_by_default) {
Compressor.prototype = new TreeTransformer;
merge(Compressor.prototype, {
option: function(key) { return this.options[key] },
toplevel: function(def) {
for (var i = 0, len = def.orig.length; i < len; i++)
if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"])
return false;
return true;
},
compress: function(node) {
if (this.option("expression")) {
node.process_expression(true);
@@ -249,7 +263,6 @@ merge(Compressor.prototype, {
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan) {
var reduce_vars = rescan && compressor.option("reduce_vars");
var toplevel = compressor.option("toplevel");
var safe_ids = Object.create(null);
var suppressor = new TreeWalker(function(node) {
if (node instanceof AST_Symbol) {
@@ -310,7 +323,7 @@ merge(Compressor.prototype, {
}
if (node instanceof AST_Defun) {
var d = node.name.definition();
if (!toplevel && d.global || safe_to_read(d)) {
if (d.global && !compressor.toplevel(d) || safe_to_read(d)) {
d.fixed = false;
} else {
d.fixed = node;
@@ -469,7 +482,7 @@ merge(Compressor.prototype, {
}
function reset_def(def) {
if (toplevel || !def.global || def.orig[0] instanceof AST_SymbolConst) {
if (!def.global || def.orig[0] instanceof AST_SymbolConst || compressor.toplevel(def)) {
def.fixed = undefined;
} else {
def.fixed = false;
@@ -643,7 +656,6 @@ merge(Compressor.prototype, {
// in the statement with the var value and then erase the var definition.
var scope = compressor.find_parent(AST_Scope);
var toplevel = compressor.option("toplevel");
var stat_index;
var prev_stat_index;
var def_stat_index;
@@ -694,7 +706,8 @@ merge(Compressor.prototype, {
// Only interested in cases with just one reference to the variable.
var def = var_decl.name.definition();
if (def.references.length !== 1
|| var_name == "arguments" || (!toplevel && def.global)) {
|| var_name == "arguments"
|| def.global && !compressor.toplevel(def)) {
side_effects_encountered = true;
continue;
}
@@ -1825,19 +1838,14 @@ merge(Compressor.prototype, {
});
AST_Scope.DEFMETHOD("drop_unused", function(compressor){
if (!compressor.option("unused")) return;
if (compressor.has_directive("use asm")) return;
var self = this;
if (compressor.has_directive("use asm")) return self;
var toplevel = compressor.option("toplevel");
if (compressor.option("unused")
&& (!(self instanceof AST_Toplevel) || toplevel)
&& !self.uses_eval
&& !self.uses_with) {
if (self.uses_eval || self.uses_with) return;
var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs;
var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars;
if (!drop_funcs && !drop_vars) return;
var assign_as_unused = !/keep_assign/.test(compressor.option("unused"));
var drop_funcs = /funcs/.test(toplevel);
var drop_vars = /vars/.test(toplevel);
if (!(self instanceof AST_Toplevel) || toplevel == true) {
drop_funcs = drop_vars = true;
}
var in_use = [];
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
if (self instanceof AST_Toplevel && compressor.top_retain) {
@@ -2107,7 +2115,6 @@ merge(Compressor.prototype, {
}
);
self.transform(tt);
}
});
AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){
@@ -3683,7 +3690,7 @@ merge(Compressor.prototype, {
}
var name = d.name.length;
var overhead = 0;
if (compressor.option("unused") && (!d.global || compressor.option("toplevel"))) {
if (compressor.option("unused") && (!d.global || compressor.toplevel(d))) {
overhead = (name + 2 + value) / d.references.length;
}
d.should_replace = value <= name + overhead ? fn : false;

View File

@@ -2327,3 +2327,93 @@ iife_assign: {
}
expect_stdout: "1"
}
issue_1850_1: {
options = {
reduce_vars: true,
toplevel: false,
unused: true,
}
input: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect_stdout: true
}
issue_1850_2: {
options = {
reduce_vars: true,
toplevel: "funcs",
unused: true,
}
input: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect: {
var a = 1;
(function() {
console.log(a, a, a);
})();
}
expect_stdout: true
}
issue_1850_3: {
options = {
reduce_vars: true,
toplevel: "vars",
unused: true,
}
input: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect_stdout: true
}
issue_1850_4: {
options = {
reduce_vars: true,
toplevel: true,
unused: true,
}
input: {
function f() {
console.log(a, a, a);
}
var a = 1;
f();
}
expect: {
var a = 1;
(function() {
console.log(a, a, a);
})();
}
expect_stdout: true
}