2014-12-19 01:13:54 -06:00
|
|
|
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// Unused import checking
|
|
|
|
//
|
|
|
|
// Although this is mostly a lint pass, it lives in here because it depends on
|
|
|
|
// resolve data structures and because it finalises the privacy information for
|
|
|
|
// `use` directives.
|
|
|
|
//
|
|
|
|
|
2014-12-22 11:04:23 -06:00
|
|
|
use std::ops::{Deref, DerefMut};
|
|
|
|
|
2014-12-19 01:13:54 -06:00
|
|
|
use Resolver;
|
|
|
|
use Namespace::{TypeNS, ValueNS};
|
|
|
|
|
|
|
|
use rustc::lint;
|
|
|
|
use syntax::ast;
|
|
|
|
use syntax::codemap::{Span, DUMMY_SP};
|
2015-07-31 02:04:06 -05:00
|
|
|
|
|
|
|
use rustc_front::hir;
|
|
|
|
use rustc_front::hir::{ViewPathGlob, ViewPathList, ViewPathSimple};
|
2015-11-17 16:51:44 -06:00
|
|
|
use rustc_front::intravisit::Visitor;
|
2014-12-19 01:13:54 -06:00
|
|
|
|
2015-10-26 14:31:11 -05:00
|
|
|
struct UnusedImportCheckVisitor<'a, 'b: 'a, 'tcx: 'b> {
|
|
|
|
resolver: &'a mut Resolver<'b, 'tcx>,
|
2014-12-19 01:13:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver.
|
2015-01-01 13:53:20 -06:00
|
|
|
impl<'a, 'b, 'tcx:'b> Deref for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
|
|
|
|
type Target = Resolver<'b, 'tcx>;
|
|
|
|
|
2014-11-23 03:29:41 -06:00
|
|
|
fn deref<'c>(&'c self) -> &'c Resolver<'b, 'tcx> {
|
2014-12-19 01:13:54 -06:00
|
|
|
&*self.resolver
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-01 13:53:20 -06:00
|
|
|
impl<'a, 'b, 'tcx:'b> DerefMut for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
|
2014-11-23 03:29:41 -06:00
|
|
|
fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b, 'tcx> {
|
2014-12-19 01:13:54 -06:00
|
|
|
&mut *self.resolver
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-25 16:01:16 -06:00
|
|
|
impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
|
2015-10-26 14:31:11 -05:00
|
|
|
// We have information about whether `use` (import) directives are actually
|
|
|
|
// used now. If an import is not used at all, we signal a lint error. If an
|
|
|
|
// import is only used for a single namespace, we remove the other namespace
|
|
|
|
// from the recorded privacy information. That means in privacy.rs, we will
|
|
|
|
// only check imports and namespaces which are used. In particular, this
|
|
|
|
// means that if an import could name either a public or private item, we
|
|
|
|
// will check the correct thing, dependent on how the import is used.
|
2014-12-19 01:13:54 -06:00
|
|
|
fn finalize_import(&mut self, id: ast::NodeId, span: Span) {
|
2014-12-20 02:09:35 -06:00
|
|
|
debug!("finalizing import uses for {:?}",
|
2015-10-26 14:31:11 -05:00
|
|
|
self.session.codemap().span_to_snippet(span));
|
2014-12-19 01:13:54 -06:00
|
|
|
|
|
|
|
if !self.used_imports.contains(&(id, TypeNS)) &&
|
|
|
|
!self.used_imports.contains(&(id, ValueNS)) {
|
|
|
|
self.session.add_lint(lint::builtin::UNUSED_IMPORTS,
|
|
|
|
id,
|
|
|
|
span,
|
|
|
|
"unused import".to_string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-23 03:29:41 -06:00
|
|
|
impl<'a, 'b, 'v, 'tcx> Visitor<'v> for UnusedImportCheckVisitor<'a, 'b, 'tcx> {
|
2015-07-31 02:04:06 -05:00
|
|
|
fn visit_item(&mut self, item: &hir::Item) {
|
2014-12-19 01:13:54 -06:00
|
|
|
// Ignore is_public import statements because there's no way to be sure
|
|
|
|
// whether they're used or not. Also ignore imports with a dummy span
|
|
|
|
// because this means that they were generated in some fashion by the
|
|
|
|
// compiler and we don't need to consider them.
|
2016-01-29 00:33:14 -06:00
|
|
|
if item.vis == hir::Public || item.span.source_equal(&DUMMY_SP) {
|
2014-12-19 01:13:54 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-23 13:34:36 -06:00
|
|
|
match item.node {
|
2015-07-31 02:04:06 -05:00
|
|
|
hir::ItemExternCrate(_) => {
|
2015-11-21 13:39:05 -06:00
|
|
|
if let Some(crate_num) = self.session.cstore.extern_mod_stmt_cnum(item.id) {
|
2014-12-19 01:13:54 -06:00
|
|
|
if !self.used_crates.contains(&crate_num) {
|
|
|
|
self.session.add_lint(lint::builtin::UNUSED_EXTERN_CRATES,
|
2014-12-23 13:34:36 -06:00
|
|
|
item.id,
|
|
|
|
item.span,
|
2014-12-19 01:13:54 -06:00
|
|
|
"unused extern crate".to_string());
|
|
|
|
}
|
|
|
|
}
|
2015-10-26 14:31:11 -05:00
|
|
|
}
|
2015-07-31 02:04:06 -05:00
|
|
|
hir::ItemUse(ref p) => {
|
2014-12-19 01:13:54 -06:00
|
|
|
match p.node {
|
2014-12-23 13:34:36 -06:00
|
|
|
ViewPathSimple(_, _) => {
|
|
|
|
self.finalize_import(item.id, p.span)
|
2014-12-19 01:13:54 -06:00
|
|
|
}
|
|
|
|
|
2014-12-23 13:34:36 -06:00
|
|
|
ViewPathList(_, ref list) => {
|
2015-01-31 11:20:46 -06:00
|
|
|
for i in list {
|
2014-12-19 01:13:54 -06:00
|
|
|
self.finalize_import(i.node.id(), i.span);
|
|
|
|
}
|
|
|
|
}
|
2014-12-23 13:34:36 -06:00
|
|
|
ViewPathGlob(_) => {
|
|
|
|
if !self.used_imports.contains(&(item.id, TypeNS)) &&
|
|
|
|
!self.used_imports.contains(&(item.id, ValueNS)) {
|
2014-12-19 01:13:54 -06:00
|
|
|
self.session
|
|
|
|
.add_lint(lint::builtin::UNUSED_IMPORTS,
|
2014-12-23 13:34:36 -06:00
|
|
|
item.id,
|
2014-12-19 01:13:54 -06:00
|
|
|
p.span,
|
|
|
|
"unused import".to_string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-12-23 13:34:36 -06:00
|
|
|
_ => {}
|
2014-12-19 01:13:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-31 02:04:06 -05:00
|
|
|
pub fn check_crate(resolver: &mut Resolver, krate: &hir::Crate) {
|
2014-12-19 01:13:54 -06:00
|
|
|
let mut visitor = UnusedImportCheckVisitor { resolver: resolver };
|
2015-11-17 16:51:44 -06:00
|
|
|
krate.visit_all_items(&mut visitor);
|
2014-12-19 01:13:54 -06:00
|
|
|
}
|