diff options
| author | Seo Sanghyeon <sanxiyn@gmail.com> | 2016-04-19 22:43:10 +0900 |
|---|---|---|
| committer | Seo Sanghyeon <sanxiyn@gmail.com> | 2016-05-03 18:51:19 +0900 |
| commit | 24d86137f5d04bfade044e96bbb429db4b248c1d (patch) | |
| tree | 3e61936eb5dfa3e07d3409d670507799a01805de /src/librustc_resolve | |
| parent | 7ad1900e1cdb2bd9dbf9560c8c50c5912578723c (diff) | |
| download | rust-24d86137f5d04bfade044e96bbb429db4b248c1d.tar.gz rust-24d86137f5d04bfade044e96bbb429db4b248c1d.zip | |
Warn unused trait imports
Diffstat (limited to 'src/librustc_resolve')
| -rw-r--r-- | src/librustc_resolve/check_unused.rs | 10 | ||||
| -rw-r--r-- | src/librustc_resolve/lib.rs | 45 |
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 { |
