Skip to content

Commit bcf3418

Browse files
committed
Improve unused_extern_crate warnings.
1 parent 6fe2371 commit bcf3418

File tree

5 files changed

+41
-31
lines changed

5 files changed

+41
-31
lines changed

src/librustc_resolve/build_reduced_graph.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ impl<'a> Resolver<'a> {
246246
// n.b. we don't need to look at the path option here, because cstore already did
247247
let crate_id = self.session.cstore.extern_mod_stmt_cnum(item.id).unwrap();
248248
let module = self.get_extern_crate_root(crate_id);
249+
self.populate_module_if_necessary(module);
250+
let used = self.process_legacy_macro_imports(item, module, expansion);
249251
let binding =
250252
(module, ty::Visibility::Public, sp, expansion).to_name_binding(self.arenas);
251253
let directive = self.arenas.alloc_import_directive(ImportDirective {
@@ -257,11 +259,11 @@ impl<'a> Resolver<'a> {
257259
module_path: Vec::new(),
258260
vis: Cell::new(vis),
259261
expansion: expansion,
262+
used: Cell::new(used),
260263
});
264+
self.potentially_unused_imports.push(directive);
261265
let imported_binding = self.import(binding, directive);
262266
self.define(parent, ident, TypeNS, imported_binding);
263-
self.populate_module_if_necessary(module);
264-
self.process_legacy_macro_imports(item, module, expansion);
265267
}
266268

267269
ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
@@ -519,7 +521,6 @@ impl<'a> Resolver<'a> {
519521
binding: &'a NameBinding<'a>,
520522
span: Span,
521523
allow_shadowing: bool) {
522-
self.used_crates.insert(binding.def().def_id().krate);
523524
self.macro_names.insert(name);
524525
if self.builtin_macros.insert(name, binding).is_some() && !allow_shadowing {
525526
let msg = format!("`{}` is already in scope", name);
@@ -529,22 +530,23 @@ impl<'a> Resolver<'a> {
529530
}
530531
}
531532

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

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

550552
if let Some(span) = legacy_imports.import_all {
@@ -563,9 +565,7 @@ impl<'a> Resolver<'a> {
563565
}
564566
}
565567
for (name, span) in legacy_imports.reexports {
566-
let krate = module.def_id().unwrap().krate;
567-
self.used_crates.insert(krate);
568-
self.session.cstore.export_macros(krate);
568+
self.session.cstore.export_macros(module.def_id().unwrap().krate);
569569
let ident = Ident::with_empty_ctxt(name);
570570
let result = self.resolve_ident_in_module(module, ident, MacroNS, false, None);
571571
if let Ok(binding) = result {
@@ -574,6 +574,7 @@ impl<'a> Resolver<'a> {
574574
span_err!(self.session, span, E0470, "reexported macro not found");
575575
}
576576
}
577+
used
577578
}
578579

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

src/librustc_resolve/check_unused.rs

Lines changed: 16 additions & 11 deletions
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

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,7 +1098,6 @@ pub struct Resolver<'a> {
10981098
pub glob_map: GlobMap,
10991099

11001100
used_imports: FxHashSet<(NodeId, Namespace)>,
1101-
used_crates: FxHashSet<CrateNum>,
11021101
pub maybe_unused_trait_imports: NodeSet,
11031102

11041103
privacy_errors: Vec<PrivacyError<'a>>,
@@ -1123,6 +1122,8 @@ pub struct Resolver<'a> {
11231122

11241123
// Avoid duplicated errors for "name already defined".
11251124
name_already_seen: FxHashMap<Name, Span>,
1125+
1126+
potentially_unused_imports: Vec<&'a ImportDirective<'a>>,
11261127
}
11271128

11281129
pub struct ResolverArenas<'a> {
@@ -1270,7 +1271,6 @@ impl<'a> Resolver<'a> {
12701271
glob_map: NodeMap(),
12711272

12721273
used_imports: FxHashSet(),
1273-
used_crates: FxHashSet(),
12741274
maybe_unused_trait_imports: NodeSet(),
12751275

12761276
privacy_errors: Vec::new(),
@@ -1296,6 +1296,7 @@ impl<'a> Resolver<'a> {
12961296
invocations: invocations,
12971297
name_already_seen: FxHashMap(),
12981298
whitelisted_legacy_custom_derives: Vec::new(),
1299+
potentially_unused_imports: Vec::new(),
12991300
}
13001301
}
13011302

@@ -1341,15 +1342,11 @@ impl<'a> Resolver<'a> {
13411342

13421343
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
13431344
-> bool /* true if an error was reported */ {
1344-
// track extern crates for unused_extern_crate lint
1345-
if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleData::def_id) {
1346-
self.used_crates.insert(krate);
1347-
}
1348-
13491345
match binding.kind {
13501346
NameBindingKind::Import { directive, binding, ref used, legacy_self_import }
13511347
if !used.get() => {
13521348
used.set(true);
1349+
directive.used.set(true);
13531350
if legacy_self_import {
13541351
self.warn_legacy_self_import(directive);
13551352
return false;

src/librustc_resolve/resolve_imports.rs

Lines changed: 2 additions & 0 deletions
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

Lines changed: 5 additions & 0 deletions
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)