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