From e9d8d238ef76c7991b316bbfbd9f857d84bd39cf Mon Sep 17 00:00:00 2001
From: Michael Howell <michael@notriddle.com>
Date: Sat, 12 Nov 2022 21:46:05 -0700
Subject: [PATCH 1/4] diagnostics: suggest changing `s@self::{macro}@::macro`
 for exported

Fixes #99695
---
 compiler/rustc_resolve/src/diagnostics.rs | 30 ++++++++++++++++++++++-
 tests/ui/imports/issue-99695.fixed        | 17 +++++++++++++
 tests/ui/imports/issue-99695.rs           | 16 ++++++++++++
 tests/ui/imports/issue-99695.stderr       | 16 ++++++++++++
 4 files changed, 78 insertions(+), 1 deletion(-)
 create mode 100644 tests/ui/imports/issue-99695.fixed
 create mode 100644 tests/ui/imports/issue-99695.rs
 create mode 100644 tests/ui/imports/issue-99695.stderr

diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index f24e405018b74..2a5cc288380f4 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -2125,9 +2125,31 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
 
                 let source_map = self.r.session.source_map();
 
+                // Make sure this is actually crate-relative.
+                let use_and_crate = import.use_span.with_hi(after_crate_name.lo());
+                let is_definitely_crate =
+                    source_map.span_to_snippet(use_and_crate).map_or(false, |s| {
+                        let mut s = s.trim();
+                        debug!("check_for_module_export_macro: s={s:?}",);
+                        s = s
+                            .split_whitespace()
+                            .rev()
+                            .next()
+                            .expect("split_whitespace always yields at least once");
+                        debug!("check_for_module_export_macro: s={s:?}",);
+                        if s.ends_with("::") {
+                            s = &s[..s.len() - 2];
+                        } else {
+                            return false;
+                        }
+                        s = s.trim();
+                        debug!("check_for_module_export_macro: s={s:?}",);
+                        s != "self" && s != "super"
+                    });
+
                 // Add the import to the start, with a `{` if required.
                 let start_point = source_map.start_point(after_crate_name);
