From d5010ecf4465f587a50f7572f0ea8204ac5e6378 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 23 May 2018 19:25:59 -0400 Subject: [PATCH 1/3] extend `unused_extern_crates` lint with a suggestion to remove --- src/librustc_typeck/check_unused.rs | 4 ++- .../extern-crate-idiomatic-in-2018.fixed | 36 +++++++++++++++++++ .../extern-crate-idiomatic-in-2018.rs | 36 +++++++++++++++++++ .../extern-crate-idiomatic-in-2018.stderr | 14 ++++++++ 4 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed create mode 100644 src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs create mode 100644 src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index bff849d7ae8e9..b5772df1306ed 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -109,6 +109,8 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let id = tcx.hir.hir_to_node_id(hir_id); let lint = lint::builtin::UNUSED_EXTERN_CRATES; let msg = "unused extern crate"; - tcx.lint_node(lint, id, span, msg); + tcx.struct_span_lint_node(lint, id, span, msg) + .span_suggestion_short(span, "remove it", "".to_string()) + .emit(); } } diff --git a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed new file mode 100644 index 0000000000000..d8bf656cf2dd6 --- /dev/null +++ b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed @@ -0,0 +1,36 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:edition-lint-paths.rs +// run-rustfix +// compile-flags:--edition 2018 + +// The "normal case". Ideally we would remove the `extern crate` here, +// but we don't. + +#![feature(rust_2018_preview)] +#![deny(absolute_path_not_starting_with_crate)] +#![deny(unused_extern_crates)] +#![allow(dead_code)] + + +//~^ ERROR unused extern crate + +extern crate edition_lint_paths as bar; + +fn main() { + // This is not considered to *use* the `extern crate` in Rust 2018: + use edition_lint_paths::foo; + foo(); + + // But this should be a use of the (renamed) crate: + crate::bar::foo(); +} + diff --git a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs new file mode 100644 index 0000000000000..6e741257d8089 --- /dev/null +++ b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs @@ -0,0 +1,36 @@ +// Copyright 2018 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:edition-lint-paths.rs +// run-rustfix +// compile-flags:--edition 2018 + +// The "normal case". Ideally we would remove the `extern crate` here, +// but we don't. + +#![feature(rust_2018_preview)] +#![deny(absolute_path_not_starting_with_crate)] +#![deny(unused_extern_crates)] +#![allow(dead_code)] + +extern crate edition_lint_paths; +//~^ ERROR unused extern crate + +extern crate edition_lint_paths as bar; + +fn main() { + // This is not considered to *use* the `extern crate` in Rust 2018: + use edition_lint_paths::foo; + foo(); + + // But this should be a use of the (renamed) crate: + crate::bar::foo(); +} + diff --git a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr new file mode 100644 index 0000000000000..8fae69e8bd5a3 --- /dev/null +++ b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr @@ -0,0 +1,14 @@ +error: unused extern crate + --> $DIR/extern-crate-idiomatic-in-2018.rs:23:1 + | +LL | extern crate edition_lint_paths; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + | +note: lint level defined here + --> $DIR/extern-crate-idiomatic-in-2018.rs:20:9 + | +LL | #![deny(unused_extern_crates)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From 8b39808ffebbd185f0aae5bb0f14a9d09950b519 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 25 May 2018 16:53:49 -0400 Subject: [PATCH 2/3] merge UNNECESSARY_EXTERN_CRATE and UNUSED_EXTERN_CRATES --- src/librustc/hir/lowering.rs | 4 +- src/librustc/hir/map/collector.rs | 2 +- src/librustc/hir/mod.rs | 6 +- src/librustc/hir/print.rs | 20 +- src/librustc/ich/impls_hir.rs | 9 +- src/librustc/ty/mod.rs | 2 +- src/librustc_lint/builtin.rs | 66 ------ src/librustc_lint/lib.rs | 3 +- src/librustc_typeck/check_unused.rs | 223 +++++++++++++----- src/librustdoc/clean/mod.rs | 2 +- .../edition-extern-crate-allowed.rs | 3 +- .../ui-fulldeps/unnecessary-extern-crate.rs | 84 +++++-- .../unnecessary-extern-crate.stderr | 108 ++++++--- .../rfc-2166-underscore-imports/basic.stderr | 2 +- .../extern-crate-idiomatic-in-2018.fixed | 6 +- .../extern-crate-idiomatic-in-2018.rs | 4 +- .../extern-crate-idiomatic-in-2018.stderr | 17 +- .../suggestions/removing-extern-crate.fixed | 6 +- .../suggestions/removing-extern-crate.stderr | 24 +- 19 files changed, 365 insertions(+), 226 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index f816ba9ab8143..1e48a54e018d6 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2433,7 +2433,7 @@ impl<'a> LoweringContext<'a> { self.with_hir_id_owner(new_id, |this| { let vis = match vis { hir::Visibility::Public => hir::Visibility::Public, - hir::Visibility::Crate => hir::Visibility::Crate, + hir::Visibility::Crate(sugar) => hir::Visibility::Crate(sugar), hir::Visibility::Inherited => hir::Visibility::Inherited, hir::Visibility::Restricted { ref path, id: _ } => { hir::Visibility::Restricted { @@ -3704,7 +3704,7 @@ impl<'a> LoweringContext<'a> { ) -> hir::Visibility { match v.node { VisibilityKind::Public => hir::Public, - VisibilityKind::Crate(..) => hir::Visibility::Crate, + VisibilityKind::Crate(sugar) => hir::Visibility::Crate(sugar), VisibilityKind::Restricted { ref path, id, .. } => hir::Visibility::Restricted { path: P(self.lower_path(id, path, ParamMode::Explicit)), id: if let Some(owner) = explicit_owner { diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 13df1ced6032e..7835d4e782c43 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -463,7 +463,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { fn visit_vis(&mut self, visibility: &'hir Visibility) { match *visibility { Visibility::Public | - Visibility::Crate | + Visibility::Crate(_) | Visibility::Inherited => {} Visibility::Restricted { id, .. } => { self.insert(id, NodeVisibility(visibility)); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index ebc59964172ac..b7c66398f8500 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -35,7 +35,7 @@ use mir::mono::Linkage; use syntax_pos::{Span, DUMMY_SP}; use syntax::codemap::{self, Spanned}; use rustc_target::spec::abi::Abi; -use syntax::ast::{self, Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect}; +use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect}; use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem}; use syntax::attr::InlineAttr; use syntax::ext::hygiene::SyntaxContext; @@ -1953,7 +1953,7 @@ pub struct PolyTraitRef { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Visibility { Public, - Crate, + Crate(CrateSugar), Restricted { path: P, id: NodeId }, Inherited, } @@ -1964,7 +1964,7 @@ impl Visibility { match self { &Public | &Inherited => false, - &Crate | + &Crate(_) | &Restricted { .. } => true, } } diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 4bee4f9add025..2cf627fdc162f 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -801,15 +801,25 @@ impl<'a> State<'a> { pub fn print_visibility(&mut self, vis: &hir::Visibility) -> io::Result<()> { match *vis { - hir::Public => self.word_nbsp("pub"), - hir::Visibility::Crate => self.word_nbsp("pub(crate)"), + hir::Public => self.word_nbsp("pub")?, + hir::Visibility::Crate(ast::CrateSugar::JustCrate) => self.word_nbsp("crate")?, + hir::Visibility::Crate(ast::CrateSugar::PubCrate) => self.word_nbsp("pub(crate)")?, hir::Visibility::Restricted { ref path, .. } => { self.s.word("pub(")?; - self.print_path(path, false)?; - self.word_nbsp(")") + if path.segments.len() == 1 && path.segments[0].name == keywords::Super.name() { + // Special case: `super` can print like `pub(super)`. + self.s.word("super")?; + } else { + // Everything else requires `in` at present. + self.word_nbsp("in")?; + self.print_path(path, false)?; + } + self.word_nbsp(")")?; } - hir::Inherited => Ok(()), + hir::Inherited => () } + + Ok(()) } pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) -> io::Result<()> { diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 9b202f55f3c0a..397638fc55d4b 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -751,6 +751,11 @@ impl_stable_hash_for!(enum hir::ImplItemKind { Type(t) }); +impl_stable_hash_for!(enum ::syntax::ast::CrateSugar { + JustCrate, + PubCrate, +}); + impl<'a> HashStable> for hir::Visibility { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, @@ -758,10 +763,12 @@ impl<'a> HashStable> for hir::Visibility { mem::discriminant(self).hash_stable(hcx, hasher); match *self { hir::Visibility::Public | - hir::Visibility::Crate | hir::Visibility::Inherited => { // No fields to hash. } + hir::Visibility::Crate(sugar) => { + sugar.hash_stable(hcx, hasher); + } hir::Visibility::Restricted { ref path, id } => { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { id.hash_stable(hcx, hasher); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 646c60c139c85..419bffcae0643 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -270,7 +270,7 @@ impl Visibility { pub fn from_hir(visibility: &hir::Visibility, id: NodeId, tcx: TyCtxt) -> Self { match *visibility { hir::Public => Visibility::Public, - hir::Visibility::Crate => Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)), + hir::Visibility::Crate(_) => Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)), hir::Visibility::Restricted { ref path, .. } => match path.def { // If there is no resolution, `resolve` will have already reported an error, so // assume that the visibility is public to avoid reporting more privacy errors. diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 8a0850595c889..79c7a79114761 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1548,72 +1548,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedBrokenConst { } } -declare_lint! { - pub UNNECESSARY_EXTERN_CRATES, - Allow, - "suggest removing `extern crate` for the 2018 edition" -} - -pub struct ExternCrate(/* depth */ u32); - -impl ExternCrate { - pub fn new() -> Self { - ExternCrate(0) - } -} - -impl LintPass for ExternCrate { - fn get_lints(&self) -> LintArray { - lint_array!(UNNECESSARY_EXTERN_CRATES) - } -} - -impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExternCrate { - fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { - if !cx.tcx.features().extern_absolute_paths { - return - } - if let hir::ItemExternCrate(ref orig) = it.node { - if it.attrs.iter().any(|a| a.check_name("macro_use")) { - return - } - let mut err = cx.struct_span_lint(UNNECESSARY_EXTERN_CRATES, - it.span, "`extern crate` is unnecessary in the new edition"); - if it.vis == hir::Visibility::Public || self.0 > 1 || orig.is_some() { - let pub_ = if it.vis == hir::Visibility::Public { - "pub " - } else { - "" - }; - - let help = format!("use `{}use`", pub_); - - if let Some(orig) = orig { - err.span_suggestion(it.span, &help, - format!("{}use {} as {};", pub_, orig, it.name)); - } else { - err.span_suggestion(it.span, &help, - format!("{}use {};", pub_, it.name)); - } - } else { - err.span_suggestion(it.span, "remove it", "".into()); - } - - err.emit(); - } - } - - fn check_mod(&mut self, _: &LateContext, _: &hir::Mod, - _: Span, _: ast::NodeId) { - self.0 += 1; - } - - fn check_mod_post(&mut self, _: &LateContext, _: &hir::Mod, - _: Span, _: ast::NodeId) { - self.0 += 1; - } -} - /// Lint for trait and lifetime bounds that don't depend on type parameters /// which either do nothing, or stop the item from being used. pub struct TrivialConstraints; diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index c5994d0536ee0..d6ce5b2ea57fe 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -145,7 +145,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { TypeLimits, MissingDoc, MissingDebugImplementations, - ExternCrate, ); add_lint_group!(sess, @@ -185,7 +184,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { "rust_2018_idioms", BARE_TRAIT_OBJECTS, UNREACHABLE_PUB, - UNNECESSARY_EXTERN_CRATES); + UNUSED_EXTERN_CRATES); // Guidelines for creating a future incompatibility lint: // diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index b5772df1306ed..66dc76b1d94a0 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -14,11 +14,46 @@ use rustc::ty::TyCtxt; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; -use rustc::hir::def_id::LOCAL_CRATE; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::hir::print::visibility_qualified; use rustc::hir; use rustc::util::nodemap::DefIdSet; +use rustc_data_structures::fx::FxHashMap; + +pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + let mut used_trait_imports = DefIdSet(); + for &body_id in tcx.hir.krate().bodies.keys() { + let item_def_id = tcx.hir.body_owner_def_id(body_id); + let imports = tcx.used_trait_imports(item_def_id); + debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports); + used_trait_imports.extend(imports.iter()); + } + + let mut visitor = CheckVisitor { tcx, used_trait_imports }; + tcx.hir.krate().visit_all_item_likes(&mut visitor); + + unused_crates_lint(tcx); +} + +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CheckVisitor<'a, 'tcx> { + fn visit_item(&mut self, item: &hir::Item) { + if item.vis == hir::Public || item.span == DUMMY_SP { + return; + } + if let hir::ItemUse(ref path, _) = item.node { + self.check_import(item.id, path.span); + } + } + + fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) { + } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + } +} + struct CheckVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, used_trait_imports: DefIdSet, @@ -45,72 +80,146 @@ impl<'a, 'tcx> CheckVisitor<'a, 'tcx> { } } -impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CheckVisitor<'a, 'tcx> { - fn visit_item(&mut self, item: &hir::Item) { - if item.vis == hir::Public || item.span == DUMMY_SP { - return; - } - if let hir::ItemUse(ref path, _) = item.node { - self.check_import(item.id, path.span); - } +fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) { + let lint = lint::builtin::UNUSED_EXTERN_CRATES; + + // Collect first the crates that are completely unused. These we + // can always suggest removing (no matter which edition we are + // in). + let unused_extern_crates: FxHashMap = + tcx.maybe_unused_extern_crates(LOCAL_CRATE) + .iter() + .filter(|&&(def_id, _)| { + // The `def_id` here actually was calculated during resolution (at least + // at the time of this writing) and is being shipped to us via a side + // channel of the tcx. There may have been extra expansion phases, + // however, which ended up removing the `def_id` *after* expansion such + // as the `ReplaceBodyWithLoop` pass (which is a bit of a hack, but hey) + // + // As a result we need to verify that `def_id` is indeed still valid for + // our AST and actually present in the HIR map. If it's not there then + // there's safely nothing to warn about, and otherwise we carry on with + // our execution. + // + // Note that if we carry through to the `extern_mod_stmt_cnum` query + // below it'll cause a panic because `def_id` is actually bogus at this + // point in time otherwise. + if let Some(id) = tcx.hir.as_local_node_id(def_id) { + if tcx.hir.find(id).is_none() { + return false; + } + } + true + }) + .filter(|&&(def_id, _)| { + let cnum = tcx.extern_mod_stmt_cnum(def_id).unwrap(); + !tcx.is_compiler_builtins(cnum) + && !tcx.is_panic_runtime(cnum) + && !tcx.has_global_allocator(cnum) + }) + .cloned() + .collect(); + + // Issue lints for fully unused crates that suggest removing them. + for (&def_id, &span) in &unused_extern_crates { + assert_eq!(def_id.krate, LOCAL_CRATE); + let hir_id = tcx.hir.definitions().def_index_to_hir_id(def_id.index); + let id = tcx.hir.hir_to_node_id(hir_id); + let msg = "unused extern crate"; + tcx.struct_span_lint_node(lint, id, span, msg) + .span_suggestion_short(span, "remove it", "".to_string()) + .emit(); } - fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) { + // If we are not in Rust 2018 edition, we are done. + if !tcx.sess.rust_2018() { + return; } - fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { + // Otherwise, we can *also* suggest rewriting `extern crate` + // into `use` etc. + let mut crates_to_convert_to_use = vec![]; + tcx.hir.krate().visit_all_item_likes(&mut CollectExternCrateVisitor { + tcx, + unused_extern_crates: &unused_extern_crates, + crates_to_convert_to_use: &mut crates_to_convert_to_use, + }); + + for to_convert in &crates_to_convert_to_use { + assert_eq!(to_convert.def_id.krate, LOCAL_CRATE); + let hir_id = tcx.hir.definitions().def_index_to_hir_id(to_convert.def_id.index); + let id = tcx.hir.hir_to_node_id(hir_id); + let item = tcx.hir.expect_item(id); + let msg = "`extern crate` is not idiomatic in the new edition"; + + let help = format!( + "convert it to a `{}`", + visibility_qualified(&item.vis, "use") + ); + + let base_replacement = match to_convert.orig_name { + Some(orig_name) => format!("use {} as {};", orig_name, item.name), + None => format!("use {};", item.name), + }; + let replacement = visibility_qualified(&item.vis, &base_replacement); + + tcx.struct_span_lint_node(lint, id, to_convert.span, msg) + .span_suggestion_short(to_convert.span, &help, replacement) + .emit(); } } -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let mut used_trait_imports = DefIdSet(); - for &body_id in tcx.hir.krate().bodies.keys() { - let item_def_id = tcx.hir.body_owner_def_id(body_id); - let imports = tcx.used_trait_imports(item_def_id); - debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports); - used_trait_imports.extend(imports.iter()); - } +struct CollectExternCrateVisitor<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + unused_extern_crates: &'a FxHashMap, + crates_to_convert_to_use: &'a mut Vec, +} - let mut visitor = CheckVisitor { tcx, used_trait_imports }; - tcx.hir.krate().visit_all_item_likes(&mut visitor); +struct ExternCrateToConvertToUse { + /// def-id of the extern crate + def_id: DefId, + + /// span from the item + span: Span, - for &(def_id, span) in tcx.maybe_unused_extern_crates(LOCAL_CRATE).iter() { - // The `def_id` here actually was calculated during resolution (at least - // at the time of this writing) and is being shipped to us via a side - // channel of the tcx. There may have been extra expansion phases, - // however, which ended up removing the `def_id` *after* expansion such - // as the `ReplaceBodyWithLoop` pass (which is a bit of a hack, but hey) - // - // As a result we need to verify that `def_id` is indeed still valid for - // our AST and actually present in the HIR map. If it's not there then - // there's safely nothing to warn about, and otherwise we carry on with - // our execution. - // - // Note that if we carry through to the `extern_mod_stmt_cnum` query - // below it'll cause a panic because `def_id` is actually bogus at this - // point in time otherwise. - if let Some(id) = tcx.hir.as_local_node_id(def_id) { - if tcx.hir.find(id).is_none() { - continue + /// if `Some`, then this is renamed (`extern crate orig_name as + /// crate_name`), and -- perhaps surprisingly -- this stores the + /// *original* name (`item.name` will contain the new name) + orig_name: Option, +} + +impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CollectExternCrateVisitor<'a, 'tcx> { + fn visit_item(&mut self, item: &hir::Item) { + if let hir::ItemExternCrate(orig_name) = item.node { + let extern_crate_def_id = self.tcx.hir.local_def_id(item.id); + + // If the crate is fully unused, we are going to suggest + // removing it anyway, so ignore it. + if self.unused_extern_crates.contains_key(&extern_crate_def_id) { + return; } + + // If the extern crate has any attributes, they may have funky + // semantics we can't entirely understand. Ignore it. + if !self.tcx.get_attrs(extern_crate_def_id).is_empty() { + return; + } + + // Otherwise, we can convert it into a `use` of some kind. + self.crates_to_convert_to_use.push( + ExternCrateToConvertToUse { + def_id: extern_crate_def_id, + span: item.span, + orig_name, + } + ); } - let cnum = tcx.extern_mod_stmt_cnum(def_id).unwrap(); - if tcx.is_compiler_builtins(cnum) { - continue - } - if tcx.is_panic_runtime(cnum) { - continue - } - if tcx.has_global_allocator(cnum) { - continue - } - assert_eq!(def_id.krate, LOCAL_CRATE); - let hir_id = tcx.hir.definitions().def_index_to_hir_id(def_id.index); - let id = tcx.hir.hir_to_node_id(hir_id); - let lint = lint::builtin::UNUSED_EXTERN_CRATES; - let msg = "unused extern crate"; - tcx.struct_span_lint_node(lint, id, span, msg) - .span_suggestion_short(span, "remove it", "".to_string()) - .emit(); + } + + fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) { + } + + fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) { } } + diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2e3ea3de7b0b7..a57f3a42939ee 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -3030,7 +3030,7 @@ impl Clean> for hir::Visibility { Some(match *self { hir::Visibility::Public => Visibility::Public, hir::Visibility::Inherited => Visibility::Inherited, - hir::Visibility::Crate => Visibility::Crate, + hir::Visibility::Crate(_) => Visibility::Crate, hir::Visibility::Restricted { ref path, .. } => { let path = path.clean(cx); let did = register_def(cx, path.def); diff --git a/src/test/compile-fail/edition-extern-crate-allowed.rs b/src/test/compile-fail/edition-extern-crate-allowed.rs index 286ee896161a6..7368564e250d1 100644 --- a/src/test/compile-fail/edition-extern-crate-allowed.rs +++ b/src/test/compile-fail/edition-extern-crate-allowed.rs @@ -12,8 +12,9 @@ // compile-flags: --edition 2015 // compile-pass -#![deny(rust_2018_idioms)] +#![warn(rust_2018_idioms)] extern crate edition_extern_crate_allowed; +//~^ WARNING unused extern crate fn main() {} diff --git a/src/test/ui-fulldeps/unnecessary-extern-crate.rs b/src/test/ui-fulldeps/unnecessary-extern-crate.rs index fc6cb6bd053e6..0811c79b0a4b9 100644 --- a/src/test/ui-fulldeps/unnecessary-extern-crate.rs +++ b/src/test/ui-fulldeps/unnecessary-extern-crate.rs @@ -10,48 +10,90 @@ // compile-flags: --edition 2018 -#![deny(unnecessary_extern_crates)] +#![deny(unused_extern_crates)] #![feature(alloc, test, libc)] extern crate alloc; -//~^ ERROR `extern crate` is unnecessary in the new edition +//~^ ERROR unused extern crate //~| HELP remove extern crate alloc as x; -//~^ ERROR `extern crate` is unnecessary in the new edition -//~| HELP use `use` +//~^ ERROR unused extern crate +//~| HELP remove #[macro_use] extern crate test; + pub extern crate test as y; -//~^ ERROR `extern crate` is unnecessary in the new edition -//~| HELP use `pub use` +//~^ ERROR `extern crate` is not idiomatic in the new edition +//~| HELP convert it to a `pub use` + pub extern crate libc; -//~^ ERROR `extern crate` is unnecessary in the new edition -//~| HELP use `pub use` +//~^ ERROR `extern crate` is not idiomatic in the new edition +//~| HELP convert it to a `pub use` + +pub(crate) extern crate libc as a; +//~^ ERROR `extern crate` is not idiomatic in the new edition +//~| HELP convert it to a `pub(crate) use` +crate extern crate libc as b; +//~^ ERROR `extern crate` is not idiomatic in the new edition +//~| HELP convert it to a `crate use` mod foo { + pub(in crate::foo) extern crate libc as c; + //~^ ERROR `extern crate` is not idiomatic in the new edition + //~| HELP convert it to a `pub(in crate::foo) use` + + pub(super) extern crate libc as d; + //~^ ERROR `extern crate` is not idiomatic in the new edition + //~| HELP convert it to a `pub(super) use` + extern crate alloc; - //~^ ERROR `extern crate` is unnecessary in the new edition - //~| HELP use `use` + //~^ ERROR unused extern crate + //~| HELP remove + extern crate alloc as x; - //~^ ERROR `extern crate` is unnecessary in the new edition - //~| HELP use `use` + //~^ ERROR unused extern crate + //~| HELP remove + pub extern crate test; - //~^ ERROR `extern crate` is unnecessary in the new edition - //~| HELP use `pub use` + //~^ ERROR `extern crate` is not idiomatic in the new edition + //~| HELP convert it + pub extern crate test as y; - //~^ ERROR `extern crate` is unnecessary in the new edition - //~| HELP use `pub use` + //~^ ERROR `extern crate` is not idiomatic in the new edition + //~| HELP convert it + mod bar { extern crate alloc; - //~^ ERROR `extern crate` is unnecessary in the new edition - //~| HELP use `use` + //~^ ERROR unused extern crate + //~| HELP remove + extern crate alloc as x; - //~^ ERROR `extern crate` is unnecessary in the new edition - //~| HELP use `use` + //~^ ERROR unused extern crate + //~| HELP remove + + pub(in crate::foo::bar) extern crate libc as e; + //~^ ERROR `extern crate` is not idiomatic in the new edition + //~| HELP convert it to a `pub(in crate::foo::bar) use` + + fn dummy() { + unsafe { + e::getpid(); + } + } + } + + fn dummy() { + unsafe { + c::getpid(); + d::getpid(); + } } } -fn main() {} +fn main() { + unsafe { a::getpid(); } + unsafe { b::getpid(); } +} diff --git a/src/test/ui-fulldeps/unnecessary-extern-crate.stderr b/src/test/ui-fulldeps/unnecessary-extern-crate.stderr index b9ccf5b19e03a..a64125c794379 100644 --- a/src/test/ui-fulldeps/unnecessary-extern-crate.stderr +++ b/src/test/ui-fulldeps/unnecessary-extern-crate.stderr @@ -1,68 +1,98 @@ -error: `extern crate` is unnecessary in the new edition - --> $DIR/unnecessary-extern-crate.rs:16:1 +error: unused extern crate + --> $DIR/unnecessary-extern-crate.rs:51:5 | -LL | extern crate alloc; - | ^^^^^^^^^^^^^^^^^^^ help: remove it +LL | extern crate alloc; + | ^^^^^^^^^^^^^^^^^^^ help: remove it | note: lint level defined here --> $DIR/unnecessary-extern-crate.rs:13:9 | -LL | #![deny(unnecessary_extern_crates)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(unused_extern_crates)] + | ^^^^^^^^^^^^^^^^^^^^ -error: `extern crate` is unnecessary in the new edition +error: unused extern crate --> $DIR/unnecessary-extern-crate.rs:19:1 | LL | extern crate alloc as x; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x;` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + +error: unused extern crate + --> $DIR/unnecessary-extern-crate.rs:55:5 + | +LL | extern crate alloc as x; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + +error: unused extern crate + --> $DIR/unnecessary-extern-crate.rs:68:9 + | +LL | extern crate alloc; + | ^^^^^^^^^^^^^^^^^^^ help: remove it + +error: unused extern crate + --> $DIR/unnecessary-extern-crate.rs:16:1 + | +LL | extern crate alloc; + | ^^^^^^^^^^^^^^^^^^^ help: remove it -error: `extern crate` is unnecessary in the new edition - --> $DIR/unnecessary-extern-crate.rs:25:1 +error: unused extern crate + --> $DIR/unnecessary-extern-crate.rs:72:9 + | +LL | extern crate alloc as x; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + +error: `extern crate` is not idiomatic in the new edition + --> $DIR/unnecessary-extern-crate.rs:26:1 | LL | pub extern crate test as y; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y;` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `pub use` -error: `extern crate` is unnecessary in the new edition - --> $DIR/unnecessary-extern-crate.rs:28:1 +error: `extern crate` is not idiomatic in the new edition + --> $DIR/unnecessary-extern-crate.rs:30:1 | LL | pub extern crate libc; - | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use libc;` + | ^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `pub use` -error: `extern crate` is unnecessary in the new edition - --> $DIR/unnecessary-extern-crate.rs:34:5 +error: `extern crate` is not idiomatic in the new edition + --> $DIR/unnecessary-extern-crate.rs:34:1 | -LL | extern crate alloc; - | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc;` +LL | pub(crate) extern crate libc as a; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `pub(crate) use` -error: `extern crate` is unnecessary in the new edition - --> $DIR/unnecessary-extern-crate.rs:37:5 +error: `extern crate` is not idiomatic in the new edition + --> $DIR/unnecessary-extern-crate.rs:38:1 | -LL | extern crate alloc as x; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x;` +LL | crate extern crate libc as b; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `crate use` -error: `extern crate` is unnecessary in the new edition - --> $DIR/unnecessary-extern-crate.rs:40:5 +error: `extern crate` is not idiomatic in the new edition + --> $DIR/unnecessary-extern-crate.rs:43:5 | -LL | pub extern crate test; - | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test;` +LL | pub(in crate::foo) extern crate libc as c; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `pub(in crate::foo) use` -error: `extern crate` is unnecessary in the new edition - --> $DIR/unnecessary-extern-crate.rs:43:5 +error: `extern crate` is not idiomatic in the new edition + --> $DIR/unnecessary-extern-crate.rs:47:5 | -LL | pub extern crate test as y; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y;` +LL | pub(super) extern crate libc as d; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `pub(super) use` -error: `extern crate` is unnecessary in the new edition - --> $DIR/unnecessary-extern-crate.rs:47:9 +error: `extern crate` is not idiomatic in the new edition + --> $DIR/unnecessary-extern-crate.rs:59:5 | -LL | extern crate alloc; - | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc;` +LL | pub extern crate test; + | ^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `pub use` -error: `extern crate` is unnecessary in the new edition - --> $DIR/unnecessary-extern-crate.rs:50:9 +error: `extern crate` is not idiomatic in the new edition + --> $DIR/unnecessary-extern-crate.rs:63:5 | -LL | extern crate alloc as x; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x;` +LL | pub extern crate test as y; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `pub use` + +error: `extern crate` is not idiomatic in the new edition + --> $DIR/unnecessary-extern-crate.rs:76:9 + | +LL | pub(in crate::foo::bar) extern crate libc as e; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `pub(in crate::foo::bar) use` -error: aborting due to 10 previous errors +error: aborting due to 15 previous errors diff --git a/src/test/ui/rfc-2166-underscore-imports/basic.stderr b/src/test/ui/rfc-2166-underscore-imports/basic.stderr index 4530d0fa604aa..c12c74b50e264 100644 --- a/src/test/ui/rfc-2166-underscore-imports/basic.stderr +++ b/src/test/ui/rfc-2166-underscore-imports/basic.stderr @@ -20,7 +20,7 @@ warning: unused extern crate --> $DIR/basic.rs:33:5 | LL | extern crate core as _; //~ WARN unused extern crate - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it | note: lint level defined here --> $DIR/basic.rs:14:25 diff --git a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed index d8bf656cf2dd6..4f99c1240f8f4 100644 --- a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed +++ b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.fixed @@ -16,14 +16,14 @@ // but we don't. #![feature(rust_2018_preview)] -#![deny(absolute_path_not_starting_with_crate)] -#![deny(unused_extern_crates)] +#![deny(rust_2018_idioms)] #![allow(dead_code)] //~^ ERROR unused extern crate -extern crate edition_lint_paths as bar; +use edition_lint_paths as bar; +//~^ ERROR `extern crate` is not idiomatic in the new edition fn main() { // This is not considered to *use* the `extern crate` in Rust 2018: diff --git a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs index 6e741257d8089..9c1235a296799 100644 --- a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs +++ b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.rs @@ -16,14 +16,14 @@ // but we don't. #![feature(rust_2018_preview)] -#![deny(absolute_path_not_starting_with_crate)] -#![deny(unused_extern_crates)] +#![deny(rust_2018_idioms)] #![allow(dead_code)] extern crate edition_lint_paths; //~^ ERROR unused extern crate extern crate edition_lint_paths as bar; +//~^ ERROR `extern crate` is not idiomatic in the new edition fn main() { // This is not considered to *use* the `extern crate` in Rust 2018: diff --git a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr index 8fae69e8bd5a3..b3afa2bd1d592 100644 --- a/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr +++ b/src/test/ui/rust-2018/extern-crate-idiomatic-in-2018.stderr @@ -1,14 +1,21 @@ error: unused extern crate - --> $DIR/extern-crate-idiomatic-in-2018.rs:23:1 + --> $DIR/extern-crate-idiomatic-in-2018.rs:22:1 | LL | extern crate edition_lint_paths; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it | note: lint level defined here - --> $DIR/extern-crate-idiomatic-in-2018.rs:20:9 + --> $DIR/extern-crate-idiomatic-in-2018.rs:19:9 | -LL | #![deny(unused_extern_crates)] - | ^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(rust_2018_idioms)] + | ^^^^^^^^^^^^^^^^ + = note: #[deny(unused_extern_crates)] implied by #[deny(rust_2018_idioms)] -error: aborting due to previous error +error: `extern crate` is not idiomatic in the new edition + --> $DIR/extern-crate-idiomatic-in-2018.rs:25:1 + | +LL | extern crate edition_lint_paths as bar; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use` + +error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/removing-extern-crate.fixed b/src/test/ui/suggestions/removing-extern-crate.fixed index 723137f5db0c1..83b35cec80956 100644 --- a/src/test/ui/suggestions/removing-extern-crate.fixed +++ b/src/test/ui/suggestions/removing-extern-crate.fixed @@ -16,12 +16,12 @@ #![warn(rust_2018_idioms)] #![allow(unused_imports)] -use std as foo; + mod another { - use std as foo; - use std; + + } fn main() {} diff --git a/src/test/ui/suggestions/removing-extern-crate.stderr b/src/test/ui/suggestions/removing-extern-crate.stderr index 39d22de02776c..e7caab5ec5459 100644 --- a/src/test/ui/suggestions/removing-extern-crate.stderr +++ b/src/test/ui/suggestions/removing-extern-crate.stderr @@ -1,31 +1,31 @@ -warning: `extern crate` is unnecessary in the new edition - --> $DIR/removing-extern-crate.rs:19:1 +warning: unused extern crate + --> $DIR/removing-extern-crate.rs:24:5 | -LL | extern crate std as foo; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use std as foo;` +LL | extern crate std; + | ^^^^^^^^^^^^^^^^^ help: remove it | note: lint level defined here --> $DIR/removing-extern-crate.rs:16:9 | LL | #![warn(rust_2018_idioms)] | ^^^^^^^^^^^^^^^^ - = note: #[warn(unnecessary_extern_crates)] implied by #[warn(rust_2018_idioms)] + = note: #[warn(unused_extern_crates)] implied by #[warn(rust_2018_idioms)] -warning: `extern crate` is unnecessary in the new edition +warning: unused extern crate --> $DIR/removing-extern-crate.rs:20:1 | LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ help: remove it -warning: `extern crate` is unnecessary in the new edition +warning: unused extern crate --> $DIR/removing-extern-crate.rs:23:5 | LL | extern crate std as foo; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use std as foo;` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it -warning: `extern crate` is unnecessary in the new edition - --> $DIR/removing-extern-crate.rs:24:5 +warning: unused extern crate + --> $DIR/removing-extern-crate.rs:19:1 | -LL | extern crate std; - | ^^^^^^^^^^^^^^^^^ help: use `use`: `use std;` +LL | extern crate std as foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it From b37cc851e65bd018556ccf7fc2cba1c7647b08db Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 29 May 2018 11:31:34 -0400 Subject: [PATCH 3/3] rework to report errors from crates in a consistent order We first collect unused crates into a map and then walk all extern crates in crate order. --- src/librustc_typeck/check_unused.rs | 90 +++++++++---------- .../unnecessary-extern-crate.stderr | 54 +++++------ .../suggestions/removing-extern-crate.stderr | 12 +-- 3 files changed, 74 insertions(+), 82 deletions(-) diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index 66dc76b1d94a0..41adde0d4a188 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -120,62 +120,68 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) { .cloned() .collect(); - // Issue lints for fully unused crates that suggest removing them. - for (&def_id, &span) in &unused_extern_crates { - assert_eq!(def_id.krate, LOCAL_CRATE); - let hir_id = tcx.hir.definitions().def_index_to_hir_id(def_id.index); - let id = tcx.hir.hir_to_node_id(hir_id); - let msg = "unused extern crate"; - tcx.struct_span_lint_node(lint, id, span, msg) - .span_suggestion_short(span, "remove it", "".to_string()) - .emit(); - } - - // If we are not in Rust 2018 edition, we are done. - if !tcx.sess.rust_2018() { - return; - } - - // Otherwise, we can *also* suggest rewriting `extern crate` - // into `use` etc. - let mut crates_to_convert_to_use = vec![]; + // Collect all the extern crates (in a reliable order). + let mut crates_to_lint = vec![]; tcx.hir.krate().visit_all_item_likes(&mut CollectExternCrateVisitor { tcx, - unused_extern_crates: &unused_extern_crates, - crates_to_convert_to_use: &mut crates_to_convert_to_use, + crates_to_lint: &mut crates_to_lint, }); - for to_convert in &crates_to_convert_to_use { - assert_eq!(to_convert.def_id.krate, LOCAL_CRATE); - let hir_id = tcx.hir.definitions().def_index_to_hir_id(to_convert.def_id.index); + for extern_crate in &crates_to_lint { + assert!(extern_crate.def_id.is_local()); + + // If the crate is fully unused, we suggest removing it altogether. + // We do this in any edition. + if let Some(&span) = unused_extern_crates.get(&extern_crate.def_id) { + assert_eq!(extern_crate.def_id.krate, LOCAL_CRATE); + let hir_id = tcx.hir.definitions().def_index_to_hir_id(extern_crate.def_id.index); + let id = tcx.hir.hir_to_node_id(hir_id); + let msg = "unused extern crate"; + tcx.struct_span_lint_node(lint, id, span, msg) + .span_suggestion_short(span, "remove it", "".to_string()) + .emit(); + continue; + } + + // If we are not in Rust 2018 edition, then we don't make any further + // suggestions. + if !tcx.sess.rust_2018() { + continue; + } + + // If the extern crate has any attributes, they may have funky + // semantics we can't faithfully represent using `use` (most + // notably `#[macro_use]`). Ignore it. + if !tcx.get_attrs(extern_crate.def_id).is_empty() { + continue; + } + + // Otherwise, we can convert it into a `use` of some kind. + let hir_id = tcx.hir.definitions().def_index_to_hir_id(extern_crate.def_id.index); let id = tcx.hir.hir_to_node_id(hir_id); let item = tcx.hir.expect_item(id); let msg = "`extern crate` is not idiomatic in the new edition"; - let help = format!( "convert it to a `{}`", visibility_qualified(&item.vis, "use") ); - - let base_replacement = match to_convert.orig_name { + let base_replacement = match extern_crate.orig_name { Some(orig_name) => format!("use {} as {};", orig_name, item.name), None => format!("use {};", item.name), }; let replacement = visibility_qualified(&item.vis, &base_replacement); - - tcx.struct_span_lint_node(lint, id, to_convert.span, msg) - .span_suggestion_short(to_convert.span, &help, replacement) + tcx.struct_span_lint_node(lint, id, extern_crate.span, msg) + .span_suggestion_short(extern_crate.span, &help, replacement) .emit(); } } struct CollectExternCrateVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - unused_extern_crates: &'a FxHashMap, - crates_to_convert_to_use: &'a mut Vec, + crates_to_lint: &'a mut Vec, } -struct ExternCrateToConvertToUse { +struct ExternCrateToLint { /// def-id of the extern crate def_id: DefId, @@ -192,22 +198,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CollectExternCrateVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &hir::Item) { if let hir::ItemExternCrate(orig_name) = item.node { let extern_crate_def_id = self.tcx.hir.local_def_id(item.id); - - // If the crate is fully unused, we are going to suggest - // removing it anyway, so ignore it. - if self.unused_extern_crates.contains_key(&extern_crate_def_id) { - return; - } - - // If the extern crate has any attributes, they may have funky - // semantics we can't entirely understand. Ignore it. - if !self.tcx.get_attrs(extern_crate_def_id).is_empty() { - return; - } - - // Otherwise, we can convert it into a `use` of some kind. - self.crates_to_convert_to_use.push( - ExternCrateToConvertToUse { + self.crates_to_lint.push( + ExternCrateToLint { def_id: extern_crate_def_id, span: item.span, orig_name, diff --git a/src/test/ui-fulldeps/unnecessary-extern-crate.stderr b/src/test/ui-fulldeps/unnecessary-extern-crate.stderr index a64125c794379..a4307112157b0 100644 --- a/src/test/ui-fulldeps/unnecessary-extern-crate.stderr +++ b/src/test/ui-fulldeps/unnecessary-extern-crate.stderr @@ -1,8 +1,8 @@ error: unused extern crate - --> $DIR/unnecessary-extern-crate.rs:51:5 + --> $DIR/unnecessary-extern-crate.rs:16:1 | -LL | extern crate alloc; - | ^^^^^^^^^^^^^^^^^^^ help: remove it +LL | extern crate alloc; + | ^^^^^^^^^^^^^^^^^^^ help: remove it | note: lint level defined here --> $DIR/unnecessary-extern-crate.rs:13:9 @@ -16,30 +16,6 @@ error: unused extern crate LL | extern crate alloc as x; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it -error: unused extern crate - --> $DIR/unnecessary-extern-crate.rs:55:5 - | -LL | extern crate alloc as x; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it - -error: unused extern crate - --> $DIR/unnecessary-extern-crate.rs:68:9 - | -LL | extern crate alloc; - | ^^^^^^^^^^^^^^^^^^^ help: remove it - -error: unused extern crate - --> $DIR/unnecessary-extern-crate.rs:16:1 - | -LL | extern crate alloc; - | ^^^^^^^^^^^^^^^^^^^ help: remove it - -error: unused extern crate - --> $DIR/unnecessary-extern-crate.rs:72:9 - | -LL | extern crate alloc as x; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it - error: `extern crate` is not idiomatic in the new edition --> $DIR/unnecessary-extern-crate.rs:26:1 | @@ -76,6 +52,18 @@ error: `extern crate` is not idiomatic in the new edition LL | pub(super) extern crate libc as d; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `pub(super) use` +error: unused extern crate + --> $DIR/unnecessary-extern-crate.rs:51:5 + | +LL | extern crate alloc; + | ^^^^^^^^^^^^^^^^^^^ help: remove it + +error: unused extern crate + --> $DIR/unnecessary-extern-crate.rs:55:5 + | +LL | extern crate alloc as x; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + error: `extern crate` is not idiomatic in the new edition --> $DIR/unnecessary-extern-crate.rs:59:5 | @@ -88,6 +76,18 @@ error: `extern crate` is not idiomatic in the new edition LL | pub extern crate test as y; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `pub use` +error: unused extern crate + --> $DIR/unnecessary-extern-crate.rs:68:9 + | +LL | extern crate alloc; + | ^^^^^^^^^^^^^^^^^^^ help: remove it + +error: unused extern crate + --> $DIR/unnecessary-extern-crate.rs:72:9 + | +LL | extern crate alloc as x; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it + error: `extern crate` is not idiomatic in the new edition --> $DIR/unnecessary-extern-crate.rs:76:9 | diff --git a/src/test/ui/suggestions/removing-extern-crate.stderr b/src/test/ui/suggestions/removing-extern-crate.stderr index e7caab5ec5459..f2eed27a26693 100644 --- a/src/test/ui/suggestions/removing-extern-crate.stderr +++ b/src/test/ui/suggestions/removing-extern-crate.stderr @@ -1,8 +1,8 @@ warning: unused extern crate - --> $DIR/removing-extern-crate.rs:24:5 + --> $DIR/removing-extern-crate.rs:19:1 | -LL | extern crate std; - | ^^^^^^^^^^^^^^^^^ help: remove it +LL | extern crate std as foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it | note: lint level defined here --> $DIR/removing-extern-crate.rs:16:9 @@ -24,8 +24,8 @@ LL | extern crate std as foo; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it warning: unused extern crate - --> $DIR/removing-extern-crate.rs:19:1 + --> $DIR/removing-extern-crate.rs:24:5 | -LL | extern crate std as foo; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it +LL | extern crate std; + | ^^^^^^^^^^^^^^^^^ help: remove it