]> git.lizzy.rs Git - rust.git/blob - src/librustc_resolve/check_unused.rs
Auto merge of #27856 - nikomatsakis:move-def-id-to-rustc, r=eddyb
[rust.git] / src / librustc_resolve / check_unused.rs
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 //
19
20 use std::ops::{Deref, DerefMut};
21
22 use Resolver;
23 use Namespace::{TypeNS, ValueNS};
24
25 use rustc::lint;
26 use rustc::middle::privacy::{DependsOn, LastImport, Used, Unused};
27 use syntax::ast;
28 use syntax::ast::{ViewPathGlob, ViewPathList, ViewPathSimple};
29 use syntax::codemap::{Span, DUMMY_SP};
30 use syntax::visit::{self, Visitor};
31
32 struct UnusedImportCheckVisitor<'a, 'b:'a, 'tcx:'b> {
33     resolver: &'a mut Resolver<'b, 'tcx>
34 }
35
36 // Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver.
37 impl<'a, 'b, 'tcx:'b> Deref for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
38     type Target = Resolver<'b, 'tcx>;
39
40     fn deref<'c>(&'c self) -> &'c Resolver<'b, 'tcx> {
41         &*self.resolver
42     }
43 }
44
45 impl<'a, 'b, 'tcx:'b> DerefMut for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
46     fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b, 'tcx> {
47         &mut *self.resolver
48     }
49 }
50
51 impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
52     // We have information about whether `use` (import) directives are actually used now.
53     // If an import is not used at all, we signal a lint error. If an import is only used
54     // for a single namespace, we remove the other namespace from the recorded privacy
55     // information. That means in privacy.rs, we will only check imports and namespaces
56     // which are used. In particular, this means that if an import could name either a
57     // public or private item, we will check the correct thing, dependent on how the import
58     // is used.
59     fn finalize_import(&mut self, id: ast::NodeId, span: Span) {
60         debug!("finalizing import uses for {:?}",
61                 self.session.codemap().span_to_snippet(span));
62
63         if !self.used_imports.contains(&(id, TypeNS)) &&
64            !self.used_imports.contains(&(id, ValueNS)) {
65             self.session.add_lint(lint::builtin::UNUSED_IMPORTS,
66                                   id,
67                                   span,
68                                   "unused import".to_string());
69         }
70
71         let mut def_map = self.def_map.borrow_mut();
72         let path_res = if let Some(r) = def_map.get_mut(&id) {
73             r
74         } else {
75             return;
76         };
77         let (v_priv, t_priv) = match path_res.last_private {
78             LastImport { value_priv, type_priv, .. } => (value_priv, type_priv),
79             _ => {
80                 panic!("we should only have LastImport for `use` directives")
81             }
82         };
83
84         let mut v_used = if self.used_imports.contains(&(id, ValueNS)) {
85             Used
86         } else {
87             Unused
88         };
89         let t_used = if self.used_imports.contains(&(id, TypeNS)) {
90             Used
91         } else {
92             Unused
93         };
94
95         match (v_priv, t_priv) {
96             // Since some items may be both in the value _and_ type namespaces (e.g., structs)
97             // we might have two LastPrivates pointing at the same thing. There is no point
98             // checking both, so lets not check the value one.
99             (Some(DependsOn(def_v)), Some(DependsOn(def_t))) if def_v == def_t => v_used = Unused,
100             _ => {},
101         }
102
103         path_res.last_private = LastImport {
104             value_priv: v_priv,
105             value_used: v_used,
106             type_priv: t_priv,
107             type_used: t_used
108         };
109     }
110 }
111
112 impl<'a, 'b, 'v, 'tcx> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
113     fn visit_item(&mut self, item: &ast::Item) {
114         // Ignore is_public import statements because there's no way to be sure
115         // whether they're used or not. Also ignore imports with a dummy span
116         // because this means that they were generated in some fashion by the
117         // compiler and we don't need to consider them.
118         if item.vis == ast::Public || item.span == DUMMY_SP {
119             visit::walk_item(self, item);
120             return;
121         }
122
123         match item.node {
124             ast::ItemExternCrate(_) => {
125                 if let Some(crate_num) = self.session.cstore.find_extern_mod_stmt_cnum(item.id) {
126                     if !self.used_crates.contains(&crate_num) {
127                         self.session.add_lint(lint::builtin::UNUSED_EXTERN_CRATES,
128                                               item.id,
129                                               item.span,
130                                               "unused extern crate".to_string());
131                     }
132                 }
133             },
134             ast::ItemUse(ref p) => {
135                 match p.node {
136                     ViewPathSimple(_, _) => {
137                         self.finalize_import(item.id, p.span)
138                     }
139
140                     ViewPathList(_, ref list) => {
141                         for i in list {
142                             self.finalize_import(i.node.id(), i.span);
143                         }
144                     }
145                     ViewPathGlob(_) => {
146                         if !self.used_imports.contains(&(item.id, TypeNS)) &&
147                            !self.used_imports.contains(&(item.id, ValueNS)) {
148                             self.session
149                                 .add_lint(lint::builtin::UNUSED_IMPORTS,
150                                           item.id,
151                                           p.span,
152                                           "unused import".to_string());
153                         }
154                     }
155                 }
156             }
157             _ => {}
158         }
159
160         visit::walk_item(self, item);
161     }
162 }
163
164 pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) {
165     let mut visitor = UnusedImportCheckVisitor { resolver: resolver };
166     visit::walk_crate(&mut visitor, krate);
167 }