Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lint unused extern crate #17134

Merged
merged 2 commits into from
Sep 12, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/librustc/lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1525,6 +1525,9 @@ impl LintPass for Stability {
declare_lint!(pub UNUSED_IMPORTS, Warn,
"imports that are never used")

declare_lint!(pub UNUSED_EXTERN_CRATE, Allow,
"extern crates that are never used")

declare_lint!(pub UNNECESSARY_QUALIFICATION, Allow,
"detects unnecessarily qualified names")

Expand Down Expand Up @@ -1569,6 +1572,7 @@ impl LintPass for HardwiredLints {
fn get_lints(&self) -> LintArray {
lint_array!(
UNUSED_IMPORTS,
UNUSED_EXTERN_CRATE,
UNNECESSARY_QUALIFICATION,
UNRECOGNIZED_LINT,
UNUSED_VARIABLE,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/lint/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ impl LintStore {

add_lint_group!(sess, "unused",
UNUSED_IMPORTS, UNUSED_VARIABLE, DEAD_ASSIGNMENT, DEAD_CODE,
UNUSED_MUT, UNREACHABLE_CODE)
UNUSED_MUT, UNREACHABLE_CODE, UNUSED_EXTERN_CRATE)

// We have one lint pass defined in this module.
self.register_pass(sess, false, box GatherNodeLevels as LintPassObject);
Expand Down
65 changes: 63 additions & 2 deletions src/librustc/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use middle::subst::{ParamSpace, FnSpace, TypeSpace};
use middle::ty::{ExplicitSelfCategory, StaticExplicitSelfCategory};
use util::nodemap::{NodeMap, DefIdSet, FnvHashMap};

use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate};
use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum};
use syntax::ast::{DeclItem, DefId, Expr, ExprAgain, ExprBreak, ExprField};
use syntax::ast::{ExprFnBlock, ExprForLoop, ExprLoop, ExprWhile, ExprMethodCall};
use syntax::ast::{ExprPath, ExprProc, ExprStruct, ExprUnboxedFn, FnDecl};
Expand Down Expand Up @@ -899,6 +899,7 @@ struct Resolver<'a> {
emit_errors: bool,

used_imports: HashSet<(NodeId, Namespace)>,
used_crates: HashSet<CrateNum>,
}

struct BuildReducedGraphVisitor<'a, 'b:'a> {
Expand Down Expand Up @@ -987,6 +988,7 @@ impl<'a> Resolver<'a> {
export_map2: RefCell::new(NodeMap::new()),
trait_map: NodeMap::new(),
used_imports: HashSet::new(),
used_crates: HashSet::new(),
external_exports: DefIdSet::new(),
last_private: NodeMap::new(),

Expand Down Expand Up @@ -2453,7 +2455,14 @@ impl<'a> Resolver<'a> {
debug!("(resolving single import) found \
import in ns {:?}", namespace);
let id = import_resolution.id(namespace);
// track used imports and extern crates as well
this.used_imports.insert((id, namespace));
match target_module.def_id.get() {
Some(DefId{krate: kid, ..}) => {
this.used_crates.insert(kid);
},
_ => {}
}
return BoundResult(target_module, bindings);
}
}
Expand Down Expand Up @@ -2496,6 +2505,11 @@ impl<'a> Resolver<'a> {
Some(module) => {
debug!("(resolving single import) found external \
module");
// track the module as used.
match module.def_id.get() {
Some(DefId{krate: kid, ..}) => { self.used_crates.insert(kid); },
_ => {}
}
let name_bindings =
Rc::new(Resolver::create_name_bindings_from_module(
module));
Expand Down Expand Up @@ -3030,6 +3044,14 @@ impl<'a> Resolver<'a> {
(_, _) => {
search_module = module_def.clone();

// track extern crates for unused_extern_crate lint
match module_def.def_id.get() {
Some(did) => {
self.used_crates.insert(did.krate);
}
_ => {}
}

// Keep track of the closest
// private module used when
// resolving this import chain.
Expand Down Expand Up @@ -3213,7 +3235,12 @@ impl<'a> Resolver<'a> {
Some(target) => {
debug!("(resolving item in lexical scope) using \
import resolution");
// track used imports and extern crates as well
self.used_imports.insert((import_resolution.id(namespace), namespace));
match target.target_module.def_id.get() {
Some(DefId{krate: kid, ..}) => { self.used_crates.insert(kid); },
_ => {}
}
return Success((target, false));
}
}
Expand Down Expand Up @@ -3492,7 +3519,12 @@ impl<'a> Resolver<'a> {
Some(target) => {
debug!("(resolving name in module) resolved to \
import");
// track used imports and extern crates as well
self.used_imports.insert((import_resolution.id(namespace), namespace));
match target.target_module.def_id.get() {
Some(DefId{krate: kid, ..}) => { self.used_crates.insert(kid); },
_ => {}
}
return Success((target, true));
}
}
Expand Down Expand Up @@ -5061,7 +5093,14 @@ impl<'a> Resolver<'a> {
Some(def) => {
// Found it.
let id = import_resolution.id(namespace);
// track imports and extern crates as well
self.used_imports.insert((id, namespace));
match target.target_module.def_id.get() {
Some(DefId{krate: kid, ..}) => {
self.used_crates.insert(kid);
},
_ => {}
}
return ImportNameDefinition(def, LastMod(AllPublic));
}
None => {
Expand All @@ -5085,6 +5124,8 @@ impl<'a> Resolver<'a> {
match module.def_id.get() {
None => {} // Continue.
Some(def_id) => {
// track used crates
self.used_crates.insert(def_id.krate);
let lp = if module.is_public {LastMod(AllPublic)} else {
LastMod(DependsOn(def_id))
};
Expand Down Expand Up @@ -5168,6 +5209,10 @@ impl<'a> Resolver<'a> {
},
_ => (),
}
match containing_module.def_id.get() {
Some(DefId{krate: kid, ..}) => { self.used_crates.insert(kid); },
_ => {}
}
return Some(def);
}

Expand Down Expand Up @@ -5787,6 +5832,10 @@ impl<'a> Resolver<'a> {
if self.trait_item_map.borrow().contains_key(&(name, did)) {
add_trait_info(&mut found_traits, did, name);
self.used_imports.insert((import.type_id, TypeNS));
match target.target_module.def_id.get() {
Some(DefId{krate: kid, ..}) => { self.used_crates.insert(kid); },
_ => {}
}
}
}

Expand Down Expand Up @@ -5859,10 +5908,22 @@ impl<'a> Resolver<'a> {
if vi.span == DUMMY_SP { return }

match vi.node {
ViewItemExternCrate(..) => {} // ignore
ViewItemExternCrate(_, _, id) => {
match self.session.cstore.find_extern_mod_stmt_cnum(id)
{
Some(crate_num) => if !self.used_crates.contains(&crate_num) {
self.session.add_lint(lint::builtin::UNUSED_EXTERN_CRATE,
id,
vi.span,
"unused extern crate".to_string());
},
_ => {}
}
},
ViewItemUse(ref p) => {
match p.node {
ViewPathSimple(_, _, id) => self.finalize_import(id, p.span),

ViewPathList(_, ref list, _) => {
for i in list.iter() {
self.finalize_import(i.node.id(), i.span);
Expand Down
2 changes: 0 additions & 2 deletions src/librustc_back/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@
#[phase(plugin, link)]
extern crate log;
extern crate syntax;
extern crate libc;
extern crate flate;
extern crate serialize;

pub mod abi;
Expand Down
2 changes: 0 additions & 2 deletions src/libsyntax/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate libc;

use codemap::{Pos, Span};
use codemap;
use diagnostics;
Expand Down
32 changes: 32 additions & 0 deletions src/test/compile-fail/lint-unused-extern-crate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 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.

#![feature(globs)]
#![deny(unused_extern_crate)]
#![allow(unused_variable)]

extern crate libc; //~ ERROR: unused extern crate

extern crate "collections" as collecs; // no error, it is used

extern crate rand; // no error, the use marks it as used
// even if imported objects aren't used

extern crate time; // no error, the use * marks it as used

#[allow(unused_imports)]
use rand::isaac::IsaacRng;

use time::*;

fn main() {
let x: collecs::vec::Vec<uint> = Vec::new();
let y = now();
}