First class block scope
- Make let, const, and class symbols be declared in a block scope. - Piggy back on existing catch symbol implementation to get block-aware mangling working - Make sure unused block-scoped declarations can be dropped - Don't eliminate a block if it has a block-scoped declaration - Remove silly empty anonymous blocks left over from drop_unused - AST_Toplevel now gets to call drop_unused too, since block-scoped variables aren't global! - Don't consider block declarations global
This commit is contained in:
committed by
Richard van Velzen
parent
6702cae918
commit
634f231b78
19
lib/ast.js
19
lib/ast.js
@@ -282,9 +282,10 @@ var AST_With = DEFNODE("With", "expression", {
|
|||||||
|
|
||||||
/* -----[ scope and functions ]----- */
|
/* -----[ scope and functions ]----- */
|
||||||
|
|
||||||
var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
|
var AST_Scope = DEFNODE("Scope", "is_block_scope directives variables functions uses_with uses_eval parent_scope enclosed cname", {
|
||||||
$documentation: "Base class for all statements introducing a lexical scope",
|
$documentation: "Base class for all statements introducing a lexical scope",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
|
is_block_scope: "[boolean] identifies a block scope",
|
||||||
directives: "[string*/S] an array of directives declared in this scope",
|
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",
|
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",
|
functions: "[Object/S] like `variables`, but only lists function declarations",
|
||||||
@@ -1077,9 +1078,17 @@ var AST_SymbolVar = DEFNODE("SymbolVar", null, {
|
|||||||
$documentation: "Symbol defining a variable",
|
$documentation: "Symbol defining a variable",
|
||||||
}, AST_SymbolDeclaration);
|
}, AST_SymbolDeclaration);
|
||||||
|
|
||||||
|
var AST_SymbolBlockDeclaration = DEFNODE("SymbolBlockDeclaration", null, {
|
||||||
|
$documentation: "Base class for block-scoped declaration symbols"
|
||||||
|
}, AST_SymbolDeclaration);
|
||||||
|
|
||||||
var AST_SymbolConst = DEFNODE("SymbolConst", null, {
|
var AST_SymbolConst = DEFNODE("SymbolConst", null, {
|
||||||
$documentation: "A constant declaration"
|
$documentation: "A constant declaration"
|
||||||
}, AST_SymbolDeclaration);
|
}, AST_SymbolBlockDeclaration);
|
||||||
|
|
||||||
|
var AST_SymbolLet = DEFNODE("SymbolLet", null, {
|
||||||
|
$documentation: "A block-scoped `let` declaration"
|
||||||
|
}, AST_SymbolBlockDeclaration);
|
||||||
|
|
||||||
var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
|
var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
|
||||||
$documentation: "Symbol naming a function argument",
|
$documentation: "Symbol naming a function argument",
|
||||||
@@ -1099,7 +1108,7 @@ var AST_SymbolLambda = DEFNODE("SymbolLambda", null, {
|
|||||||
|
|
||||||
var AST_SymbolDefClass = DEFNODE("SymbolDefClass", null, {
|
var AST_SymbolDefClass = DEFNODE("SymbolDefClass", null, {
|
||||||
$documentation: "Symbol naming a class's name in a class declaration. Lexically scoped to its containing scope, and accessible within the class."
|
$documentation: "Symbol naming a class's name in a class declaration. Lexically scoped to its containing scope, and accessible within the class."
|
||||||
}, AST_SymbolDeclaration);
|
}, AST_SymbolBlockDeclaration);
|
||||||
|
|
||||||
var AST_SymbolClass = DEFNODE("SymbolClass", null, {
|
var AST_SymbolClass = DEFNODE("SymbolClass", null, {
|
||||||
$documentation: "Symbol naming a class's name. Lexically scoped to the class."
|
$documentation: "Symbol naming a class's name. Lexically scoped to the class."
|
||||||
@@ -1107,11 +1116,11 @@ var AST_SymbolClass = DEFNODE("SymbolClass", null, {
|
|||||||
|
|
||||||
var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
|
var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
|
||||||
$documentation: "Symbol naming the exception in catch",
|
$documentation: "Symbol naming the exception in catch",
|
||||||
}, AST_SymbolDeclaration);
|
}, AST_SymbolBlockDeclaration);
|
||||||
|
|
||||||
var AST_SymbolImport = DEFNODE("SymbolImport", null, {
|
var AST_SymbolImport = DEFNODE("SymbolImport", null, {
|
||||||
$documentation: "Symbol refering to an imported name",
|
$documentation: "Symbol refering to an imported name",
|
||||||
}, AST_SymbolDeclaration);
|
}, AST_SymbolBlockDeclaration);
|
||||||
|
|
||||||
var AST_SymbolImportForeign = DEFNODE("SymbolImportForeign", null, {
|
var AST_SymbolImportForeign = DEFNODE("SymbolImportForeign", null, {
|
||||||
$documentation: "A symbol imported from a module, but it is defined in the other module, and its real name is irrelevant for this module's purposes",
|
$documentation: "A symbol imported from a module, but it is defined in the other module, and its real name is irrelevant for this module's purposes",
|
||||||
|
|||||||
@@ -190,6 +190,14 @@ merge(Compressor.prototype, {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function can_be_evicted_from_block(node) {
|
||||||
|
return !(
|
||||||
|
node instanceof AST_DefClass ||
|
||||||
|
node instanceof AST_Let ||
|
||||||
|
node instanceof AST_Const
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function loop_body(x) {
|
function loop_body(x) {
|
||||||
if (x instanceof AST_Switch) return x;
|
if (x instanceof AST_Switch) return x;
|
||||||
if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) {
|
if (x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) {
|
||||||
@@ -311,7 +319,7 @@ merge(Compressor.prototype, {
|
|||||||
function eliminate_spurious_blocks(statements) {
|
function eliminate_spurious_blocks(statements) {
|
||||||
var seen_dirs = [];
|
var seen_dirs = [];
|
||||||
return statements.reduce(function(a, stat){
|
return statements.reduce(function(a, stat){
|
||||||
if (stat instanceof AST_BlockStatement) {
|
if (stat instanceof AST_BlockStatement && all(stat.body, can_be_evicted_from_block)) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
a.push.apply(a, eliminate_spurious_blocks(stat.body));
|
a.push.apply(a, eliminate_spurious_blocks(stat.body));
|
||||||
} else if (stat instanceof AST_EmptyStatement) {
|
} else if (stat instanceof AST_EmptyStatement) {
|
||||||
@@ -633,7 +641,7 @@ merge(Compressor.prototype, {
|
|||||||
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
||||||
compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
|
compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
|
||||||
stat.walk(new TreeWalker(function(node){
|
stat.walk(new TreeWalker(function(node){
|
||||||
if (node instanceof AST_Definitions) {
|
if (node instanceof AST_Var) {
|
||||||
compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
|
compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
|
||||||
node.remove_initializers();
|
node.remove_initializers();
|
||||||
target.push(node);
|
target.push(node);
|
||||||
@@ -957,6 +965,8 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
def(AST_Defun, function(compressor){ return true });
|
def(AST_Defun, function(compressor){ return true });
|
||||||
def(AST_Function, function(compressor){ return false });
|
def(AST_Function, function(compressor){ return false });
|
||||||
|
def(AST_Class, function(compressor){ return false });
|
||||||
|
def(AST_DefClass, function(compressor){ return true });
|
||||||
def(AST_Binary, function(compressor){
|
def(AST_Binary, function(compressor){
|
||||||
return this.left.has_side_effects(compressor)
|
return this.left.has_side_effects(compressor)
|
||||||
|| this.right.has_side_effects(compressor);
|
|| this.right.has_side_effects(compressor);
|
||||||
@@ -1067,7 +1077,11 @@ merge(Compressor.prototype, {
|
|||||||
OPT(AST_BlockStatement, function(self, compressor){
|
OPT(AST_BlockStatement, function(self, compressor){
|
||||||
self.body = tighten_body(self.body, compressor);
|
self.body = tighten_body(self.body, compressor);
|
||||||
switch (self.body.length) {
|
switch (self.body.length) {
|
||||||
case 1: return self.body[0];
|
case 1:
|
||||||
|
if (can_be_evicted_from_block(self.body[0])) {
|
||||||
|
return self.body[0];
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 0: return make_node(AST_EmptyStatement, self);
|
case 0: return make_node(AST_EmptyStatement, self);
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
@@ -1077,7 +1091,6 @@ merge(Compressor.prototype, {
|
|||||||
var self = this;
|
var self = this;
|
||||||
if (compressor.has_directive("use asm")) return self;
|
if (compressor.has_directive("use asm")) return self;
|
||||||
if (compressor.option("unused")
|
if (compressor.option("unused")
|
||||||
&& !(self instanceof AST_Toplevel)
|
|
||||||
&& !self.uses_eval
|
&& !self.uses_eval
|
||||||
) {
|
) {
|
||||||
var in_use = [];
|
var in_use = [];
|
||||||
@@ -1166,8 +1179,11 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Defun && node !== self) {
|
if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) {
|
||||||
if (!member(node.name.definition(), in_use)) {
|
var keep =
|
||||||
|
member(node.name.definition(), in_use) ||
|
||||||
|
node.name.definition().global;
|
||||||
|
if (!keep) {
|
||||||
compressor.warn("Dropping unused function {name} [{file}:{line},{col}]", {
|
compressor.warn("Dropping unused function {name} [{file}:{line},{col}]", {
|
||||||
name : node.name.name,
|
name : node.name.name,
|
||||||
file : node.name.start.file,
|
file : node.name.start.file,
|
||||||
@@ -1182,6 +1198,7 @@ merge(Compressor.prototype, {
|
|||||||
var def = node.definitions.filter(function(def){
|
var def = node.definitions.filter(function(def){
|
||||||
if (def.is_destructuring()) return true;
|
if (def.is_destructuring()) return true;
|
||||||
if (member(def.name.definition(), in_use)) return true;
|
if (member(def.name.definition(), in_use)) return true;
|
||||||
|
if (def.name.definition().global) return true;
|
||||||
var w = {
|
var w = {
|
||||||
name : def.name.name,
|
name : def.name.name,
|
||||||
file : def.name.start.file,
|
file : def.name.start.file,
|
||||||
@@ -1260,6 +1277,12 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_BlockStatement) {
|
||||||
|
descend(node, this);
|
||||||
|
if (in_list && all(node.body, can_be_evicted_from_block)) {
|
||||||
|
return MAP.splice(node.body);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (node instanceof AST_Scope && node !== self)
|
if (node instanceof AST_Scope && node !== self)
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|||||||
13
lib/parse.js
13
lib/parse.js
@@ -1214,11 +1214,14 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function vardefs(no_in, in_const) {
|
function vardefs(no_in, kind) {
|
||||||
var a = [];
|
var a = [];
|
||||||
var def;
|
var def;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
var sym_type = in_const ? AST_SymbolConst : AST_SymbolVar;
|
var sym_type =
|
||||||
|
kind === "var" ? AST_SymbolVar :
|
||||||
|
kind === "const" ? AST_SymbolConst :
|
||||||
|
kind === "let" ? AST_SymbolLet : null;
|
||||||
if (is("punc", "{") || is("punc", "[")) {
|
if (is("punc", "{") || is("punc", "[")) {
|
||||||
def = new AST_VarDef({
|
def = new AST_VarDef({
|
||||||
start: S.token,
|
start: S.token,
|
||||||
@@ -1287,7 +1290,7 @@ function parse($TEXT, options) {
|
|||||||
var var_ = function(no_in) {
|
var var_ = function(no_in) {
|
||||||
return new AST_Var({
|
return new AST_Var({
|
||||||
start : prev(),
|
start : prev(),
|
||||||
definitions : vardefs(no_in, false),
|
definitions : vardefs(no_in, "var"),
|
||||||
end : prev()
|
end : prev()
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -1295,7 +1298,7 @@ function parse($TEXT, options) {
|
|||||||
var let_ = function(no_in) {
|
var let_ = function(no_in) {
|
||||||
return new AST_Let({
|
return new AST_Let({
|
||||||
start : prev(),
|
start : prev(),
|
||||||
definitions : vardefs(no_in, false),
|
definitions : vardefs(no_in, "let"),
|
||||||
end : prev()
|
end : prev()
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -1303,7 +1306,7 @@ function parse($TEXT, options) {
|
|||||||
var const_ = function() {
|
var const_ = function() {
|
||||||
return new AST_Const({
|
return new AST_Const({
|
||||||
start : prev(),
|
start : prev(),
|
||||||
definitions : vardefs(false, true),
|
definitions : vardefs(false, "const"),
|
||||||
end : prev()
|
end : prev()
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
41
lib/scope.js
41
lib/scope.js
@@ -106,11 +106,15 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
var in_destructuring = null;
|
var in_destructuring = null;
|
||||||
var in_export;
|
var in_export;
|
||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
if (options.screw_ie8 && node instanceof AST_Catch) {
|
var create_a_block_scope =
|
||||||
|
(options.screw_ie8 && node instanceof AST_Catch) ||
|
||||||
|
((node instanceof AST_Block) && node.creates_block_scope());
|
||||||
|
if (create_a_block_scope) {
|
||||||
var save_scope = scope;
|
var save_scope = scope;
|
||||||
scope = new AST_Scope(node);
|
scope = new AST_Scope(node);
|
||||||
scope.init_scope_vars(nesting);
|
scope.init_scope_vars(nesting);
|
||||||
scope.parent_scope = save_scope;
|
scope.parent_scope = save_scope;
|
||||||
|
scope.is_block_scope = true;
|
||||||
descend();
|
descend();
|
||||||
scope = save_scope;
|
scope = save_scope;
|
||||||
return true;
|
return true;
|
||||||
@@ -174,7 +178,11 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
// scope when we encounter the AST_Defun node (which is
|
// scope when we encounter the AST_Defun node (which is
|
||||||
// instanceof AST_Scope) but we get to the symbol a bit
|
// instanceof AST_Scope) but we get to the symbol a bit
|
||||||
// later.
|
// later.
|
||||||
(node.scope = defun.parent_scope).def_function(node, in_export);
|
var parent_lambda = defun.parent_scope;
|
||||||
|
while (parent_lambda.is_block_scope) {
|
||||||
|
parent_lambda = parent_lambda.parent_scope;
|
||||||
|
}
|
||||||
|
(node.scope = parent_lambda).def_function(node, in_export);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolClass) {
|
else if (node instanceof AST_SymbolClass) {
|
||||||
defun.def_variable(node, in_export);
|
defun.def_variable(node, in_export);
|
||||||
@@ -188,8 +196,9 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
(node.scope = defun.parent_scope).def_function(node, in_export);
|
(node.scope = defun.parent_scope).def_function(node, in_export);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolVar
|
else if (node instanceof AST_SymbolVar
|
||||||
|| node instanceof AST_SymbolConst) {
|
|| node instanceof AST_SymbolConst
|
||||||
var def = defun.def_variable(node, in_export);
|
|| node instanceof AST_SymbolLet) {
|
||||||
|
var def = ((node instanceof AST_SymbolBlockDeclaration) ? scope : defun).def_variable(node, in_export);
|
||||||
def.constant = node instanceof AST_SymbolConst;
|
def.constant = node instanceof AST_SymbolConst;
|
||||||
def.destructuring = in_destructuring;
|
def.destructuring = in_destructuring;
|
||||||
def.init = tw.parent().value;
|
def.init = tw.parent().value;
|
||||||
@@ -279,6 +288,14 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
|
|||||||
this.nesting = nesting; // the nesting level of this scope (0 means toplevel)
|
this.nesting = nesting; // the nesting level of this scope (0 means toplevel)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_Block.DEFMETHOD("creates_block_scope", function() {
|
||||||
|
return (
|
||||||
|
!(this instanceof AST_Lambda) &&
|
||||||
|
!(this instanceof AST_Toplevel) &&
|
||||||
|
!(this instanceof AST_Class)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
|
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
|
||||||
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
||||||
this.uses_arguments = false;
|
this.uses_arguments = false;
|
||||||
@@ -312,17 +329,10 @@ AST_Scope.DEFMETHOD("def_variable", function(symbol, in_export){
|
|||||||
def = new SymbolDef(this, this.variables.size(), symbol);
|
def = new SymbolDef(this, this.variables.size(), symbol);
|
||||||
this.variables.set(symbol.name, def);
|
this.variables.set(symbol.name, def);
|
||||||
def.object_destructuring_arg = symbol.object_destructuring_arg;
|
def.object_destructuring_arg = symbol.object_destructuring_arg;
|
||||||
def.global = !this.parent_scope;
|
if (in_export) {
|
||||||
if (symbol instanceof AST_SymbolImport) {
|
|
||||||
// Imports are not global
|
|
||||||
def.global = false;
|
|
||||||
// TODO The real fix comes with block scoping being first class in uglifyJS,
|
|
||||||
// enabling import definitions to behave like module-level let declarations
|
|
||||||
}
|
|
||||||
if (!this.parent_scope && in_export) {
|
|
||||||
def.global = false;
|
|
||||||
def.export = true;
|
def.export = true;
|
||||||
}
|
}
|
||||||
|
def.global = !this.parent_scope && !(symbol instanceof AST_SymbolBlockDeclaration);
|
||||||
} else {
|
} else {
|
||||||
def = this.variables.get(symbol.name);
|
def = this.variables.get(symbol.name);
|
||||||
def.orig.push(symbol);
|
def.orig.push(symbol);
|
||||||
@@ -466,7 +476,10 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
|||||||
node.mangled_name = name;
|
node.mangled_name = name;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (options.screw_ie8 && node instanceof AST_SymbolCatch) {
|
var mangle_with_block_scope =
|
||||||
|
(options.screw_ie8 && node instanceof AST_SymbolCatch) ||
|
||||||
|
node instanceof AST_SymbolBlockDeclaration;
|
||||||
|
if (mangle_with_block_scope) {
|
||||||
to_mangle.push(node.definition());
|
to_mangle.push(node.definition());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,3 +31,103 @@ do_not_hoist_let: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_not_remove_anon_blocks_if_they_have_decls: {
|
||||||
|
input: {
|
||||||
|
function x() {
|
||||||
|
{
|
||||||
|
let x;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var x;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const y;
|
||||||
|
class Zee {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let y;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
var y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function x(){
|
||||||
|
{
|
||||||
|
let x
|
||||||
|
}
|
||||||
|
var x;
|
||||||
|
{
|
||||||
|
const y;
|
||||||
|
class Zee {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let y
|
||||||
|
}
|
||||||
|
var y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_unused_in_global_block: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
{
|
||||||
|
let x;
|
||||||
|
const y;
|
||||||
|
class Zee {};
|
||||||
|
var w;
|
||||||
|
}
|
||||||
|
let ex;
|
||||||
|
const why;
|
||||||
|
class Zed {};
|
||||||
|
var wut;
|
||||||
|
console.log(x, y, Zee);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var w;
|
||||||
|
var wut;
|
||||||
|
console.log(x, y, Zee);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
regression_block_scope_resolves: {
|
||||||
|
mangle = { };
|
||||||
|
options = {
|
||||||
|
dead_code: false
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
(function () {
|
||||||
|
if(1) {
|
||||||
|
let x;
|
||||||
|
const y;
|
||||||
|
class Zee {};
|
||||||
|
}
|
||||||
|
if(1) {
|
||||||
|
let ex;
|
||||||
|
const why;
|
||||||
|
class Zi {};
|
||||||
|
}
|
||||||
|
console.log(x, y, Zee, ex, why, Zi);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function () {
|
||||||
|
if (1) {
|
||||||
|
let a;
|
||||||
|
const b;
|
||||||
|
class c {};
|
||||||
|
}
|
||||||
|
if (1) {
|
||||||
|
let a;
|
||||||
|
const b;
|
||||||
|
class c {};
|
||||||
|
}
|
||||||
|
console.log(x, y, Zee, ex, why, Zi);
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,3 +87,25 @@ dead_code_constant_boolean_should_warn_more: {
|
|||||||
var moo;
|
var moo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dead_code_block_decls_die: {
|
||||||
|
options = {
|
||||||
|
dead_code : true,
|
||||||
|
conditionals : true,
|
||||||
|
booleans : true,
|
||||||
|
evaluate : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
if (0) {
|
||||||
|
let foo = 6;
|
||||||
|
const bar = 12;
|
||||||
|
class Baz {};
|
||||||
|
var qux;
|
||||||
|
}
|
||||||
|
console.log(foo, bar, Baz);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var qux;
|
||||||
|
console.log(foo, bar, Baz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -164,6 +164,72 @@ used_var_in_catch: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unused_block_decls_in_catch: {
|
||||||
|
options = { unused: true };
|
||||||
|
input: {
|
||||||
|
function foo() {
|
||||||
|
try {
|
||||||
|
foo();
|
||||||
|
} catch(ex) {
|
||||||
|
let x = 10;
|
||||||
|
const y = 10;
|
||||||
|
class Zee {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo() {
|
||||||
|
try {
|
||||||
|
foo();
|
||||||
|
} catch(ex) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
used_block_decls_in_catch: {
|
||||||
|
options = { unused: true };
|
||||||
|
input: {
|
||||||
|
function foo() {
|
||||||
|
try {
|
||||||
|
foo();
|
||||||
|
} catch(ex) {
|
||||||
|
let x = 10;
|
||||||
|
const y = 10;
|
||||||
|
class Zee {};
|
||||||
|
}
|
||||||
|
console.log(x, y, Zee);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo() {
|
||||||
|
try {
|
||||||
|
foo();
|
||||||
|
} catch(ex) {}
|
||||||
|
console.log(x, y, Zee);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unused_block_decls: {
|
||||||
|
options = { unused: true };
|
||||||
|
input: {
|
||||||
|
function foo() {
|
||||||
|
{
|
||||||
|
const x;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let y;
|
||||||
|
}
|
||||||
|
console.log(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo() {
|
||||||
|
console.log(x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unused_keep_harmony_destructuring: {
|
unused_keep_harmony_destructuring: {
|
||||||
options = { unused: true };
|
options = { unused: true };
|
||||||
input: {
|
input: {
|
||||||
|
|||||||
Reference in New Issue
Block a user