]> git.proxmox.com Git - rustc.git/blame - src/librustc_resolve/check_unused.rs
New upstream version 1.23.0+dfsg1
[rustc.git] / src / librustc_resolve / check_unused.rs
CommitLineData
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
22use std::ops::{Deref, DerefMut};
23
24use Resolver;
32a655c1 25use resolve_imports::ImportDirectiveSubclass;
1a4d82fc 26
32a655c1 27use rustc::{lint, ty};
476ff2be 28use rustc::util::nodemap::NodeMap;
a7813a04
XL
29use syntax::ast::{self, ViewPathGlob, ViewPathList, ViewPathSimple};
30use syntax::visit::{self, Visitor};
476ff2be 31use syntax_pos::{Span, MultiSpan, DUMMY_SP};
e9174d1e 32
1a4d82fc 33
a7813a04
XL
34struct 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
41impl<'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
49impl<'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 55impl<'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
78impl<'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 117pub 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}