Skip to content

Commit 2efec3c

Browse files
committed
Improve unused_extern_crate warnings.
1 parent 633f38a commit 2efec3c

File tree

5 files changed

+41
-31
lines changed

5 files changed

+41
-31
lines changed

src/librustc_resolve/build_reduced_graph.rs

+14-13
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,8 @@ impl<'a> Resolver<'a> {
249249
// n.b. we don't need to look at the path option here, because cstore already did
250250
let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id).unwrap();
251251
let module = self.get_extern_crate_root(crate_id);
252+
self.populate_module_if_necessary(module);
253+
let used = self.process_legacy_macro_imports(item, module, expansion);
252254
let binding =
253255
(module, ty::Visibility::Public, sp, expansion).to_name_binding(self.arenas);
254256
let directive = self.arenas.alloc_import_directive(ImportDirective {
@@ -260,11 +262,11 @@ impl<'a> Resolver<'a> {
260262
module_path: Vec::new(),
261263
vis: Cell::new(vis),
262264
expansion: expansion,
265+
used: Cell::new(used),
263266
});
267+
self.potentially_unused_imports.push(directive);
264268
let imported_binding = self.import(binding, directive);
265269
self.define(parent, ident, TypeNS, imported_binding);
266-
self.populate_module_if_necessary(module);
267-
self.process_legacy_macro_imports(item, module, expansion);
268270
}
269271

