]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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. | |
4 | // | |
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. | |
10 | ||
11 | ||
12 | // | |
13 | // Unused import checking | |
14 | // | |
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 | |
17 | // `use` directives. | |
18 | // | |
a7813a04 XL |
19 | // Unused trait imports can't be checked until the method resolution. We save |
20 | // candidates here, and do the acutal check in librustc_typeck/check_unused.rs. | |
1a4d82fc JJ |
21 | |
22 | use std::ops::{Deref, DerefMut}; | |
23 | ||
24 | use Resolver; | |
32a655c1 | 25 | use resolve_imports::ImportDirectiveSubclass; |
1a4d82fc | 26 | |
32a655c1 | 27 | use rustc::{lint, ty}; |
476ff2be | 28 | use rustc::util::nodemap::NodeMap; |
a7813a04 XL |
29 | use syntax::ast::{self, ViewPathGlob, ViewPathList, ViewPathSimple}; |
30 | use syntax::visit::{self, Visitor}; | |
476ff2be | 31 | use syntax_pos::{Span, MultiSpan, DUMMY_SP}; |
e9174d1e | 32 | |
1a4d82fc | 33 | |
a7813a04 XL |
34 | struct UnusedImportCheckVisitor<'a, 'b: 'a> { |
35 | resolver: &'a mut Resolver<'b>, | |
476ff2be SL |
36 | /// All the (so far) unused imports, grouped path list |
37 | unused_imports: NodeMap<NodeMap<Span>>, | |
1a4d82fc JJ |
38 | } |
39 | ||
40 | // Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver. | |
a7813a04 XL |
41 | impl<'a, 'b> Deref for UnusedImportCheckVisitor<'a, 'b> { |
42 | type Target = Resolver<'b>; | |
1a4d82fc | 43 | |
a7813a04 | 44 | fn deref<'c>(&'c self) -> &'c Resolver<'b> { |
1a4d82fc JJ |
45 | &*self.resolver |
46 | } | |
47 | } | |
48 | ||
a7813a04 XL |
49 | impl<'a, 'b> DerefMut for UnusedImportCheckVisitor<'a, 'b> { |
50 | fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> { | |
1a4d82fc JJ |
51 | &mut *self.resolver |
52 | } | |
53 | } | |
54 | ||
a7813a04 | 55 | impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> { |
92a42be0 | 56 | // We have information about whether `use` (import) directives are actually |
54a0048b | 57 | // used now. If an import is not used at all, we signal a lint error. |
476ff2be SL |
58 | fn check_import(&mut self, item_id: ast::NodeId, id: ast::NodeId, span: Span) { |
59 | let mut used = false; | |
60 | self.per_ns(|this, ns| used |= this.used_imports.contains(&(id, ns))); | |
61 | if !used { | |
a7813a04 XL |
62 | if self.maybe_unused_trait_imports.contains(&id) { |
63 | // Check later. | |
64 | return; | |
65 | } | |
476ff2be | 66 | self.unused_imports.entry(item_id).or_insert_with(NodeMap).insert(id, span); |
a7813a04 XL |
67 | } else { |
68 | // This trait import is definitely used, in a way other than | |
69 | // method resolution. | |
70 | self.maybe_unused_trait_imports.remove(&id); | |
476ff2be SL |
71 | if let Some(i) = self.unused_imports.get_mut(&item_id) { |
72 | i.remove(&id); | |
73 | } | |
1a4d82fc | 74 | } |
1a4d82fc JJ |
75 | } |
76 | } | |
77 | ||
476ff2be SL |
78 | impl<'a, 'b> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b> { |
79 | fn visit_item(&mut self, item: &'a ast::Item) { | |
a7813a04 | 80 | visit::walk_item(self, item); |
1a4d82fc JJ |
81 | // Ignore is_public import statements because there's no way to be sure |
82 | // whether they're used or not. Also ignore imports with a dummy span | |
83 | // because this means that they were generated in some fashion by the | |
84 | // compiler and we don't need to consider them. | |
a7813a04 | 85 | if item.vis == ast::Visibility::Public || item.span.source_equal(&DUMMY_SP) { |
1a4d82fc JJ |
86 | return; |
87 | } | |
88 | ||
85aaf69f | 89 | match item.node { |
a7813a04 | 90 | ast::ItemKind::Use(ref p) => { |
1a4d82fc | 91 | match p.node { |
9e0c209e | 92 | ViewPathSimple(..) => { |
476ff2be | 93 | self.check_import(item.id, item.id, p.span) |
1a4d82fc JJ |
94 | } |
95 | ||
85aaf69f | 96 | ViewPathList(_, ref list) => { |
476ff2be SL |
97 | if list.len() == 0 { |
98 | self.unused_imports | |
99 | .entry(item.id) | |
100 | .or_insert_with(NodeMap) | |
101 | .insert(item.id, item.span); | |
102 | } | |
85aaf69f | 103 | for i in list { |
476ff2be | 104 | self.check_import(item.id, i.node.id, i.span); |
1a4d82fc JJ |
105 | } |
106 | } | |
85aaf69f | 107 | ViewPathGlob(_) => { |
476ff2be | 108 | self.check_import(item.id, item.id, p.span); |
1a4d82fc JJ |
109 | } |
110 | } | |
111 | } | |
85aaf69f | 112 | _ => {} |
1a4d82fc | 113 | } |
1a4d82fc JJ |
114 | } |
115 | } | |
116 | ||
a7813a04 | 117 | pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) { |
32a655c1 SL |
118 | for directive in resolver.potentially_unused_imports.iter() { |
119 | match directive.subclass { | |
120 | _ if directive.used.get() || | |
121 | directive.vis.get() == ty::Visibility::Public || | |
122 | directive.span.source_equal(&DUMMY_SP) => {} | |
abe05a73 | 123 | ImportDirectiveSubclass::ExternCrate(_) => { |
3b2f2976 | 124 | resolver.maybe_unused_extern_crates.push((directive.id, directive.span)); |
32a655c1 SL |
125 | } |
126 | ImportDirectiveSubclass::MacroUse => { | |
127 | let lint = lint::builtin::UNUSED_IMPORTS; | |
3b2f2976 XL |
128 | let msg = "unused `#[macro_use]` import"; |
129 | resolver.session.buffer_lint(lint, directive.id, directive.span, msg); | |
32a655c1 SL |
130 | } |
131 | _ => {} | |
132 | } | |
133 | } | |
134 | ||
476ff2be | 135 | let mut visitor = UnusedImportCheckVisitor { |
3b2f2976 | 136 | resolver, |
476ff2be SL |
137 | unused_imports: NodeMap(), |
138 | }; | |
a7813a04 | 139 | visit::walk_crate(&mut visitor, krate); |
476ff2be SL |
140 | |
141 | for (id, spans) in &visitor.unused_imports { | |
142 | let len = spans.len(); | |
143 | let mut spans = spans.values().map(|s| *s).collect::<Vec<Span>>(); | |
144 | spans.sort(); | |
145 | let ms = MultiSpan::from_spans(spans.clone()); | |
146 | let mut span_snippets = spans.iter() | |
147 | .filter_map(|s| { | |
148 | match visitor.session.codemap().span_to_snippet(*s) { | |
149 | Ok(s) => Some(format!("`{}`", s)), | |
150 | _ => None, | |
151 | } | |
152 | }).collect::<Vec<String>>(); | |
153 | span_snippets.sort(); | |
154 | let msg = format!("unused import{}{}", | |
155 | if len > 1 { "s" } else { "" }, | |
156 | if span_snippets.len() > 0 { | |
157 | format!(": {}", span_snippets.join(", ")) | |
158 | } else { | |
159 | String::new() | |
160 | }); | |
3b2f2976 | 161 | visitor.session.buffer_lint(lint::builtin::UNUSED_IMPORTS, *id, ms, &msg); |
476ff2be | 162 | } |
1a4d82fc | 163 | } |