about summary refs log tree commit diff
diff options
context:
space:
mode:
authorHaitao Li <lihaitao@gmail.com>2011-11-10 23:31:55 +0800
committerBrian Anderson <banderson@mozilla.com>2011-11-10 19:19:10 -0800
commit9bc2f1800dcf97aff968478569c52204ec6d3998 (patch)
treec9320f95e83f1a87405470a37fc26f54f9a4ecc8
parentf705f681218f45a9d011a4bdd5575b31fdafce2d (diff)
downloadrust-9bc2f1800dcf97aff968478569c52204ec6d3998.tar.gz
rust-9bc2f1800dcf97aff968478569c52204ec6d3998.zip
rustc: Add support of warning on unused imports
Fixes issue #889
-rw-r--r--src/comp/middle/resolve.rs44
-rw-r--r--src/test/compile-fail/unused-imports-warn.rs19
2 files changed, 54 insertions, 9 deletions
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index 7745f8b94c2..501d675564a 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -50,7 +50,9 @@ tag import_state {
     resolving(span);
     resolved(option::t<def>, /* value */
              option::t<def>, /* type */
-             option::t<def>); /* module */
+             option::t<def>, /* module */
+             /* used for reporting unused import warning */
+             ast::ident, codemap::span);
 }
 
 type ext_hash = hashmap<{did: def_id, ident: str, ns: namespace}, def>;
@@ -106,6 +108,7 @@ type env =
      mod_map: hashmap<ast::node_id, @indexed_mod>,
      ext_map: hashmap<def_id, [ident]>,
      ext_cache: ext_hash,
+     mutable used_imports: option::t<[ast::node_id]>,
      mutable reported: [{ident: str, sc: scope}],
      mutable currently_resolving: node_id,
      sess: session};
@@ -127,6 +130,7 @@ fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) ->
           mod_map: new_int_hash::<@indexed_mod>(),
           ext_map: new_def_hash::<[ident]>(),
           ext_cache: new_ext_hash(),
+          mutable used_imports: none,
           mutable reported: [],
           mutable currently_resolving: -1,
           sess: sess};
@@ -134,11 +138,12 @@ fn resolve_crate(sess: session, amap: ast_map::map, crate: @ast::crate) ->
     resolve_imports(*e);
     check_for_collisions(e, *crate);
     check_bad_exports(e);
+    e.used_imports = some([]);
     resolve_names(e, crate);
+    check_unused_imports(e);
     ret {def_map: e.def_map, ext_map: e.ext_map};
 }
 
-
 // Locate all modules and imports and index them, so that the next passes can
 // resolve through them.
 fn map_crate(e: @env, c: @ast::crate) {
@@ -239,12 +244,26 @@ fn resolve_imports(e: env) {
           todo(node_id, name, path, span, scopes) {
             resolve_import(e, local_def(node_id), name, path, span, scopes);
           }
-          resolved(_, _, _) { }
+          resolved(_, _, _, _, _) { }
         }
     };
     e.sess.abort_if_errors();
 }
 
+fn check_unused_imports(e: @env) {
+    let used = option::get(e.used_imports);
+    e.imports.items {|k, v|
+        alt v {
+            resolved(val, ty, md, name, sp) {
+              if !vec::member(k, used) {
+                e.sess.span_warn(sp, "unused import " + name);
+              }
+            }
+            _ { }
+        }
+    };
+}
+
 fn resolve_names(e: @env, c: @ast::crate) {
     let v =
         @{visit_native_item: visit_native_item_with_scope,
@@ -439,7 +458,7 @@ fn resolve_import(e: env, defid: ast::def_id, name: ast::ident,
         if is_none(val) && is_none(typ) && is_none(md) {
             unresolved_err(e, sc, sp, name, "import");
         } else {
-            e.imports.insert(id, resolved(val, typ, md));
+            e.imports.insert(id, resolved(val, typ, md, name, sp));
         }
     }
     // This function has cleanup code at the end. Do not return without going
@@ -483,8 +502,8 @@ fn resolve_import(e: env, defid: ast::def_id, name: ast::ident,
     // resolved state, to avoid having it reported later as a cyclic
     // import
     alt e.imports.find(defid.node) {
-      some(resolving(_)) {
-        e.imports.insert(defid.node, resolved(none, none, none));
+      some(resolving(sp)) {
+        e.imports.insert(defid.node, resolved(none, none, none, "", sp));
       }
       _ { }
     }
@@ -931,7 +950,14 @@ fn lookup_import(e: env, defid: def_id, ns: namespace) -> option::t<def> {
         }
         ret none;
       }
-      resolved(val, typ, md) {
+      resolved(val, typ, md, _, _) {
+        alt e.used_imports {
+          none. { }
+          some(lst_) {
+            let lst = lst_ + [defid.node];
+            e.used_imports = option::some(lst);
+          }
+        }
         ret alt ns { ns_value. { val } ns_type. { typ } ns_module. { md } };
       }
     }
@@ -1008,7 +1034,7 @@ fn lookup_glob_in_mod(e: env, info: @indexed_mod, sp: span, id: ident,
         let val = per_ns(e, info, sp, id, ns_value, dr);
         let typ = per_ns(e, info, sp, id, ns_type, dr);
         let md = per_ns(e, info, sp, id, ns_module, dr);
-        info.glob_imported_names.insert(id, resolved(val, typ, md));
+        info.glob_imported_names.insert(id, resolved(val, typ, md, id, sp));
     }
     alt info.glob_imported_names.get(id) {
       todo(_, _, _, _, _) { e.sess.bug("Shouldn't've put a todo in."); }
@@ -1016,7 +1042,7 @@ fn lookup_glob_in_mod(e: env, info: @indexed_mod, sp: span, id: ident,
         ret none::<def>; //circularity is okay in import globs
 
       }
-      resolved(val, typ, md) {
+      resolved(val, typ, md, _, _) {
         ret alt wanted_ns {
               ns_value. { val }
               ns_type. { typ }
diff --git a/src/test/compile-fail/unused-imports-warn.rs b/src/test/compile-fail/unused-imports-warn.rs
new file mode 100644
index 00000000000..88e42e0490a
--- /dev/null
+++ b/src/test/compile-fail/unused-imports-warn.rs
@@ -0,0 +1,19 @@
+// error-pattern:unused import
+import cal = bar::c::cc;
+
+mod foo {
+    type point = {x: int, y: int};
+    type square = {p: point, h: uint, w: uint};
+}
+
+mod bar {
+    mod c {
+        import foo::point;
+        import foo::square;
+        fn cc(p: point) -> str { ret 2 * (p.x + p.y); }
+    }
+}
+
+fn main() {
+    cal({x:3, y:9});
+}