Skip to content

Commit

Permalink
fix #445 by adjusting AST_Switch's scope
Browse files Browse the repository at this point in the history
  • Loading branch information
fabiosantoscode committed Sep 7, 2019
1 parent 11094c1 commit d0c5217
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 15 deletions.
29 changes: 22 additions & 7 deletions lib/scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ import {
AST_Sequence,
AST_String,
AST_Sub,
AST_Switch,
AST_SwitchBranch,
AST_Symbol,
AST_SymbolBlockDeclaration,
Expand Down Expand Up @@ -213,7 +214,21 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
for_scopes.push(scope);
}
}
descend();

if (node instanceof AST_Switch) {
// XXX: HACK! Ensure the switch expression gets the correct scope (the parent scope) and the body gets the contained scope
// AST_Switch has a scope within the body, but it itself "is a block scope"
// This means the switched expression has to belong to the outer scope
// while the body inside belongs to the switch itself.
// This is pretty nasty and warrants an AST change similar to AST_Try (read above)
const the_block_scope = scope;
scope = save_scope;
node.expression.walk(tw);
scope = the_block_scope;
node.body.forEach(node => node.walk(tw));
} else {
descend();
}
scope = save_scope;
return true;
}
Expand Down Expand Up @@ -276,9 +291,12 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
// This deals with the name of the class being available
// inside the class.
mark_export((node.scope = defun.parent_scope).def_function(node, defun), 1);
} else if (node instanceof AST_SymbolVar
} else if (
node instanceof AST_SymbolVar
|| node instanceof AST_SymbolLet
|| node instanceof AST_SymbolConst) {
|| node instanceof AST_SymbolConst
|| node instanceof AST_SymbolCatch
) {
var def;
if (node instanceof AST_SymbolBlockDeclaration) {
def = scope.def_variable(node, null);
Expand Down Expand Up @@ -309,8 +327,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
node.reference(options);
}
}
} else if (node instanceof AST_SymbolCatch) {
scope.def_variable(node);
} else if (node instanceof AST_LabelRef) {
var sym = labels.get(node.name);
if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", {
Expand Down Expand Up @@ -415,8 +431,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) {
// https://github.com/mishoo/UglifyJS2/issues/1753
// https://bugs.webkit.org/show_bug.cgi?id=171041
if (options.safari10) {
for (var i = 0; i < for_scopes.length; i++) {
var scope = for_scopes[i];
for (const scope of for_scopes) {
scope.parent_scope.variables.forEach(function(def) {
push_uniq(scope.enclosed, def);
});
Expand Down
16 changes: 8 additions & 8 deletions lib/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,19 @@ import {

function def_transform(node, descend) {
node.DEFMETHOD("transform", function(tw, in_list) {
var x, y;
let transformed = undefined;
tw.push(this);
if (tw.before) x = tw.before(this, descend, in_list);
if (x === undefined) {
x = this;
descend(x, tw);
if (tw.before) transformed = tw.before(this, descend, in_list);
if (transformed === undefined) {
transformed = this;
descend(transformed, tw);
if (tw.after) {
y = tw.after(x, in_list);
if (y !== undefined) x = y;
const after_ret = tw.after(transformed, in_list);
if (after_ret !== undefined) transformed = after_ret;
}
}
tw.pop();
return x;
return transformed;
});
}

Expand Down
2 changes: 2 additions & 0 deletions test/compress/.eslintrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"globals": {
"options": true,
"mangle": true,
"rename": true,
"beautify": true,
"console": false,
"window": false,
Expand Down
21 changes: 21 additions & 0 deletions test/compress/switch.js
Original file line number Diff line number Diff line change
Expand Up @@ -864,3 +864,24 @@ issue_1750: {
}
expect_stdout: "0 2"
}

issue_445: {
mangle = true;
input: {
const leak = () => {}

function scan() {
let len = leak();
let ch = 0;
switch (ch = 123) {
case "never-reached":
const ch = leak();
leak(ch);
}
return len === 123 ? "FAIL" : "PASS";
}

console.log(scan());
}
expect_stdout: "PASS"
}

0 comments on commit d0c5217

Please sign in to comment.