drop unused variables
authorMihai Bazon <mihai@bazon.net>
Wed, 19 Sep 2012 09:27:38 +0000 (12:27 +0300)
committerMihai Bazon <mihai@bazon.net>
Wed, 19 Sep 2012 09:27:38 +0000 (12:27 +0300)
lib/compress.js
lib/scope.js

index 9d5dac1..834cc38 100644 (file)
@@ -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();
index 0e615eb..196af91 100644 (file)
@@ -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(){