From 396a26e3628e4be6ae67ee2bcb52e955de42b116 Mon Sep 17 00:00:00 2001 From: Chen Yangjian <252317+dotnil@users.noreply.github.com> Date: Tue, 7 Aug 2018 19:33:14 +0800 Subject: [PATCH] Fix: make sure function name doesn't collide with argument names Usually the function name is dropped if the function is a function expression. But when `ie8` option is enabled, the function name is kept and mangled which may break legacy Safari for said reason. Since symbol names are now [mangled from within](https://github.com/mishoo/UglifyJS2/pull/2948#issuecomment-368095376), this fix adds argument names to existing names when mangling the name of a function expression. --- lib/scope.js | 9 +++++++++ test/mocha/safari9.js | 26 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 test/mocha/safari9.js diff --git a/lib/scope.js b/lib/scope.js index c88ce8fc..e1127c9d 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -320,6 +320,15 @@ 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 + if (options.ie8 && (def.init instanceof AST_Function && def.init.argnames.length > 0)) { + for (var i = 0, len = def.init.argnames.length; i < len; i++) { + var arg = def.init.argnames[i]; + names[arg.definition().mangled_name] = true; + } + } var scopes = [ scope ]; def.references.forEach(function(sym) { var scope = sym.scope; diff --git a/test/mocha/safari9.js b/test/mocha/safari9.js new file mode 100644 index 00000000..278bd181 --- /dev/null +++ b/test/mocha/safari9.js @@ -0,0 +1,26 @@ +var assert = require('assert'); +var UglifyJS = require('../..'); + +describe('legacy safari', function() { + it('Should make sure mangled function name is different from its argument names', function () { + assert.strictEqual( + UglifyJS.minify([ + 'function main() {', + ' "use strict";', + ' ', + ' function n(a,b,c) {', + ' console.log(c)', + ' }', + ' E.on = function f2() {', + ' E.on(function(e) {', + ' return n(this,e)', + ' })', + ' }', + '}' + ].join('\n'), { + ie8: true + }).code, + 'function main(){"use strict";E.on=function(){E.on(function(n){return function c(n,o,t){console.log(t)}()})}}' + ) + }) +})