@@ -689,6 +689,16 @@ merge(Compressor.prototype, {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function is_undeclared_ref(node) {
|
||||||
|
return node instanceof AST_SymbolRef && node.definition().undeclared;
|
||||||
|
}
|
||||||
|
|
||||||
|
var global_names = makePredicate("Array Boolean console Error Function Math Number RegExp Object String");
|
||||||
|
AST_SymbolRef.DEFMETHOD("is_declared", function(compressor) {
|
||||||
|
return !this.definition().undeclared
|
||||||
|
|| compressor.option("unsafe") && global_names(this.name);
|
||||||
|
});
|
||||||
|
|
||||||
function tighten_body(statements, compressor) {
|
function tighten_body(statements, compressor) {
|
||||||
var CHANGED, max_iter = 10;
|
var CHANGED, max_iter = 10;
|
||||||
do {
|
do {
|
||||||
@@ -758,7 +768,7 @@ merge(Compressor.prototype, {
|
|||||||
|| node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression)
|
|| node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression)
|
||||||
|| node instanceof AST_Debugger
|
|| node instanceof AST_Debugger
|
||||||
|| node instanceof AST_IterationStatement && !(node instanceof AST_For)
|
|| node instanceof AST_IterationStatement && !(node instanceof AST_For)
|
||||||
|| node instanceof AST_SymbolRef && node.undeclared()
|
|| node instanceof AST_SymbolRef && !node.is_declared(compressor)
|
||||||
|| node instanceof AST_Try
|
|| node instanceof AST_Try
|
||||||
|| node instanceof AST_With
|
|| node instanceof AST_With
|
||||||
|| parent instanceof AST_For && node !== parent.init) {
|
|| parent instanceof AST_For && node !== parent.init) {
|
||||||
@@ -1320,12 +1330,12 @@ merge(Compressor.prototype, {
|
|||||||
// returns true if this node may be null, undefined or contain `AST_Accessor`
|
// returns true if this node may be null, undefined or contain `AST_Accessor`
|
||||||
(function(def) {
|
(function(def) {
|
||||||
AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
|
AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
|
||||||
var pure_getters = compressor.option("pure_getters");
|
return !compressor.option("pure_getters")
|
||||||
return !pure_getters || this._throw_on_access(pure_getters);
|
|| this._dot_throw(compressor);
|
||||||
});
|
});
|
||||||
|
|
||||||
function is_strict(pure_getters) {
|
function is_strict(compressor) {
|
||||||
return /strict/.test(pure_getters);
|
return /strict/.test(compressor.option("pure_getters"));
|
||||||
}
|
}
|
||||||
|
|
||||||
def(AST_Node, is_strict);
|
def(AST_Node, is_strict);
|
||||||
@@ -1333,8 +1343,8 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Undefined, return_true);
|
def(AST_Undefined, return_true);
|
||||||
def(AST_Constant, return_false);
|
def(AST_Constant, return_false);
|
||||||
def(AST_Array, return_false);
|
def(AST_Array, return_false);
|
||||||
def(AST_Object, function(pure_getters) {
|
def(AST_Object, function(compressor) {
|
||||||
if (!is_strict(pure_getters)) return false;
|
if (!is_strict(compressor)) return false;
|
||||||
for (var i = this.properties.length; --i >=0;)
|
for (var i = this.properties.length; --i >=0;)
|
||||||
if (this.properties[i].value instanceof AST_Accessor) return true;
|
if (this.properties[i].value instanceof AST_Accessor) return true;
|
||||||
return false;
|
return false;
|
||||||
@@ -1344,37 +1354,38 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_UnaryPrefix, function() {
|
def(AST_UnaryPrefix, function() {
|
||||||
return this.operator == "void";
|
return this.operator == "void";
|
||||||
});
|
});
|
||||||
def(AST_Binary, function(pure_getters) {
|
def(AST_Binary, function(compressor) {
|
||||||
switch (this.operator) {
|
switch (this.operator) {
|
||||||
case "&&":
|
case "&&":
|
||||||
return this.left._throw_on_access(pure_getters);
|
return this.left._dot_throw(compressor);
|
||||||
case "||":
|
case "||":
|
||||||
return this.left._throw_on_access(pure_getters)
|
return this.left._dot_throw(compressor)
|
||||||
&& this.right._throw_on_access(pure_getters);
|
&& this.right._dot_throw(compressor);
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
def(AST_Assign, function(pure_getters) {
|
def(AST_Assign, function(compressor) {
|
||||||
return this.operator == "="
|
return this.operator == "="
|
||||||
&& this.right._throw_on_access(pure_getters);
|
&& this.right._dot_throw(compressor);
|
||||||
})
|
})
|
||||||
def(AST_Conditional, function(pure_getters) {
|
def(AST_Conditional, function(compressor) {
|
||||||
return this.consequent._throw_on_access(pure_getters)
|
return this.consequent._dot_throw(compressor)
|
||||||
|| this.alternative._throw_on_access(pure_getters);
|
|| this.alternative._dot_throw(compressor);
|
||||||
})
|
})
|
||||||
def(AST_Sequence, function(pure_getters) {
|
def(AST_Sequence, function(compressor) {
|
||||||
return this.expressions[this.expressions.length - 1]._throw_on_access(pure_getters);
|
return this.expressions[this.expressions.length - 1]._dot_throw(compressor);
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(pure_getters) {
|
def(AST_SymbolRef, function(compressor) {
|
||||||
if (this.is_undefined) return true;
|
if (this.is_undefined) return true;
|
||||||
if (!is_strict(pure_getters)) return false;
|
if (!is_strict(compressor)) return false;
|
||||||
|
if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
|
||||||
if (this.is_immutable()) return false;
|
if (this.is_immutable()) return false;
|
||||||
var fixed = this.fixed_value();
|
var fixed = this.fixed_value();
|
||||||
return !fixed || fixed._throw_on_access(pure_getters);
|
return !fixed || fixed._dot_throw(compressor);
|
||||||
});
|
});
|
||||||
})(function(node, func) {
|
})(function(node, func) {
|
||||||
node.DEFMETHOD("_throw_on_access", func);
|
node.DEFMETHOD("_dot_throw", func);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ boolean/negation helpers ]----- */
|
/* -----[ boolean/negation helpers ]----- */
|
||||||
@@ -1735,11 +1746,8 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
var global_objs = {
|
var global_objs = {
|
||||||
Array: Array,
|
Array: Array,
|
||||||
Boolean: Boolean,
|
|
||||||
Math: Math,
|
Math: Math,
|
||||||
Number: Number,
|
Number: Number,
|
||||||
RegExp: RegExp,
|
|
||||||
Object: Object,
|
|
||||||
String: String,
|
String: String,
|
||||||
};
|
};
|
||||||
function convert_to_predicate(obj) {
|
function convert_to_predicate(obj) {
|
||||||
@@ -1776,7 +1784,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
var exp = this.expression;
|
var exp = this.expression;
|
||||||
var val;
|
var val;
|
||||||
if (exp instanceof AST_SymbolRef && exp.undeclared()) {
|
if (is_undeclared_ref(exp)) {
|
||||||
if (!(static_values[exp.name] || return_false)(key)) return this;
|
if (!(static_values[exp.name] || return_false)(key)) return this;
|
||||||
val = global_objs[exp.name];
|
val = global_objs[exp.name];
|
||||||
} else {
|
} else {
|
||||||
@@ -1868,7 +1876,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
var val;
|
var val;
|
||||||
var e = exp.expression;
|
var e = exp.expression;
|
||||||
if (e instanceof AST_SymbolRef && e.undeclared()) {
|
if (is_undeclared_ref(e)) {
|
||||||
if (!(static_fns[e.name] || return_false)(key)) return this;
|
if (!(static_fns[e.name] || return_false)(key)) return this;
|
||||||
val = global_objs[e.name];
|
val = global_objs[e.name];
|
||||||
} else {
|
} else {
|
||||||
@@ -2050,7 +2058,7 @@ merge(Compressor.prototype, {
|
|||||||
|| this.expression.has_side_effects(compressor);
|
|| this.expression.has_side_effects(compressor);
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(compressor){
|
def(AST_SymbolRef, function(compressor){
|
||||||
return this.undeclared();
|
return !this.is_declared(compressor);
|
||||||
});
|
});
|
||||||
def(AST_SymbolDeclaration, return_false);
|
def(AST_SymbolDeclaration, return_false);
|
||||||
def(AST_Object, function(compressor){
|
def(AST_Object, function(compressor){
|
||||||
@@ -2684,8 +2692,8 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
return expression;
|
return expression;
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function() {
|
def(AST_SymbolRef, function(compressor) {
|
||||||
return this.undeclared() ? this : null;
|
return this.is_declared(compressor) ? null : this;
|
||||||
});
|
});
|
||||||
def(AST_Object, function(compressor, first_in_statement){
|
def(AST_Object, function(compressor, first_in_statement){
|
||||||
var values = trim(this.properties, compressor, first_in_statement);
|
var values = trim(this.properties, compressor, first_in_statement);
|
||||||
@@ -3147,7 +3155,7 @@ merge(Compressor.prototype, {
|
|||||||
self.args.length = last;
|
self.args.length = last;
|
||||||
}
|
}
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
if (exp instanceof AST_SymbolRef && exp.undeclared()) {
|
if (is_undeclared_ref(exp)) {
|
||||||
switch (exp.name) {
|
switch (exp.name) {
|
||||||
case "Array":
|
case "Array":
|
||||||
if (self.args.length != 1) {
|
if (self.args.length != 1) {
|
||||||
@@ -3274,8 +3282,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressor.option("unsafe_Func")
|
if (compressor.option("unsafe_Func")
|
||||||
&& exp instanceof AST_SymbolRef
|
&& is_undeclared_ref(exp)
|
||||||
&& exp.undeclared()
|
|
||||||
&& exp.name == "Function") {
|
&& exp.name == "Function") {
|
||||||
// new Function() => function(){}
|
// new Function() => function(){}
|
||||||
if (self.args.length == 0) return make_node(AST_Function, self, {
|
if (self.args.length == 0) return make_node(AST_Function, self, {
|
||||||
@@ -3392,9 +3399,7 @@ merge(Compressor.prototype, {
|
|||||||
while (name.expression) {
|
while (name.expression) {
|
||||||
name = name.expression;
|
name = name.expression;
|
||||||
}
|
}
|
||||||
if (name instanceof AST_SymbolRef
|
if (is_undeclared_ref(name) && name.name == "console") {
|
||||||
&& name.name == "console"
|
|
||||||
&& name.undeclared()) {
|
|
||||||
return make_node(AST_Undefined, self).optimize(compressor);
|
return make_node(AST_Undefined, self).optimize(compressor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3415,7 +3420,7 @@ merge(Compressor.prototype, {
|
|||||||
OPT(AST_New, function(self, compressor){
|
OPT(AST_New, function(self, compressor){
|
||||||
if (compressor.option("unsafe")) {
|
if (compressor.option("unsafe")) {
|
||||||
var exp = self.expression;
|
var exp = self.expression;
|
||||||
if (exp instanceof AST_SymbolRef && exp.undeclared()) {
|
if (is_undeclared_ref(exp)) {
|
||||||
switch (exp.name) {
|
switch (exp.name) {
|
||||||
case "Object":
|
case "Object":
|
||||||
case "RegExp":
|
case "RegExp":
|
||||||
@@ -3709,7 +3714,7 @@ merge(Compressor.prototype, {
|
|||||||
&& self.right instanceof AST_UnaryPrefix
|
&& self.right instanceof AST_UnaryPrefix
|
||||||
&& self.right.operator == "typeof") {
|
&& self.right.operator == "typeof") {
|
||||||
var expr = self.right.expression;
|
var expr = self.right.expression;
|
||||||
if (expr instanceof AST_SymbolRef ? !expr.undeclared()
|
if (expr instanceof AST_SymbolRef ? expr.is_declared(compressor)
|
||||||
: !(expr instanceof AST_PropAccess && compressor.option("ie8"))) {
|
: !(expr instanceof AST_PropAccess && compressor.option("ie8"))) {
|
||||||
self.right = expr;
|
self.right = expr;
|
||||||
self.left = make_node(AST_Undefined, self.left).optimize(compressor);
|
self.left = make_node(AST_Undefined, self.left).optimize(compressor);
|
||||||
@@ -4035,7 +4040,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
// testing against !self.scope.uses_with first is an optimization
|
// testing against !self.scope.uses_with first is an optimization
|
||||||
if (!compressor.option("ie8")
|
if (!compressor.option("ie8")
|
||||||
&& self.undeclared()
|
&& is_undeclared_ref(self)
|
||||||
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
|
&& (!self.scope.uses_with || !compressor.find_parent(AST_With))) {
|
||||||
switch (self.name) {
|
switch (self.name) {
|
||||||
case "undefined":
|
case "undefined":
|
||||||
@@ -4454,7 +4459,7 @@ merge(Compressor.prototype, {
|
|||||||
&& self.expression instanceof AST_Dot
|
&& self.expression instanceof AST_Dot
|
||||||
&& self.expression.property == "prototype") {
|
&& self.expression.property == "prototype") {
|
||||||
var exp = self.expression.expression;
|
var exp = self.expression.expression;
|
||||||
if (exp instanceof AST_SymbolRef && exp.undeclared()) switch (exp.name) {
|
if (is_undeclared_ref(exp)) switch (exp.name) {
|
||||||
case "Array":
|
case "Array":
|
||||||
self.expression = make_node(AST_Array, self.expression, {
|
self.expression = make_node(AST_Array, self.expression, {
|
||||||
elements: []
|
elements: []
|
||||||
|
|||||||
@@ -373,14 +373,6 @@ AST_Symbol.DEFMETHOD("unreferenced", function(){
|
|||||||
&& !(this.scope.uses_eval || this.scope.uses_with);
|
&& !(this.scope.uses_eval || this.scope.uses_with);
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Symbol.DEFMETHOD("undeclared", function(){
|
|
||||||
return this.definition().undeclared;
|
|
||||||
});
|
|
||||||
|
|
||||||
AST_LabelRef.DEFMETHOD("undeclared", return_false);
|
|
||||||
|
|
||||||
AST_Label.DEFMETHOD("undeclared", return_false);
|
|
||||||
|
|
||||||
AST_Symbol.DEFMETHOD("definition", function(){
|
AST_Symbol.DEFMETHOD("definition", function(){
|
||||||
return this.thedef;
|
return this.thedef;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -230,3 +230,82 @@ accessor: {
|
|||||||
}
|
}
|
||||||
expect: {}
|
expect: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2233_1: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
Array.isArray;
|
||||||
|
Boolean;
|
||||||
|
console.log;
|
||||||
|
Error.name;
|
||||||
|
Function.length;
|
||||||
|
Math.random;
|
||||||
|
Number.isNaN;
|
||||||
|
RegExp;
|
||||||
|
Object.defineProperty;
|
||||||
|
String.fromCharCode;
|
||||||
|
}
|
||||||
|
expect: {}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2233_2: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var RegExp;
|
||||||
|
Array.isArray;
|
||||||
|
RegExp;
|
||||||
|
UndeclaredGlobal;
|
||||||
|
function foo() {
|
||||||
|
var Number;
|
||||||
|
AnotherUndeclaredGlobal;
|
||||||
|
Math.sin;
|
||||||
|
Number.isNaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var RegExp;
|
||||||
|
UndeclaredGlobal;
|
||||||
|
function foo() {
|
||||||
|
var Number;
|
||||||
|
AnotherUndeclaredGlobal;
|
||||||
|
Number.isNaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2233_3: {
|
||||||
|
options = {
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var RegExp;
|
||||||
|
Array.isArray;
|
||||||
|
RegExp;
|
||||||
|
UndeclaredGlobal;
|
||||||
|
function foo() {
|
||||||
|
var Number;
|
||||||
|
AnotherUndeclaredGlobal;
|
||||||
|
Math.sin;
|
||||||
|
Number.isNaN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
UndeclaredGlobal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user