Skip to content

Commit 1614d92

Browse files
committed
rustc_resolve: move unused import checking into its own module.
1 parent c54fc98 commit 1614d92

File tree

2 files changed

+178
-141
lines changed

2 files changed

+178
-141
lines changed

src/librustc_resolve/check_unused.rs

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

src/librustc_resolve/lib.rs

Lines changed: 17 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ use std::mem::replace;
9696
use std::rc::{Rc, Weak};
9797
use std::uint;
9898

99+
mod check_unused;
100+
99101
#[deriving(Copy)]
100102
struct BindingInfo {
101103
span: Span,
@@ -935,17 +937,6 @@ impl<'a, 'b, 'v> Visitor<'v> for BuildReducedGraphVisitor<'a, 'b> {
935937

936938
}
937939

938-
struct UnusedImportCheckVisitor<'a, 'b:'a> {
939-
resolver: &'a mut Resolver<'b>
940-
}
941-
942-
impl<'a, 'b, 'v> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b> {
943-
fn visit_view_item(&mut self, vi: &ViewItem) {
944-
self.resolver.check_for_item_unused_imports(vi);
945-
visit::walk_view_item(self, vi);
946-
}
947-
}
948-
949940
#[deriving(PartialEq)]
950941
enum FallbackChecks {
951942
Everything,
@@ -1006,22 +997,6 @@ impl<'a> Resolver<'a> {
1006997
emit_errors: true,
1007998
}
1008999
}
1009-
/// The main name resolution procedure.
1010-
fn resolve(&mut self, krate: &ast::Crate) {
1011-
self.build_reduced_graph(krate);
1012-
self.session.abort_if_errors();
1013-
1014-
self.resolve_imports();
1015-
self.session.abort_if_errors();
1016-
1017-
self.record_exports();
1018-
self.session.abort_if_errors();
1019-
1020-
self.resolve_crate(krate);
1021-
self.session.abort_if_errors();
1022-
1023-
self.check_for_unused_imports(krate);
1024-
}
10251000

10261001
//
10271002
// Reduced graph building
@@ -6068,119 +6043,6 @@ impl<'a> Resolver<'a> {
60686043
}
60696044
}
60706045

6071-
//
6072-
// Unused import checking
6073-
//
6074-
// Although this is mostly a lint pass, it lives in here because it depends on
6075-
// resolve data structures and because it finalises the privacy information for
6076-
// `use` directives.
6077-
//
6078-
6079-
fn check_for_unused_imports(&mut self, krate: &ast::Crate) {
6080-
let mut visitor = UnusedImportCheckVisitor{ resolver: self };
6081-
visit::walk_crate(&mut visitor, krate);
6082-
}
6083-
6084-
fn check_for_item_unused_imports(&mut self, vi: &ViewItem) {
6085-
// Ignore is_public import statements because there's no way to be sure
6086-
// whether they're used or not. Also ignore imports with a dummy span
6087-
// because this means that they were generated in some fashion by the
6088-
// compiler and we don't need to consider them.
6089-
if vi.vis == Public { return }
6090-
if vi.span == DUMMY_SP { return }
6091-
6092-
match vi.node {
6093-
ViewItemExternCrate(_, _, id) => {
6094-
if let Some(crate_num) = self.session.cstore.find_extern_mod_stmt_cnum(id) {
6095-
if !self.used_crates.contains(&crate_num) {
6096-
self.session.add_lint(lint::builtin::UNUSED_EXTERN_CRATES,
6097-
id,
6098-
vi.span,
6099-
"unused extern crate".to_string());
6100-
}
6101-
}
6102-
},
6103-
ViewItemUse(ref p) => {
6104-
match p.node {
6105-
ViewPathSimple(_, _, id) => self.finalize_import(id, p.span),
6106-
6107-
ViewPathList(_, ref list, _) => {
6108-
for i in list.iter() {
6109-
self.finalize_import(i.node.id(), i.span);
6110-
}
6111-
},
6112-
ViewPathGlob(_, id) => {
6113-
if !self.used_imports.contains(&(id, TypeNS)) &&
6114-
!self.used_imports.contains(&(id, ValueNS)) {
6115-
self.session
6116-
.add_lint(lint::builtin::UNUSED_IMPORTS,
6117-
id,
6118-
p.span,
6119-
"unused import".to_string());
6120-
}
6121-
},
6122-
}
6123-
}
6124-
}
6125-
}
6126-
6127-
// We have information about whether `use` (import) directives are actually used now.
6128-
// If an import is not used at all, we signal a lint error. If an import is only used
6129-
// for a single namespace, we remove the other namespace from the recorded privacy
6130-
// information. That means in privacy.rs, we will only check imports and namespaces
6131-
// which are used. In particular, this means that if an import could name either a
6132-
// public or private item, we will check the correct thing, dependent on how the import
6133-
// is used.
6134-
fn finalize_import(&mut self, id: NodeId, span: Span) {
6135-
debug!("finalizing import uses for {}",
6136-
self.session.codemap().span_to_snippet(span));
6137-
6138-
if !self.used_imports.contains(&(id, TypeNS)) &&
6139-
!self.used_imports.contains(&(id, ValueNS)) {
6140-
self.session.add_lint(lint::builtin::UNUSED_IMPORTS,
6141-
id,
6142-
span,
6143-
"unused import".to_string());
6144-
}
6145-
6146-
let (v_priv, t_priv) = match self.last_private.get(&id) {
6147-
Some(&LastImport {
6148-
value_priv: v,
6149-
value_used: _,
6150-
type_priv: t,
6151-
type_used: _
6152-
}) => (v, t),
6153-
Some(_) => {
6154-
panic!("we should only have LastImport for `use` directives")
6155-
}
6156-
_ => return,
6157-
};
6158-
6159-
let mut v_used = if self.used_imports.contains(&(id, ValueNS)) {
6160-
Used
6161-
} else {
6162-
Unused
6163-
};
6164-
let t_used = if self.used_imports.contains(&(id, TypeNS)) {
6165-
Used
6166-
} else {
6167-
Unused
6168-
};
6169-
6170-
match (v_priv, t_priv) {
6171-
// Since some items may be both in the value _and_ type namespaces (e.g., structs)
6172-
// we might have two LastPrivates pointing at the same thing. There is no point
6173-
// checking both, so lets not check the value one.
6174-
(Some(DependsOn(def_v)), Some(DependsOn(def_t))) if def_v == def_t => v_used = Unused,
6175-
_ => {},
6176-
}
6177-
6178-
self.last_private.insert(id, LastImport{value_priv: v_priv,
6179-
value_used: v_used,
6180-
type_priv: t_priv,
6181-
type_used: t_used});
6182-
}
6183-
61846046
//
61856047
// Diagnostics
61866048
//
@@ -6268,7 +6130,21 @@ pub fn resolve_crate(session: &Session,
62686130
krate: &Crate)
62696131
-> CrateMap {
62706132
let mut resolver = Resolver::new(session, krate.span);
6271-
resolver.resolve(krate);
6133+
6134+
resolver.build_reduced_graph(krate);
6135+
session.abort_if_errors();
6136+
6137+
resolver.resolve_imports();
6138+
session.abort_if_errors();
6139+
6140+
resolver.record_exports();
6141+
session.abort_if_errors();
6142+
6143+
resolver.resolve_crate(krate);
6144+
session.abort_if_errors();
6145+
6146+
check_unused::check_crate(&mut resolver, krate);
6147+
62726148
CrateMap {
62736149
def_map: resolver.def_map,
62746150
freevars: resolver.freevars,

0 commit comments

Comments
 (0)