From 3936430d4c21ca2f359e88ba638092eb242f853b Mon Sep 17 00:00:00 2001
From: Alik Aslanyan <inline0@protonmail.com>
Date: Wed, 22 Dec 2021 02:03:51 +0400
Subject: [PATCH 1/2] Add failing test

---
 .../auxiliary/other_crate.rs                     |  8 ++++++++
 .../dont-suggest-doc-hidden-variant-for-enum.rs  |  7 +++++++
 ...nt-suggest-doc-hidden-variant-for-enum.stderr | 16 ++++++++++++++++
 3 files changed, 31 insertions(+)
 create mode 100644 src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/other_crate.rs
 create mode 100644 src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/dont-suggest-doc-hidden-variant-for-enum.rs
 create mode 100644 src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/dont-suggest-doc-hidden-variant-for-enum.stderr

diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/other_crate.rs b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/other_crate.rs
new file mode 100644
index 0000000000000..13bf9a7a28928
--- /dev/null
+++ b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/other_crate.rs
@@ -0,0 +1,8 @@
+#![crate_type = "lib"]
+
+extern crate core;
+
+#[doc(hidden)]
+pub mod __private {
+	pub use core::option::Option::{self, None, Some};
+}
diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/dont-suggest-doc-hidden-variant-for-enum.rs b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/dont-suggest-doc-hidden-variant-for-enum.rs
new file mode 100644
index 0000000000000..71bf64dafc7c9
--- /dev/null
+++ b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/dont-suggest-doc-hidden-variant-for-enum.rs
@@ -0,0 +1,7 @@
+// aux-build:other_crate.rs
+
+extern crate other_crate;
+
+fn main() {
+    let x: Option<i32> = 1i32; //~ ERROR 6:26: 6:30: mismatched types [E0308]
+}
diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/dont-suggest-doc-hidden-variant-for-enum.stderr b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/dont-suggest-doc-hidden-variant-for-enum.stderr
new file mode 100644
index 0000000000000..709dec3ec3132
--- /dev/null
+++ b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/dont-suggest-doc-hidden-variant-for-enum.stderr
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/dont-suggest-doc-hidden-variant-for-enum.rs:6:26
+   |
+LL |     let x: Option<i32> = 1i32;
+   |            -----------   ^^^^
+   |            |             |
+   |            |             expected enum `Option`, found `i32`
+   |            |             help: try using a variant of the expected enum: `Some(1i32)`
+   |            expected due to this
+   |
+   = note: expected enum `Option<i32>`
+              found type `i32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.

From 875c9c963c1ec9ccac71112ae875599d70b0dc86 Mon Sep 17 00:00:00 2001
From: Alik Aslanyan <inline0@protonmail.com>
Date: Wed, 22 Dec 2021 02:03:52 +0400
Subject: [PATCH 2/2] Prefer visible paths which are not doc-hidden

---
 compiler/rustc_ast/src/attr/mod.rs            |   9 ++
 .../src/stable_hasher.rs                      |   6 +-
 .../src/rmeta/decoder/cstore_impl.rs          | 122 ++++++++++--------
 compiler/rustc_middle/src/query/mod.rs        |  10 +-
 compiler/rustc_middle/src/ty/print/pretty.rs  |   8 +-
 compiler/rustc_middle/src/ty/query.rs         |   2 +-
 compiler/rustc_ty_utils/src/ty.rs             |  27 ++--
 .../rustc_typeck/src/check/fn_ctxt/checks.rs  |   4 +-
 .../rustc_typeck/src/check/method/suggest.rs  |  22 ++--
 compiler/rustc_typeck/src/check/pat.rs        |   3 +-
 .../wrong_number_of_generic_args.rs           |   6 +-
 src/test/ui/proc-macro/issue-37788.rs         |   2 +-
 src/test/ui/proc-macro/issue-37788.stderr     |   2 +-
 .../auxiliary/other_crate.rs                  |   2 +-
 ...suggest-doc-hidden-variant-for-enum.stderr |  10 +-
 src/tools/clippy/clippy_lints/src/doc.rs      |   2 +-
 .../clippy_lints/src/manual_non_exhaustive.rs |   2 +-
 src/tools/clippy/clippy_lints/src/matches.rs  |   5 +-
 .../clippy/clippy_lints/src/missing_doc.rs    |   3 +-
 src/tools/clippy/clippy_utils/src/attrs.rs    |  11 +-
 20 files changed, 139 insertions(+), 119 deletions(-)

diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 927d7c6aaf6a4..fa918ff1bce1b 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -580,3 +580,12 @@ impl NestedMetaItem {
         MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem)
     }
 }
+
+/// Return true if the attributes contain `#[doc(hidden)]`
+pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool {
+    attrs
+        .iter()
+        .filter(|attr| attr.has_name(sym::doc))
+        .filter_map(ast::Attribute::meta_item_list)
+        .any(|l| list_contains_name(&l, sym::hidden))
+}
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index d87aa5ed0d552..673fd3fc0b940 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -346,9 +346,11 @@ where
     }
 }
 
