blob: 3084d9abbe1e4f8cab3a93f271145c4ad03a8f9e [file] [log] [blame]
// 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.
//
// Unused trait imports can't be checked until the method resolution. We save
// candidates here, and do the acutal check in librustc_typeck/check_unused.rs.
use std::ops::{Deref, DerefMut};
use Resolver;
use Namespace::{TypeNS, ValueNS};
use rustc::lint;
use syntax::ast::{self, ViewPathGlob, ViewPathList, ViewPathSimple};
use syntax::visit::{self, Visitor};
use syntax_pos::{Span, DUMMY_SP};
struct UnusedImportCheckVisitor<'a, 'b: 'a> {
resolver: &'a mut Resolver<'b>,
}
// Deref and DerefMut impls allow treating UnusedImportCheckVisitor as Resolver.
impl<'a, 'b> Deref for UnusedImportCheckVisitor<'a, 'b> {
type Target = Resolver<'b>;
fn deref<'c>(&'c self) -> &'c Resolver<'b> {
&*self.resolver
}
}
impl<'a, 'b> DerefMut for UnusedImportCheckVisitor<'a, 'b> {
fn deref_mut<'c>(&'c mut self) -> &'c mut Resolver<'b> {
&mut *self.resolver
}
}
impl<'a, 'b> UnusedImportCheckVisitor<'a, 'b> {
// 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.
fn check_import(&mut self, id: ast::NodeId, span: Span) {
if !self.used_imports.contains(&(id, TypeNS)) &&
!self.used_imports.contains(&(id, ValueNS)) {
if self.maybe_unused_trait_imports.contains(&id) {
// Check later.
return;
}
self.session.add_lint(lint::builtin::UNUSED_IMPORTS,
id,
span,
"unused import".to_string());
} else {
// This trait import is definitely used, in a way other than
// method resolution.
self.maybe_unused_trait_imports.remove(&id);
}
}
}
impl<'a, 'b> Visitor for UnusedImportCheckVisitor<'a, 'b> {
fn visit_item(&mut self, item: &ast::Item) {
visit::walk_item(self, item);
// 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.
if item.vis == ast::Visibility::Public || item.span.source_equal(&DUMMY_SP) {
return;
}
match item.node {
ast::ItemKind::ExternCrate(_) => {
if let Some(crate_num) = self.session.cstore.extern_mod_stmt_cnum(item.id) {
if !self.used_crates.contains(&crate_num) {
self.session.add_lint(lint::builtin::UNUSED_EXTERN_CRATES,
item.id,
item.span,
"unused extern crate".to_string());
}
}
}
ast::ItemKind::Use(ref p) => {
match p.node {
ViewPathSimple(_, _) => {
self.check_import(item.id, p.span)
}
ViewPathList(_, ref list) => {
for i in list {
self.check_import(i.node.id(), i.span);
}
}
ViewPathGlob(_) => {
self.check_import(item.id, p.span)
}
}
}
_ => {}
}
}
}
pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) {
let mut visitor = UnusedImportCheckVisitor { resolver: resolver };
visit::walk_crate(&mut visitor, krate);
}