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