about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2022-11-25 17:39:38 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2022-12-01 18:51:05 +0300
commit1f259ae6799e7e0a08e5b84fc5686e404b17eef0 (patch)
tree388417f61bf1eb19e633f3e613353f01c05b8730
parent6cd4dd3091dfe0ce4a728bd9ae177361fba23736 (diff)
downloadrust-1f259ae6799e7e0a08e5b84fc5686e404b17eef0.tar.gz
rust-1f259ae6799e7e0a08e5b84fc5686e404b17eef0.zip
rustc_hir: Change representation of import paths to support multiple resolutions
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs21
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs21
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher.rs2
-rw-r--r--compiler/rustc_hir/src/arena.rs1
-rw-r--r--compiler/rustc_hir/src/hir.rs9
-rw-r--r--compiler/rustc_hir/src/intravisit.rs9
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs2
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs2
-rw-r--r--compiler/rustc_save_analysis/src/dump_visitor.rs4
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs4
-rw-r--r--src/librustdoc/clean/mod.rs20
-rw-r--r--src/librustdoc/clean/types.rs11
-rw-r--r--src/librustdoc/html/render/span_map.rs8
-rw-r--r--src/librustdoc/visit_ast.rs59
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_types.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs59
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs3
19 files changed, 134 insertions, 112 deletions
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 2b47e908912..b26b37b0466 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -508,7 +508,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let mut resolutions = self.expect_full_res_from_use(id).fuse();
                 // We want to return *something* from this function, so hold onto the first item
                 // for later.
-                let ret_res = self.lower_res(resolutions.next().unwrap_or(Res::Err));
+                let ret_res = smallvec![self.lower_res(resolutions.next().unwrap_or(Res::Err))];
 
                 // Here, we are looping over namespaces, if they exist for the definition
                 // being imported. We only handle type and value namespaces because we
@@ -538,8 +538,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     let span = path.span;
 
                     self.with_hir_id_owner(new_node_id, |this| {
-                        let res = this.lower_res(res);
-                        let path = this.lower_path_extra(res, &path, ParamMode::Explicit);
+                        let res = smallvec![this.lower_res(res)];
+                        let path = this.lower_use_path(res, &path, ParamMode::Explicit);
                         let kind = hir::ItemKind::Use(path, hir::UseKind::Single);
                         if let Some(attrs) = attrs {
                             this.attrs.insert(hir::ItemLocalId::new(0), attrs);
@@ -556,15 +556,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     });
                 }
 
-                let path = self.lower_path_extra(ret_res, &path, ParamMode::Explicit);
+                let path = self.lower_use_path(ret_res, &path, ParamMode::Explicit);
                 hir::ItemKind::Use(path, hir::UseKind::Single)
             }
             UseTreeKind::Glob => {
-                let path = self.lower_path(
-                    id,
-                    &Path { segments, span: path.span, tokens: None },
-                    ParamMode::Explicit,
-                );
+                let res = self.expect_full_res(id);
+                let res = smallvec![self.lower_res(res)];
+                let path = Path { segments, span: path.span, tokens: None };
+                let path = self.lower_use_path(res, &path, ParamMode::Explicit);
                 hir::ItemKind::Use(path, hir::UseKind::Glob)
             }
             UseTreeKind::Nested(ref trees) => {
@@ -635,8 +634,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 }
 
                 let res = self.expect_full_res_from_use(id).next().unwrap_or(Res::Err);
-                let res = self.lower_res(res);
-                let path = self.lower_path_extra(res, &prefix, ParamMode::Explicit);
+                let res = smallvec![self.lower_res(res)];
+                let path = self.lower_use_path(res, &prefix, ParamMode::Explicit);
                 hir::ItemKind::Use(path, hir::UseKind::ListStem)
             }
         }
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index dc85b5e95ea..8d23c26e603 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -12,7 +12,7 @@ use rustc_hir::GenericArg;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::{BytePos, Span, DUMMY_SP};
 
-use smallvec::smallvec;
+use smallvec::{smallvec, SmallVec};
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
     #[instrument(level = "trace", skip(self))]