-                if let Ok(start_snippet) = source_map.span_to_snippet(start_point) {
+                if is_definitely_crate && let Ok(start_snippet) = source_map.span_to_snippet(start_point) {
                     corrections.push((
                         start_point,
                         if has_nested {
@@ -2139,6 +2161,12 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                             format!("{{{}, {}", import_snippet, start_snippet)
                         },
                     ));
+                } else {
+                    // If the root import is module-relative, add the import separately
+                    corrections.push((
+                        source_map.start_point(import.use_span).shrink_to_lo(),
+                        format!("use {module_name}::{import_snippet};\n"),
+                    ));
                 }
 
                 // Add a `};` to the end if nested, matching the `{` added at the start.
diff --git a/tests/ui/imports/issue-99695.fixed b/tests/ui/imports/issue-99695.fixed
new file mode 100644
index 0000000000000..6bf228b23aad2
--- /dev/null
+++ b/tests/ui/imports/issue-99695.fixed
@@ -0,0 +1,17 @@
+// run-rustfix
+#![allow(unused, nonstandard_style)]
+mod m {
+    #[macro_export]
+    macro_rules! nu {
+        {} => {};
+    }
+
+    pub struct other_item;
+
+    use ::nu;
+pub use self::{other_item as _};
+    //~^ ERROR unresolved import `self::nu` [E0432]
+    //~| HELP a macro with this name exists at the root of the crate
+}
+
+fn main() {}
diff --git a/tests/ui/imports/issue-99695.rs b/tests/ui/imports/issue-99695.rs
new file mode 100644
index 0000000000000..f7199f1497ab0
--- /dev/null
+++ b/tests/ui/imports/issue-99695.rs
@@ -0,0 +1,16 @@
+// run-rustfix
+#![allow(unused, nonstandard_style)]
+mod m {
+    #[macro_export]
+    macro_rules! nu {
+        {} => {};
+    }
+
+    pub struct other_item;
+
+    pub use self::{nu, other_item as _};
+    //~^ ERROR unresolved import `self::nu` [E0432]
+    //~| HELP a macro with this name exists at the root of the crate
+}
+
+fn main() {}
diff --git a/tests/ui/imports/issue-99695.stderr b/tests/ui/imports/issue-99695.stderr
new file mode 100644
index 0000000000000..0ef762e1c8230
--- /dev/null
+++ b/tests/ui/imports/issue-99695.stderr
@@ -0,0 +1,16 @@
+error[E0432]: unresolved import `self::nu`
+  --> $DIR/issue-99695.rs:11:20
+   |
+LL |     pub use self::{nu, other_item as _};
+   |                    ^^ no `nu` in `m`
+   |
+   = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+   |
+LL ~     use ::nu;
+LL ~ pub use self::{other_item as _};
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0432`.

From e237690a28f0d38ab478616fe4b247fb6eb8013f Mon Sep 17 00:00:00 2001
From: Michael Howell <michael@notriddle.com>
Date: Sat, 12 Nov 2022 22:08:07 -0700
Subject: [PATCH 2/4] diagnostics: add `};` only if `{` was added too

---
 compiler/rustc_resolve/src/diagnostics.rs | 10 +++++-----
 tests/ui/imports/issue-99695-b.fixed      | 20 ++++++++++++++++++++
 tests/ui/imports/issue-99695-b.rs         | 19 +++++++++++++++++++
 tests/ui/imports/issue-99695-b.stderr     | 16 ++++++++++++++++
 4 files changed, 60 insertions(+), 5 deletions(-)
 create mode 100644 tests/ui/imports/issue-99695-b.fixed
 create mode 100644 tests/ui/imports/issue-99695-b.rs
 create mode 100644 tests/ui/imports/issue-99695-b.stderr

diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 2a5cc288380f4..af4d7a8eafff3 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -2161,6 +2161,11 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                             format!("{{{}, {}", import_snippet, start_snippet)
                         },
                     ));
+
+                    // Add a `};` to the end if nested, matching the `{` added at the start.
+                    if !has_nested {
+                        corrections.push((source_map.end_point(after_crate_name), "};".to_string()));
+                    }
                 } else {
                     // If the root import is module-relative, add the import separately
                     corrections.push((
@@ -2168,11 +2173,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                         format!("use {module_name}::{import_snippet};\n"),
                     ));
                 }
-
-                // Add a `};` to the end if nested, matching the `{` added at the start.
-                if !has_nested {
-                    corrections.push((source_map.end_point(after_crate_name), "};".to_string()));
-                }
             }
 
             let suggestion = Some((
diff --git a/tests/ui/imports/issue-99695-b.fixed b/tests/ui/imports/issue-99695-b.fixed
new file mode 100644
index 0000000000000..0e60c73b67a44
--- /dev/null
+++ b/tests/ui/imports/issue-99695-b.fixed
@@ -0,0 +1,20 @@
+// run-rustfix
+#![allow(unused, nonstandard_style)]
+mod m {
+
+    mod p {
+        #[macro_export]
+        macro_rules! nu {
+            {} => {};
+        }
+
+        pub struct other_item;
+    }
+
+    use ::nu;
+pub use self::p::{other_item as _};
+    //~^ ERROR unresolved import `self::p::nu` [E0432]
+    //~| HELP a macro with this name exists at the root of the crate
+}
+
+fn main() {}
diff --git a/tests/ui/imports/issue-99695-b.rs b/tests/ui/imports/issue-99695-b.rs
new file mode 100644
index 0000000000000..031443a1f5df8
--- /dev/null
+++ b/tests/ui/imports/issue-99695-b.rs
@@ -0,0 +1,19 @@
+// run-rustfix
+#![allow(unused, nonstandard_style)]
+mod m {
+
+    mod p {
+        #[macro_export]
+        macro_rules! nu {
+            {} => {};
+        }
+
+        pub struct other_item;
+    }
+
+    pub use self::p::{nu, other_item as _};
+    //~^ ERROR unresolved import `self::p::nu` [E0432]
+    //~| HELP a macro with this name exists at the root of the crate
+}
+
+fn main() {}
diff --git a/tests/ui/imports/issue-99695-b.stderr b/tests/ui/imports/issue-99695-b.stderr
new file mode 100644
index 0000000000000..b6f5c726a5ca9
--- /dev/null
+++ b/tests/ui/imports/issue-99695-b.stderr
@@ -0,0 +1,16 @@
+error[E0432]: unresolved import `self::p::nu`
+  --> $DIR/issue-99695-b.rs:14:23
+   |
+LL |     pub use self::p::{nu, other_item as _};
+   |                       ^^ no `nu` in `m::p`
+   |
+   = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined
+help: a macro with this name exists at the root of the crate
+   |
+LL ~     use ::nu;
+LL ~ pub use self::p::{other_item as _};
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0432`.

From dca160a06a85cfe6d961a586543112e772e55b13 Mon Sep 17 00:00:00 2001
From: Michael Howell <michael@notriddle.com>
Date: Tue, 6 Dec 2022 08:42:30 -0700
Subject: [PATCH 3/4] diagnostics: use `module_path` to check crate import
 instead of strings

---
 compiler/rustc_resolve/src/diagnostics.rs | 24 ++++-------------------
 1 file changed, 4 insertions(+), 20 deletions(-)

diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index af4d7a8eafff3..0b60952ae3c08 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -2126,26 +2126,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 let source_map = self.r.session.source_map();
 
                 // Make sure this is actually crate-relative.
-                let use_and_crate = import.use_span.with_hi(after_crate_name.lo());
-                let is_definitely_crate =
-                    source_map.span_to_snippet(use_and_crate).map_or(false, |s| {
-                        let mut s = s.trim();
-                        debug!("check_for_module_export_macro: s={s:?}",);
-                        s = s
-                            .split_whitespace()
-                            .rev()
-                            .next()
-                            .expect("split_whitespace always yields at least once");
-                        debug!("check_for_module_export_macro: s={s:?}",);
-                        if s.ends_with("::") {
-                            s = &s[..s.len() - 2];
-                        } else {
-                            return false;
-                        }
-                        s = s.trim();
-                        debug!("check_for_module_export_macro: s={s:?}",);
-                        s != "self" && s != "super"
-                    });
+                let is_definitely_crate = import
+                    .module_path
+                    .first()
+                    .map_or(false, |f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super);
 
                 // Add the import to the start, with a `{` if required.
                 let start_point = source_map.start_point(after_crate_name);

From c07a722847497233e6590d62a3d63946409385c3 Mon Sep 17 00:00:00 2001
From: Michael Howell <michael@notriddle.com>
Date: Tue, 6 Dec 2022 08:44:48 -0700
Subject: [PATCH 4/4] diagnostics: remvoe unnecessary use of
 `source_map.start_point`

---
 compiler/rustc_resolve/src/diagnostics.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 0b60952ae3c08..8d104aa5cc592 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -2153,7 +2153,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 } else {
                     // If the root import is module-relative, add the import separately
                     corrections.push((
-                        source_map.start_point(import.use_span).shrink_to_lo(),
+                        import.use_span.shrink_to_lo(),
                         format!("use {module_name}::{import_snippet};\n"),
                     ));
                 }