diff --git a/README.md b/README.md index d57a15cefc7..d15f114ce53 100644 --- a/README.md +++ b/README.md @@ -411,6 +411,8 @@ to set `true`; it's effectively a shortcut for `foo=true`). - `pure_getters` -- the default is `false`. If you pass `true` for this, UglifyJS will assume that object property access (e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects. + Specify `"strict"` to treat `foo.bar` as side-effect-free only when + `foo` is certain to not throw, i.e. not `null` or `undefined`. - `pure_funcs` -- default `null`. You can pass an array of names and UglifyJS will assume that those functions do not produce side diff --git a/lib/compress.js b/lib/compress.js index 8df6e58ff4e..c199d13f2a6 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -71,7 +71,7 @@ function Compressor(options, false_by_default) { negate_iife : !false_by_default, passes : 1, properties : !false_by_default, - pure_getters : false, + pure_getters : !false_by_default && "strict", pure_funcs : null, reduce_vars : !false_by_default, screw_ie8 : true, @@ -1165,7 +1165,13 @@ merge(Compressor.prototype, { // may_eq_null() // returns true if this node may evaluate to null or undefined (function(def) { - def(AST_Node, return_true); + function is_strict(compressor) { + return /strict/.test(compressor.option("pure_getters")); + } + + def(AST_Node, function(compressor) { + return !is_strict(compressor); + }); def(AST_Null, return_true); def(AST_Undefined, return_true); def(AST_Constant, return_false); @@ -1198,12 +1204,9 @@ merge(Compressor.prototype, { def(AST_Seq, function(compressor) { return this.cdr.may_eq_null(compressor); }); - def(AST_PropAccess, function(compressor) { - return !compressor.option("unsafe"); - }); def(AST_SymbolRef, function(compressor) { if (this.is_undefined) return true; - if (compressor.option("unsafe")) return false; + if (!is_strict(compressor)) return false; var fixed = this.fixed_value(); return !fixed || fixed.may_eq_null(compressor); }); diff --git a/test/compress/pure_getters.js b/test/compress/pure_getters.js index 338f8639ab9..c2dcb95b78c 100644 --- a/test/compress/pure_getters.js +++ b/test/compress/pure_getters.js @@ -1,10 +1,9 @@ -side_effects: { +strict: { options = { - pure_getters: true, + pure_getters: "strict", reduce_vars: false, side_effects: true, toplevel: true, - unsafe: false, } input: { var a, b = null, c = {}; @@ -28,13 +27,12 @@ side_effects: { } } -side_effects_reduce_vars: { +strict_reduce_vars: { options = { - pure_getters: true, + pure_getters: "strict", reduce_vars: true, side_effects: true, toplevel: true, - unsafe: false, } input: { var a, b = null, c = {}; @@ -57,13 +55,38 @@ side_effects_reduce_vars: { } } -side_effects_unsafe: { +unsafe: { options = { pure_getters: true, reduce_vars: false, side_effects: true, toplevel: true, - unsafe: true, + } + input: { + var a, b = null, c = {}; + a.prop; + b.prop; + c.prop; + d.prop; + null.prop; + (void 0).prop; + undefined.prop; + } + expect: { + var a, b = null, c = {}; + d; + null.prop; + (void 0).prop; + (void 0).prop; + } +} + +unsafe_reduce_vars: { + options = { + pure_getters: true, + reduce_vars: true, + side_effects: true, + toplevel: true, } input: { var a, b = null, c = {}; diff --git a/test/compress/reduce_vars.js b/test/compress/reduce_vars.js index 842d8de4dc3..b6f711ad2c5 100644 --- a/test/compress/reduce_vars.js +++ b/test/compress/reduce_vars.js @@ -1919,7 +1919,7 @@ side_effects_assign: { pure_getters_1: { options = { - pure_getters: true, + pure_getters: "strict", reduce_vars: true, side_effects: true, toplevel: true, @@ -1941,7 +1941,7 @@ pure_getters_1: { pure_getters_2: { options = { - pure_getters: true, + pure_getters: "strict", reduce_vars: true, toplevel: true, unused: true, @@ -1956,6 +1956,21 @@ pure_getters_2: { } } +pure_getters_3: { + options = { + pure_getters: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + var a; + var a = a && a.b; + } + expect: { + } +} + catch_var: { options = { booleans: true,