aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/scope.js144
-rw-r--r--test/compress/issue-1704.js96
-rw-r--r--test/compress/issue-1733.js6
-rw-r--r--test/compress/rename.js10
-rw-r--r--test/compress/screw-ie8.js16
-rw-r--r--test/mocha/minify.js12
6 files changed, 196 insertions, 88 deletions
diff --git a/lib/scope.js b/lib/scope.js
index 6c883c66..87bfe0d6 100644
--- a/lib/scope.js
+++ b/lib/scope.js
@@ -83,8 +83,9 @@ SymbolDef.prototype = {
var def;
if (def = this.redefined()) {
this.mangled_name = def.mangled_name || def.name;
- } else
- this.mangled_name = s.next_mangled(options, this);
+ } else {
+ this.mangled_name = next_mangled_name(s, options, this);
+ }
if (this.global && cache) {
cache.set(this.name, this.mangled_name);
}
@@ -168,8 +169,8 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
var def = scope.find_variable(node);
if (node.thedef !== def) {
node.thedef = def;
- node.reference(options);
}
+ node.reference(options);
}
}
else if (node instanceof AST_SymbolCatch) {
@@ -325,56 +326,59 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, init){
return symbol.thedef = def;
});
-function next_mangled(scope, options) {
- var ext = scope.enclosed;
- out: while (true) {
- var m = base54(++scope.cname);
- if (!is_identifier(m)) continue; // skip over "do"
-
- // https://github.com/mishoo/UglifyJS2/issues/242 -- do not
- // shadow a name reserved from mangling.
- if (member(m, options.reserved)) continue;
-
- // we must ensure that the mangled name does not shadow a name
- // from some parent scope that is referenced in this or in
- // inner scopes.
- for (var i = ext.length; --i >= 0;) {
- var sym = ext[i];
- var name = sym.mangled_name || (sym.unmangleable(options) && sym.name);
- if (m == name) continue out;
- }
- return m;
+function names_in_use(scope, options) {
+ var names = scope.names_in_use;
+ if (!names) {
+ scope.names_in_use = names = Object.create(scope.mangled_names || null);
+ scope.cname_holes = [];
+ scope.enclosed.forEach(function(def) {
+ if (def.unmangleable(options)) names[def.name] = true;
+ });
}
+ return names;
}
-AST_Scope.DEFMETHOD("next_mangled", function(options){
- return next_mangled(this, options);
-});
-
-AST_Toplevel.DEFMETHOD("next_mangled", function(options){
- var name;
- do {
- name = next_mangled(this, options);
- } while (member(name, this.mangled_names));
- return name;
-});
-
-AST_Function.DEFMETHOD("next_mangled", function(options, def){
+function next_mangled_name(scope, options, def) {
+ var in_use = names_in_use(scope, options);
+ var holes = scope.cname_holes;
+ var names = Object.create(null);
// #179, #326
// in Safari strict mode, something like (function x(x){...}) is a syntax error;
// a function expression's argument cannot shadow the function expression's name
-
- var tricky_def = def.orig[0] instanceof AST_SymbolFunarg && this.name && this.name.definition();
-
- // the function's mangled_name is null when keep_fnames is true
- var tricky_name = tricky_def ? tricky_def.mangled_name || tricky_def.name : null;
-
+ if (scope instanceof AST_Function && scope.name && def.orig[0] instanceof AST_SymbolFunarg) {
+ var tricky_def = scope.name.definition();
+ // the function's mangled_name is null when keep_fnames is true
+ names[tricky_def.mangled_name || tricky_def.name] = true;
+ }
+ var scopes = [ scope ];
+ def.references.forEach(function(sym) {
+ var scope = sym.scope;
+ do {
+ if (scopes.indexOf(scope) < 0) {
+ for (var name in names_in_use(scope, options)) {
+ names[name] = true;
+ }
+ scopes.push(scope);
+ } else break;
+ } while (scope = scope.parent_scope);
+ });
+ var name;
+ for (var i = 0, len = holes.length; i < len; i++) {
+ name = base54(holes[i]);
+ if (names[name]) continue;
+ holes.splice(i, 1);
+ scope.names_in_use[name] = true;
+ return name;
+ }
while (true) {
- var name = next_mangled(this, options);
- if (!tricky_name || tricky_name != name)
- return name;
+ name = base54(++scope.cname);
+ if (in_use[name] || !is_identifier(name) || member(name, options.reserved)) continue;
+ if (!names[name]) break;
+ holes.push(scope.cname);
}
-});
+ scope.names_in_use[name] = true;
+ return name;
+}
AST_Symbol.DEFMETHOD("unmangleable", function(options){
var def = this.definition();
@@ -419,18 +423,15 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
// present (and for AST_SymbolRef-s it'll use the mangled name of
// the AST_SymbolDeclaration that it points to).
var lname = -1;
- var to_mangle = [];
-
- var mangled_names = this.mangled_names = [];
- if (options.cache) {
- this.globals.each(collect);
- if (options.cache.props) {
- options.cache.props.each(function(mangled_name) {
- push_uniq(mangled_names, mangled_name);
- });
- }
+
+ if (options.cache && options.cache.props) {
+ var mangled_names = this.mangled_names = Object.create(null);
+ options.cache.props.each(function(mangled_name) {
+ mangled_names[mangled_name] = true;
+ });
}
+ var redefined = [];
var tw = new TreeWalker(function(node, descend){
if (node instanceof AST_LabeledStatement) {
// lname is incremented when we get to the AST_Label
@@ -440,8 +441,12 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
return true; // don't descend again in TreeWalker
}
if (node instanceof AST_Scope) {
- node.variables.each(collect);
- return;
+ descend();
+ if (options.cache && node instanceof AST_Toplevel) {
+ node.globals.each(mangle);
+ }
+ node.variables.each(mangle);
+ return true;
}
if (node instanceof AST_Label) {
var name;
@@ -449,17 +454,28 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
node.mangled_name = name;
return true;
}
- if (!options.ie8 && node instanceof AST_SymbolCatch) {
- to_mangle.push(node.definition());
- return;
+ if (!options.ie8 && node instanceof AST_Catch) {
+ var def = node.argname.definition();
+ var redef = def.redefined();
+ if (redef) {
+ redefined.push(def);
+ def.references.forEach(function(ref) {
+ ref.thedef = redef;
+ ref.reference(options);
+ ref.thedef = def;
+ });
+ }
+ descend();
+ if (!redef) mangle(def);
+ return true;
}
});
this.walk(tw);
- to_mangle.forEach(function(def){ def.mangle(options) });
+ redefined.forEach(mangle);
- function collect(symbol) {
- if (!member(symbol.name, options.reserved)) {
- to_mangle.push(symbol);
+ function mangle(def) {
+ if (!member(def.name, options.reserved)) {
+ def.mangle(options);
}
}
});
diff --git a/test/compress/issue-1704.js b/test/compress/issue-1704.js
index 25e49522..043038e5 100644
--- a/test/compress/issue-1704.js
+++ b/test/compress/issue-1704.js
@@ -104,7 +104,7 @@ mangle_catch_toplevel: {
}
console.log(a);
}
- expect_exact: 'var o="FAIL";try{throw 1}catch(c){o="PASS"}console.log(o);'
+ expect_exact: 'var c="FAIL";try{throw 1}catch(o){c="PASS"}console.log(c);'
expect_stdout: "PASS"
}
@@ -148,7 +148,7 @@ mangle_catch_var_toplevel: {
}
console.log(a);
}
- expect_exact: 'var o="FAIL";try{throw 1}catch(r){var o="PASS"}console.log(o);'
+ expect_exact: 'var r="FAIL";try{throw 1}catch(o){var r="PASS"}console.log(r);'
expect_stdout: "PASS"
}
@@ -345,3 +345,95 @@ mangle_catch_redef_2_ie8_toplevel: {
expect_exact: 'try{throw"FAIL1"}catch(o){var o="FAIL2"}console.log(o);'
expect_stdout: "undefined"
}
+
+mangle_catch_redef_3: {
+ mangle = {
+ ie8: false,
+ toplevel: false,
+ }
+ input: {
+ var o = "PASS";
+ try {
+ throw 0;
+ } catch (o) {
+ (function() {
+ function f() {
+ o = "FAIL";
+ }
+ f(), f();
+ })();
+ }
+ console.log(o);
+ }
+ expect_exact: 'var o="PASS";try{throw 0}catch(o){(function(){function c(){o="FAIL"}c(),c()})()}console.log(o);'
+ expect_stdout: "PASS"
+}
+
+mangle_catch_redef_3_toplevel: {
+ mangle = {
+ ie8: false,
+ toplevel: true,
+ }
+ input: {
+ var o = "PASS";
+ try {
+ throw 0;
+ } catch (o) {
+ (function() {
+ function f() {
+ o = "FAIL";
+ }
+ f(), f();
+ })();
+ }
+ console.log(o);
+ }
+ expect_exact: 'var c="PASS";try{throw 0}catch(c){(function(){function o(){c="FAIL"}o(),o()})()}console.log(c);'
+ expect_stdout: "PASS"
+}
+
+mangle_catch_redef_ie8_3: {
+ mangle = {
+ ie8: true,
+ toplevel: false,
+ }
+ input: {
+ var o = "PASS";
+ try {
+ throw 0;
+ } catch (o) {
+ (function() {
+ function f() {
+ o = "FAIL";
+ }
+ f(), f();
+ })();
+ }
+ console.log(o);
+ }
+ expect_exact: 'var o="PASS";try{throw 0}catch(o){(function(){function c(){o="FAIL"}c(),c()})()}console.log(o);'
+ expect_stdout: "PASS"
+}
+
+mangle_catch_redef_3_ie8_toplevel: {
+ mangle = {
+ ie8: true,
+ toplevel: true,
+ }
+ input: {
+ var o = "PASS";
+ try {
+ throw 0;
+ } catch (o) {
+ (function() {
+ function f() {
+ o = "FAIL";
+ }
+ f(), f();
+ })();
+ }
+ console.log(o);
+ }
+ expect_exact: 'var c="PASS";try{throw 0}catch(c){(function(){function o(){c="FAIL"}o(),o()})()}console.log(c);'
+ expect_stdout: "PASS"
+}
diff --git a/test/compress/issue-1733.js b/test/compress/issue-1733.js
index f1e576c7..15c4a899 100644
--- a/test/compress/issue-1733.js
+++ b/test/compress/issue-1733.js
@@ -15,7 +15,7 @@ function_iife_catch: {
}
f();
}
- expect_exact: "function f(o){!function(){try{throw 0}catch(c){var o=1;console.log(c,o)}}()}f();"
+ expect_exact: "function f(o){!function(){try{throw 0}catch(o){var c=1;console.log(o,c)}}()}f();"
expect_stdout: "0 1"
}
@@ -36,7 +36,7 @@ function_iife_catch_ie8: {
}
f();
}
- expect_exact: "function f(o){!function(){try{throw 0}catch(o){var c=1;console.log(o,c)}}()}f();"
+ expect_exact: "function f(c){!function(){try{throw 0}catch(c){var o=1;console.log(c,o)}}()}f();"
expect_stdout: "0 1"
}
@@ -61,7 +61,7 @@ function_catch_catch: {
}
f();
}
- expect_exact: "var o=0;function f(){try{throw 1}catch(c){try{throw 2}catch(o){var o=3;console.log(o)}}console.log(o)}f();"
+ expect_exact: "var o=0;function f(){try{throw 1}catch(o){try{throw 2}catch(c){var c=3;console.log(c)}}console.log(c)}f();"
expect_stdout: [
"3",
"undefined",
diff --git a/test/compress/rename.js b/test/compress/rename.js
index defc6cf5..83187dff 100644
--- a/test/compress/rename.js
+++ b/test/compress/rename.js
@@ -109,7 +109,7 @@ mangle_catch_toplevel: {
}
console.log(a);
}
- expect_exact: 'var o="FAIL";try{throw 1}catch(c){o="PASS"}console.log(o);'
+ expect_exact: 'var c="FAIL";try{throw 1}catch(o){c="PASS"}console.log(c);'
expect_stdout: "PASS"
}
@@ -155,7 +155,7 @@ mangle_catch_var_toplevel: {
}
console.log(a);
}
- expect_exact: 'var o="FAIL";try{throw 1}catch(r){var o="PASS"}console.log(o);'
+ expect_exact: 'var r="FAIL";try{throw 1}catch(o){var r="PASS"}console.log(r);'
expect_stdout: "PASS"
}
@@ -451,7 +451,7 @@ function_iife_catch: {
}
f();
}
- expect_exact: "function f(o){!function(){try{throw 0}catch(c){var o=1;console.log(c,o)}}()}f();"
+ expect_exact: "function f(o){!function(){try{throw 0}catch(o){var c=1;console.log(o,c)}}()}f();"
expect_stdout: "0 1"
}
@@ -473,7 +473,7 @@ function_iife_catch_ie8: {
}
f();
}
- expect_exact: "function f(o){!function(){try{throw 0}catch(o){var c=1;console.log(o,c)}}()}f();"
+ expect_exact: "function f(c){!function(){try{throw 0}catch(c){var o=1;console.log(c,o)}}()}f();"
expect_stdout: "0 1"
}
@@ -499,7 +499,7 @@ function_catch_catch: {
}
f();
}
- expect_exact: "var o=0;function f(){try{throw 1}catch(c){try{throw 2}catch(o){var o=3;console.log(o)}}console.log(o)}f();"
+ expect_exact: "var o=0;function f(){try{throw 1}catch(o){try{throw 2}catch(c){var c=3;console.log(c)}}console.log(c)}f();"
expect_stdout: [
"3",
"undefined",
diff --git a/test/compress/screw-ie8.js b/test/compress/screw-ie8.js
index 82152b7d..b4098b8e 100644
--- a/test/compress/screw-ie8.js
+++ b/test/compress/screw-ie8.js
@@ -102,12 +102,12 @@ dont_screw_try_catch: {
};
}
expect: {
- bad = function(n){
- return function(t){
+ bad = function(t){
+ return function(n){
try{
- n()
- } catch(n) {
- t(n)
+ t()
+ } catch(t) {
+ n(t)
}
}
};
@@ -349,11 +349,11 @@ issue_2254_1: {
try {
console.log(f("PASS"));
} catch (e) {}
- function f(e) {
+ function f(t) {
try {
throw "FAIL";
- } catch (t) {
- return e;
+ } catch (e) {
+ return t;
}
}
}
diff --git a/test/mocha/minify.js b/test/mocha/minify.js
index 1b0052a4..02180a59 100644
--- a/test/mocha/minify.js
+++ b/test/mocha/minify.js
@@ -46,10 +46,10 @@ describe("minify", function() {
assert.strictEqual(compressed, [
"function n(n){return 3*n}",
"function r(n){return n/2}",
- "var o=console.log.bind(console);",
- 'function c(n){o("Foo:",2*n)}',
+ "var c=console.log.bind(console);",
+ 'function o(o){c("Foo:",2*o)}',
"var a=n(3),b=r(12);",
- 'o("qux",a,b),c(11);',
+ 'c("qux",a,b),o(11);',
].join(""));
assert.strictEqual(run_code(compressed), run_code(original));
});
@@ -79,10 +79,10 @@ describe("minify", function() {
assert.strictEqual(compressed, [
"function n(n){return 3*n}",
"function r(n){return n/2}",
- "var o=console.log.bind(console);",
- 'function c(n){o("Foo:",2*n)}',
+ "var c=console.log.bind(console);",
+ 'function o(o){c("Foo:",2*o)}',
"var a=n(3),b=r(12);",
- 'o("qux",a,b),c(11);',
+ 'c("qux",a,b),o(11);',
].join(""));
assert.strictEqual(run_code(compressed), run_code(original));
});