270272
ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
@@ -522,7 +524,6 @@ impl<'a> Resolver<'a> {
522524
binding: &'a NameBinding<'a>,
523525
span: Span,
524526
allow_shadowing: bool) {
525-
self.used_crates.insert(binding.def().def_id().krate);
526527
self.macro_names.insert(name);
527528
if self.builtin_macros.insert(name, binding).is_some() && !allow_shadowing {
528529
let msg = format!("`{}` is already in scope", name);
@@ -532,22 +533,23 @@ impl<'a> Resolver<'a> {
532533
}
533534
}
534535

535-
fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>, expansion: Mark) {
536+
// This returns true if we should consider the underlying `extern crate` to be used.
537+
fn process_legacy_macro_imports(&mut self, item: &Item, module: Module<'a>, expansion: Mark)
538+
-> bool {
536539
let allow_shadowing = expansion == Mark::root();
537540
let legacy_imports = self.legacy_macro_imports(&item.attrs);
538-
let cnum = module.def_id().unwrap().krate;
541+
let mut used = legacy_imports != LegacyMacroImports::default();
539542

540543
// `#[macro_use]` and `#[macro_reexport]` are only allowed at the crate root.
541-
if self.current_module.parent.is_some() && legacy_imports != LegacyMacroImports::default() {
544+
if self.current_module.parent.is_some() && used {
542545
span_err!(self.session, item.span, E0468,
543546
"an `extern crate` loading macros must be at the crate root");
544-
} else if !self.use_extern_macros &&
545-
self.session.cstore.dep_kind(cnum).macros_only() &&
546-
legacy_imports == LegacyMacroImports::default() {
547+
} else if !self.use_extern_macros && !used &&
548+
self.session.cstore.dep_kind(module.def_id().unwrap().krate).macros_only() {
547549
let msg = "custom derive crates and `#[no_link]` crates have no effect without \
548550
`#[macro_use]`";
549551
self.session.span_warn(item.span, msg);
550-
self.used_crates.insert(cnum); // Avoid the normal unused extern crate warning
552+
used = true; // Avoid the normal unused extern crate warning
551553
}
552554

553555
if let Some(span) = legacy_imports.import_all {
@@ -566,9 +568,7 @@ impl<'a> Resolver<'a> {
566568
}
567569
}
568570
for (name, span) in legacy_imports.reexports {
569-
let krate = module.def_id().unwrap().krate;
570-
self.used_crates.insert(krate);
571-
self.session.cstore.export_macros(krate);
571+
self.session.cstore.export_macros(module.def_id().unwrap().krate);
572572
let ident = Ident::with_empty_ctxt(name);
573573
let result = self.resolve_ident_in_module(module, ident, MacroNS, false, None);
574574
if let Ok(binding) = result {
@@ -577,6 +577,7 @@ impl<'a> Resolver<'a> {
577577
span_err!(self.session, span, E0470, "reexported macro not found");
578578
}
579579
}
580+
used
580581
}
581582

582583
// does this attribute list contain "macro_use"?

src/librustc_resolve/check_unused.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222
use std::ops::{Deref, DerefMut};
2323

2424
use Resolver;
25+
use resolve_imports::ImportDirectiveSubclass;
2526

26-
use rustc::lint;
27+
use rustc::{lint, ty};
2728
use rustc::util::nodemap::NodeMap;
2829
use syntax::ast::{self, ViewPathGlob, ViewPathList, ViewPathSimple};
2930
use syntax::visit::{self, Visitor};
@@ -86,16 +87,6 @@ impl<'a, 'b> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b> {
8687
}
8788

8889
match item.node {
89-
ast::ItemKind::ExternCrate(_) => {
90-
if let Some(crate_num) = self.session.cstore.extern_mod_stmt_cnum(item.id) {
91-
if !self.used_crates.contains(&crate_num) {
92-
self.session.add_lint(lint::builtin::UNUSED_EXTERN_CRATES,
93-
item.id,
94-
item.span,
95-
"unused extern crate".to_string());
96-
}
97-
}
98-
}
9990
ast::ItemKind::Use(ref p) => {
10091
match p.node {
10192
ViewPathSimple(..) => {
@@ -124,6 +115,20 @@ impl<'a, 'b> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b> {
124115
}
125116

126117
pub fn check_crate(resolver: &mut Resolver, krate: &ast::Crate) {
118+
for directive in resolver.potentially_unused_imports.iter() {
119+
match directive.subclass {
120+
_ if directive.used.get() ||
121+
directive.vis.get() == ty::Visibility::Public ||
122+
directive.span.source_equal(&DUMMY_SP) => {}
123+
ImportDirectiveSubclass::ExternCrate => {
124+
let lint = lint::builtin::UNUSED_EXTERN_CRATES;
125+
let msg = "unused extern crate".to_string();
126+
resolver.session.add_lint(lint, directive.id, directive.span, msg);
127+
}
128+
_ => {}
129+
}
130+
}
131+
127132
let mut visitor = UnusedImportCheckVisitor {
128133
resolver: resolver,
129134
unused_imports: NodeMap(),

src/librustc_resolve/lib.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -1099,7 +1099,6 @@ pub struct Resolver<'a> {
10991099
pub glob_map: GlobMap,
11001100

11011101
used_imports: FxHashSet<(NodeId, Namespace)>,
1102-
used_crates: FxHashSet<CrateNum>,
11031102
pub maybe_unused_trait_imports: NodeSet,
11041103

11051104
privacy_errors: Vec<PrivacyError<'a>>,
@@ -1130,6 +1129,8 @@ pub struct Resolver<'a> {
11301129

11311130
// A set of procedural macros imported by `#[macro_use]` that have already been warned about
11321131
warned_proc_macros: FxHashSet<Name>,
1132+
1133+
potentially_unused_imports: Vec<&'a ImportDirective<'a>>,
11331134
}
11341135

11351136
pub struct ResolverArenas<'a> {
@@ -1279,7 +1280,6 @@ impl<'a> Resolver<'a> {
12791280
glob_map: NodeMap(),
12801281

12811282
used_imports: FxHashSet(),
1282-
used_crates: FxHashSet(),
12831283
maybe_unused_trait_imports: NodeSet(),
12841284

12851285
privacy_errors: Vec::new(),
@@ -1309,6 +1309,7 @@ impl<'a> Resolver<'a> {
13091309
whitelisted_legacy_custom_derives: Vec::new(),
13101310
proc_macro_enabled: features.proc_macro,
13111311
warned_proc_macros: FxHashSet(),
1312+
potentially_unused_imports: Vec::new(),
13121313
}
13131314
}
13141315

@@ -1354,15 +1355,11 @@ impl<'a> Resolver<'a> {
13541355

13551356
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
13561357
-> bool /* true if an error was reported */ {
1357-
// track extern crates for unused_extern_crate lint
1358-
if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleData::def_id) {
1359-
self.used_crates.insert(krate);
1360-
}
1361-
13621358
match binding.kind {
13631359
NameBindingKind::Import { directive, binding, ref used, legacy_self_import }
13641360
if !used.get() => {
13651361
used.set(true);
1362+
directive.used.set(true);
13661363
if legacy_self_import {
13671364
self.warn_legacy_self_import(directive);
13681365
return false;

src/librustc_resolve/resolve_imports.rs

+2
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub struct ImportDirective<'a> {
6262
pub span: Span,
6363
pub vis: Cell<ty::Visibility>,
6464
pub expansion: Mark,
65+
pub used: Cell<bool>,
6566
}
6667

6768
impl<'a> ImportDirective<'a> {
@@ -257,6 +258,7 @@ impl<'a> Resolver<'a> {
257258
id: id,
258259
vis: Cell::new(vis),
259260
expansion: expansion,
261+
used: Cell::new(false),
260262
});
261263

262264
self.indeterminate_imports.push(directive);

src/test/compile-fail/lint-unused-extern-crate.rs

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ use rand::isaac::IsaacRng;
3333

3434
use other::*;
3535

36+
mod foo {
37+
// Test that this is unused even though an earler `extern crate rand` is used.
38+
extern crate rand; //~ ERROR unused extern crate
39+
}
40+
3641
fn main() {
3742
let x: collecs::vec::Vec<usize> = Vec::new();
3843
let y = foo();

0 commit comments

Comments
 (0)