handle overlapped variable definitions (#1691)
Process variable definitions with or without assigned values against: - `arguments` - named function arguments - multiple definitions within same scope Essentially demote variable declarations with no value assignments. Also fixed invalid use of `AST_VarDef` over `arguments` - should use a member of `AST_SymbolDeclaration` instead.
This commit is contained in:
@@ -260,7 +260,7 @@ merge(Compressor.prototype, {
|
|||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var d = node.definition();
|
var d = node.definition();
|
||||||
d.references.push(node);
|
d.references.push(node);
|
||||||
if (!d.fixed || !is_safe(d)
|
if (d.fixed === undefined || !is_safe(d)
|
||||||
|| is_modified(node, 0, d.fixed instanceof AST_Lambda)) {
|
|| is_modified(node, 0, d.fixed instanceof AST_Lambda)) {
|
||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
}
|
}
|
||||||
@@ -270,10 +270,10 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_VarDef) {
|
if (node instanceof AST_VarDef) {
|
||||||
var d = node.name.definition();
|
var d = node.name.definition();
|
||||||
if (d.fixed === undefined) {
|
if (d.fixed == null) {
|
||||||
d.fixed = node.value || make_node(AST_Undefined, node);
|
d.fixed = node.value;
|
||||||
mark_as_safe(d);
|
mark_as_safe(d);
|
||||||
} else {
|
} else if (node.value) {
|
||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -357,7 +357,14 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function is_safe(def) {
|
function is_safe(def) {
|
||||||
for (var i = safe_ids.length, id = def.id; --i >= 0;) {
|
for (var i = safe_ids.length, id = def.id; --i >= 0;) {
|
||||||
if (safe_ids[i][id]) return true;
|
if (safe_ids[i][id]) {
|
||||||
|
if (def.fixed == null) {
|
||||||
|
var orig = def.orig[0];
|
||||||
|
if (orig instanceof AST_SymbolFunarg || orig.name == "arguments") return false;
|
||||||
|
def.fixed = make_node(AST_Undefined, orig);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
32
lib/scope.js
32
lib/scope.js
@@ -100,15 +100,14 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
if (node instanceof AST_Catch) {
|
if (node instanceof AST_Catch) {
|
||||||
var save_scope = scope;
|
var save_scope = scope;
|
||||||
scope = new AST_Scope(node);
|
scope = new AST_Scope(node);
|
||||||
scope.init_scope_vars();
|
scope.init_scope_vars(save_scope);
|
||||||
scope.parent_scope = save_scope;
|
|
||||||
descend();
|
descend();
|
||||||
scope = save_scope;
|
scope = save_scope;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_Scope) {
|
||||||
node.init_scope_vars();
|
node.init_scope_vars(scope);
|
||||||
var save_scope = node.parent_scope = scope;
|
var save_scope = scope;
|
||||||
var save_defun = defun;
|
var save_defun = defun;
|
||||||
var save_labels = labels;
|
var save_labels = labels;
|
||||||
defun = scope = node;
|
defun = scope = node;
|
||||||
@@ -243,23 +242,24 @@ AST_Toplevel.DEFMETHOD("def_global", function(node){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("init_scope_vars", function(){
|
AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope){
|
||||||
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
|
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
|
||||||
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
||||||
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
||||||
this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
|
this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval`
|
||||||
this.parent_scope = null; // the parent scope
|
this.parent_scope = parent_scope; // the parent scope
|
||||||
this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
|
this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes
|
||||||
this.cname = -1; // the current index for mangling functions/variables
|
this.cname = -1; // the current index for mangling functions/variables
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
|
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
|
||||||
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
||||||
this.uses_arguments = false;
|
this.uses_arguments = false;
|
||||||
|
this.def_variable(new AST_SymbolVar({
|
||||||
var symbol = new AST_VarDef({ name: "arguments", start: this.start, end: this.end });
|
name: "arguments",
|
||||||
var def = new SymbolDef(this, this.variables.size(), symbol);
|
start: this.start,
|
||||||
this.variables.set(symbol.name, def);
|
end: this.end
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_SymbolRef.DEFMETHOD("reference", function(options) {
|
AST_SymbolRef.DEFMETHOD("reference", function(options) {
|
||||||
|
|||||||
@@ -425,7 +425,7 @@ iife_new: {
|
|||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
multi_def: {
|
multi_def_1: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
@@ -435,7 +435,7 @@ multi_def: {
|
|||||||
if (a)
|
if (a)
|
||||||
var b = 1;
|
var b = 1;
|
||||||
else
|
else
|
||||||
var b = 2
|
var b = 2;
|
||||||
console.log(b + 1);
|
console.log(b + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -444,7 +444,7 @@ multi_def: {
|
|||||||
if (a)
|
if (a)
|
||||||
var b = 1;
|
var b = 1;
|
||||||
else
|
else
|
||||||
var b = 2
|
var b = 2;
|
||||||
console.log(b + 1);
|
console.log(b + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -479,6 +479,33 @@ multi_def_2: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
multi_def_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
var b = 2;
|
||||||
|
if (a)
|
||||||
|
var b;
|
||||||
|
else
|
||||||
|
var b;
|
||||||
|
console.log(b + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
var b = 2;
|
||||||
|
if (a)
|
||||||
|
var b;
|
||||||
|
else
|
||||||
|
var b;
|
||||||
|
console.log(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
use_before_var: {
|
use_before_var: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
@@ -1571,3 +1598,259 @@ unary_delete: {
|
|||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
redefine_arguments_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
var arguments;
|
||||||
|
return typeof arguments;
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
var arguments = 42;
|
||||||
|
return typeof arguments;
|
||||||
|
}
|
||||||
|
function h(x) {
|
||||||
|
var arguments = x;
|
||||||
|
return typeof arguments;
|
||||||
|
}
|
||||||
|
console.log(f(), g(), h());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
var arguments;
|
||||||
|
return typeof arguments;
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
return"number";
|
||||||
|
}
|
||||||
|
function h(x) {
|
||||||
|
var arguments = x;
|
||||||
|
return typeof arguments;
|
||||||
|
}
|
||||||
|
console.log(f(), g(), h());
|
||||||
|
}
|
||||||
|
expect_stdout: "object number undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
redefine_arguments_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
var arguments;
|
||||||
|
return typeof arguments;
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
var arguments = 42;
|
||||||
|
return typeof arguments;
|
||||||
|
}
|
||||||
|
function h(x) {
|
||||||
|
var arguments = x;
|
||||||
|
return typeof arguments;
|
||||||
|
}
|
||||||
|
console.log(f(), g(), h());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
var arguments;
|
||||||
|
return typeof arguments;
|
||||||
|
}(), function() {
|
||||||
|
return"number";
|
||||||
|
}(), function(x) {
|
||||||
|
var arguments = x;
|
||||||
|
return typeof arguments;
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "object number undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
redefine_arguments_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
passes: 3,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
var arguments;
|
||||||
|
return typeof arguments;
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
var arguments = 42;
|
||||||
|
return typeof arguments;
|
||||||
|
}
|
||||||
|
function h(x) {
|
||||||
|
var arguments = x;
|
||||||
|
return typeof arguments;
|
||||||
|
}
|
||||||
|
console.log(f(), g(), h());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function() {
|
||||||
|
var arguments;
|
||||||
|
return typeof arguments;
|
||||||
|
}(), "number", "undefined");
|
||||||
|
}
|
||||||
|
expect_stdout: "object number undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
redefine_farg_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
var a;
|
||||||
|
return typeof a;
|
||||||
|
}
|
||||||
|
function g(a) {
|
||||||
|
var a = 42;
|
||||||
|
return typeof a;
|
||||||
|
}
|
||||||
|
function h(a, b) {
|
||||||
|
var a = b;
|
||||||
|
return typeof a;
|
||||||
|
}
|
||||||
|
console.log(f([]), g([]), h([]));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(a) {
|
||||||
|
var a;
|
||||||
|
return typeof a;
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
return"number";
|
||||||
|
}
|
||||||
|
function h(a, b) {
|
||||||
|
var a = b;
|
||||||
|
return typeof a;
|
||||||
|
}
|
||||||
|
console.log(f([]), g([]), h([]));
|
||||||
|
}
|
||||||
|
expect_stdout: "object number undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
redefine_farg_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
var a;
|
||||||
|
return typeof a;
|
||||||
|
}
|
||||||
|
function g(a) {
|
||||||
|
var a = 42;
|
||||||
|
return typeof a;
|
||||||
|
}
|
||||||
|
function h(a, b) {
|
||||||
|
var a = b;
|
||||||
|
return typeof a;
|
||||||
|
}
|
||||||
|
console.log(f([]), g([]), h([]));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
var a;
|
||||||
|
return typeof a;
|
||||||
|
}([]), function() {
|
||||||
|
return "number";
|
||||||
|
}(),function(a, b) {
|
||||||
|
var a = b;
|
||||||
|
return typeof a;
|
||||||
|
}([]));
|
||||||
|
}
|
||||||
|
expect_stdout: "object number undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
redefine_farg_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
keep_fargs: false,
|
||||||
|
passes: 3,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(a) {
|
||||||
|
var a;
|
||||||
|
return typeof a;
|
||||||
|
}
|
||||||
|
function g(a) {
|
||||||
|
var a = 42;
|
||||||
|
return typeof a;
|
||||||
|
}
|
||||||
|
function h(a, b) {
|
||||||
|
var a = b;
|
||||||
|
return typeof a;
|
||||||
|
}
|
||||||
|
console.log(f([]), g([]), h([]));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
var a;
|
||||||
|
return typeof a;
|
||||||
|
}([]), "number", function(a) {
|
||||||
|
var a = void 0;
|
||||||
|
return typeof a;
|
||||||
|
}([]));
|
||||||
|
}
|
||||||
|
expect_stdout: "object number undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
delay_def: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
return a;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
var a = 1;
|
||||||
|
}
|
||||||
|
console.log(f(), g());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
return a;
|
||||||
|
var a;
|
||||||
|
}
|
||||||
|
function g() {
|
||||||
|
return a;
|
||||||
|
var a = 1;
|
||||||
|
}
|
||||||
|
console.log(f(), g());
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user