about summary refs log tree commit diff
path: root/src/librustc_resolve
diff options
context:
space:
mode:
authorSeo Sanghyeon <sanxiyn@gmail.com>2016-04-19 22:43:10 +0900
committerSeo Sanghyeon <sanxiyn@gmail.com>2016-05-03 18:51:19 +0900
commit24d86137f5d04bfade044e96bbb429db4b248c1d (patch)
tree3e61936eb5dfa3e07d3409d670507799a01805de /src/librustc_resolve
parent7ad1900e1cdb2bd9dbf9560c8c50c5912578723c (diff)
downloadrust-24d86137f5d04bfade044e96bbb429db4b248c1d.tar.gz
rust-24d86137f5d04bfade044e96bbb429db4b248c1d.zip
Warn unused trait imports
Diffstat (limited to 'src/librustc_resolve')
-rw-r--r--src/librustc_resolve/check_unused.rs10
-rw-r--r--src/librustc_resolve/lib.rs45
2 files changed, 42 insertions, 13 deletions
diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs
index 9135b656736..e213a51fb38 100644
--- a/src/librustc_resolve/check_unused.rs
+++ b/src/librustc_resolve/check_unused.rs
@@ -16,6 +16,8 @@
 // resolve data structures and because it finalises the privacy information for
 // `use` directives.
 //
+// Unused trait imports can't be checked until the method resolution. We save
+// candidates here, and do the acutal check in librustc_typeck/check_unused.rs.
 
 use std::ops::{Deref, DerefMut};
 
@@ -55,10 +57,18 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
     fn check_import(&mut self, id: ast::NodeId, span: Span) {
         if !self.used_imports.contains(&(id, TypeNS)) &&
            !self.used_imports.contains(&(id, ValueNS)) {
+            if self.maybe_unused_trait_imports.contains(&id) {
+                // Check later.
+                return;
+            }
             self.session.add_lint(lint::builtin::UNUSED_IMPORTS,
                                   id,
                                   span,
                                   "unused import".to_string());
+        } else {
+            // This trait import is definitely used, in a way other than
+            // method resolution.
+            self.maybe_unused_trait_imports.remove(&id);
         }
     }
 }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 9ef927b6610..2e2b40fec4b 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -52,8 +52,8 @@ use rustc::hir::def_id::DefId;
 use rustc::hir::pat_util::pat_bindings;
 use rustc::ty;
 use rustc::ty::subst::{ParamSpace, FnSpace, TypeSpace};
-use rustc::hir::{Freevar, FreevarMap, TraitMap, GlobMap};
-use rustc::util::nodemap::{NodeMap, FnvHashMap, FnvHashSet};
+use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
+use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet};
 
 use syntax::ast::{self, FloatTy};
 use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy};
@@ -1042,6 +1042,7 @@ pub struct Resolver<'a, 'tcx: 'a> {
 
     used_imports: HashSet<(NodeId, Namespace)>,
     used_crates: HashSet<CrateNum>,
+    maybe_unused_trait_imports: NodeSet,
 
     privacy_errors: Vec<PrivacyError<'a>>,
 
@@ -1137,13 +1138,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             export_map: NodeMap(),
             trait_map: NodeMap(),
             module_map: module_map,
-            used_imports: HashSet::new(),
-            used_crates: HashSet::new(),
 
             emit_errors: true,
             make_glob_map: make_glob_map == MakeGlobMap::Yes,
             glob_map: NodeMap(),
 
+            used_imports: HashSet::new(),
+            used_crates: HashSet::new(),
+            maybe_unused_trait_imports: NodeSet(),
+
             privacy_errors: Vec::new(),
 
             arenas: arenas,
@@ -1177,7 +1180,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     }
 
     #[inline]
-    fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) {
+    fn record_use(&mut self, name: Name, binding: &'a NameBinding<'a>) {
         // track extern crates for unused_extern_crate lint
         if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleS::def_id) {
             self.used_crates.insert(krate);
@@ -1189,7 +1192,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             _ => return,
         };
 
-        self.used_imports.insert((directive.id, ns));
         if let Some(error) = privacy_error.as_ref() {
             self.privacy_errors.push((**error).clone());
         }
@@ -1492,7 +1494,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             false => module.resolve_name(name, namespace, false),
         }.and_then(|binding| {
             if record_used {
-                self.record_use(name, namespace, binding);
+                if let NameBindingKind::Import { directive, .. } = binding.kind {
+                    self.used_imports.insert((directive.id, namespace));
+                }
+                self.record_use(name, binding);
             }
             Success(binding)
         })
@@ -3094,21 +3099,27 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
     }
 
-    fn get_traits_containing_item(&mut self, name: Name) -> Vec<DefId> {
+    fn get_traits_containing_item(&mut self, name: Name) -> Vec<TraitCandidate> {
         debug!("(getting traits containing item) looking for '{}'", name);
 
-        fn add_trait_info(found_traits: &mut Vec<DefId>, trait_def_id: DefId, name: Name) {
+        fn add_trait_info(found_traits: &mut Vec<TraitCandidate>,
+                          trait_def_id: DefId,
+                          import_id: Option<NodeId>,
+                          name: Name) {
             debug!("(adding trait info) found trait {:?} for method '{}'",
                    trait_def_id,
                    name);
-            found_traits.push(trait_def_id);
+            found_traits.push(TraitCandidate {
+                def_id: trait_def_id,
+                import_id: import_id,
+            });
         }
 
         let mut found_traits = Vec::new();
         // Look for the current trait.
         if let Some((trait_def_id, _)) = self.current_trait_ref {
             if self.trait_item_map.contains_key(&(name, trait_def_id)) {
-                add_trait_info(&mut found_traits, trait_def_id, name);
+                add_trait_info(&mut found_traits, trait_def_id, None, name);
             }
         }
 
@@ -3131,8 +3142,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
                     let trait_def_id = binding.def().unwrap().def_id();
                     if self.trait_item_map.contains_key(&(name, trait_def_id)) {
-                        add_trait_info(&mut found_traits, trait_def_id, name);
-                        self.record_use(trait_name, TypeNS, binding);
+                        let mut import_id = None;
+                        if let NameBindingKind::Import { directive, .. } = binding.kind {
+                            let id = directive.id;
+                            self.maybe_unused_trait_imports.insert(id);
+                            import_id = Some(id);
+                        }
+                        add_trait_info(&mut found_traits, trait_def_id, import_id, name);
+                        self.record_use(trait_name, binding);
                     }
                 }
             };
@@ -3506,6 +3523,7 @@ fn err_path_resolution() -> PathResolution {
 pub struct CrateMap {
     pub def_map: RefCell<DefMap>,
     pub freevars: FreevarMap,
+    pub maybe_unused_trait_imports: NodeSet,
     pub export_map: ExportMap,
     pub trait_map: TraitMap,
     pub glob_map: Option<GlobMap>,
@@ -3543,6 +3561,7 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
     CrateMap {
         def_map: resolver.def_map,
         freevars: resolver.freevars,
+        maybe_unused_trait_imports: resolver.maybe_unused_trait_imports,
         export_map: resolver.export_map,
         trait_map: resolver.trait_map,
         glob_map: if resolver.make_glob_map {