rustdoc/clean/
inline.rs

1//! Support for inlining external documentation into the current AST.
2
3use std::iter::once;
4use std::sync::Arc;
5
6use rustc_data_structures::fx::FxHashSet;
7use rustc_hir as hir;
8use rustc_hir::Mutability;
9use rustc_hir::def::{DefKind, Res};
10use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId, LocalModDefId};
11use rustc_metadata::creader::{CStore, LoadedMacro};
12use rustc_middle::ty::fast_reject::SimplifiedType;
13use rustc_middle::ty::{self, TyCtxt};
14use rustc_span::def_id::LOCAL_CRATE;
15use rustc_span::hygiene::MacroKind;
16use rustc_span::symbol::{Symbol, sym};
17use thin_vec::{ThinVec, thin_vec};
18use tracing::{debug, trace};
19
20use super::{Item, extract_cfg_from_attrs};
21use crate::clean::{
22    self, Attributes, ImplKind, ItemId, Type, clean_bound_vars, clean_generics, clean_impl_item,
23    clean_middle_assoc_item, clean_middle_field, clean_middle_ty, clean_poly_fn_sig,
24    clean_trait_ref_with_constraints, clean_ty, clean_ty_alias_inner_type, clean_ty_generics,
25    clean_variant_def, utils,
26};
27use crate::core::DocContext;
28use crate::formats::item_type::ItemType;
29
30/// Attempt to inline a definition into this AST.
31///
32/// This function will fetch the definition specified, and if it is
33/// from another crate it will attempt to inline the documentation
34/// from the other crate into this crate.
35///
36/// This is primarily used for `pub use` statements which are, in general,
37/// implementation details. Inlining the documentation should help provide a
38/// better experience when reading the documentation in this use case.
39///
40/// The returned value is `None` if the definition could not be inlined,
41/// and `Some` of a vector of items if it was successfully expanded.
42pub(crate) fn try_inline(
43    cx: &mut DocContext<'_>,
44    res: Res,
45    name: Symbol,
46    attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
47    visited: &mut DefIdSet,
48) -> Option<Vec<clean::Item>> {
49    let did = res.opt_def_id()?;
50    if did.is_local() {
51        return None;
52    }
53    let mut ret = Vec::new();
54
55    debug!("attrs={attrs:?}");
56
57    let attrs_without_docs = attrs.map(|(attrs, def_id)| {
58        (attrs.iter().filter(|a| a.doc_str().is_none()).cloned().collect::<Vec<_>>(), def_id)
59    });
60    let attrs_without_docs =
61        attrs_without_docs.as_ref().map(|(attrs, def_id)| (&attrs[..], *def_id));
62
63    let import_def_id = attrs.and_then(|(_, def_id)| def_id);
64
65    let kind = match res {
66        Res::Def(DefKind::Trait, did) => {
67            record_extern_fqn(cx, did, ItemType::Trait);
68            cx.with_param_env(did, |cx| {
69                build_impls(cx, did, attrs_without_docs, &mut ret);
70                clean::TraitItem(Box::new(build_external_trait(cx, did)))
71            })
72        }
73        Res::Def(DefKind::Fn, did) => {
74            record_extern_fqn(cx, did, ItemType::Function);
75            cx.with_param_env(did, |cx| {
76                clean::enter_impl_trait(cx, |cx| clean::FunctionItem(build_function(cx, did)))
77            })
78        }
79        Res::Def(DefKind::Struct, did) => {
80            record_extern_fqn(cx, did, ItemType::Struct);
81            cx.with_param_env(did, |cx| {
82                build_impls(cx, did, attrs_without_docs, &mut ret);
83                clean::StructItem(build_struct(cx, did))
84            })
85        }
86        Res::Def(DefKind::Union, did) => {
87            record_extern_fqn(cx, did, ItemType::Union);
88            cx.with_param_env(did, |cx| {
89                build_impls(cx, did, attrs_without_docs, &mut ret);
90                clean::UnionItem(build_union(cx, did))
91            })
92        }
93        Res::Def(DefKind::TyAlias, did) => {
94            record_extern_fqn(cx, did, ItemType::TypeAlias);
95            cx.with_param_env(did, |cx| {
96                build_impls(cx, did, attrs_without_docs, &mut ret);
97                clean::TypeAliasItem(build_type_alias(cx, did, &mut ret))
98            })
99        }
100        Res::Def(DefKind::Enum, did) => {
101            record_extern_fqn(cx, did, ItemType::Enum);
102            cx.with_param_env(did, |cx| {
103                build_impls(cx, did, attrs_without_docs, &mut ret);
104                clean::EnumItem(build_enum(cx, did))
105            })
106        }
107        Res::Def(DefKind::ForeignTy, did) => {
108            record_extern_fqn(cx, did, ItemType::ForeignType);
109            cx.with_param_env(did, |cx| {
110                build_impls(cx, did, attrs_without_docs, &mut ret);
111                clean::ForeignTypeItem
112            })
113        }
114        // Never inline enum variants but leave them shown as re-exports.
115        Res::Def(DefKind::Variant, _) => return None,
116        // Assume that enum variants and struct types are re-exported next to
117        // their constructors.
118        Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => return Some(Vec::new()),
119        Res::Def(DefKind::Mod, did) => {
120            record_extern_fqn(cx, did, ItemType::Module);
121            clean::ModuleItem(build_module(cx, did, visited))
122        }
123        Res::Def(DefKind::Static { .. }, did) => {
124            record_extern_fqn(cx, did, ItemType::Static);
125            cx.with_param_env(did, |cx| {
126                clean::StaticItem(build_static(cx, did, cx.tcx.is_mutable_static(did)))
127            })
128        }
129        Res::Def(DefKind::Const, did) => {
130            record_extern_fqn(cx, did, ItemType::Constant);
131            cx.with_param_env(did, |cx| {
132                let ct = build_const_item(cx, did);
133                clean::ConstantItem(Box::new(ct))
134            })
135        }
136        Res::Def(DefKind::Macro(kind), did) => {
137            let mac = build_macro(cx, did, name, kind);
138
139            let type_kind = match kind {
140                MacroKind::Bang => ItemType::Macro,
141                MacroKind::Attr => ItemType::ProcAttribute,
142                MacroKind::Derive => ItemType::ProcDerive,
143            };
144            record_extern_fqn(cx, did, type_kind);
145            mac
146        }
147        _ => return None,
148    };
149
150    cx.inlined.insert(did.into());
151    let mut item =
152        crate::clean::generate_item_with_correct_attrs(cx, kind, did, name, import_def_id, None);
153    // The visibility needs to reflect the one from the reexport and not from the "source" DefId.
154    item.inline_stmt_id = import_def_id;
155    ret.push(item);
156    Some(ret)
157}
158
159pub(crate) fn try_inline_glob(
160    cx: &mut DocContext<'_>,
161    res: Res,
162    current_mod: LocalModDefId,
163    visited: &mut DefIdSet,
164    inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
165    import: &hir::Item<'_>,
166) -> Option<Vec<clean::Item>> {
167    let did = res.opt_def_id()?;
168    if did.is_local() {
169        return None;
170    }
171
172    match res {
173        Res::Def(DefKind::Mod, did) => {
174            // Use the set of module reexports to filter away names that are not actually
175            // reexported by the glob, e.g. because they are shadowed by something else.
176            let reexports = cx
177                .tcx
178                .module_children_local(current_mod.to_local_def_id())
179                .iter()
180                .filter(|child| !child.reexport_chain.is_empty())
181                .filter_map(|child| child.res.opt_def_id())
182                .filter(|def_id| !cx.tcx.is_doc_hidden(def_id))
183                .collect();
184            let attrs = cx.tcx.hir().attrs(import.hir_id());
185            let mut items = build_module_items(
186                cx,
187                did,
188                visited,
189                inlined_names,
190                Some(&reexports),
191                Some((attrs, Some(import.owner_id.def_id))),
192            );
193            items.retain(|item| {
194                if let Some(name) = item.name {
195                    // If an item with the same type and name already exists,
196                    // it takes priority over the inlined stuff.
197                    inlined_names.insert((item.type_(), name))
198                } else {
199                    true
200                }
201            });
202            Some(items)
203        }
204        // glob imports on things like enums aren't inlined even for local exports, so just bail
205        _ => None,
206    }
207}
208
209pub(crate) fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> &'hir [hir::Attribute] {
210    cx.tcx.get_attrs_unchecked(did)
211}
212
213pub(crate) fn item_relative_path(tcx: TyCtxt<'_>, def_id: DefId) -> Vec<Symbol> {
214    tcx.def_path(def_id)
215        .data
216        .into_iter()
217        .filter_map(|elem| {
218            // extern blocks (and a few others things) have an empty name.
219            match elem.data.get_opt_name() {
220                Some(s) if !s.is_empty() => Some(s),
221                _ => None,
222            }
223        })
224        .collect()
225}
226
227/// Record an external fully qualified name in the external_paths cache.
228///
229/// These names are used later on by HTML rendering to generate things like
230/// source links back to the original item.
231pub(crate) fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemType) {
232    if did.is_local() {
233        if cx.cache.exact_paths.contains_key(&did) {
234            return;
235        }
236    } else if cx.cache.external_paths.contains_key(&did) {
237        return;
238    }
239
240    let crate_name = cx.tcx.crate_name(did.krate);
241
242    let relative = item_relative_path(cx.tcx, did);
243    let fqn = if let ItemType::Macro = kind {
244        // Check to see if it is a macro 2.0 or built-in macro
245        if matches!(
246            CStore::from_tcx(cx.tcx).load_macro_untracked(did, cx.tcx),
247            LoadedMacro::MacroDef { def, .. } if !def.macro_rules
248        ) {
249            once(crate_name).chain(relative).collect()
250        } else {
251            vec![crate_name, *relative.last().expect("relative was empty")]
252        }
253    } else {
254        once(crate_name).chain(relative).collect()
255    };
256
257    if did.is_local() {
258        cx.cache.exact_paths.insert(did, fqn);
259    } else {
260        cx.cache.external_paths.insert(did, (fqn, kind));
261    }
262}
263
264pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait {
265    let trait_items = cx
266        .tcx
267        .associated_items(did)
268        .in_definition_order()
269        .filter(|item| !item.is_impl_trait_in_trait())
270        .map(|item| clean_middle_assoc_item(item, cx))
271        .collect();
272
273    let predicates = cx.tcx.predicates_of(did);
274    let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
275    let generics = filter_non_trait_generics(did, generics);
276    let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
277    clean::Trait { def_id: did, generics, items: trait_items, bounds: supertrait_bounds }
278}
279
280pub(crate) fn build_function(cx: &mut DocContext<'_>, def_id: DefId) -> Box<clean::Function> {
281    let sig = cx.tcx.fn_sig(def_id).instantiate_identity();
282    // The generics need to be cleaned before the signature.
283    let mut generics =
284        clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id));
285    let bound_vars = clean_bound_vars(sig.bound_vars());
286
287    // At the time of writing early & late-bound params are stored separately in rustc,
288    // namely in `generics.params` and `bound_vars` respectively.
289    //
290    // To reestablish the original source code order of the generic parameters, we
291    // need to manually sort them by their definition span after concatenation.
292    //
293    // See also:
294    // * https://rustc-dev-guide.rust-lang.org/bound-vars-and-params.html
295    // * https://rustc-dev-guide.rust-lang.org/what-does-early-late-bound-mean.html
296    let has_early_bound_params = !generics.params.is_empty();
297    let has_late_bound_params = !bound_vars.is_empty();
298    generics.params.extend(bound_vars);
299    if has_early_bound_params && has_late_bound_params {
300        // If this ever becomes a performances bottleneck either due to the sorting
301        // or due to the query calls, consider inserting the late-bound lifetime params
302        // right after the last early-bound lifetime param followed by only sorting
303        // the slice of lifetime params.
304        generics.params.sort_by_key(|param| cx.tcx.def_ident_span(param.def_id).unwrap());
305    }
306
307    let decl = clean_poly_fn_sig(cx, Some(def_id), sig);
308
309    Box::new(clean::Function { decl, generics })
310}
311
312fn build_enum(cx: &mut DocContext<'_>, did: DefId) -> clean::Enum {
313    let predicates = cx.tcx.explicit_predicates_of(did);
314
315    clean::Enum {
316        generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
317        variants: cx.tcx.adt_def(did).variants().iter().map(|v| clean_variant_def(v, cx)).collect(),
318    }
319}
320
321fn build_struct(cx: &mut DocContext<'_>, did: DefId) -> clean::Struct {
322    let predicates = cx.tcx.explicit_predicates_of(did);
323    let variant = cx.tcx.adt_def(did).non_enum_variant();
324
325    clean::Struct {
326        ctor_kind: variant.ctor_kind(),
327        generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
328        fields: variant.fields.iter().map(|x| clean_middle_field(x, cx)).collect(),
329    }
330}
331
332fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union {
333    let predicates = cx.tcx.explicit_predicates_of(did);
334    let variant = cx.tcx.adt_def(did).non_enum_variant();
335
336    let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
337    let fields = variant.fields.iter().map(|x| clean_middle_field(x, cx)).collect();
338    clean::Union { generics, fields }
339}
340
341fn build_type_alias(
342    cx: &mut DocContext<'_>,
343    did: DefId,
344    ret: &mut Vec<Item>,
345) -> Box<clean::TypeAlias> {
346    let predicates = cx.tcx.explicit_predicates_of(did);
347    let ty = cx.tcx.type_of(did).instantiate_identity();
348    let type_ = clean_middle_ty(ty::Binder::dummy(ty), cx, Some(did), None);
349    let inner_type = clean_ty_alias_inner_type(ty, cx, ret);
350
351    Box::new(clean::TypeAlias {
352        type_,
353        generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
354        inner_type,
355        item_type: None,
356    })
357}
358
359/// Builds all inherent implementations of an ADT (struct/union/enum) or Trait item/path/reexport.
360pub(crate) fn build_impls(
361    cx: &mut DocContext<'_>,
362    did: DefId,
363    attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
364    ret: &mut Vec<clean::Item>,
365) {
366    let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls");
367    let tcx = cx.tcx;
368
369    // for each implementation of an item represented by `did`, build the clean::Item for that impl
370    for &did in tcx.inherent_impls(did).iter() {
371        cx.with_param_env(did, |cx| {
372            build_impl(cx, did, attrs, ret);
373        });
374    }
375
376    // This pretty much exists expressly for `dyn Error` traits that exist in the `alloc` crate.
377    // See also:
378    //
379    // * https://github.com/rust-lang/rust/issues/103170 — where it didn't used to get documented
380    // * https://github.com/rust-lang/rust/pull/99917 — where the feature got used
381    // * https://github.com/rust-lang/rust/issues/53487 — overall tracking issue for Error
382    if tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) {
383        let type_ =
384            if tcx.is_trait(did) { SimplifiedType::Trait(did) } else { SimplifiedType::Adt(did) };
385        for &did in tcx.incoherent_impls(type_).iter() {
386            cx.with_param_env(did, |cx| {
387                build_impl(cx, did, attrs, ret);
388            });
389        }
390    }
391}
392
393pub(crate) fn merge_attrs(
394    cx: &mut DocContext<'_>,
395    old_attrs: &[hir::Attribute],
396    new_attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
397) -> (clean::Attributes, Option<Arc<clean::cfg::Cfg>>) {
398    // NOTE: If we have additional attributes (from a re-export),
399    // always insert them first. This ensure that re-export
400    // doc comments show up before the original doc comments
401    // when we render them.
402    if let Some((inner, item_id)) = new_attrs {
403        let mut both = inner.to_vec();
404        both.extend_from_slice(old_attrs);
405        (
406            if let Some(item_id) = item_id {
407                Attributes::from_hir_with_additional(old_attrs, (inner, item_id.to_def_id()))
408            } else {
409                Attributes::from_hir(&both)
410            },
411            extract_cfg_from_attrs(both.iter(), cx.tcx, &cx.cache.hidden_cfg),
412        )
413    } else {
414        (
415            Attributes::from_hir(old_attrs),
416            extract_cfg_from_attrs(old_attrs.iter(), cx.tcx, &cx.cache.hidden_cfg),
417        )
418    }
419}
420
421/// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl`.
422pub(crate) fn build_impl(
423    cx: &mut DocContext<'_>,
424    did: DefId,
425    attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
426    ret: &mut Vec<clean::Item>,
427) {
428    if !cx.inlined.insert(did.into()) {
429        return;
430    }
431
432    let tcx = cx.tcx;
433    let _prof_timer = tcx.sess.prof.generic_activity("build_impl");
434
435    let associated_trait = tcx.impl_trait_ref(did).map(ty::EarlyBinder::skip_binder);
436
437    // Do not inline compiler-internal items unless we're a compiler-internal crate.
438    let is_compiler_internal = |did| {
439        tcx.lookup_stability(did)
440            .is_some_and(|stab| stab.is_unstable() && stab.feature == sym::rustc_private)
441    };
442    let document_compiler_internal = is_compiler_internal(LOCAL_CRATE.as_def_id());
443    let is_directly_public = |cx: &mut DocContext<'_>, did| {
444        cx.cache.effective_visibilities.is_directly_public(tcx, did)
445            && (document_compiler_internal || !is_compiler_internal(did))
446    };
447
448    // Only inline impl if the implemented trait is
449    // reachable in rustdoc generated documentation
450    if !did.is_local()
451        && let Some(traitref) = associated_trait
452        && !is_directly_public(cx, traitref.def_id)
453    {
454        return;
455    }
456
457    let impl_item = match did.as_local() {
458        Some(did) => match &tcx.hir().expect_item(did).kind {
459            hir::ItemKind::Impl(impl_) => Some(impl_),
460            _ => panic!("`DefID` passed to `build_impl` is not an `impl"),
461        },
462        None => None,
463    };
464
465    let for_ = match &impl_item {
466        Some(impl_) => clean_ty(impl_.self_ty, cx),
467        None => clean_middle_ty(
468            ty::Binder::dummy(tcx.type_of(did).instantiate_identity()),
469            cx,
470            Some(did),
471            None,
472        ),
473    };
474
475    // Only inline impl if the implementing type is
476    // reachable in rustdoc generated documentation
477    if !did.is_local()
478        && let Some(did) = for_.def_id(&cx.cache)
479        && !is_directly_public(cx, did)
480    {
481        return;
482    }
483
484    let document_hidden = cx.render_options.document_hidden;
485    let predicates = tcx.explicit_predicates_of(did);
486    let (trait_items, generics) = match impl_item {
487        Some(impl_) => (
488            impl_
489                .items
490                .iter()
491                .map(|item| tcx.hir().impl_item(item.id))
492                .filter(|item| {
493                    // Filter out impl items whose corresponding trait item has `doc(hidden)`
494                    // not to document such impl items.
495                    // For inherent impls, we don't do any filtering, because that's already done in strip_hidden.rs.
496
497                    // When `--document-hidden-items` is passed, we don't
498                    // do any filtering, too.
499                    if document_hidden {
500                        return true;
501                    }
502                    if let Some(associated_trait) = associated_trait {
503                        let assoc_kind = match item.kind {
504                            hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
505                            hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
506                            hir::ImplItemKind::Type(..) => ty::AssocKind::Type,
507                        };
508                        let trait_item = tcx
509                            .associated_items(associated_trait.def_id)
510                            .find_by_name_and_kind(
511                                tcx,
512                                item.ident,
513                                assoc_kind,
514                                associated_trait.def_id,
515                            )
516                            .unwrap(); // SAFETY: For all impl items there exists trait item that has the same name.
517                        !tcx.is_doc_hidden(trait_item.def_id)
518                    } else {
519                        true
520                    }
521                })
522                .map(|item| clean_impl_item(item, cx))
523                .collect::<Vec<_>>(),
524            clean_generics(impl_.generics, cx),
525        ),
526        None => (
527            tcx.associated_items(did)
528                .in_definition_order()
529                .filter(|item| !item.is_impl_trait_in_trait())
530                .filter(|item| {
531                    // If this is a trait impl, filter out associated items whose corresponding item
532                    // in the associated trait is marked `doc(hidden)`.
533                    // If this is an inherent impl, filter out private associated items.
534                    if let Some(associated_trait) = associated_trait {
535                        let trait_item = tcx
536                            .associated_items(associated_trait.def_id)
537                            .find_by_name_and_kind(
538                                tcx,
539                                item.ident(tcx),
540                                item.kind,
541                                associated_trait.def_id,
542                            )
543                            .unwrap(); // corresponding associated item has to exist
544                        document_hidden || !tcx.is_doc_hidden(trait_item.def_id)
545                    } else {
546                        item.visibility(tcx).is_public()
547                    }
548                })
549                .map(|item| clean_middle_assoc_item(item, cx))
550                .collect::<Vec<_>>(),
551            clean::enter_impl_trait(cx, |cx| {
552                clean_ty_generics(cx, tcx.generics_of(did), predicates)
553            }),
554        ),
555    };
556    let polarity = tcx.impl_polarity(did);
557    let trait_ = associated_trait
558        .map(|t| clean_trait_ref_with_constraints(cx, ty::Binder::dummy(t), ThinVec::new()));
559    if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() {
560        super::build_deref_target_impls(cx, &trait_items, ret);
561    }
562
563    // Return if the trait itself or any types of the generic parameters are doc(hidden).
564    let mut stack: Vec<&Type> = vec![&for_];
565
566    if let Some(did) = trait_.as_ref().map(|t| t.def_id()) {
567        if !document_hidden && tcx.is_doc_hidden(did) {
568            return;
569        }
570    }
571    if let Some(generics) = trait_.as_ref().and_then(|t| t.generics()) {
572        stack.extend(generics);
573    }
574
575    while let Some(ty) = stack.pop() {
576        if let Some(did) = ty.def_id(&cx.cache)
577            && !document_hidden
578            && tcx.is_doc_hidden(did)
579        {
580            return;
581        }
582        if let Some(generics) = ty.generics() {
583            stack.extend(generics);
584        }
585    }
586
587    if let Some(did) = trait_.as_ref().map(|t| t.def_id()) {
588        cx.with_param_env(did, |cx| {
589            record_extern_trait(cx, did);
590        });
591    }
592
593    let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs);
594    trace!("merged_attrs={merged_attrs:?}");
595
596    trace!(
597        "build_impl: impl {:?} for {:?}",
598        trait_.as_ref().map(|t| t.def_id()),
599        for_.def_id(&cx.cache)
600    );
601    ret.push(clean::Item::from_def_id_and_attrs_and_parts(
602        did,
603        None,
604        clean::ImplItem(Box::new(clean::Impl {
605            safety: hir::Safety::Safe,
606            generics,
607            trait_,
608            for_,
609            items: trait_items,
610            polarity,
611            kind: if utils::has_doc_flag(tcx, did, sym::fake_variadic) {
612                ImplKind::FakeVariadic
613            } else {
614                ImplKind::Normal
615            },
616        })),
617        merged_attrs,
618        cfg,
619    ));
620}
621
622fn build_module(cx: &mut DocContext<'_>, did: DefId, visited: &mut DefIdSet) -> clean::Module {
623    let items = build_module_items(cx, did, visited, &mut FxHashSet::default(), None, None);
624
625    let span = clean::Span::new(cx.tcx.def_span(did));
626    clean::Module { items, span }
627}
628
629fn build_module_items(
630    cx: &mut DocContext<'_>,
631    did: DefId,
632    visited: &mut DefIdSet,
633    inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
634    allowed_def_ids: Option<&DefIdSet>,
635    attrs: Option<(&[hir::Attribute], Option<LocalDefId>)>,
636) -> Vec<clean::Item> {
637    let mut items = Vec::new();
638
639    // If we're re-exporting a re-export it may actually re-export something in
640    // two namespaces, so the target may be listed twice. Make sure we only
641    // visit each node at most once.
642    for item in cx.tcx.module_children(did).iter() {
643        if item.vis.is_public() {
644            let res = item.res.expect_non_local();
645            if let Some(def_id) = res.opt_def_id()
646                && let Some(allowed_def_ids) = allowed_def_ids
647                && !allowed_def_ids.contains(&def_id)
648            {
649                continue;
650            }
651            if let Some(def_id) = res.mod_def_id() {
652                // If we're inlining a glob import, it's possible to have
653                // two distinct modules with the same name. We don't want to
654                // inline it, or mark any of its contents as visited.
655                if did == def_id
656                    || inlined_names.contains(&(ItemType::Module, item.ident.name))
657                    || !visited.insert(def_id)
658                {
659                    continue;
660                }
661            }
662            if let Res::PrimTy(p) = res {
663                // Primitive types can't be inlined so generate an import instead.
664                let prim_ty = clean::PrimitiveType::from(p);
665                items.push(clean::Item {
666                    name: None,
667                    // We can use the item's `DefId` directly since the only information ever used
668                    // from it is `DefId.krate`.
669                    item_id: ItemId::DefId(did),
670                    inner: Box::new(clean::ItemInner {
671                        attrs: Default::default(),
672                        stability: None,
673                        kind: clean::ImportItem(clean::Import::new_simple(
674                            item.ident.name,
675                            clean::ImportSource {
676                                path: clean::Path {
677                                    res,
678                                    segments: thin_vec![clean::PathSegment {
679                                        name: prim_ty.as_sym(),
680                                        args: clean::GenericArgs::AngleBracketed {
681                                            args: Default::default(),
682                                            constraints: ThinVec::new(),
683                                        },
684                                    }],
685                                },
686                                did: None,
687                            },
688                            true,
689                        )),
690                    }),
691                    cfg: None,
692                    inline_stmt_id: None,
693                });
694            } else if let Some(i) = try_inline(cx, res, item.ident.name, attrs, visited) {
695                items.extend(i)
696            }
697        }
698    }
699
700    items
701}
702
703pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
704    if let Some(did) = did.as_local() {
705        let hir_id = tcx.local_def_id_to_hir_id(did);
706        rustc_hir_pretty::id_to_string(&tcx.hir(), hir_id)
707    } else {
708        tcx.rendered_const(did).clone()
709    }
710}
711
712fn build_const_item(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant {
713    let mut generics =
714        clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id));
715    clean::simplify::move_bounds_to_generic_parameters(&mut generics);
716    let ty = clean_middle_ty(
717        ty::Binder::dummy(cx.tcx.type_of(def_id).instantiate_identity()),
718        cx,
719        None,
720        None,
721    );
722    clean::Constant { generics, type_: ty, kind: clean::ConstantKind::Extern { def_id } }
723}
724
725fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::Static {
726    clean::Static {
727        type_: Box::new(clean_middle_ty(
728            ty::Binder::dummy(cx.tcx.type_of(did).instantiate_identity()),
729            cx,
730            Some(did),
731            None,
732        )),
733        mutability: if mutable { Mutability::Mut } else { Mutability::Not },
734        expr: None,
735    }
736}
737
738fn build_macro(
739    cx: &mut DocContext<'_>,
740    def_id: DefId,
741    name: Symbol,
742    macro_kind: MacroKind,
743) -> clean::ItemKind {
744    match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) {
745        LoadedMacro::MacroDef { def, .. } => match macro_kind {
746            MacroKind::Bang => clean::MacroItem(clean::Macro {
747                source: utils::display_macro_source(cx, name, &def),
748                macro_rules: def.macro_rules,
749            }),
750            MacroKind::Derive | MacroKind::Attr => {
751                clean::ProcMacroItem(clean::ProcMacro { kind: macro_kind, helpers: Vec::new() })
752            }
753        },
754        LoadedMacro::ProcMacro(ext) => clean::ProcMacroItem(clean::ProcMacro {
755            kind: ext.macro_kind(),
756            helpers: ext.helper_attrs,
757        }),
758    }
759}
760
761/// A trait's generics clause actually contains all of the predicates for all of
762/// its associated types as well. We specifically move these clauses to the
763/// associated types instead when displaying, so when we're generating the
764/// generics for the trait itself we need to be sure to remove them.
765/// We also need to remove the implied "recursive" Self: Trait bound.
766///
767/// The inverse of this filtering logic can be found in the `Clean`
768/// implementation for `AssociatedType`
769fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics {
770    for pred in &mut g.where_predicates {
771        if let clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref mut bounds, .. } =
772            *pred
773        {
774            bounds.retain(|bound| match bound {
775                clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => {
776                    trait_.def_id() != trait_did
777                }
778                _ => true,
779            });
780        }
781    }
782
783    g.where_predicates.retain(|pred| match pred {
784        clean::WherePredicate::BoundPredicate {
785            ty:
786                clean::QPath(box clean::QPathData {
787                    self_type: clean::Generic(_),
788                    trait_: Some(trait_),
789                    ..
790                }),
791            bounds,
792            ..
793        } => !bounds.is_empty() && trait_.def_id() != trait_did,
794        _ => true,
795    });
796    g
797}
798
799/// Supertrait bounds for a trait are also listed in the generics coming from
800/// the metadata for a crate, so we want to separate those out and create a new
801/// list of explicit supertrait bounds to render nicely.
802fn separate_supertrait_bounds(
803    mut g: clean::Generics,
804) -> (clean::Generics, Vec<clean::GenericBound>) {
805    let mut ty_bounds = Vec::new();
806    g.where_predicates.retain(|pred| match *pred {
807        clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref bounds, .. } => {
808            ty_bounds.extend(bounds.iter().cloned());
809            false
810        }
811        _ => true,
812    });
813    (g, ty_bounds)
814}
815
816pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
817    if did.is_local() {
818        return;
819    }
820
821    {
822        if cx.external_traits.contains_key(&did) || cx.active_extern_traits.contains(&did) {
823            return;
824        }
825    }
826
827    {
828        cx.active_extern_traits.insert(did);
829    }
830
831    debug!("record_extern_trait: {did:?}");
832    let trait_ = build_external_trait(cx, did);
833
834    cx.external_traits.insert(did, trait_);
835    cx.active_extern_traits.remove(&did);
836}