@@ -144,13 +144,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         );
     }
 
-    pub(crate) fn lower_path_extra(
+    pub(crate) fn lower_use_path(
         &mut self,
-        res: Res,
+        res: SmallVec<[Res; 3]>,
         p: &Path,
         param_mode: ParamMode,
-    ) -> &'hir hir::Path<'hir> {
-        self.arena.alloc(hir::Path {
+    ) -> &'hir hir::UsePath<'hir> {
+        self.arena.alloc(hir::UsePath {
             res,
             segments: self.arena.alloc_from_iter(p.segments.iter().map(|segment| {
                 self.lower_path_segment(
@@ -165,17 +165,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         })
     }
 
-    pub(crate) fn lower_path(
-        &mut self,
-        id: NodeId,
-        p: &Path,
-        param_mode: ParamMode,
-    ) -> &'hir hir::Path<'hir> {
-        let res = self.expect_full_res(id);
-        let res = self.lower_res(res);
-        self.lower_path_extra(res, p, param_mode)
-    }
-
     pub(crate) fn lower_path_segment(
         &mut self,
         path_span: Span,
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index ce859173418..e2c33e7e062 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -399,7 +399,7 @@ where
     }
 }
 
-impl<A, CTX> HashStable<CTX> for SmallVec<[A; 1]>
+impl<A, const N: usize, CTX> HashStable<CTX> for SmallVec<[A; N]>
 where
     A: HashStable<CTX>,
 {
diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs
index 44335b7f42e..c89e7eb75f8 100644
--- a/compiler/rustc_hir/src/arena.rs
+++ b/compiler/rustc_hir/src/arena.rs
@@ -39,6 +39,7 @@ macro_rules! arena_types {
             [] param: rustc_hir::Param<'tcx>,
             [] pat: rustc_hir::Pat<'tcx>,
             [] path: rustc_hir::Path<'tcx>,
+            [] use_path: rustc_hir::UsePath<'tcx>,
             [] path_segment: rustc_hir::PathSegment<'tcx>,
             [] poly_trait_ref: rustc_hir::PolyTraitRef<'tcx>,
             [] qpath: rustc_hir::QPath<'tcx>,
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 81aedcce877..118eafe2910 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -183,14 +183,17 @@ impl Lifetime {
 /// `std::cmp::PartialEq`. It's represented as a sequence of identifiers,
 /// along with a bunch of supporting information.
 #[derive(Debug, HashStable_Generic)]
-pub struct Path<'hir> {
+pub struct Path<'hir, R = Res> {
     pub span: Span,
     /// The resolution for the path.
-    pub res: Res,
+    pub res: R,
     /// The segments in the path: the things separated by `::`.
     pub segments: &'hir [PathSegment<'hir>],
 }
 
+/// Up to three resolutions for type, value and macro namespaces.
+pub type UsePath<'hir> = Path<'hir, SmallVec<[Res; 3]>>;
+
 impl Path<'_> {
     pub fn is_global(&self) -> bool {
         !self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot
@@ -3068,7 +3071,7 @@ pub enum ItemKind<'hir> {
     /// or just
     ///
     /// `use foo::bar::baz;` (with `as baz` implicitly on the right).
-    Use(&'hir Path<'hir>, UseKind),
+    Use(&'hir UsePath<'hir>, UseKind),
 
     /// A `static` item.
     Static(&'hir Ty<'hir>, Mutability, BodyId),
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 9eeb04c8e01..cbb530424ca 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -367,7 +367,7 @@ pub trait Visitor<'v>: Sized {
     fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl<'v>, b: BodyId, _: Span, id: HirId) {
         walk_fn(self, fk, fd, b, id)
     }
-    fn visit_use(&mut self, path: &'v Path<'v>, hir_id: HirId) {
+    fn visit_use(&mut self, path: &'v UsePath<'v>, hir_id: HirId) {
         walk_use(self, path, hir_id)
     }
     fn visit_trait_item(&mut self, ti: &'v TraitItem<'v>) {
@@ -938,9 +938,12 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'
     }
 }
 
-pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>, hir_id: HirId) {
+pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v UsePath<'v>, hir_id: HirId) {
     visitor.visit_id(hir_id);
-    visitor.visit_path(path, hir_id);
+    let UsePath { segments, ref res, span } = *path;
+    for &res in res {
+        visitor.visit_path(&Path { segments, res, span }, hir_id);
+    }
 }
 
 pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem<'v>) {
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 95729822677..2460a23bb3f 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1591,7 +1591,7 @@ impl<'a> State<'a> {
         self.print_ident(Ident::with_dummy_span(name))
     }
 
-    pub fn print_path(&mut self, path: &hir::Path<'_>, colons_before_params: bool) {
+    pub fn print_path<R>(&mut self, path: &hir::Path<'_, R>, colons_before_params: bool) {
         self.maybe_print_comment(path.span.lo());
 
         for (i, segment) in path.segments.iter().enumerate() {
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 20951878e00..a7854cd4998 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -369,7 +369,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         hir_visit::walk_fn(self, fk, fd, b, id)
     }
 
-    fn visit_use(&mut self, p: &'v hir::Path<'v>, hir_id: hir::HirId) {
+    fn visit_use(&mut self, p: &'v hir::UsePath<'v>, hir_id: hir::HirId) {
         // This is `visit_use`, but the type is `Path` so record it that way.
         self.record("Path", Id::None, p);
         hir_visit::walk_use(self, p, hir_id)
diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs
index fae20c2ba5f..b4528853825 100644
--- a/compiler/rustc_save_analysis/src/dump_visitor.rs
+++ b/compiler/rustc_save_analysis/src/dump_visitor.rs
@@ -185,13 +185,13 @@ impl<'tcx> DumpVisitor<'tcx> {
         }
     }
 
-    fn write_sub_paths(&mut self, path: &'tcx hir::Path<'tcx>) {
+    fn write_sub_paths<R>(&mut self, path: &'tcx hir::Path<'tcx, R>) {
         self.write_segments(path.segments)
     }
 
     // As write_sub_paths, but does not process the last ident in the path (assuming it
     // will be processed elsewhere). See note on write_sub_paths about global.
-    fn write_sub_paths_truncated(&mut self, path: &'tcx hir::Path<'tcx>) {
+    fn write_sub_paths_truncated<R>(&mut self, path: &'tcx hir::Path<'tcx, R>) {
         if let [segments @ .., _] = path.segments {
             self.write_segments(segments)
         }
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index 4fa0c14715e..f05eb2b7432 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -594,7 +594,9 @@ impl<'tcx> SaveContext<'tcx> {
         match self.tcx.hir().get(hir_id) {
             Node::TraitRef(tr) => tr.path.res,
 
-            Node::Item(&hir::Item { kind: hir::ItemKind::Use(path, _), .. }) => path.res,
+            Node::Item(&hir::Item { kind: hir::ItemKind::Use(path, _), .. }) => {
+                path.res.get(0).copied().unwrap_or(Res::Err)
+            }
             Node::PathSegment(seg) => {
                 if seg.res != Res::Err {
                     seg.res
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index b18788a033f..80909919ba2 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2233,6 +2233,26 @@ fn clean_extern_crate<'tcx>(
 fn clean_use_statement<'tcx>(
     import: &hir::Item<'tcx>,
     name: Symbol,
+    path: &hir::UsePath<'tcx>,
+    kind: hir::UseKind,
+    cx: &mut DocContext<'tcx>,
+    inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
+) -> Vec<Item> {
+    let mut items = Vec::new();
+    let hir::UsePath { segments, ref res, span } = *path;
+    for &res in res {
+        if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
+            continue;
+        }
+        let path = hir::Path { segments, res, span };
+        items.append(&mut clean_use_statement_inner(import, name, &path, kind, cx, inlined_names));
+    }
+    items
+}
+
+fn clean_use_statement_inner<'tcx>(
+    import: &hir::Item<'tcx>,
+    name: Symbol,
     path: &hir::Path<'tcx>,
     kind: hir::UseKind,
     cx: &mut DocContext<'tcx>,
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index ed4e9508f43..2590bb0df3f 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -242,7 +242,9 @@ impl ExternalCrate {
                         hir::ItemKind::Use(path, hir::UseKind::Single)
                             if tcx.visibility(id.owner_id).is_public() =>
                         {
-                            as_keyword(path.res.expect_non_local())
+                            path.res
+                                .iter()
+                                .find_map(|res| as_keyword(res.expect_non_local()))
                                 .map(|(_, prim)| (id.owner_id.to_def_id(), prim))
                         }
                         _ => None,
@@ -310,10 +312,11 @@ impl ExternalCrate {
                         hir::ItemKind::Use(path, hir::UseKind::Single)
                             if tcx.visibility(id.owner_id).is_public() =>
                         {
-                            as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
+                            path.res
+                                .iter()
+                                .find_map(|res| as_primitive(res.expect_non_local()))
                                 // Pretend the primitive is local.
-                                (id.owner_id.to_def_id(), prim)
-                            })
+                                .map(|(_, prim)| (id.owner_id.to_def_id(), prim))
                         }
                         _ => None,
                     }
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index b898db24246..4514894cabe 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -190,12 +190,4 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
         }
         intravisit::walk_expr(self, expr);
     }
-
-    fn visit_use(&mut self, path: &'tcx rustc_hir::Path<'tcx>, id: HirId) {
-        if self.handle_macro(path.span) {
-            return;
-        }
-        self.handle_path(path);
-        intravisit::walk_use(self, path, id);
-    }
 }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index c788b9f4093..22068ebe041 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -301,39 +301,40 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             hir::ItemKind::GlobalAsm(..) => {}
             hir::ItemKind::Use(_, hir::UseKind::ListStem) => {}
             hir::ItemKind::Use(path, kind) => {
-                let is_glob = kind == hir::UseKind::Glob;
-
-                // Struct and variant constructors and proc macro stubs always show up alongside
-                // their definitions, we've already processed them so just discard these.
-                if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = path.res {
-                    return;
-                }
-
-                let attrs = self.cx.tcx.hir().attrs(item.hir_id());
+                for &res in &path.res {
+                    // Struct and variant constructors and proc macro stubs always show up alongside
+                    // their definitions, we've already processed them so just discard these.
+                    if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
+                        continue;
+                    }
 
-                // If there was a private module in the current path then don't bother inlining
-                // anything as it will probably be stripped anyway.
-                if is_pub && self.inside_public_path {
-                    let please_inline = attrs.iter().any(|item| match item.meta_item_list() {
-                        Some(ref list) if item.has_name(sym::doc) => {
-                            list.iter().any(|i| i.has_name(sym::inline))
+                    let attrs = self.cx.tcx.hir().attrs(item.hir_id());
+
+                    // If there was a private module in the current path then don't bother inlining
+                    // anything as it will probably be stripped anyway.
+                    if is_pub && self.inside_public_path {
+                        let please_inline = attrs.iter().any(|item| match item.meta_item_list() {
+                            Some(ref list) if item.has_name(sym::doc) => {
+                                list.iter().any(|i| i.has_name(sym::inline))
+                            }
+                            _ => false,
+                        });
+                        let is_glob = kind == hir::UseKind::Glob;
+                        let ident = if is_glob { None } else { Some(name) };
+                        if self.maybe_inline_local(
+                            item.hir_id(),
+                            res,
+                            ident,
+                            is_glob,
+                            om,
+                            please_inline,
+                        ) {
+                            continue;
                         }
-                        _ => false,
-                    });
-                    let ident = if is_glob { None } else { Some(name) };
-                    if self.maybe_inline_local(
-                        item.hir_id(),
-                        path.res,
-                        ident,
-                        is_glob,
-                        om,
-                        please_inline,
-                    ) {
-                        return;
                     }
-                }
 
-                om.items.push((item, renamed, parent_id))
+                    om.items.push((item, renamed, parent_id))
+                }
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
                 // `#[macro_export] macro_rules!` items are handled separately in `visit()`,
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
index aee3d8c4f08..1f56d0118a4 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
@@ -106,7 +106,9 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
 
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         if let ItemKind::Use(path, UseKind::Single) = &item.kind {
-            self.check_res_emit(cx, &path.res, item.span);
+            for res in &path.res {
+                self.check_res_emit(cx, res, item.span);
+            }
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index 594f6af76b3..e2e6a87a301 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -94,7 +94,10 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
             let hir_id = item.hir_id();
             let attrs = cx.tcx.hir().attrs(hir_id);
             if let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use));
-            if let Res::Def(DefKind::Mod, id) = path.res;
+            if let Some(id) = path.res.iter().find_map(|res| match res {
+                Res::Def(DefKind::Mod, id) => Some(id),
+                _ => None,
+            });
             if !id.is_local();
             then {
                 for kid in cx.tcx.module_children(id).iter() {
diff --git a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
index 4712846939e..773174679db 100644
--- a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
@@ -66,35 +66,38 @@ impl LateLintPass<'_> for ImportRename {
     }
 
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if_chain! {
-            if let ItemKind::Use(path, UseKind::Single) = &item.kind;
-            if let Res::Def(_, id) = path.res;
-            if let Some(name) = self.renames.get(&id);
-            // Remove semicolon since it is not present for nested imports
-            let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';');
-            if let Some(snip) = snippet_opt(cx, span_without_semi);
-            if let Some(import) = match snip.split_once(" as ") {
-                None => Some(snip.as_str()),
-                Some((import, rename)) => {
-                    if rename.trim() == name.as_str() {
-                        None
-                    } else {
-                        Some(import.trim())
+        if let ItemKind::Use(path, UseKind::Single) = &item.kind {
+            for &res in &path.res {
+                if_chain! {
+                    if let Res::Def(_, id) = res;
+                    if let Some(name) = self.renames.get(&id);
+                    // Remove semicolon since it is not present for nested imports
+                    let span_without_semi = cx.sess().source_map().span_until_char(item.span, ';');
+                    if let Some(snip) = snippet_opt(cx, span_without_semi);
+                    if let Some(import) = match snip.split_once(" as ") {
+                        None => Some(snip.as_str()),
+                        Some((import, rename)) => {
+                            if rename.trim() == name.as_str() {
+                                None
+                            } else {
+                                Some(import.trim())
+                            }
+                        },
+                    };
+                    then {
+                        span_lint_and_sugg(
+                            cx,
+                            MISSING_ENFORCED_IMPORT_RENAMES,
+                            span_without_semi,
+                            "this import should be renamed",
+                            "try",
+                            format!(
+                                "{import} as {name}",
+                            ),
+                            Applicability::MachineApplicable,
+                        );
                     }
-                },
-            };
-            then {
-                span_lint_and_sugg(
-                    cx,
-                    MISSING_ENFORCED_IMPORT_RENAMES,
-                    span_without_semi,
-                    "this import should be renamed",
-                    "try",
-                    format!(
-                        "{import} as {name}",
-                    ),
-                    Applicability::MachineApplicable,
-                );
+                }
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index 833dc4913b4..d612d249c2f 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
 
 fn is_not_macro_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
     if let ItemKind::Use(path, _) = item.kind {
-        if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = path.res {
+        if path.res.iter().all(|res| matches!(res, Res::Def(DefKind::Macro(MacroKind::Bang), _))) {
             return false;
         }
     } else if let ItemKind::Macro(..) = item.kind {
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index be98344470b..e4d1ee195c4 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -176,7 +176,8 @@ impl LateLintPass<'_> for WildcardImports {
                     format!("{import_source_snippet}::{imports_string}")
                 };
 
-                let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res {
+                // Glob imports always have a single resolution.
+                let (lint, message) = if let Res::Def(DefKind::Enum, _) = use_path.res[0] {
                     (ENUM_GLOB_USE, "usage of wildcard import for enum variants")
                 } else {
                     (WILDCARD_IMPORTS, "usage of wildcard import")