Skip to content

Commit b20ecc7

Browse files
committed
rustdoc: Migrate some logic to module_reexports
1 parent d11b916 commit b20ecc7

File tree

2 files changed

+34
-147
lines changed

2 files changed

+34
-147
lines changed

src/librustdoc/clean/mod.rs

+29-140
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
2121
use rustc_hir::PredicateOrigin;
2222
use rustc_hir_analysis::hir_ty_to_ty;
2323
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
24+
use rustc_middle::metadata::Reexport;
2425
use rustc_middle::middle::resolve_bound_vars as rbv;
2526
use rustc_middle::ty::fold::TypeFolder;
2627
use rustc_middle::ty::InternalSubsts;
@@ -2056,141 +2057,44 @@ fn clean_bare_fn_ty<'tcx>(
20562057
BareFunctionDecl { unsafety: bare_fn.unsafety, abi: bare_fn.abi, decl, generic_params }
20572058
}
20582059

2059-
/// Get DefId of of an item's user-visible parent.
2060-
///
2061-
/// "User-visible" should account for re-exporting and inlining, which is why this function isn't
2062-
/// just `tcx.parent(def_id)`. If the provided `path` has more than one path element, the `DefId`
2063-
/// of the second-to-last will be given.
2064-
///
2065-
/// ```text
2066-
/// use crate::foo::Bar;
2067-
/// ^^^ DefId of this item will be returned
2068-
/// ```
2069-
///
2070-
/// If the provided path has only one item, `tcx.parent(def_id)` will be returned instead.
2071-
fn get_path_parent_def_id(
2072-
tcx: TyCtxt<'_>,
2073-
def_id: DefId,
2074-
path: &hir::UsePath<'_>,
2075-
) -> Option<DefId> {
2076-
if let [.., parent_segment, _] = &path.segments {
2077-
match parent_segment.res {
2078-
hir::def::Res::Def(_, parent_def_id) => Some(parent_def_id),
2079-
_ if parent_segment.ident.name == kw::Crate => {
2080-
// In case the "parent" is the crate, it'll give `Res::Err` so we need to
2081-
// circumvent it this way.
2082-
Some(tcx.parent(def_id))
2083-
}
2084-
_ => None,
2085-
}
2086-
} else {
2087-
// If the path doesn't have a parent, then the parent is the current module.
2088-
Some(tcx.parent(def_id))
2089-
}
2090-
}
2091-
2092-
/// This visitor is used to find an HIR Item based on its `use` path. This doesn't use the ordinary
2093-
/// name resolver because it does not walk all the way through a chain of re-exports.
2094-
pub(crate) struct OneLevelVisitor<'hir> {
2095-
map: rustc_middle::hir::map::Map<'hir>,
2096-
pub(crate) item: Option<&'hir hir::Item<'hir>>,
2097-
looking_for: Ident,
2060+
pub(crate) fn reexport_chain<'tcx>(
2061+
tcx: TyCtxt<'tcx>,
2062+
import_def_id: LocalDefId,
20982063
target_def_id: LocalDefId,
2099-
}
2100-
2101-
impl<'hir> OneLevelVisitor<'hir> {
2102-
pub(crate) fn new(map: rustc_middle::hir::map::Map<'hir>, target_def_id: LocalDefId) -> Self {
2103-
Self { map, item: None, looking_for: Ident::empty(), target_def_id }
2104-
}
2105-
2106-
pub(crate) fn find_target(
2107-
&mut self,
2108-
tcx: TyCtxt<'_>,
2109-
def_id: DefId,
2110-
path: &hir::UsePath<'_>,
2111-
) -> Option<&'hir hir::Item<'hir>> {
2112-
let parent_def_id = get_path_parent_def_id(tcx, def_id, path)?;
2113-
let parent = self.map.get_if_local(parent_def_id)?;
2114-
2115-
// We get the `Ident` we will be looking for into `item`.
2116-
self.looking_for = path.segments[path.segments.len() - 1].ident;
2117-
// We reset the `item`.
2118-
self.item = None;
2119-
2120-
match parent {
2121-
hir::Node::Item(parent_item) => {
2122-
hir::intravisit::walk_item(self, parent_item);
2123-
}
2124-
hir::Node::Crate(m) => {
2125-
hir::intravisit::walk_mod(
2126-
self,
2127-
m,
2128-
tcx.local_def_id_to_hir_id(parent_def_id.as_local().unwrap()),
2129-
);
2130-
}
2131-
_ => return None,
2132-
}
2133-
self.item
2134-
}
2135-
}
2136-
2137-
impl<'hir> hir::intravisit::Visitor<'hir> for OneLevelVisitor<'hir> {
2138-
type NestedFilter = rustc_middle::hir::nested_filter::All;
2139-
2140-
fn nested_visit_map(&mut self) -> Self::Map {
2141-
self.map
2142-
}
2143-
2144-
fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
2145-
if self.item.is_none()
2146-
&& item.ident == self.looking_for
2147-
&& (matches!(item.kind, hir::ItemKind::Use(_, _))
2148-
|| item.owner_id.def_id == self.target_def_id)
2064+
) -> &'tcx [Reexport] {
2065+
for child in tcx.module_reexports(tcx.local_parent(import_def_id)).unwrap_or_default() {
2066+
if child.res.opt_def_id() == Some(target_def_id.to_def_id())
2067+
&& child.reexport_chain[0].id() == Some(import_def_id.to_def_id())
21492068
{
2150-
self.item = Some(item);
2069+
return &child.reexport_chain;
21512070
}
21522071
}
2072+
&[]
21532073
}
21542074

