From e8da72d304778cdaf4570f24838effee73f6b993 Mon Sep 17 00:00:00 2001 From: Mihai Bazon Date: Wed, 19 Sep 2012 12:27:38 +0300 Subject: [PATCH] drop unused variables --- lib/compress.js | 55 ++++++++++++++++++++++++++++++++++++++++++++++++- lib/scope.js | 3 ++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/lib/compress.js b/lib/compress.js index 9d5dac17..834cc388 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -65,6 +65,7 @@ function Compressor(options, false_by_default) { booleans : !false_by_default, loops : !false_by_default, unused_func : !false_by_default, + unused_vars : !false_by_default, hoist_funs : !false_by_default, hoist_vars : !false_by_default, if_return : !false_by_default, @@ -222,6 +223,9 @@ function Compressor(options, false_by_default) { // step. nevertheless, it's good to check. continue loop; case stat instanceof AST_If: + // compressor.warn("Current if: {code}", { + // code: stat.condition.print_to_string() + // }); if (stat.body instanceof AST_Return) { //--- // pretty silly case, but: @@ -692,7 +696,7 @@ function Compressor(options, false_by_default) { }); def(AST_Binary, function(){ return this.left.has_side_effects() - || this.right.has_side_effects (); + || this.right.has_side_effects(); }); def(AST_Assign, function(){ return true }); def(AST_Conditional, function(){ @@ -721,6 +725,13 @@ function Compressor(options, false_by_default) { return true; return false; }); + def(AST_Dot, function(){ + return this.expression.has_side_effects(); + }); + def(AST_Sub, function(){ + return this.expression.has_side_effects() + || this.property.has_side_effects(); + }); })(function(node, func){ node.DEFMETHOD("has_side_effects", func); }); @@ -793,9 +804,49 @@ function Compressor(options, false_by_default) { return self; }); + AST_Scope.DEFMETHOD("drop_unused_vars", function(compressor){ + if (compressor.option("unused_vars")) { + var self = this; + var tw = new TreeWalker(function(node){ + if (node !== self) { + if (node instanceof AST_Scope) + return true; // don't go in nested scopes + if (node instanceof AST_Definitions) { + if (!(tw.parent() instanceof AST_ForIn)) { + var a = node.definitions; + for (var i = a.length; --i >= 0;) { + var def = a[i]; + var sym = def.name; + if (sym.unreferenced()) { + var warn = { + name: sym.name, + line: sym.start.line, + col: sym.start.col + }; + if (def.value && def.value.has_side_effects()) { + compressor.warn("Side effects in initialization of unreferenced variable {name} [{line},{col}]", warn); + } else { + compressor.warn("Dropping unreferenced variable {name} [{line},{col}]", warn); + a.splice(i, 1); + } + } + } + } + return true; + } + if (!(node instanceof AST_Statement)) { + return true; // pointless to visit expressions + } + } + }); + this.walk(tw); + } + }); + AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){ var hoist_funs = compressor.option("hoist_funs"); var hoist_vars = compressor.option("hoist_vars"); + this.drop_unused_vars(compressor); if (hoist_funs || hoist_vars) { var self = this; var hoisted = []; @@ -1161,6 +1212,8 @@ function Compressor(options, false_by_default) { }); SQUEEZE(AST_Definitions, function(self, compressor){ + if (self.definitions.length == 0) + return make_node(AST_EmptyStatement, self); if (self.hoisted) { var seq = self.to_assignments(); var p = compressor.parent(); diff --git a/lib/scope.js b/lib/scope.js index 0e615eb8..196af91c 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -296,7 +296,8 @@ AST_Label.DEFMETHOD("unmangleable", function(){ }); AST_Symbol.DEFMETHOD("unreferenced", function(){ - return this.definition().references.length == 0; + return this.definition().references.length == 0 + && !(this.scope.uses_eval || this.scope.uses_with); }); AST_Symbol.DEFMETHOD("undeclared", function(){ -- 2.34.1