Skip to content

Commit 8c80fe7

Browse files
Correctly import all attributes from multi-level import
1 parent 01a6f30 commit 8c80fe7

File tree

1 file changed

+87
-7
lines changed

1 file changed

+87
-7
lines changed

src/librustdoc/clean/mod.rs

+87-7
Original file line numberDiff line numberDiff line change
@@ -1942,6 +1942,79 @@ fn clean_bare_fn_ty<'tcx>(
19421942
BareFunctionDecl { unsafety: bare_fn.unsafety, abi: bare_fn.abi, decl, generic_params }
19431943
}
19441944

1945+
/// This visitor is used to go through only the "top level" of a item and not enter any sub
1946+
/// item while looking for a given `Ident` which is stored into `item` if found.
1947+
struct OneLevelVisitor<'hir> {
1948+
map: rustc_middle::hir::map::Map<'hir>,
1949+
item: Option<&'hir hir::Item<'hir>>,
1950+
looking_for: Ident,
1951+
target_hir_id: hir::HirId,
1952+
}
1953+
1954+
impl<'hir> OneLevelVisitor<'hir> {
1955+
fn new(map: rustc_middle::hir::map::Map<'hir>, target_hir_id: hir::HirId) -> Self {
1956+
Self { map, item: None, looking_for: Ident::empty(), target_hir_id }
1957+
}
1958+
1959+
fn reset(&mut self, looking_for: Ident) {
1960+
self.looking_for = looking_for;
1961+
self.item = None;
1962+
}
1963+
}
1964+
1965+
impl<'hir> hir::intravisit::Visitor<'hir> for OneLevelVisitor<'hir> {
1966+
type NestedFilter = rustc_middle::hir::nested_filter::All;
1967+
1968+
fn nested_visit_map(&mut self) -> Self::Map {
1969+
self.map
1970+
}
1971+
1972+
fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
1973+
if self.item.is_none()
1974+
&& item.ident == self.looking_for
1975+
&& matches!(item.kind, hir::ItemKind::Use(_, _))
1976+
|| item.hir_id() == self.target_hir_id
1977+
{
1978+
self.item = Some(item);
1979+
}
1980+
}
1981+
}
1982+
1983+
/// Because a `Use` item directly links to the imported item, we need to manually go through each
1984+
/// import one by one. To do so, we go to the parent item and look for the `Ident` into it. Then,
1985+
/// if we found the "end item" (the imported one), we stop there because we don't need its
1986+
/// documentation. Otherwise, we repeat the same operation until we find the "end item".
1987+
fn get_all_import_attributes<'hir>(
1988+
mut item: &hir::Item<'hir>,
1989+
tcx: TyCtxt<'hir>,
1990+
target_hir_id: hir::HirId,
1991+
attributes: &mut Vec<ast::Attribute>,
1992+
) {
1993+
let hir_map = tcx.hir();
1994+
let mut visitor = OneLevelVisitor::new(hir_map, target_hir_id);
1995+
// If the item is an import and has at least a path with two parts, we go into it.
1996+
while let hir::ItemKind::Use(path, _) = item.kind &&
1997+
path.segments.len() > 1 &&
1998+
let hir::def::Res::Def(_, def_id) = path.segments[path.segments.len() - 2].res
1999+
{
2000+
if let Some(hir::Node::Item(parent_item)) = hir_map.get_if_local(def_id) {
2001+
// We add the attributes from this import into the list.
2002+
attributes.extend_from_slice(hir_map.attrs(item.hir_id()));
2003+
// We get the `Ident` we will be looking for into `item`.
2004+
let looking_for = path.segments[path.segments.len() - 1].ident;
2005+
visitor.reset(looking_for);
2006+
hir::intravisit::walk_item(&mut visitor, parent_item);
2007+
if let Some(i) = visitor.item {
2008+
item = i;
2009+
} else {
2010+
break;
2011+
}
2012+
} else {
2013+
break;
2014+
}
2015+
}
2016+
}
2017+
19452018
fn clean_maybe_renamed_item<'tcx>(
19462019
cx: &mut DocContext<'tcx>,
19472020
item: &hir::Item<'tcx>,
@@ -2023,13 +2096,20 @@ fn clean_maybe_renamed_item<'tcx>(
20232096
}
20242097
_ => unreachable!("not yet converted"),
20252098
};
2026-
if let Some(import_id) = import_id {
2027-
let (attrs, cfg) = inline::merge_attrs(
2028-
cx,
2029-
Some(cx.tcx.parent_module(import_id).to_def_id()),
2030-
inline::load_attrs(cx, def_id),
2031-
Some(inline::load_attrs(cx, cx.tcx.hir().local_def_id(import_id).to_def_id())),
2032-
);
2099+
2100+
let mut extra_attrs = Vec::new();
2101+
if let Some(hir::Node::Item(use_node)) =
2102+
import_id.and_then(|hir_id| cx.tcx.hir().find(hir_id))
2103+
{
2104+
// We get all the various imports' attributes.
2105+
get_all_import_attributes(use_node, cx.tcx, item.hir_id(), &mut extra_attrs);
2106+
}
2107+
2108+
if !extra_attrs.is_empty() {
2109+
extra_attrs.extend_from_slice(inline::load_attrs(cx, def_id));
2110+
let attrs = Attributes::from_ast(&extra_attrs);
2111+
let cfg = extra_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg);
2112+
20332113
vec![Item::from_def_id_and_attrs_and_parts(
20342114
def_id,
20352115
Some(name),

0 commit comments

Comments
 (0)