diff --git a/lib/ast.js b/lib/ast.js index ab4b2897..8739e03c 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -134,11 +134,10 @@ var AST_Debugger = DEFNODE("Debugger", null, { $documentation: "Represents a debugger statement", }, AST_Statement); -var AST_Directive = DEFNODE("Directive", "value scope quote", { +var AST_Directive = DEFNODE("Directive", "value quote", { $documentation: "Represents a directive, like \"use strict\";", $propdoc: { value: "[string] The value of this directive as a plain string (it's not an AST_String!)", - scope: "[AST_Scope/S] The scope that this directive affects", quote: "[string] the original quote character" }, }, AST_Statement); @@ -303,10 +302,9 @@ var AST_With = DEFNODE("With", "expression", { /* -----[ scope and functions ]----- */ -var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", { +var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", { $documentation: "Base class for all statements introducing a lexical scope", $propdoc: { - directives: "[string*/S] an array of directives declared in this scope", variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope", functions: "[Object/S] like `variables`, but only lists function declarations", uses_with: "[boolean/S] tells whether this scope uses the `with` statement", diff --git a/lib/compress.js b/lib/compress.js index 4e753627..388e2d43 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -875,7 +875,7 @@ merge(Compressor.prototype, { } } - function has_overlapping_symbol(fn, arg) { + function has_overlapping_symbol(fn, arg, fn_strict) { var found = false, scan_this = !(fn instanceof AST_Arrow); arg.walk(new TreeWalker(function(node, descend) { if (found) return true; @@ -886,7 +886,7 @@ merge(Compressor.prototype, { } return found = true; } - if (scan_this && node instanceof AST_This) { + if ((fn_strict || scan_this) && node instanceof AST_This) { return found = true; } if (node instanceof AST_Scope && !(node instanceof AST_Arrow)) { @@ -911,6 +911,8 @@ merge(Compressor.prototype, { && all(iife.args, function(arg) { return !(arg instanceof AST_Expansion); })) { + var fn_strict = compressor.has_directive("use strict"); + if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false; var names = Object.create(null); for (var i = fn.argnames.length; --i >= 0;) { var sym = fn.argnames[i]; @@ -919,7 +921,7 @@ merge(Compressor.prototype, { if (sym instanceof AST_Expansion) { var elements = iife.args.slice(i); if (all(elements, function(arg) { - return !has_overlapping_symbol(fn, arg); + return !has_overlapping_symbol(fn, arg, fn_strict); })) { candidates.unshift(make_node(AST_VarDef, sym, { name: sym.expression, @@ -931,7 +933,7 @@ merge(Compressor.prototype, { } else { var arg = iife.args[i]; if (!arg) arg = make_node(AST_Undefined, sym).transform(compressor); - else if (has_overlapping_symbol(fn, arg)) arg = null; + else if (has_overlapping_symbol(fn, arg, fn_strict)) arg = null; if (arg) candidates.unshift(make_node(AST_VarDef, sym, { name: sym, value: arg diff --git a/lib/output.js b/lib/output.js index 339faf9e..e4aa01f8 100644 --- a/lib/output.js +++ b/lib/output.js @@ -506,13 +506,17 @@ function OutputStream(options) { nodetype.DEFMETHOD("_codegen", generator); }; - var use_asm = false; var in_directive = false; + var active_scope = null; + var use_asm = null; AST_Node.DEFMETHOD("print", function(stream, force_parens){ - var self = this, generator = self._codegen, prev_use_asm = use_asm; - if (self instanceof AST_Directive && self.value == "use asm" && stream.parent() instanceof AST_Scope) { - use_asm = true; + var self = this, generator = self._codegen; + if (self instanceof AST_Scope) { + active_scope = self; + } + else if (!use_asm && self instanceof AST_Directive && self.value == "use asm") { + use_asm = active_scope; } function doit() { self.add_comments(stream); @@ -526,8 +530,8 @@ function OutputStream(options) { doit(); } stream.pop_node(); - if (self instanceof AST_Scope) { - use_asm = prev_use_asm; + if (self === use_asm) { + use_asm = null; } }); AST_Node.DEFMETHOD("_print", AST_Node.prototype.print); diff --git a/package.json b/package.json index 381756d3..f0633b46 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony", "author": "Mihai Bazon (http://lisperator.net/)", "license": "BSD-2-Clause", - "version": "3.1.1", + "version": "3.1.2", "engines": { "node": ">=0.8.0" }, diff --git a/test/compress/asm.js b/test/compress/asm.js index 9b227326..527e6b43 100644 --- a/test/compress/asm.js +++ b/test/compress/asm.js @@ -104,3 +104,65 @@ asm_mixed: { } } +asm_toplevel: { + options = {} + input: { + "use asm"; + 0.0; + function f() { + 0.0; + (function(){ + 0.0; + }); + } + 0.0; + } + expect_exact: '"use asm";0.0;function f(){0.0;(function(){0.0})}0.0;' +} + +asm_function_expression: { + options = {} + input: { + 0.0; + var a = function() { + "use asm"; + 0.0; + } + function f() { + 0.0; + return function(){ + "use asm"; + 0.0; + } + 0.0; + } + 0.0; + } + expect_exact: '0;var a=function(){"use asm";0.0};function f(){0;return function(){"use asm";0.0};0}0;' +} + +asm_nested_functions: { + options = {} + input: { + 0.0; + function a() { + "use asm"; + 0.0; + } + 0.0; + function b() { + 0.0; + function c(){ + "use asm"; + 0.0; + } + 0.0; + function d(){ + 0.0; + } + 0.0; + } + 0.0; + } + expect_exact: '0;function a(){"use asm";0.0}0;function b(){0;function c(){"use asm";0.0}0;function d(){0}0}0;' +} diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index 55fc1753..6639d9ff 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -2725,3 +2725,73 @@ issue_2313_2: { } expect_stdout: "0" } + +issue_2319_1: { + options = { + collapse_vars: true, + unused: true, + } + input: { + console.log(function(a) { + return a; + }(!function() { + return this; + }())); + } + expect: { + console.log(function(a) { + return !function() { + return this; + }(); + }()); + } + expect_stdout: "false" +} + +issue_2319_2: { + options = { + collapse_vars: true, + unused: true, + } + input: { + console.log(function(a) { + "use strict"; + return a; + }(!function() { + return this; + }())); + } + expect: { + console.log(function(a) { + "use strict"; + return a; + }(!function() { + return this; + }())); + } + expect_stdout: "false" +} + +issue_2319_3: { + options = { + collapse_vars: true, + unused: true, + } + input: { + "use strict"; + console.log(function(a) { + return a; + }(!function() { + return this; + }())); + } + expect: { + "use strict"; + console.log(function(a) { + return !function() { + return this; + }(); + }()); + } + expect_stdout: "true" +}