diff --git a/compiler/rustc_error_messages/locales/en-US/typeck.ftl b/compiler/rustc_error_messages/locales/en-US/typeck.ftl index 494b8f913934f..0014da17c88e5 100644 --- a/compiler/rustc_error_messages/locales/en-US/typeck.ftl +++ b/compiler/rustc_error_messages/locales/en-US/typeck.ftl @@ -123,3 +123,11 @@ typeck_manual_implementation = .help = add `#![feature(unboxed_closures)]` to the crate attributes to enable typeck_substs_on_overridden_impl = could not resolve substs on overridden impl + +typeck_unused_extern_crate = + unused extern crate + .suggestion = remove it + +typeck_extern_crate_not_idiomatic = + `extern crate` is not idiomatic in the new edition + .suggestion = convert it to a `{$msg_code}` diff --git a/compiler/rustc_typeck/src/check_unused.rs b/compiler/rustc_typeck/src/check_unused.rs index 4a3cfa1ca376a..1d23ed9292180 100644 --- a/compiler/rustc_typeck/src/check_unused.rs +++ b/compiler/rustc_typeck/src/check_unused.rs @@ -1,5 +1,5 @@ +use crate::errors::{ExternCrateNotIdiomatic, UnusedExternCrate}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -108,25 +108,16 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) { // We do this in any edition. if extern_crate.warn_if_unused { if let Some(&span) = unused_extern_crates.get(&def_id) { + // Removal suggestion span needs to include attributes (Issue #54400) let id = tcx.hir().local_def_id_to_hir_id(def_id); - tcx.struct_span_lint_hir(lint, id, span, |lint| { - // Removal suggestion span needs to include attributes (Issue #54400) - let span_with_attrs = tcx - .hir() - .attrs(id) - .iter() - .map(|attr| attr.span) - .fold(span, |acc, attr_span| acc.to(attr_span)); - - lint.build("unused extern crate") - .span_suggestion_short( - span_with_attrs, - "remove it", - "", - Applicability::MachineApplicable, - ) - .emit(); - }); + let span_with_attrs = tcx + .hir() + .attrs(id) + .iter() + .map(|attr| attr.span) + .fold(span, |acc, attr_span| acc.to(attr_span)); + + tcx.emit_spanned_lint(lint, id, span, UnusedExternCrate { span: span_with_attrs }); continue; } } @@ -158,23 +149,23 @@ fn unused_crates_lint(tcx: TyCtxt<'_>) { if !tcx.hir().attrs(id).is_empty() { continue; } - tcx.struct_span_lint_hir(lint, id, extern_crate.span, |lint| { - // Otherwise, we can convert it into a `use` of some kind. - let base_replacement = match extern_crate.orig_name { - Some(orig_name) => format!("use {} as {};", orig_name, item.ident.name), - None => format!("use {};", item.ident.name), - }; - let vis = tcx.sess.source_map().span_to_snippet(item.vis_span).unwrap_or_default(); - let add_vis = |to| if vis.is_empty() { to } else { format!("{} {}", vis, to) }; - lint.build("`extern crate` is not idiomatic in the new edition") - .span_suggestion_short( - extern_crate.span, - &format!("convert it to a `{}`", add_vis("use".to_string())), - add_vis(base_replacement), - Applicability::MachineApplicable, - ) - .emit(); - }) + + let base_replacement = match extern_crate.orig_name { + Some(orig_name) => format!("use {} as {};", orig_name, item.ident.name), + None => format!("use {};", item.ident.name), + }; + let vis = tcx.sess.source_map().span_to_snippet(item.vis_span).unwrap_or_default(); + let add_vis = |to| if vis.is_empty() { to } else { format!("{} {}", vis, to) }; + tcx.emit_spanned_lint( + lint, + id, + extern_crate.span, + ExternCrateNotIdiomatic { + span: extern_crate.span, + msg_code: add_vis("use".to_string()), + suggestion_code: add_vis(base_replacement), + }, + ); } } diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 0438ac02ea91a..76599721e586f 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -1,6 +1,6 @@ //! Errors emitted by typeck. use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed}; -use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; +use rustc_macros::{LintDiagnostic, SessionDiagnostic, SessionSubdiagnostic}; use rustc_middle::ty::Ty; use rustc_session::{parse::ParseSess, SessionDiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -324,3 +324,19 @@ pub struct SubstsOnOverriddenImpl { #[primary_span] pub span: Span, } + +#[derive(LintDiagnostic)] +#[lint(typeck::unused_extern_crate)] +pub struct UnusedExternCrate { + #[suggestion(applicability = "machine-applicable", code = "")] + pub span: Span, +} + +#[derive(LintDiagnostic)] +#[lint(typeck::extern_crate_not_idiomatic)] +pub struct ExternCrateNotIdiomatic { + #[suggestion_short(applicability = "machine-applicable", code = "{suggestion_code}")] + pub span: Span, + pub msg_code: String, + pub suggestion_code: String, +}