2155-
/// Because a `Use` item directly links to the imported item, we need to manually go through each
2156-
/// import one by one. To do so, we go to the parent item and look for the `Ident` into it. Then,
2157-
/// if we found the "end item" (the imported one), we stop there because we don't need its
2158-
/// documentation. Otherwise, we repeat the same operation until we find the "end item".
2075+
/// Collect attributes from the whole import chain.
21592076
fn get_all_import_attributes<'hir>(
2160-
mut item: &hir::Item<'hir>,
21612077
cx: &mut DocContext<'hir>,
2078+
import_def_id: LocalDefId,
21622079
target_def_id: LocalDefId,
21632080
is_inline: bool,
2164-
mut prev_import: LocalDefId,
21652081
) -> Vec<(Cow<'hir, ast::Attribute>, Option<DefId>)> {
2166-
let mut attributes: Vec<(Cow<'hir, ast::Attribute>, Option<DefId>)> = Vec::new();
2082+
let mut attrs = Vec::new();
21672083
let mut first = true;
2168-
let hir_map = cx.tcx.hir();
2169-
let mut visitor = OneLevelVisitor::new(hir_map, target_def_id);
2170-
let mut visited = FxHashSet::default();
2171-
2172-
// If the item is an import and has at least a path with two parts, we go into it.
2173-
while let hir::ItemKind::Use(path, _) = item.kind && visited.insert(item.hir_id()) {
2174-
let import_parent = cx.tcx.opt_local_parent(prev_import).map(|def_id| def_id.to_def_id());
2084+
for def_id in reexport_chain(cx.tcx, import_def_id, target_def_id)
2085+
.iter()
2086+
.flat_map(|reexport| reexport.id())
2087+
{
2088+
let import_attrs = inline::load_attrs(cx, def_id);
21752089
if first {
21762090
// This is the "original" reexport so we get all its attributes without filtering them.
2177-
attributes = hir_map.attrs(item.hir_id())
2178-
.iter()
2179-
.map(|attr| (Cow::Borrowed(attr), import_parent))
2180-
.collect::<Vec<_>>();
2091+
attrs = import_attrs.iter().map(|attr| (Cow::Borrowed(attr), Some(def_id))).collect();
21812092
first = false;
21822093
} else {
2183-
add_without_unwanted_attributes(&mut attributes, hir_map.attrs(item.hir_id()), is_inline, import_parent);
2094+
add_without_unwanted_attributes(&mut attrs, import_attrs, is_inline, Some(def_id));
21842095
}
2185-
2186-
if let Some(i) = visitor.find_target(cx.tcx, item.owner_id.def_id.to_def_id(), path) {
2187-
item = i;
2188-
} else {
2189-
break;
2190-
}
2191-
prev_import = item.owner_id.def_id;
21922096
}
2193-
attributes
2097+
attrs
21942098
}
21952099

21962100
fn filter_tokens_from_list(
@@ -2375,39 +2279,24 @@ fn clean_maybe_renamed_item<'tcx>(
23752279
_ => unreachable!("not yet converted"),
23762280
};
23772281

2378-
let attrs = if let Some(import_id) = import_id &&
2379-
let Some(hir::Node::Item(use_node)) = cx.tcx.hir().find_by_def_id(import_id)
2380-
{
2282+
let target_attrs = inline::load_attrs(cx, def_id);
2283+
let attrs = if let Some(import_id) = import_id {
23812284
let is_inline = inline::load_attrs(cx, import_id.to_def_id())
23822285
.lists(sym::doc)
23832286
.get_word_attr(sym::inline)
23842287
.is_some();
2385-
// Then we get all the various imports' attributes.
2386-
let mut attrs = get_all_import_attributes(
2387-
use_node,
2388-
cx,
2389-
item.owner_id.def_id,
2390-
is_inline,
2391-
import_id,
2392-
);
2393-
2394-
add_without_unwanted_attributes(
2395-
&mut attrs,
2396-
inline::load_attrs(cx, def_id),
2397-
is_inline,
2398-
None
2399-
);
2288+
let mut attrs =
2289+
get_all_import_attributes(cx, import_id, item.owner_id.def_id, is_inline);
2290+
add_without_unwanted_attributes(&mut attrs, target_attrs, is_inline, None);
24002291
attrs
24012292
} else {
24022293
// We only keep the item's attributes.
2403-
inline::load_attrs(cx, def_id).iter().map(|attr| (Cow::Borrowed(attr), None)).collect::<Vec<_>>()
2294+
target_attrs.iter().map(|attr| (Cow::Borrowed(attr), None)).collect()
24042295
};
24052296

24062297
let cfg = attrs.cfg(cx.tcx, &cx.cache.hidden_cfg);
2407-
let attrs = Attributes::from_ast_iter(attrs.iter().map(|(attr, did)| match attr {
2408-
Cow::Borrowed(attr) => (*attr, *did),
2409-
Cow::Owned(attr) => (attr, *did)
2410-
}), false);
2298+
let attrs =
2299+
Attributes::from_ast_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false);
24112300

24122301
let mut item =
24132302
Item::from_def_id_and_attrs_and_parts(def_id, Some(name), kind, Box::new(attrs), cfg);

src/librustdoc/visit_ast.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
1313
use rustc_span::symbol::{kw, sym, Symbol};
1414
use rustc_span::Span;
1515

16-
use std::mem;
16+
use std::{iter, mem};
1717

18-
use crate::clean::{cfg::Cfg, AttributesExt, NestedAttributesExt, OneLevelVisitor};
18+
use crate::clean::{cfg::Cfg, reexport_chain, AttributesExt, NestedAttributesExt};
1919
use crate::core;
2020

2121
/// This module is used to store stuff from Rust's AST in a more convenient
@@ -220,7 +220,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
220220
renamed: Option<Symbol>,
221221
glob: bool,
222222
please_inline: bool,
223-
path: &hir::UsePath<'_>,
224223
) -> bool {
225224
debug!("maybe_inline_local res: {:?}", res);
226225

@@ -266,9 +265,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
266265
}
267266

268267
if !please_inline &&
269-
let mut visitor = OneLevelVisitor::new(self.cx.tcx.hir(), res_did) &&
270-
let Some(item) = visitor.find_target(self.cx.tcx, def_id.to_def_id(), path) &&
271-
let item_def_id = item.owner_id.def_id &&
268+
let Some(item_def_id) = reexport_chain(self.cx.tcx, def_id, res_did).iter()
269+
.flat_map(|reexport| reexport.id()).map(|id| id.expect_local())
270+
.chain(iter::once(res_did)).nth(1) &&
272271
item_def_id != def_id &&
273272
self
274273
.cx
@@ -383,7 +382,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
383382
ident,
384383
is_glob,
385384
please_inline,
386-
path,
387385
) {
388386
continue;
389387
}

0 commit comments

Comments
 (0)