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