-impl<A, CTX> HashStable<CTX> for SmallVec<[A; 1]>
+impl<T, CTX, const N: usize> HashStable<CTX> for SmallVec<[T; N]>
 where
-    A: HashStable<CTX>,
+    T: HashStable<CTX>,
+    [T; N]: smallvec::Array,
+    <[T; N] as smallvec::Array>::Item: HashStable<CTX>,
 {
     #[inline]
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 4e5d21049a0d9..b82970721de66 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -133,8 +133,8 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     generator_kind => { cdata.generator_kind(def_id.index) }
     opt_def_kind => { Some(cdata.def_kind(def_id.index)) }
     def_span => { cdata.get_span(def_id.index, &tcx.sess) }
-    def_ident_span => {
-        cdata.try_item_ident(def_id.index, &tcx.sess).ok().map(|ident| ident.span)
+    def_ident => {
+        cdata.try_item_ident(def_id.index, &tcx.sess).ok()
     }
     lookup_stability => {
         cdata.get_stability(def_id.index).map(|s| tcx.intern_stability(s))
@@ -290,15 +290,11 @@ pub fn provide(providers: &mut Providers) {
         // external item that is visible from at least one local module) to a
         // sufficiently visible parent (considering modules that re-export the
         // external item to be parents).
-        visible_parent_map: |tcx, ()| {
-            use std::collections::hash_map::Entry;
-            use std::collections::vec_deque::VecDeque;
+        visible_parents_map: |tcx, ()| {
+            use rustc_data_structures::fx::FxHashSet;
+            use std::collections::VecDeque;
 
-            let mut visible_parent_map: DefIdMap<DefId> = Default::default();
-            // This is a secondary visible_parent_map, storing the DefId of parents that re-export
-            // the child as `_`. Since we prefer parents that don't do this, merge this map at the
-            // end, only if we're missing any keys from the former.
-            let mut fallback_map: DefIdMap<DefId> = Default::default();
+            let mut visible_parents_map: DefIdMap<SmallVec<[DefId; 4]>> = DefIdMap::default();
 
             // Issue 46112: We want the map to prefer the shortest
             // paths when reporting the path to an item. Therefore we
@@ -310,59 +306,81 @@ pub fn provide(providers: &mut Providers) {
             // only get paths that are locally minimal with respect to
             // whatever crate we happened to encounter first in this
             // traversal, but not globally minimal across all crates.
-            let bfs_queue = &mut VecDeque::new();
-
-            for &cnum in tcx.crates(()) {
-                // Ignore crates without a corresponding local `extern crate` item.
-                if tcx.missing_extern_crate_item(cnum) {
-                    continue;
+            let mut bfs_queue = VecDeque::default();
+
+            bfs_queue.extend(
+                tcx.crates(())
+                    .into_iter()
+                    // Ignore crates without a corresponding local `extern crate` item.
+                    .filter(|cnum| !tcx.missing_extern_crate_item(**cnum))
+                    .map(|cnum| DefId { krate: *cnum, index: CRATE_DEF_INDEX }),
+            );
+
+            // Iterate over graph using BFS.
+            // Filter out any non-public items.
+            while let Some(parent) = bfs_queue.pop_front() {
+                for child in tcx
+                    .item_children(parent)
+                    .iter()
+                    .filter(|child| child.vis.is_public())
+                    .filter_map(|child| child.res.opt_def_id())
+                {
+                    visible_parents_map
+                        .entry(child)
+                        .or_insert_with(|| {
+                            // If we encounter node the first time
+                            // add it to queue for next iterations
+                            bfs_queue.push_back(child);
+                            Default::default()
+                        })
+                        .push(parent);
                 }
+            }
 
-                bfs_queue.push_back(DefId { krate: cnum, index: CRATE_DEF_INDEX });
+            // Iterate over parents vector to remove duplicate elements
+            // while preserving order
+            let mut dedup_set = FxHashSet::default();
+            for (_, parents) in &mut visible_parents_map {
+                parents.retain(|parent| dedup_set.insert(*parent));
+
+                // Reuse hashset allocation.
+                dedup_set.clear();
             }
 
-            let mut add_child = |bfs_queue: &mut VecDeque<_>, export: &Export, parent: DefId| {
-                if !export.vis.is_public() {
-                    return;
-                }
+            visible_parents_map
+        },
+        best_visible_parent: |tcx, child| {
+            // Use `min_by_key` because it returns
+            // first match in case keys are equal
+            tcx.visible_parents_map(())
+                .get(&child)?
+                .into_iter()
+                .min_by_key(|parent| {
+                    // If this is just regular export in another module, assign it a neutral score.
+                    let mut score = 0;
+
+                    // If child and parent are local, we prefer them
+                    if child.is_local() && parent.is_local() {
+                        score += 1;
+                    }
 
-                if let Some(child) = export.res.opt_def_id() {
-                    if export.ident.name == kw::Underscore {
-                        fallback_map.insert(child, parent);
-                        return;
+                    // Even if child and parent are local, if parent is `#[doc(hidden)]`
+                    // We reduce their score to avoid showing items not popping in documentation.
+                    if ast::attr::is_doc_hidden(tcx.item_attrs(**parent)) {
+                        score -= 2;
                     }
 
-                    match visible_parent_map.entry(child) {
-                        Entry::Occupied(mut entry) => {
-                            // If `child` is defined in crate `cnum`, ensure
-                            // that it is mapped to a parent in `cnum`.
-                            if child.is_local() && entry.get().is_local() {
-                                entry.insert(parent);
-                            }
-                        }
-                        Entry::Vacant(entry) => {
-                            entry.insert(parent);
-                            bfs_queue.push_back(child);
+                    // If parent identifier is _ we prefer it only as last resort if other items are not available
+                    if let Some(ident) = tcx.def_ident(**parent) {
+                        if ident.name == kw::Underscore {
+                            score -= 3;
                         }
                     }
-                }
-            };
-
-            while let Some(def) = bfs_queue.pop_front() {
-                for child in tcx.item_children(def).iter() {
-                    add_child(bfs_queue, child, def);
-                }
-            }
 
-            // Fill in any missing entries with the (less preferable) path ending in `::_`.
-            // We still use this path in a diagnostic that suggests importing `::*`.
-            for (child, parent) in fallback_map {
-                visible_parent_map.entry(child).or_insert(parent);
-            }
-
-            visible_parent_map
+                    -score
+                })
+                .map(ToOwned::to_owned)
         },
-
         dependency_formats: |tcx, ()| Lrc::new(crate::dependency_format::calculate(tcx)),
         has_global_allocator: |tcx, cnum| {
             assert_eq!(cnum, LOCAL_CRATE);
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index ad3f61d07843a..fd1e5c182ea97 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -977,8 +977,8 @@ rustc_queries! {
     }
 
     /// Gets the span for the identifier of the definition.
-    query def_ident_span(def_id: DefId) -> Option<Span> {
-        desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) }
+    query def_ident(def_id: DefId) -> Option<Ident> {
+        desc { |tcx| "looking up ident for `{}`'s identifier", tcx.def_path_str(def_id) }
         separate_provide_extern
     }
 
@@ -1552,10 +1552,14 @@ rustc_queries! {
         desc { "calculating the missing lang items in a crate" }
         separate_provide_extern
     }
-    query visible_parent_map(_: ()) -> DefIdMap<DefId> {
+
+    query visible_parents_map(_: ()) -> DefIdMap<smallvec::SmallVec<[DefId; 4]>> {
         storage(ArenaCacheSelector<'tcx>)
         desc { "calculating the visible parent map" }
     }
+    query best_visible_parent(child: DefId) -> Option<DefId> {
+        desc { "calculating best visible parent" }
+    }
     query trimmed_def_paths(_: ()) -> FxHashMap<DefId, Symbol> {
         storage(ArenaCacheSelector<'tcx>)
         desc { "calculating trimmed def paths" }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 47a9234419c2d..b4fe26b0a0379 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -387,8 +387,6 @@ pub trait PrettyPrinter<'tcx>:
             return Ok((self, false));
         }
 
-        let visible_parent_map = self.tcx().visible_parent_map(());
-
         let mut cur_def_key = self.tcx().def_key(def_id);
         debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key);
 
@@ -404,7 +402,7 @@ pub trait PrettyPrinter<'tcx>:
             cur_def_key = self.tcx().def_key(parent);
         }
 
-        let visible_parent = match visible_parent_map.get(&def_id).cloned() {
+        let visible_parent = match self.tcx().best_visible_parent(def_id) {
             Some(parent) => parent,
             None => return Ok((self, false)),
         };
@@ -431,7 +429,7 @@ pub trait PrettyPrinter<'tcx>:
             // `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
             // private so the "true" path to `CommandExt` isn't accessible.
             //
-            // In this case, the `visible_parent_map` will look something like this:
+            // In this case, the `visible_parents_map` will look something like this:
             //
             // (child) -> (parent)
             // `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
@@ -451,7 +449,7 @@ pub trait PrettyPrinter<'tcx>:
             // do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
             // the visible parent (`std::os`). If these do not match, then we iterate over
             // the children of the visible parent (as was done when computing
-            // `visible_parent_map`), looking for the specific child we currently have and then
+            // `visible_parents_map`), looking for the specific child we currently have and then
             // have access to the re-exported name.
             DefPathData::TypeNs(ref mut name) if Some(visible_parent) != actual_parent => {
                 // Item might be re-exported several times, but filter for the one
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index 2f91503afdfaf..c119d34a3d8fe 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -30,7 +30,7 @@ use crate::traits::specialization_graph;
 use crate::traits::{self, ImplSource};
 use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::util::AlwaysRequiresDrop;
-use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
+use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, Ident, ParamEnvAnd, Ty, TyCtxt};
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::steal::Steal;
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 6c2657bd64bdb..df73de4fcd02e 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -3,7 +3,7 @@ use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
-use rustc_span::{sym, Span};
+use rustc_span::{sym, symbol::Ident};
 use rustc_trait_selection::traits;
 
 fn sized_constraint_for_ty<'tcx>(
@@ -216,19 +216,16 @@ fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
     ty::AssocItems::new(items)
 }
 
-fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
-    tcx.hir()
-        .get_if_local(def_id)
-        .and_then(|node| match node {
-            // A `Ctor` doesn't have an identifier itself, but its parent
-            // struct/variant does. Compare with `hir::Map::opt_span`.
-            hir::Node::Ctor(ctor) => ctor
-                .ctor_hir_id()
-                .and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id)))
-                .and_then(|parent| parent.ident()),
-            _ => node.ident(),
-        })
-        .map(|ident| ident.span)
+fn def_ident(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ident> {
+    tcx.hir().get_if_local(def_id).and_then(|node| match node {
+        // A `Ctor` doesn't have an identifier itself, but its parent
+        // struct/variant does. Compare with `hir::Map::opt_span`.
+        hir::Node::Ctor(ctor) => ctor
+            .ctor_hir_id()
+            .and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id)))
+            .and_then(|parent| parent.ident()),
+        _ => node.ident(),
+    })
 }
 
 /// If the given `DefId` describes an item belonging to a trait,
@@ -624,7 +621,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
         associated_item_def_ids,
         associated_items,
         adt_sized_constraint,
-        def_ident_span,
+        def_ident,
         param_env,
         param_env_reveal_all_normalized,
         trait_of_item,
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 11b63a99043b7..e4f4d368481c9 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -197,8 +197,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
 
             if let Some(def_id) = def_id {
-                if let Some(def_span) = tcx.def_ident_span(def_id) {
-                    let mut spans: MultiSpan = def_span.into();
+                if let Some(def_ident) = tcx.def_ident(def_id) {
+                    let mut spans: MultiSpan = def_ident.span.into();
 
                     let params = tcx
                         .hir()
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index d5a4de86d4d1e..3a5ee76f44953 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -12,7 +12,7 @@ use rustc_hir::{ExprKind, Node, QPath};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams, StripReferences};
 use rustc_middle::ty::print::with_crate_prefix;
-use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_span::lev_distance;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
@@ -1310,17 +1310,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         mut msg: String,
         candidates: Vec<DefId>,
     ) {
-        let parent_map = self.tcx.visible_parent_map(());
-
         // Separate out candidates that must be imported with a glob, because they are named `_`
         // and cannot be referred with their identifier.
         let (candidates, globs): (Vec<_>, Vec<_>) = candidates.into_iter().partition(|trait_did| {
-            if let Some(parent_did) = parent_map.get(trait_did) {
+            if let Some(parent_did) = self.tcx.best_visible_parent(*trait_did) {
                 // If the item is re-exported as `_`, we should suggest a glob-import instead.
-                if Some(*parent_did) != self.tcx.parent(*trait_did)
+                if Some(parent_did) != self.tcx.best_visible_parent(*trait_did)
                     && self
                         .tcx
-                        .item_children(*parent_did)
+                        .item_children(parent_did)
                         .iter()
                         .filter(|child| child.res.opt_def_id() == Some(*trait_did))
                         .all(|child| child.ident.name == kw::Underscore)
@@ -1347,14 +1345,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             });
 
             let glob_path_strings = globs.iter().map(|trait_did| {
-                let parent_did = parent_map.get(trait_did).unwrap();
-
                 // Produce an additional newline to separate the new use statement
                 // from the directly following item.
                 let additional_newline = if found_use { "" } else { "\n" };
                 format!(
                     "use {}::*; // trait {}\n{}",
-                    with_crate_prefix(|| self.tcx.def_path_str(*parent_did)),
+                    with_crate_prefix(|| self
+                        .tcx
+                        .def_path_str(self.tcx.best_visible_parent(*trait_did).unwrap())),
                     self.tcx.item_name(*trait_did),
                     additional_newline
                 )
@@ -1385,19 +1383,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             for (i, trait_did) in
                 globs.iter().take(limit.saturating_sub(candidates.len())).enumerate()
             {
-                let parent_did = parent_map.get(trait_did).unwrap();
+                let parent_did = self.tcx.best_visible_parent(*trait_did).unwrap();
 
                 if candidates.len() + globs.len() > 1 {
                     msg.push_str(&format!(
                         "\ncandidate #{}: `use {}::*; // trait {}`",
                         candidates.len() + i + 1,
-                        with_crate_prefix(|| self.tcx.def_path_str(*parent_did)),
+                        with_crate_prefix(|| self.tcx.def_path_str(parent_did)),
                         self.tcx.item_name(*trait_did),
                     ));
                 } else {
                     msg.push_str(&format!(
                         "\n`use {}::*; // trait {}`",
-                        with_crate_prefix(|| self.tcx.def_path_str(*parent_did)),
+                        with_crate_prefix(|| self.tcx.def_path_str(parent_did)),
                         self.tcx.item_name(*trait_did),
                     ));
                 }
diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs
index ec06e0b11264d..694417389a837 100644
--- a/compiler/rustc_typeck/src/check/pat.rs
+++ b/compiler/rustc_typeck/src/check/pat.rs
@@ -1025,7 +1025,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
         let last_subpat_span = *subpat_spans.last().unwrap();
         let res_span = self.tcx.def_span(res.def_id());
-        let def_ident_span = self.tcx.def_ident_span(res.def_id()).unwrap_or(res_span);
+        let def_ident_span =
+            self.tcx.def_ident(res.def_id()).map(|ident| ident.span).unwrap_or(res_span);
         let field_def_spans = if fields.is_empty() {
             vec![res_span]
         } else {
diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
index a1c2945770920..733764c13ba35 100644
--- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
@@ -730,9 +730,9 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
 
     /// Builds the `type defined here` message.
     fn show_definition(&self, err: &mut DiagnosticBuilder<'_>) {
-        let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) {
-            if self.tcx.sess.source_map().span_to_snippet(def_span).is_ok() {
-                def_span.into()
+        let mut spans: MultiSpan = if let Some(def_ident) = self.tcx.def_ident(self.def_id) {
+            if self.tcx.sess.source_map().span_to_snippet(def_ident.span).is_ok() {
+                def_ident.span.into()
             } else {
                 return;
             }
diff --git a/src/test/ui/proc-macro/issue-37788.rs b/src/test/ui/proc-macro/issue-37788.rs
index 73b1f0d58c837..7adc7a55e4f7a 100644
--- a/src/test/ui/proc-macro/issue-37788.rs
+++ b/src/test/ui/proc-macro/issue-37788.rs
@@ -4,6 +4,6 @@
 extern crate test_macros;
 
 fn main() {
-    // Test that constructing the `visible_parent_map` (in `cstore_impl.rs`) does not ICE.
+    // Test that constructing the `visible_parents_map` (in `cstore_impl.rs`) does not ICE.
     std::cell::Cell::new(0) //~ ERROR mismatched types
 }
diff --git a/src/test/ui/proc-macro/issue-37788.stderr b/src/test/ui/proc-macro/issue-37788.stderr
index 345520d4852ae..899752893172b 100644
--- a/src/test/ui/proc-macro/issue-37788.stderr
+++ b/src/test/ui/proc-macro/issue-37788.stderr
@@ -3,7 +3,7 @@ error[E0308]: mismatched types
    |
 LL | fn main() {
    |           - expected `()` because of default return type
-LL |     // Test that constructing the `visible_parent_map` (in `cstore_impl.rs`) does not ICE.
+LL |     // Test that constructing the `visible_parents_map` (in `cstore_impl.rs`) does not ICE.
 LL |     std::cell::Cell::new(0)
    |     ^^^^^^^^^^^^^^^^^^^^^^^- help: consider using a semicolon here: `;`
    |     |
diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/other_crate.rs b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/other_crate.rs
index 13bf9a7a28928..5a5079d8204ac 100644
--- a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/other_crate.rs
+++ b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/auxiliary/other_crate.rs
@@ -4,5 +4,5 @@ extern crate core;
 
 #[doc(hidden)]
 pub mod __private {
-	pub use core::option::Option::{self, None, Some};
+    pub use core::option::Option::{self, None, Some};
 }
diff --git a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/dont-suggest-doc-hidden-variant-for-enum.stderr b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/dont-suggest-doc-hidden-variant-for-enum.stderr
index 709dec3ec3132..e9dcee0659af3 100644
--- a/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/dont-suggest-doc-hidden-variant-for-enum.stderr
+++ b/src/test/ui/suggestions/dont-suggest-doc-hidden-variant-for-enum/dont-suggest-doc-hidden-variant-for-enum.stderr
@@ -2,14 +2,16 @@ error[E0308]: mismatched types
   --> $DIR/dont-suggest-doc-hidden-variant-for-enum.rs:6:26
    |
 LL |     let x: Option<i32> = 1i32;
-   |            -----------   ^^^^
-   |            |             |
-   |            |             expected enum `Option`, found `i32`
-   |            |             help: try using a variant of the expected enum: `Some(1i32)`
+   |            -----------   ^^^^ expected enum `Option`, found `i32`
+   |            |
    |            expected due to this
    |
    = note: expected enum `Option<i32>`
               found type `i32`
+help: try wrapping the expression in `Some`
+   |
+LL |     let x: Option<i32> = Some(1i32);
+   |                          +++++    +
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index 3650e4f91a001..0e7ace0b400b0 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -1,4 +1,3 @@
-use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_then};
 use clippy_utils::source::{first_line_of_span, snippet_with_applicability};
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
@@ -7,6 +6,7 @@ use if_chain::if_chain;
 use itertools::Itertools;
 use rustc_ast::ast::{Async, AttrKind, Attribute, Fn, FnRetTy, ItemKind};
 use rustc_ast::token::CommentKind;
+use rustc_ast::attr::is_doc_hidden;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::EmitterWriter;
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index 63a72d4fddeb0..4144ca4bfad65 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -1,9 +1,9 @@
-use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::{meets_msrv, msrvs};
 use if_chain::if_chain;
 use rustc_ast::ast::{FieldDef, Item, ItemKind, Variant, VariantData, VisibilityKind};
+use rustc_ast::attr::is_doc_hidden;
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_semver::RustcVersion;
diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs
index 22970507f964c..b9a721186f6f2 100644
--- a/src/tools/clippy/clippy_lints/src/matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches.rs
@@ -15,7 +15,7 @@ use clippy_utils::{
 use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
 use core::iter::{once, ExactSizeIterator};
 use if_chain::if_chain;
-use rustc_ast::ast::{Attribute, LitKind};
+use rustc_ast::{ast::{LitKind, Attribute}, attr::is_doc_hidden};
 use rustc_errors::Applicability;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::LangItem::{OptionNone, OptionSome};
@@ -1021,7 +1021,8 @@ impl CommonPrefixSearcher<'a> {
 
 fn is_hidden(cx: &LateContext<'_>, variant_def: &VariantDef) -> bool {
     let attrs = cx.tcx.get_attrs(variant_def.def_id);
-    clippy_utils::attrs::is_doc_hidden(attrs) || clippy_utils::attrs::is_unstable(attrs)
+
+    is_doc_hidden(attrs) || clippy_utils::attrs::is_unstable(attrs)
 }
 
 #[allow(clippy::too_many_lines)]
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index fc0483a929a7a..cacdaf2dd0950 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -5,9 +5,8 @@
 // [`missing_doc`]: https://github.com/rust-lang/rust/blob/cf9cf7c923eb01146971429044f216a3ca905e06/compiler/rustc_lint/src/builtin.rs#L415
 //
 
-use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint;
-use rustc_ast::ast;
+use rustc_ast::{ast, attr::is_doc_hidden};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty;
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index 25a84d1665089..23c6d69ff1770 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -1,4 +1,4 @@
-use rustc_ast::{ast, attr};
+use rustc_ast::ast;
 use rustc_errors::Applicability;
 use rustc_session::Session;
 use rustc_span::sym;
@@ -148,15 +148,6 @@ pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool {
     attrs.iter().any(|attr| sess.is_proc_macro_attr(attr))
 }
 
-/// Return true if the attributes contain `#[doc(hidden)]`
-pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool {
-    attrs
-        .iter()
-        .filter(|attr| attr.has_name(sym::doc))
-        .filter_map(ast::Attribute::meta_item_list)
-        .any(|l| attr::list_contains_name(&l, sym::hidden))
-}
-
 /// Return true if the attributes contain `#[unstable]`
 pub fn is_unstable(attrs: &[ast::Attribute]) -> bool {
     attrs.iter().any(|attr| attr.has_name(sym::unstable))