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>;
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};
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};
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) {
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,
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
// 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));
}
_ { }
}
}
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 } };
}
}
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."); }
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 }