Skip to content

Commit 875c9c9

Browse files
committed
Prefer visible paths which are not doc-hidden
1 parent 3936430 commit 875c9c9

File tree

20 files changed

+139
-119
lines changed

20 files changed

+139
-119
lines changed

compiler/rustc_ast/src/attr/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -580,3 +580,12 @@ impl NestedMetaItem {
580580
MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem)
581581
}
582582
}
583+
584+
/// Return true if the attributes contain `#[doc(hidden)]`
585+
pub fn is_doc_hidden(attrs: &[ast::Attribute]) -> bool {
586+
attrs
587+
.iter()
588+
.filter(|attr| attr.has_name(sym::doc))
589+
.filter_map(ast::Attribute::meta_item_list)
590+
.any(|l| list_contains_name(&l, sym::hidden))
591+
}

compiler/rustc_data_structures/src/stable_hasher.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -346,9 +346,11 @@ where
346346
}
347347
}
348348

349-
impl<A, CTX> HashStable<CTX> for SmallVec<[A; 1]>
349+
impl<T, CTX, const N: usize> HashStable<CTX> for SmallVec<[T; N]>
350350
where
351-
A: HashStable<CTX>,
351+
T: HashStable<CTX>,
352+
[T; N]: smallvec::Array,
353+
<[T; N] as smallvec::Array>::Item: HashStable<CTX>,
352354
{
353355
#[inline]
354356
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+70-52
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ provide! { <'tcx> tcx, def_id, other, cdata,
133133
generator_kind => { cdata.generator_kind(def_id.index) }
134134
opt_def_kind => { Some(cdata.def_kind(def_id.index)) }
135135
def_span => { cdata.get_span(def_id.index, &tcx.sess) }
136-
def_ident_span => {
137-
cdata.try_item_ident(def_id.index, &tcx.sess).ok().map(|ident| ident.span)
136+
def_ident => {
137+
cdata.try_item_ident(def_id.index, &tcx.sess).ok()
138138
}
139139
lookup_stability => {
140140
cdata.get_stability(def_id.index).map(|s| tcx.intern_stability(s))
@@ -290,15 +290,11 @@ pub fn provide(providers: &mut Providers) {
290290
// external item that is visible from at least one local module) to a
291291
// sufficiently visible parent (considering modules that re-export the
292292
// external item to be parents).
293-
visible_parent_map: |tcx, ()| {
294-
use std::collections::hash_map::Entry;
295-
use std::collections::vec_deque::VecDeque;
293+
visible_parents_map: |tcx, ()| {
294+
use rustc_data_structures::fx::FxHashSet;
295+
use std::collections::VecDeque;
296296

297-
let mut visible_parent_map: DefIdMap<DefId> = Default::default();
298-
// This is a secondary visible_parent_map, storing the DefId of parents that re-export
299-
// the child as `_`. Since we prefer parents that don't do this, merge this map at the
300-
// end, only if we're missing any keys from the former.
301-
let mut fallback_map: DefIdMap<DefId> = Default::default();
297+
let mut visible_parents_map: DefIdMap<SmallVec<[DefId; 4]>> = DefIdMap::default();
302298

303299
// Issue 46112: We want the map to prefer the shortest
304300
// paths when reporting the path to an item. Therefore we
@@ -310,59 +306,81 @@ pub fn provide(providers: &mut Providers) {
310306
// only get paths that are locally minimal with respect to
311307
// whatever crate we happened to encounter first in this
312308
// traversal, but not globally minimal across all crates.
313-
let bfs_queue = &mut VecDeque::new();
314-
315-
for &cnum in tcx.crates(()) {
316-
// Ignore crates without a corresponding local `extern crate` item.
317-
if tcx.missing_extern_crate_item(cnum) {
318-
continue;
309+
let mut bfs_queue = VecDeque::default();
310+
311+
bfs_queue.extend(
312+
tcx.crates(())
313+
.into_iter()
314+
// Ignore crates without a corresponding local `extern crate` item.
315+
.filter(|cnum| !tcx.missing_extern_crate_item(**cnum))
316+
.map(|cnum| DefId { krate: *cnum, index: CRATE_DEF_INDEX }),
317+
);
318+
319+
// Iterate over graph using BFS.
320+
// Filter out any non-public items.
321+
while let Some(parent) = bfs_queue.pop_front() {
322+
for child in tcx
323+
.item_children(parent)
324+
.iter()
325+
.filter(|child| child.vis.is_public())
326+
.filter_map(|child| child.res.opt_def_id())
327+
{
328+
visible_parents_map
329+
.entry(child)
330+
.or_insert_with(|| {
331+
// If we encounter node the first time
332+
// add it to queue for next iterations
333+
bfs_queue.push_back(child);
334+
Default::default()
335+
})
336+
.push(parent);
319337
}
338+
}
320339

321-
bfs_queue.push_back(DefId { krate: cnum, index: CRATE_DEF_INDEX });
340+
// Iterate over parents vector to remove duplicate elements
341+
// while preserving order
342+
let mut dedup_set = FxHashSet::default();
343+
for (_, parents) in &mut visible_parents_map {
344+
parents.retain(|parent| dedup_set.insert(*parent));
345+
346+
// Reuse hashset allocation.
347+
dedup_set.clear();
322348
}
323349

324-
let mut add_child = |bfs_queue: &mut VecDeque<_>, export: &Export, parent: DefId| {
325-
if !export.vis.is_public() {
326-
return;
327-
}
350+
visible_parents_map
351+
},
352+
best_visible_parent: |tcx, child| {
353+
// Use `min_by_key` because it returns
354+
// first match in case keys are equal
355+
tcx.visible_parents_map(())
356+
.get(&child)?
357+
.into_iter()
358+
.min_by_key(|parent| {
359+
// If this is just regular export in another module, assign it a neutral score.
360+
let mut score = 0;
361+
362+
// If child and parent are local, we prefer them
363+
if child.is_local() && parent.is_local() {
364+
score += 1;
365+
}
328366

329-
if let Some(child) = export.res.opt_def_id() {
330-
if export.ident.name == kw::Underscore {
331-
fallback_map.insert(child, parent);
332-
return;
367+
// Even if child and parent are local, if parent is `#[doc(hidden)]`
368+
// We reduce their score to avoid showing items not popping in documentation.
369+
if ast::attr::is_doc_hidden(tcx.item_attrs(**parent)) {
370+
score -= 2;
333371
}
334372

335-
match visible_parent_map.entry(child) {
336-
Entry::Occupied(mut entry) => {
337-
// If `child` is defined in crate `cnum`, ensure
338-
// that it is mapped to a parent in `cnum`.
339-
if child.is_local() && entry.get().is_local() {
340-
entry.insert(parent);
341-
}
342-
}
343-
Entry::Vacant(entry) => {
344-
entry.insert(parent);
345-
bfs_queue.push_back(child);
373+
// If parent identifier is _ we prefer it only as last resort if other items are not available
374+
if let Some(ident) = tcx.def_ident(**parent) {
375+
if ident.name == kw::Underscore {
376+
score -= 3;
346377
}
347378
}
348-
}
349-
};
350-
351-
while let Some(def) = bfs_queue.pop_front() {
352-
for child in tcx.item_children(def).iter() {
353-
add_child(bfs_queue, child, def);
354-
}
355-
}
356379

357-
// Fill in any missing entries with the (less preferable) path ending in `::_`.
358-
// We still use this path in a diagnostic that suggests importing `::*`.
359-
for (child, parent) in fallback_map {
360-
visible_parent_map.entry(child).or_insert(parent);
361-
}
362-
363-
visible_parent_map
380+
-score
381+
})
382+
.map(ToOwned::to_owned)
364383
},
365-
366384
dependency_formats: |tcx, ()| Lrc::new(crate::dependency_format::calculate(tcx)),
367385
has_global_allocator: |tcx, cnum| {
368386
assert_eq!(cnum, LOCAL_CRATE);

compiler/rustc_middle/src/query/mod.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -977,8 +977,8 @@ rustc_queries! {
977977
}
978978

979979
/// Gets the span for the identifier of the definition.
980-
query def_ident_span(def_id: DefId) -> Option<Span> {
981-
desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) }
980+
query def_ident(def_id: DefId) -> Option<Ident> {
981+
desc { |tcx| "looking up ident for `{}`'s identifier", tcx.def_path_str(def_id) }
982982
separate_provide_extern
983983
}
984984

@@ -1552,10 +1552,14 @@ rustc_queries! {
15521552
desc { "calculating the missing lang items in a crate" }
15531553
separate_provide_extern
15541554
}
1555-
query visible_parent_map(_: ()) -> DefIdMap<DefId> {
1555+
1556+
query visible_parents_map(_: ()) -> DefIdMap<smallvec::SmallVec<[DefId; 4]>> {
15561557
storage(ArenaCacheSelector<'tcx>)
15571558
desc { "calculating the visible parent map" }
15581559
}
1560+
query best_visible_parent(child: DefId) -> Option<DefId> {
1561+
desc { "calculating best visible parent" }
1562+
}
15591563
query trimmed_def_paths(_: ()) -> FxHashMap<DefId, Symbol> {
15601564
storage(ArenaCacheSelector<'tcx>)
15611565
desc { "calculating trimmed def paths" }

compiler/rustc_middle/src/ty/print/pretty.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,6 @@ pub trait PrettyPrinter<'tcx>:
387387
return Ok((self, false));
388388
}
389389

390-
let visible_parent_map = self.tcx().visible_parent_map(());
391-
392390
let mut cur_def_key = self.tcx().def_key(def_id);
393391
debug!("try_print_visible_def_path: cur_def_key={:?}", cur_def_key);
394392

@@ -404,7 +402,7 @@ pub trait PrettyPrinter<'tcx>:
404402
cur_def_key = self.tcx().def_key(parent);
405403
}
406404

407-
let visible_parent = match visible_parent_map.get(&def_id).cloned() {
405+
let visible_parent = match self.tcx().best_visible_parent(def_id) {
408406
Some(parent) => parent,
409407
None => return Ok((self, false)),
410408
};
@@ -431,7 +429,7 @@ pub trait PrettyPrinter<'tcx>:
431429
// `std::os::unix` rexports the contents of `std::sys::unix::ext`. `std::sys` is
432430
// private so the "true" path to `CommandExt` isn't accessible.
433431
//
434-
// In this case, the `visible_parent_map` will look something like this:
432+
// In this case, the `visible_parents_map` will look something like this:
435433
//
436434
// (child) -> (parent)
437435
// `std::sys::unix::ext::process::CommandExt` -> `std::sys::unix::ext::process`
@@ -451,7 +449,7 @@ pub trait PrettyPrinter<'tcx>:
451449
// do this, we compare the parent of `std::sys::unix::ext` (`std::sys::unix`) with
452450
// the visible parent (`std::os`). If these do not match, then we iterate over
453451
// the children of the visible parent (as was done when computing
454-
// `visible_parent_map`), looking for the specific child we currently have and then
452+
// `visible_parents_map`), looking for the specific child we currently have and then
455453
// have access to the re-exported name.
456454
DefPathData::TypeNs(ref mut name) if Some(visible_parent) != actual_parent => {
457455
// Item might be re-exported several times, but filter for the one

compiler/rustc_middle/src/ty/query.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use crate::traits::specialization_graph;
3030
use crate::traits::{self, ImplSource};
3131
use crate::ty::subst::{GenericArg, SubstsRef};
3232
use crate::ty::util::AlwaysRequiresDrop;
33-
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
33+
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, Ident, ParamEnvAnd, Ty, TyCtxt};
3434
use rustc_ast::expand::allocator::AllocatorKind;
3535
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
3636
use rustc_data_structures::steal::Steal;

compiler/rustc_ty_utils/src/ty.rs

+12-15
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use rustc_hir as hir;
33
use rustc_hir::def_id::{DefId, LocalDefId};
44
use rustc_middle::ty::subst::Subst;
55
use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
6-
use rustc_span::{sym, Span};
6+
use rustc_span::{sym, symbol::Ident};
77
use rustc_trait_selection::traits;
88

99
fn sized_constraint_for_ty<'tcx>(
@@ -216,19 +216,16 @@ fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
216216
ty::AssocItems::new(items)
217217
}
218218

219-
fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
220-
tcx.hir()
221-
.get_if_local(def_id)
222-
.and_then(|node| match node {
223-
// A `Ctor` doesn't have an identifier itself, but its parent
224-
// struct/variant does. Compare with `hir::Map::opt_span`.
225-
hir::Node::Ctor(ctor) => ctor
226-
.ctor_hir_id()
227-
.and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id)))
228-
.and_then(|parent| parent.ident()),
229-
_ => node.ident(),
230-
})
231-
.map(|ident| ident.span)
219+
fn def_ident(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ident> {
220+
tcx.hir().get_if_local(def_id).and_then(|node| match node {
221+
// A `Ctor` doesn't have an identifier itself, but its parent
222+
// struct/variant does. Compare with `hir::Map::opt_span`.
223+
hir::Node::Ctor(ctor) => ctor
224+
.ctor_hir_id()
225+
.and_then(|ctor_id| tcx.hir().find(tcx.hir().get_parent_node(ctor_id)))
226+
.and_then(|parent| parent.ident()),
227+
_ => node.ident(),
228+
})
232229
}
233230

234231
/// If the given `DefId` describes an item belonging to a trait,
@@ -624,7 +621,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
624621
associated_item_def_ids,
625622
associated_items,
626623
adt_sized_constraint,
627-
def_ident_span,
624+
def_ident,
628625
param_env,
629626
param_env_reveal_all_normalized,
630627
trait_of_item,

compiler/rustc_typeck/src/check/fn_ctxt/checks.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
197197
}
198198

199199
if let Some(def_id) = def_id {
200-
if let Some(def_span) = tcx.def_ident_span(def_id) {
201-
let mut spans: MultiSpan = def_span.into();
200+
if let Some(def_ident) = tcx.def_ident(def_id) {
201+
let mut spans: MultiSpan = def_ident.span.into();
202202

203203
let params = tcx
204204
.hir()

compiler/rustc_typeck/src/check/method/suggest.rs

+10-12
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_hir::{ExprKind, Node, QPath};
1212
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1313
use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams, StripReferences};
1414
use rustc_middle::ty::print::with_crate_prefix;
15-
use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
15+
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
1616
use rustc_span::lev_distance;
1717
use rustc_span::symbol::{kw, sym, Ident};
1818
use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
@@ -1310,17 +1310,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13101310
mut msg: String,
13111311
candidates: Vec<DefId>,
13121312
) {
1313-
let parent_map = self.tcx.visible_parent_map(());
1314-
13151313
// Separate out candidates that must be imported with a glob, because they are named `_`
13161314
// and cannot be referred with their identifier.
13171315
let (candidates, globs): (Vec<_>, Vec<_>) = candidates.into_iter().partition(|trait_did| {
1318-
if let Some(parent_did) = parent_map.get(trait_did) {
1316+
if let Some(parent_did) = self.tcx.best_visible_parent(*trait_did) {
13191317
// If the item is re-exported as `_`, we should suggest a glob-import instead.
1320-
if Some(*parent_did) != self.tcx.parent(*trait_did)
1318+
if Some(parent_did) != self.tcx.best_visible_parent(*trait_did)
13211319
&& self
13221320
.tcx
1323-
.item_children(*parent_did)
1321+
.item_children(parent_did)
13241322
.iter()
13251323
.filter(|child| child.res.opt_def_id() == Some(*trait_did))
13261324
.all(|child| child.ident.name == kw::Underscore)
@@ -1347,14 +1345,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13471345
});
13481346

13491347
let glob_path_strings = globs.iter().map(|trait_did| {
1350-
let parent_did = parent_map.get(trait_did).unwrap();
1351-
13521348
// Produce an additional newline to separate the new use statement
13531349
// from the directly following item.
13541350
let additional_newline = if found_use { "" } else { "\n" };
13551351
format!(
13561352
"use {}::*; // trait {}\n{}",
1357-
with_crate_prefix(|| self.tcx.def_path_str(*parent_did)),
1353+
with_crate_prefix(|| self
1354+
.tcx
1355+
.def_path_str(self.tcx.best_visible_parent(*trait_did).unwrap())),
13581356
self.tcx.item_name(*trait_did),
13591357
additional_newline
13601358
)
@@ -1385,19 +1383,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13851383
for (i, trait_did) in
13861384
globs.iter().take(limit.saturating_sub(candidates.len())).enumerate()
13871385
{
1388-
let parent_did = parent_map.get(trait_did).unwrap();
1386+
let parent_did = self.tcx.best_visible_parent(*trait_did).unwrap();
13891387

13901388
if candidates.len() + globs.len() > 1 {
13911389
msg.push_str(&format!(
13921390
"\ncandidate #{}: `use {}::*; // trait {}`",
13931391
candidates.len() + i + 1,
1394-
with_crate_prefix(|| self.tcx.def_path_str(*parent_did)),
1392+
with_crate_prefix(|| self.tcx.def_path_str(parent_did)),
13951393
self.tcx.item_name(*trait_did),
13961394
));
13971395
} else {
13981396
msg.push_str(&format!(
13991397
"\n`use {}::*; // trait {}`",
1400-
with_crate_prefix(|| self.tcx.def_path_str(*parent_did)),
1398+
with_crate_prefix(|| self.tcx.def_path_str(parent_did)),
14011399
self.tcx.item_name(*trait_did),
14021400
));
14031401
}

compiler/rustc_typeck/src/check/pat.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
10251025
};
10261026
let last_subpat_span = *subpat_spans.last().unwrap();
10271027
let res_span = self.tcx.def_span(res.def_id());
1028-
let def_ident_span = self.tcx.def_ident_span(res.def_id()).unwrap_or(res_span);
1028+
let def_ident_span =
1029+
self.tcx.def_ident(res.def_id()).map(|ident| ident.span).unwrap_or(res_span);
10291030
let field_def_spans = if fields.is_empty() {
10301031
vec![res_span]
10311032
} else {

0 commit comments

Comments
 (0)