1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 // Unused import checking
15 // Although this is mostly a lint pass, it lives in here because it depends on
16 // resolve data structures and because it finalises the privacy information for
20 use std::ops::{Deref, DerefMut};
23 use Namespace::{TypeNS, ValueNS};
26 use rustc::middle::privacy::{DependsOn, LastImport, Used, Unused};
28 use syntax::codemap::{Span, DUMMY_SP};
31 use rustc_front::hir::{ViewPathGlob, ViewPathList, ViewPathSimple};
32 use rustc_front::intravisit::Visitor;
34 struct UnusedImportCheckVisitor<'a, 'b: 'a, 'tcx: 'b> {
35 resolver: &'a mut Resolver<'b, 'tcx>,
38 // Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver.
39 impl<'a, 'b, 'tcx:'b> Deref for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
40 type Target = Resolver<'b, 'tcx>;
42 fn deref<'c>(&'c self) -> &'c Resolver<'b, 'tcx> {
47 impl<'a, 'b, 'tcx:'b> DerefMut for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
48 fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b, 'tcx> {
53 impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
54 // We have information about whether `use` (import) directives are actually
55 // used now. If an import is not used at all, we signal a lint error. If an
56 // import is only used for a single namespace, we remove the other namespace
57 // from the recorded privacy information. That means in privacy.rs, we will
58 // only check imports and namespaces which are used. In particular, this
59 // means that if an import could name either a public or private item, we
60 // will check the correct thing, dependent on how the import is used.
61 fn finalize_import(&mut self, id: ast::NodeId, span: Span) {
62 debug!("finalizing import uses for {:?}",
63 self.session.codemap().span_to_snippet(span));
65 if !self.used_imports.contains(&(id, TypeNS)) &&
66 !self.used_imports.contains(&(id, ValueNS)) {
67 self.session.add_lint(lint::builtin::UNUSED_IMPORTS,
70 "unused import".to_string());
73 let mut def_map = self.def_map.borrow_mut();
74 let path_res = if let Some(r) = def_map.get_mut(&id) {
79 let (v_priv, t_priv) = match path_res.last_private {
80 LastImport { value_priv, type_priv, .. } => (value_priv, type_priv),
82 panic!("we should only have LastImport for `use` directives")
86 let mut v_used = if self.used_imports.contains(&(id, ValueNS)) {
91 let t_used = if self.used_imports.contains(&(id, TypeNS)) {
97 match (v_priv, t_priv) {
98 // Since some items may be both in the value _and_ type namespaces (e.g., structs)
99 // we might have two LastPrivates pointing at the same thing. There is no point
100 // checking both, so lets not check the value one.
101 (Some(DependsOn(def_v)), Some(DependsOn(def_t))) if def_v == def_t => v_used = Unused,
105 path_res.last_private = LastImport {
114 impl<'a, 'b, 'v, 'tcx> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
115 fn visit_item(&mut self, item: &hir::Item) {
116 // Ignore is_public import statements because there's no way to be sure
117 // whether they're used or not. Also ignore imports with a dummy span
118 // because this means that they were generated in some fashion by the
119 // compiler and we don't need to consider them.
120 if item.vis == hir::Public || item.span.source_equal(&DUMMY_SP) {
125 hir::ItemExternCrate(_) => {
126 if let Some(crate_num) = self.session.cstore.extern_mod_stmt_cnum(item.id) {
127 if !self.used_crates.contains(&crate_num) {
128 self.session.add_lint(lint::builtin::UNUSED_EXTERN_CRATES,
131 "unused extern crate".to_string());
135 hir::ItemUse(ref p) => {
137 ViewPathSimple(_, _) => {
138 self.finalize_import(item.id, p.span)
141 ViewPathList(_, ref list) => {
143 self.finalize_import(i.node.id(), i.span);
147 if !self.used_imports.contains(&(item.id, TypeNS)) &&
148 !self.used_imports.contains(&(item.id, ValueNS)) {
150 .add_lint(lint::builtin::UNUSED_IMPORTS,
153 "unused import".to_string());
163 pub fn check_crate(resolver: &mut Resolver, krate: &hir::Crate) {
164 let mut visitor = UnusedImportCheckVisitor { resolver: resolver };
165 krate.visit_all_items(&mut visitor);