From 98fb65eff9885f1dea6372f007962d9cbeb4a40c Mon Sep 17 00:00:00 2001
From: PragmaTwice <twice.mliu@gmail.com>
Date: Wed, 17 Aug 2022 17:47:44 +0800
Subject: [PATCH 1/4] Migrate lint reports in typeck::check_unused to
 LintDiagnostic

---
 .../locales/en-US/typeck.ftl                  |  8 +++
 compiler/rustc_typeck/src/check_unused.rs     | 63 ++++++++-----------
 compiler/rustc_typeck/src/errors.rs           | 20 +++++-
 3 files changed, 54 insertions(+), 37 deletions(-)

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..7dfd2e9cb48be 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,21 @@ pub struct SubstsOnOverriddenImpl {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(LintDiagnostic)]
+#[lint(typeck::unused_extern_crate)]
+pub struct UnusedExternCrate {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "")]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[lint(typeck::extern_crate_not_idiomatic)]
+pub struct ExternCrateNotIdiomatic {
+    #[primary_span]
+    #[suggestion(applicability = "machine-applicable", code = "{suggestion_code}")]
+    pub span: Span,
+    pub msg_code: String,
+    pub suggestion_code: String,
+}

From 52418d661bf7c66b8605c041a249203458036993 Mon Sep 17 00:00:00 2001
From: Twice <twice@apache.org>
Date: Wed, 17 Aug 2022 20:45:18 +0800
Subject: [PATCH 2/4] use `suggestion_short` in `LintDiagnostic`

Co-authored-by: David Wood <agile.lion3441@fuligin.ink>
---
 compiler/rustc_typeck/src/errors.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs
index 7dfd2e9cb48be..a33d88dfee0c7 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_typeck/src/errors.rs
@@ -337,7 +337,7 @@ pub struct UnusedExternCrate {
 #[lint(typeck::extern_crate_not_idiomatic)]
 pub struct ExternCrateNotIdiomatic {
     #[primary_span]
-    #[suggestion(applicability = "machine-applicable", code = "{suggestion_code}")]
+    #[suggestion_short(applicability = "machine-applicable", code = "{suggestion_code}")]
     pub span: Span,
     pub msg_code: String,
     pub suggestion_code: String,

From b704843c4438387a66111b3464bb3987c45ce294 Mon Sep 17 00:00:00 2001
From: PragmaTwice <twice.mliu@gmail.com>
Date: Wed, 17 Aug 2022 21:05:21 +0800
Subject: [PATCH 3/4] fix test file

---
 .../issue-54400-unused-extern-crate-attr-span.stderr        | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr b/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr
index 2ef97e7f20e9f..01bd924a415bb 100644
--- a/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr
+++ b/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr
@@ -1,11 +1,9 @@
 error: unused extern crate
-  --> $DIR/issue-54400-unused-extern-crate-attr-span.rs:12:1
+  --> $DIR/issue-54400-unused-extern-crate-attr-span.rs:11:1
    |
 LL | / #[cfg(blandiloquence)]
 LL | | extern crate edition_lint_paths;
-   | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
-   | |________________________________|
-   |                                  help: remove it
+   | |________________________________^ help: remove it
    |
 note: the lint level is defined here
   --> $DIR/issue-54400-unused-extern-crate-attr-span.rs:6:9

From 9efe97951165a144c17ab08c8842f4f1cf23b4da Mon Sep 17 00:00:00 2001
From: PragmaTwice <twice.mliu@gmail.com>
Date: Wed, 17 Aug 2022 22:08:06 +0800
Subject: [PATCH 4/4] remove #[primary_span]

---
 compiler/rustc_typeck/src/errors.rs                         | 2 --
 .../issue-54400-unused-extern-crate-attr-span.stderr        | 6 ++++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs
index a33d88dfee0c7..76599721e586f 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_typeck/src/errors.rs
@@ -328,7 +328,6 @@ pub struct SubstsOnOverriddenImpl {
 #[derive(LintDiagnostic)]
 #[lint(typeck::unused_extern_crate)]
 pub struct UnusedExternCrate {
-    #[primary_span]
     #[suggestion(applicability = "machine-applicable", code = "")]
     pub span: Span,
 }
@@ -336,7 +335,6 @@ pub struct UnusedExternCrate {
 #[derive(LintDiagnostic)]
 #[lint(typeck::extern_crate_not_idiomatic)]
 pub struct ExternCrateNotIdiomatic {
-    #[primary_span]
     #[suggestion_short(applicability = "machine-applicable", code = "{suggestion_code}")]
     pub span: Span,
     pub msg_code: String,
diff --git a/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr b/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr
index 01bd924a415bb..2ef97e7f20e9f 100644
--- a/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr
+++ b/src/test/ui/rust-2018/issue-54400-unused-extern-crate-attr-span.stderr
@@ -1,9 +1,11 @@
 error: unused extern crate
-  --> $DIR/issue-54400-unused-extern-crate-attr-span.rs:11:1
+  --> $DIR/issue-54400-unused-extern-crate-attr-span.rs:12:1
    |
 LL | / #[cfg(blandiloquence)]
 LL | | extern crate edition_lint_paths;
-   | |________________________________^ help: remove it
+   | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+   | |________________________________|
+   |                                  help: remove it
    |
 note: the lint level is defined here
   --> $DIR/issue-54400-unused-extern-crate-attr-span.rs:6:9