@@ -5453,6 +5453,7 @@ merge(Compressor.prototype, {
|
||||
var in_use_ids = Object.create(null); // avoid expensive linear scans of in_use
|
||||
var value_read = Object.create(null);
|
||||
var value_modified = Object.create(null);
|
||||
var var_defs = Object.create(null);
|
||||
if (self instanceof AST_Toplevel && compressor.top_retain) {
|
||||
self.variables.each(function(def) {
|
||||
if (compressor.top_retain(def) && !(def.id in in_use_ids)) {
|
||||
@@ -5462,7 +5463,6 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
}
|
||||
var assignments = new Dictionary();
|
||||
var var_defs_by_id = new Dictionary();
|
||||
var initializations = new Dictionary();
|
||||
// pass 1: find out which symbols are directly used in
|
||||
// this scope (not in nested scopes).
|
||||
@@ -5495,10 +5495,10 @@ merge(Compressor.prototype, {
|
||||
defn.name.mark_symbol(function(name) {
|
||||
if (!(name instanceof AST_SymbolDeclaration)) return;
|
||||
var def = name.definition();
|
||||
var_defs_by_id.add(def.id, defn);
|
||||
var_defs[def.id] = (var_defs[def.id] || 0) + 1;
|
||||
if (node instanceof AST_Var && def.orig[0] instanceof AST_SymbolCatch) {
|
||||
var redef = def.redefined();
|
||||
if (redef) var_defs_by_id.add(redef.id, defn);
|
||||
if (redef) var_defs[redef.id] = (var_defs[redef.id] || 0) + 1;
|
||||
}
|
||||
if (!(def.id in in_use_ids) && (!drop_vars
|
||||
|| (node instanceof AST_Const ? def.redefined() : def.const_redefs)
|
||||
@@ -5518,7 +5518,7 @@ merge(Compressor.prototype, {
|
||||
}
|
||||
if (node instanceof AST_SymbolFunarg) {
|
||||
var def = node.definition();
|
||||
var_defs_by_id.add(def.id, node);
|
||||
var_defs[def.id] = (var_defs[def.id] || 0) + 1;
|
||||
assignments.add(def.id, node);
|
||||
return true;
|
||||
}
|
||||
@@ -5577,6 +5577,7 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
};
|
||||
// pass 3: we should drop declarations not in_use
|
||||
var trim_defns = [];
|
||||
var unused_fn_names = [];
|
||||
var calls_to_drop_args = [];
|
||||
var fns_with_marked_args = [];
|
||||
@@ -5743,8 +5744,9 @@ merge(Compressor.prototype, {
|
||||
var is_var = node instanceof AST_Var;
|
||||
node.definitions.forEach(function(def) {
|
||||
if (def.value) def.value = def.value.transform(tt);
|
||||
var value = def.value;
|
||||
if (def.name instanceof AST_Destructured) {
|
||||
var name = trim_destructured(def.name, def.value, function(node) {
|
||||
var name = trim_destructured(def.name, value, function(node) {
|
||||
if (!drop_vars) return node;
|
||||
if (node.definition().id in in_use_ids) return node;
|
||||
if (is_catch(node)) return node;
|
||||
@@ -5754,7 +5756,7 @@ merge(Compressor.prototype, {
|
||||
if (name) {
|
||||
flush();
|
||||
} else {
|
||||
var value = def.value.drop_side_effect_free(compressor);
|
||||
value = value.drop_side_effect_free(compressor);
|
||||
if (value) side_effects.push(value);
|
||||
}
|
||||
return;
|
||||
@@ -5762,27 +5764,25 @@ merge(Compressor.prototype, {
|
||||
var sym = def.name.definition();
|
||||
var drop_sym = is_var ? can_drop_symbol(def.name) : is_safe_lexical(sym);
|
||||
if (!drop_sym || !drop_vars || sym.id in in_use_ids) {
|
||||
if (def.value && indexOf_assign(sym, def) < 0) {
|
||||
var write_only = def.value.write_only;
|
||||
var value = def.value.drop_side_effect_free(compressor);
|
||||
if (value && indexOf_assign(sym, def) < 0) {
|
||||
var write_only = value.write_only;
|
||||
value = value.drop_side_effect_free(compressor);
|
||||
if (def.value !== value) {
|
||||
sym.references.forEach(function(node) {
|
||||
if (node.fixed === sym.fixed) node.fixed = def.value;
|
||||
});
|
||||
def.value = null;
|
||||
if (value) {
|
||||
AST_Node.warn("Side effects in last use of variable {name} [{file}:{line},{col}]", template(def.name));
|
||||
side_effects.push(value);
|
||||
}
|
||||
} else if (def.value.write_only !== write_only) {
|
||||
def.value.write_only = write_only;
|
||||
value = null;
|
||||
trim_defns.push(def);
|
||||
} else if (value.write_only !== write_only) {
|
||||
value.write_only = write_only;
|
||||
}
|
||||
}
|
||||
var old_def, var_defs = var_defs_by_id.get(sym.id);
|
||||
if (!def.value && !(node instanceof AST_Let)) {
|
||||
if (drop_sym && var_defs.length > 1) {
|
||||
var old_def;
|
||||
if (!value && !(node instanceof AST_Let)) {
|
||||
if (drop_sym && var_defs[sym.id] > 1) {
|
||||
AST_Node.info("Dropping declaration of variable {name} [{file}:{line},{col}]", template(def.name));
|
||||
remove(var_defs, def);
|
||||
var_defs[sym.id]--;
|
||||
sym.eliminated++;
|
||||
} else {
|
||||
head.push(def);
|
||||
@@ -5790,20 +5790,20 @@ merge(Compressor.prototype, {
|
||||
} else if (compressor.option("functions")
|
||||
&& !compressor.option("ie8")
|
||||
&& !(node instanceof AST_Const || node instanceof AST_Let)
|
||||
&& var_defs.length == 1
|
||||
&& var_defs[sym.id] == 1
|
||||
&& sym.assignments == 0
|
||||
&& def.value instanceof AST_Function
|
||||
&& value instanceof AST_Function
|
||||
&& (sym.references.length ? all(sym.references, function(ref) {
|
||||
return def.value === ref.fixed_value();
|
||||
}) : def.value === def.name.fixed_value())
|
||||
&& (!def.value.name || (old_def = def.value.name.definition()).assignments == 0
|
||||
return value === ref.fixed_value();
|
||||
}) : value === def.name.fixed_value())
|
||||
&& (!value.name || (old_def = value.name.definition()).assignments == 0
|
||||
&& (old_def.name == def.name.name || all(old_def.references, function(ref) {
|
||||
return ref.scope.find_variable(def.name.name) === def.name.definition();
|
||||
})))
|
||||
&& can_declare_defun()
|
||||
&& can_rename(def.value, def.name.name)) {
|
||||
&& can_rename(value, def.name.name)) {
|
||||
AST_Node.warn("Declaring {name} as function [{file}:{line},{col}]", template(def.name));
|
||||
var defun = make_node(AST_Defun, def, def.value);
|
||||
var defun = make_node(AST_Defun, def, value);
|
||||
defun.name = make_node(AST_SymbolDefun, def.name, def.name);
|
||||
var name_def = def.name.scope.resolve().def_function(defun.name);
|
||||
if (old_def) old_def.forEach(function(node) {
|
||||
@@ -5813,26 +5813,25 @@ merge(Compressor.prototype, {
|
||||
});
|
||||
body.push(defun);
|
||||
} else {
|
||||
if (drop_sym && var_defs.length > 1 && sym.orig.indexOf(def.name) > sym.eliminated) {
|
||||
remove(var_defs, def);
|
||||
if (drop_sym && var_defs[sym.id] > 1 && sym.orig.indexOf(def.name) > sym.eliminated) {
|
||||
var_defs[sym.id]--;
|
||||
duplicated++;
|
||||
}
|
||||
flush();
|
||||
}
|
||||
} else if (is_catch(def.name)) {
|
||||
var value = def.value && def.value.drop_side_effect_free(compressor);
|
||||
value = value && value.drop_side_effect_free(compressor);
|
||||
if (value) side_effects.push(value);
|
||||
var var_defs = var_defs_by_id.get(sym.id);
|
||||
if (var_defs.length > 1) {
|
||||
if (var_defs[sym.id] > 1) {
|
||||
AST_Node.warn("Dropping duplicated declaration of variable {name} [{file}:{line},{col}]", template(def.name));
|
||||
remove(var_defs, def);
|
||||
var_defs[sym.id]--;
|
||||
sym.eliminated++;
|
||||
} else {
|
||||
def.value = null;
|
||||
head.push(def);
|
||||
}
|
||||
} else {
|
||||
var value = def.value && !def.value.single_use && def.value.drop_side_effect_free(compressor);
|
||||
value = value && !value.single_use && value.drop_side_effect_free(compressor);
|
||||
if (value) {
|
||||
AST_Node.warn("Side effects in initialization of unused variable {name} [{file}:{line},{col}]", template(def.name));
|
||||
side_effects.push(value);
|
||||
@@ -5865,9 +5864,9 @@ merge(Compressor.prototype, {
|
||||
body.push(make_node(AST_SimpleStatement, node, {
|
||||
body: make_sequence(node, side_effects)
|
||||
}));
|
||||
} else if (def.value) {
|
||||
side_effects.push(def.value);
|
||||
def.value = make_sequence(def.value, side_effects);
|
||||
} else if (value) {
|
||||
side_effects.push(value);
|
||||
def.value = make_sequence(value, side_effects);
|
||||
} else {
|
||||
def.value = make_node(AST_UnaryPrefix, def, {
|
||||
operator: "void",
|
||||
@@ -6017,6 +6016,9 @@ merge(Compressor.prototype, {
|
||||
&& self.body[0].value == "use strict") {
|
||||
self.body.length = 0;
|
||||
}
|
||||
trim_defns.forEach(function(def) {
|
||||
def.value = null;
|
||||
});
|
||||
unused_fn_names.forEach(function(fn) {
|
||||
fn.name = null;
|
||||
});
|
||||
|
||||
@@ -3197,3 +3197,54 @@ issue_4464_3: {
|
||||
"function",
|
||||
]
|
||||
}
|
||||
|
||||
issue_4558_1: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
pure_getters: true,
|
||||
reduce_vars: true,
|
||||
sequences: true,
|
||||
side_effects: true,
|
||||
toplevel: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
var a = 0;
|
||||
var b = 1, b = c >>>= a;
|
||||
var c = 0;
|
||||
b && 0[a++],
|
||||
console.log(a);
|
||||
}
|
||||
expect: {
|
||||
var a = 0;
|
||||
var b = c >>>= a;
|
||||
var c;
|
||||
b && a++,
|
||||
console.log(a);
|
||||
}
|
||||
expect_stdout: "0"
|
||||
}
|
||||
|
||||
issue_4558_2: {
|
||||
options = {
|
||||
evaluate: true,
|
||||
ie8: true,
|
||||
reduce_vars: true,
|
||||
unused: true,
|
||||
}
|
||||
input: {
|
||||
(function() {
|
||||
var a = 1;
|
||||
var b = (a = NaN) || (console.log("PASS"), 2);
|
||||
return a;
|
||||
})();
|
||||
}
|
||||
expect: {
|
||||
(function() {
|
||||
var a;
|
||||
(a = NaN) || console.log("PASS");
|
||||
return a;
|
||||
})();
|
||||
}
|
||||
expect_stdout: "PASS"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user