1mod auto_trait;
25mod blanket_impl;
26pub(crate) mod cfg;
27pub(crate) mod inline;
28mod render_macro_matchers;
29mod simplify;
30pub(crate) mod types;
31pub(crate) mod utils;
32
33use std::borrow::Cow;
34use std::collections::BTreeMap;
35use std::mem;
36
37use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry};
38use rustc_data_structures::thin_vec::ThinVec;
39use rustc_errors::codes::*;
40use rustc_errors::{FatalError, struct_span_code_err};
41use rustc_hir as hir;
42use rustc_hir::attrs::{AttributeKind, DocAttribute, DocInline};
43use rustc_hir::def::{CtorKind, DefKind, MacroKinds, Res};
44use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId};
45use rustc_hir::{LangItem, PredicateOrigin, find_attr};
46use rustc_hir_analysis::{lower_const_arg_for_rustdoc, lower_ty};
47use rustc_middle::metadata::Reexport;
48use rustc_middle::middle::resolve_bound_vars as rbv;
49use rustc_middle::ty::{
50 self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode, Unnormalized,
51};
52use rustc_middle::{bug, span_bug};
53use rustc_span::ExpnKind;
54use rustc_span::hygiene::{AstPass, MacroKind};
55use rustc_span::symbol::{Ident, Symbol, kw};
56use rustc_trait_selection::traits::wf::object_region_bounds;
57use tracing::{debug, instrument};
58use utils::*;
59
60pub(crate) use self::cfg::{CfgInfo, extract_cfg_from_attrs};
61pub(crate) use self::types::*;
62pub(crate) use self::utils::{krate, register_res, synthesize_auto_trait_and_blanket_impls};
63use crate::core::DocContext;
64use crate::formats::item_type::ItemType;
65use crate::visit_ast::Module as DocModule;
66
67pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
68 let mut items: Vec<Item> = vec![];
69 let mut inserted = FxHashSet::default();
70 items.extend(doc.foreigns.iter().map(|(item, renamed, import_id)| {
71 let item = clean_maybe_renamed_foreign_item(cx, item, *renamed, *import_id);
72 if let Some(name) = item.name
73 && (cx.document_hidden() || !item.is_doc_hidden())
74 {
75 inserted.insert((item.type_(), name));
76 }
77 item
78 }));
79 items.extend(doc.mods.iter().filter_map(|x| {
80 if !inserted.insert((ItemType::Module, x.name)) {
81 return None;
82 }
83 let item = clean_doc_module(x, cx);
84 if !cx.document_hidden() && item.is_doc_hidden() {
85 inserted.remove(&(ItemType::Module, x.name));
89 }
90 Some(item)
91 }));
92
93 items.extend(doc.items.values().flat_map(|(item, renamed, import_ids)| {
99 if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
101 return Vec::new();
102 }
103 let v = clean_maybe_renamed_item(cx, item, *renamed, import_ids);
104 for item in &v {
105 if let Some(name) = item.name
106 && (cx.document_hidden() || !item.is_doc_hidden())
107 {
108 inserted.insert((item.type_(), name));
109 }
110 }
111 v
112 }));
113 items.extend(doc.inlined_foreigns.iter().flat_map(|((_, renamed), (res, local_import_id))| {
114 let Some(def_id) = res.opt_def_id() else { return Vec::new() };
115 let name = renamed.unwrap_or_else(|| cx.tcx.item_name(def_id));
116 let import = cx.tcx.hir_expect_item(*local_import_id);
117 match import.kind {
118 hir::ItemKind::Use(path, kind) => {
119 let hir::UsePath { segments, span, .. } = *path;
120 let path = hir::Path { segments, res: *res, span };
121 clean_use_statement_inner(
122 import,
123 Some(name),
124 &path,
125 kind,
126 cx,
127 &mut Default::default(),
128 )
129 }
130 _ => unreachable!(),
131 }
132 }));
133 items.extend(doc.items.values().flat_map(|(item, renamed, _)| {
134 if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
136 clean_use_statement(item, *renamed, path, hir::UseKind::Glob, cx, &mut inserted)
137 } else {
138 Vec::new()
140 }
141 }));
142
143 let span = Span::new({
147 let where_outer = doc.where_outer(cx.tcx);
148 let sm = cx.sess().source_map();
149 let outer = sm.lookup_char_pos(where_outer.lo());
150 let inner = sm.lookup_char_pos(doc.where_inner.lo());
151 if outer.file.start_pos == inner.file.start_pos {
152 where_outer
154 } else {
155 doc.where_inner
157 }
158 });
159
160 let kind = ModuleItem(Module { items, span });
161 generate_item_with_correct_attrs(
162 cx,
163 kind,
164 doc.def_id.to_def_id(),
165 doc.name,
166 doc.import_id.as_slice(),
167 doc.renamed,
168 )
169}
170
171fn is_glob_import(tcx: TyCtxt<'_>, import_id: LocalDefId) -> bool {
172 if let hir::Node::Item(item) = tcx.hir_node_by_def_id(import_id)
173 && let hir::ItemKind::Use(_, use_kind) = item.kind
174 {
175 use_kind == hir::UseKind::Glob
176 } else {
177 false
178 }
179}
180
181pub(crate) fn macro_reexport_is_inline(
183 tcx: TyCtxt<'_>,
184 import_id: LocalDefId,
185 def_id: DefId,
186) -> bool {
187 if !matches!(tcx.def_kind(def_id), DefKind::Macro(MacroKinds::BANG)) {
188 return false;
189 }
190
191 for reexport_def_id in reexport_chain(tcx, import_id, def_id).iter().flat_map(|r| r.id()) {
192 let is_hidden = tcx.is_doc_hidden(reexport_def_id);
193 let is_inline = find_attr!(
194 inline::load_attrs(tcx, reexport_def_id),
195 Doc(d)
196 if d.inline.first().is_some_and(|(inline, _)| *inline == DocInline::Inline)
197 );
198
199 if is_hidden {
201 return false;
202 }
203 if is_inline {
204 return true;
205 }
206 }
207 false
208}
209
210fn generate_item_with_correct_attrs(
211 cx: &mut DocContext<'_>,
212 kind: ItemKind,
213 def_id: DefId,
214 name: Symbol,
215 import_ids: &[LocalDefId],
216 renamed: Option<Symbol>,
217) -> Item {
218 let tcx = cx.tcx;
219 let target_attrs = inline::load_attrs(tcx, def_id);
220 let attrs = if !import_ids.is_empty() {
221 let mut attrs = Vec::with_capacity(import_ids.len());
222 let mut is_inline = false;
223
224 for import_id in import_ids.iter().copied() {
225 let import_is_inline = find_attr!(
231 inline::load_attrs(tcx, import_id.to_def_id()),
232 Doc(d)
233 if d.inline.first().is_some_and(|(inline, _)| *inline == DocInline::Inline)
234 ) || (is_glob_import(tcx, import_id)
235 && (cx.document_hidden() || !tcx.is_doc_hidden(def_id)))
236 || macro_reexport_is_inline(tcx, import_id, def_id);
237 attrs.extend(get_all_import_attributes(cx, import_id, def_id, is_inline));
238 is_inline = is_inline || import_is_inline;
239 }
240 let keep_target_cfg = is_inline || matches!(kind, ItemKind::TypeAliasItem(..));
241 add_without_unwanted_attributes(&mut attrs, target_attrs, keep_target_cfg, None);
242 attrs
243 } else {
244 target_attrs.iter().map(|attr| (Cow::Borrowed(attr), None)).collect()
246 };
247 let attrs = Attributes::from_hir_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false);
248
249 let name = renamed.or(Some(name));
250 let mut item = Item::from_def_id_and_attrs_and_parts(def_id, name, kind, attrs, None);
251 item.inner.inline_stmt_id = import_ids.first().copied();
253 item
254}
255
256fn clean_generic_bound<'tcx>(
257 bound: &hir::GenericBound<'tcx>,
258 cx: &mut DocContext<'tcx>,
259) -> Option<GenericBound> {
260 Some(match bound {
261 hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
262 hir::GenericBound::Trait(t) => {
263 if let hir::BoundConstness::Maybe(_) = t.modifiers.constness
265 && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap())
266 {
267 return None;
268 }
269
270 GenericBound::TraitBound(clean_poly_trait_ref(t, cx), t.modifiers)
271 }
272 hir::GenericBound::Use(args, ..) => {
273 GenericBound::Use(args.iter().map(|arg| clean_precise_capturing_arg(arg, cx)).collect())
274 }
275 })
276}
277
278pub(crate) fn clean_trait_ref_with_constraints<'tcx>(
279 cx: &mut DocContext<'tcx>,
280 trait_ref: ty::PolyTraitRef<'tcx>,
281 constraints: ThinVec<AssocItemConstraint>,
282) -> Path {
283 let kind = ItemType::from_def_id(trait_ref.def_id(), cx.tcx);
284 if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
285 span_bug!(cx.tcx.def_span(trait_ref.def_id()), "`TraitRef` had unexpected kind {kind:?}");
286 }
287 inline::record_extern_fqn(cx, trait_ref.def_id(), kind);
288 let path = clean_middle_path(
289 cx,
290 trait_ref.def_id(),
291 true,
292 constraints,
293 trait_ref.map_bound(|tr| tr.args),
294 );
295
296 debug!(?trait_ref);
297
298 path
299}
300
301fn clean_poly_trait_ref_with_constraints<'tcx>(
302 cx: &mut DocContext<'tcx>,
303 poly_trait_ref: ty::PolyTraitRef<'tcx>,
304 constraints: ThinVec<AssocItemConstraint>,
305) -> GenericBound {
306 GenericBound::TraitBound(
307 PolyTrait {
308 trait_: clean_trait_ref_with_constraints(cx, poly_trait_ref, constraints),
309 generic_params: clean_bound_vars(poly_trait_ref.bound_vars(), cx.tcx),
310 },
311 hir::TraitBoundModifiers::NONE,
312 )
313}
314
315fn clean_lifetime(lifetime: &hir::Lifetime, cx: &DocContext<'_>) -> Lifetime {
316 if let Some(
317 rbv::ResolvedArg::EarlyBound(did)
318 | rbv::ResolvedArg::LateBound(_, _, did)
319 | rbv::ResolvedArg::Free(_, did),
320 ) = cx.tcx.named_bound_var(lifetime.hir_id)
321 && let Some(lt) = cx.args.get(&did.to_def_id()).and_then(|arg| arg.as_lt())
322 {
323 return *lt;
324 }
325 Lifetime(lifetime.ident.name)
326}
327
328pub(crate) fn clean_precise_capturing_arg(
329 arg: &hir::PreciseCapturingArg<'_>,
330 cx: &DocContext<'_>,
331) -> PreciseCapturingArg {
332 match arg {
333 hir::PreciseCapturingArg::Lifetime(lt) => {
334 PreciseCapturingArg::Lifetime(clean_lifetime(lt, cx))
335 }
336 hir::PreciseCapturingArg::Param(param) => PreciseCapturingArg::Param(param.ident.name),
337 }
338}
339
340pub(crate) fn clean_const_item_rhs<'tcx>(
341 ct_rhs: hir::ConstItemRhs<'tcx>,
342 parent: DefId,
343) -> ConstantKind {
344 match ct_rhs {
345 hir::ConstItemRhs::Body(body) => ConstantKind::Local { def_id: parent, body },
346 hir::ConstItemRhs::TypeConst(ct) => clean_const(ct),
347 }
348}
349
350pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind {
351 match &constant.kind {
352 hir::ConstArgKind::Path(qpath) => {
353 ConstantKind::Path { path: qpath_to_string(qpath).into() }
354 }
355 hir::ConstArgKind::Struct(..) => {
356 ConstantKind::Path { path: "/* STRUCT EXPR */".to_string().into() }
358 }
359 hir::ConstArgKind::TupleCall(..) => {
360 ConstantKind::Path { path: "/* TUPLE CALL */".to_string().into() }
361 }
362 hir::ConstArgKind::Tup(..) => {
363 ConstantKind::Path { path: "/* TUPLE EXPR */".to_string().into() }
365 }
366 hir::ConstArgKind::Array(..) => {
367 ConstantKind::Path { path: "/* ARRAY EXPR */".to_string().into() }
368 }
369 hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body },
370 hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer,
371 hir::ConstArgKind::Literal { .. } => {
372 ConstantKind::Path { path: "/* LITERAL */".to_string().into() }
373 }
374 }
375}
376
377pub(crate) fn clean_middle_const<'tcx>(
378 constant: ty::Binder<'tcx, ty::Const<'tcx>>,
379) -> ConstantKind {
380 ConstantKind::TyConst { expr: constant.skip_binder().to_string().into() }
382}
383
384pub(crate) fn clean_middle_region<'tcx>(
385 region: ty::Region<'tcx>,
386 tcx: TyCtxt<'tcx>,
387) -> Option<Lifetime> {
388 region.get_name(tcx).map(Lifetime)
389}
390
391fn clean_where_predicate<'tcx>(
392 predicate: &hir::WherePredicate<'tcx>,
393 cx: &mut DocContext<'tcx>,
394) -> Option<WherePredicate> {
395 if !predicate.kind.in_where_clause() {
396 return None;
397 }
398 Some(match predicate.kind {
399 hir::WherePredicateKind::BoundPredicate(wbp) => {
400 let bound_params = wbp
401 .bound_generic_params
402 .iter()
403 .map(|param| clean_generic_param(cx, None, param))
404 .collect();
405 WherePredicate::BoundPredicate {
406 ty: clean_ty(wbp.bounded_ty, cx),
407 bounds: wbp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
408 bound_params,
409 }
410 }
411
412 hir::WherePredicateKind::RegionPredicate(wrp) => WherePredicate::RegionPredicate {
413 lifetime: clean_lifetime(wrp.lifetime, cx),
414 bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
415 },
416
417 hir::WherePredicateKind::EqPredicate(_) => bug!("EqPredicate"),
420 })
421}
422
423pub(crate) fn clean_predicate<'tcx>(
424 predicate: ty::Clause<'tcx>,
425 cx: &mut DocContext<'tcx>,
426) -> Option<WherePredicate> {
427 let bound_predicate = predicate.kind();
428 match bound_predicate.skip_binder() {
429 ty::ClauseKind::Trait(pred) => clean_poly_trait_predicate(bound_predicate.rebind(pred), cx),
430 ty::ClauseKind::RegionOutlives(pred) => Some(clean_region_outlives_predicate(pred, cx.tcx)),
431 ty::ClauseKind::TypeOutlives(pred) => {
432 Some(clean_type_outlives_predicate(bound_predicate.rebind(pred), cx))
433 }
434 ty::ClauseKind::Projection(pred) => {
435 Some(clean_projection_predicate(bound_predicate.rebind(pred), cx))
436 }
437 ty::ClauseKind::ConstEvaluatable(..)
439 | ty::ClauseKind::WellFormed(..)
440 | ty::ClauseKind::ConstArgHasType(..)
441 | ty::ClauseKind::UnstableFeature(..)
442 | ty::ClauseKind::HostEffect(_) => None,
444 }
445}
446
447fn clean_poly_trait_predicate<'tcx>(
448 pred: ty::PolyTraitPredicate<'tcx>,
449 cx: &mut DocContext<'tcx>,
450) -> Option<WherePredicate> {
451 if Some(pred.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait() {
454 return None;
455 }
456
457 let poly_trait_ref = pred.map_bound(|pred| pred.trait_ref);
458 Some(WherePredicate::BoundPredicate {
459 ty: clean_middle_ty(poly_trait_ref.self_ty(), cx, None, None),
460 bounds: vec![clean_poly_trait_ref_with_constraints(cx, poly_trait_ref, ThinVec::new())],
461 bound_params: Vec::new(),
462 })
463}
464
465fn clean_region_outlives_predicate<'tcx>(
466 pred: ty::RegionOutlivesPredicate<'tcx>,
467 tcx: TyCtxt<'tcx>,
468) -> WherePredicate {
469 let ty::OutlivesPredicate(a, b) = pred;
470
471 WherePredicate::RegionPredicate {
472 lifetime: clean_middle_region(a, tcx).expect("failed to clean lifetime"),
473 bounds: vec![GenericBound::Outlives(
474 clean_middle_region(b, tcx).expect("failed to clean bounds"),
475 )],
476 }
477}
478
479fn clean_type_outlives_predicate<'tcx>(
480 pred: ty::Binder<'tcx, ty::TypeOutlivesPredicate<'tcx>>,
481 cx: &mut DocContext<'tcx>,
482) -> WherePredicate {
483 let ty::OutlivesPredicate(ty, lt) = pred.skip_binder();
484
485 WherePredicate::BoundPredicate {
486 ty: clean_middle_ty(pred.rebind(ty), cx, None, None),
487 bounds: vec![GenericBound::Outlives(
488 clean_middle_region(lt, cx.tcx).expect("failed to clean lifetimes"),
489 )],
490 bound_params: Vec::new(),
491 }
492}
493
494fn clean_middle_term<'tcx>(
495 term: ty::Binder<'tcx, ty::Term<'tcx>>,
496 cx: &mut DocContext<'tcx>,
497) -> Term {
498 match term.skip_binder().kind() {
499 ty::TermKind::Ty(ty) => Term::Type(clean_middle_ty(term.rebind(ty), cx, None, None)),
500 ty::TermKind::Const(c) => Term::Constant(clean_middle_const(term.rebind(c))),
501 }
502}
503
504fn clean_hir_term<'tcx>(
505 assoc_item: Option<DefId>,
506 term: &hir::Term<'tcx>,
507 cx: &mut DocContext<'tcx>,
508) -> Term {
509 match term {
510 hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)),
511 hir::Term::Const(c) => {
512 let ty = cx.tcx.type_of(assoc_item.unwrap()).instantiate_identity().skip_norm_wip();
514 let ct = lower_const_arg_for_rustdoc(cx.tcx, c, ty);
515 Term::Constant(clean_middle_const(ty::Binder::dummy(ct)))
516 }
517 }
518}
519
520fn clean_projection_predicate<'tcx>(
521 pred: ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>,
522 cx: &mut DocContext<'tcx>,
523) -> WherePredicate {
524 WherePredicate::EqPredicate {
525 lhs: clean_projection(pred.map_bound(|p| p.projection_term), cx, None),
526 rhs: clean_middle_term(pred.map_bound(|p| p.term), cx),
527 }
528}
529
530fn clean_projection<'tcx>(
531 proj: ty::Binder<'tcx, ty::AliasTerm<'tcx>>,
532 cx: &mut DocContext<'tcx>,
533 parent_def_id: Option<DefId>,
534) -> QPathData {
535 let trait_ = clean_trait_ref_with_constraints(
536 cx,
537 proj.map_bound(|proj| proj.trait_ref(cx.tcx)),
538 ThinVec::new(),
539 );
540 let self_type = clean_middle_ty(proj.map_bound(|proj| proj.self_ty()), cx, None, None);
541 let self_def_id = match parent_def_id {
542 Some(parent_def_id) => cx.tcx.opt_parent(parent_def_id).or(Some(parent_def_id)),
543 None => self_type.def_id(&cx.cache),
544 };
545 let should_fully_qualify = should_fully_qualify_path(self_def_id, &trait_, &self_type);
546
547 QPathData {
548 assoc: projection_to_path_segment(proj, cx),
549 self_type,
550 should_fully_qualify,
551 trait_: Some(trait_),
552 }
553}
554
555fn should_fully_qualify_path(self_def_id: Option<DefId>, trait_: &Path, self_type: &Type) -> bool {
556 !trait_.segments.is_empty()
557 && self_def_id
558 .zip(Some(trait_.def_id()))
559 .map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_)
560}
561
562fn projection_to_path_segment<'tcx>(
563 proj: ty::Binder<'tcx, ty::AliasTerm<'tcx>>,
564 cx: &mut DocContext<'tcx>,
565) -> PathSegment {
566 let def_id = proj.skip_binder().def_id();
567 let generics = cx.tcx.generics_of(def_id);
568 PathSegment {
569 name: cx.tcx.item_name(def_id),
570 args: GenericArgs::AngleBracketed {
571 args: clean_middle_generic_args(
572 cx,
573 proj.map_bound(|ty| &ty.args[generics.parent_count..]),
574 false,
575 def_id,
576 ),
577 constraints: Default::default(),
578 },
579 }
580}
581
582fn clean_generic_param_def(
583 def: &ty::GenericParamDef,
584 defaults: ParamDefaults,
585 cx: &mut DocContext<'_>,
586) -> GenericParamDef {
587 let (name, kind) = match def.kind {
588 ty::GenericParamDefKind::Lifetime => {
589 (def.name, GenericParamDefKind::Lifetime { outlives: ThinVec::new() })
590 }
591 ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
592 let default = if let ParamDefaults::Yes = defaults
593 && has_default
594 {
595 Some(clean_middle_ty(
596 ty::Binder::dummy(
597 cx.tcx.type_of(def.def_id).instantiate_identity().skip_norm_wip(),
598 ),
599 cx,
600 Some(def.def_id),
601 None,
602 ))
603 } else {
604 None
605 };
606 (
607 def.name,
608 GenericParamDefKind::Type {
609 bounds: ThinVec::new(), default: default.map(Box::new),
611 synthetic,
612 },
613 )
614 }
615 ty::GenericParamDefKind::Const { has_default } => (
616 def.name,
617 GenericParamDefKind::Const {
618 ty: Box::new(clean_middle_ty(
619 ty::Binder::dummy(
620 cx.tcx.type_of(def.def_id).instantiate_identity().skip_norm_wip(),
621 ),
622 cx,
623 Some(def.def_id),
624 None,
625 )),
626 default: if let ParamDefaults::Yes = defaults
627 && has_default
628 {
629 Some(Box::new(
630 cx.tcx
631 .const_param_default(def.def_id)
632 .instantiate_identity()
633 .skip_norm_wip()
634 .to_string(),
635 ))
636 } else {
637 None
638 },
639 },
640 ),
641 };
642
643 GenericParamDef { name, def_id: def.def_id, kind }
644}
645
646enum ParamDefaults {
648 Yes,
649 No,
650}
651
652fn clean_generic_param<'tcx>(
653 cx: &mut DocContext<'tcx>,
654 generics: Option<&hir::Generics<'tcx>>,
655 param: &hir::GenericParam<'tcx>,
656) -> GenericParamDef {
657 let (name, kind) = match param.kind {
658 hir::GenericParamKind::Lifetime { .. } => {
659 let outlives = if let Some(generics) = generics {
660 generics
661 .outlives_for_param(param.def_id)
662 .filter(|bp| !bp.in_where_clause)
663 .flat_map(|bp| bp.bounds)
664 .map(|bound| match bound {
665 hir::GenericBound::Outlives(lt) => clean_lifetime(lt, cx),
666 _ => panic!(),
667 })
668 .collect()
669 } else {
670 ThinVec::new()
671 };
672 (param.name.ident().name, GenericParamDefKind::Lifetime { outlives })
673 }
674 hir::GenericParamKind::Type { ref default, synthetic } => {
675 let bounds = if let Some(generics) = generics {
676 generics
677 .bounds_for_param(param.def_id)
678 .filter(|bp| bp.origin != PredicateOrigin::WhereClause)
679 .flat_map(|bp| bp.bounds)
680 .filter_map(|x| clean_generic_bound(x, cx))
681 .collect()
682 } else {
683 ThinVec::new()
684 };
685 (
686 param.name.ident().name,
687 GenericParamDefKind::Type {
688 bounds,
689 default: default.map(|t| clean_ty(t, cx)).map(Box::new),
690 synthetic,
691 },
692 )
693 }
694 hir::GenericParamKind::Const { ty, default } => (
695 param.name.ident().name,
696 GenericParamDefKind::Const {
697 ty: Box::new(clean_ty(ty, cx)),
698 default: default.map(|ct| {
699 Box::new(
700 lower_const_arg_for_rustdoc(cx.tcx, ct, lower_ty(cx.tcx, ty)).to_string(),
701 )
702 }),
703 },
704 ),
705 };
706
707 GenericParamDef { name, def_id: param.def_id.to_def_id(), kind }
708}
709
710fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool {
714 match param.kind {
715 hir::GenericParamKind::Type { synthetic, .. } => synthetic,
716 _ => false,
717 }
718}
719
720fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
724 matches!(
725 param.kind,
726 hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided(_) }
727 )
728}
729
730pub(crate) fn clean_generics<'tcx>(
731 gens: &hir::Generics<'tcx>,
732 cx: &mut DocContext<'tcx>,
733) -> Generics {
734 let impl_trait_params = gens
735 .params
736 .iter()
737 .filter(|param| is_impl_trait(param))
738 .map(|param| {
739 let param = clean_generic_param(cx, Some(gens), param);
740 match param.kind {
741 GenericParamDefKind::Lifetime { .. } => unreachable!(),
742 GenericParamDefKind::Type { ref bounds, .. } => {
743 cx.impl_trait_bounds.insert(param.def_id.into(), bounds.to_vec());
744 }
745 GenericParamDefKind::Const { .. } => unreachable!(),
746 }
747 param
748 })
749 .collect::<Vec<_>>();
750
751 let mut bound_predicates = FxIndexMap::default();
752 let mut region_predicates = FxIndexMap::default();
753 let mut eq_predicates = ThinVec::default();
754 for pred in gens.predicates.iter().filter_map(|x| clean_where_predicate(x, cx)) {
755 match pred {
756 WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
757 match bound_predicates.entry(ty) {
758 IndexEntry::Vacant(v) => {
759 v.insert((bounds, bound_params));
760 }
761 IndexEntry::Occupied(mut o) => {
762 for bound in bounds {
764 if !o.get().0.contains(&bound) {
765 o.get_mut().0.push(bound);
766 }
767 }
768 for bound_param in bound_params {
769 if !o.get().1.contains(&bound_param) {
770 o.get_mut().1.push(bound_param);
771 }
772 }
773 }
774 }
775 }
776 WherePredicate::RegionPredicate { lifetime, bounds } => {
777 match region_predicates.entry(lifetime) {
778 IndexEntry::Vacant(v) => {
779 v.insert(bounds);
780 }
781 IndexEntry::Occupied(mut o) => {
782 for bound in bounds {
784 if !o.get().contains(&bound) {
785 o.get_mut().push(bound);
786 }
787 }
788 }
789 }
790 }
791 WherePredicate::EqPredicate { lhs, rhs } => {
792 eq_predicates.push(WherePredicate::EqPredicate { lhs, rhs });
793 }
794 }
795 }
796
797 let mut params = ThinVec::with_capacity(gens.params.len());
798 for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
802 let mut p = clean_generic_param(cx, Some(gens), p);
803 match &mut p.kind {
804 GenericParamDefKind::Lifetime { outlives } => {
805 if let Some(region_pred) = region_predicates.get_mut(&Lifetime(p.name)) {
806 for outlive in outlives.drain(..) {
808 let outlive = GenericBound::Outlives(outlive);
809 if !region_pred.contains(&outlive) {
810 region_pred.push(outlive);
811 }
812 }
813 }
814 }
815 GenericParamDefKind::Type { bounds, synthetic: false, .. } => {
816 if let Some(bound_pred) = bound_predicates.get_mut(&Type::Generic(p.name)) {
817 for bound in bounds.drain(..) {
819 if !bound_pred.0.contains(&bound) {
820 bound_pred.0.push(bound);
821 }
822 }
823 }
824 }
825 GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
826 }
828 }
829 params.push(p);
830 }
831 params.extend(impl_trait_params);
832
833 Generics {
834 params,
835 where_predicates: bound_predicates
836 .into_iter()
837 .map(|(ty, (bounds, bound_params))| WherePredicate::BoundPredicate {
838 ty,
839 bounds,
840 bound_params,
841 })
842 .chain(
843 region_predicates
844 .into_iter()
845 .map(|(lifetime, bounds)| WherePredicate::RegionPredicate { lifetime, bounds }),
846 )
847 .chain(eq_predicates)
848 .collect(),
849 }
850}
851
852fn clean_ty_generics<'tcx>(cx: &mut DocContext<'tcx>, def_id: DefId) -> Generics {
853 clean_ty_generics_inner(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id))
854}
855
856fn clean_ty_generics_inner<'tcx>(
857 cx: &mut DocContext<'tcx>,
858 gens: &ty::Generics,
859 preds: ty::GenericPredicates<'tcx>,
860) -> Generics {
861 let mut impl_trait = BTreeMap::<u32, Vec<GenericBound>>::default();
864
865 let params: ThinVec<_> = gens
866 .own_params
867 .iter()
868 .filter(|param| match param.kind {
869 ty::GenericParamDefKind::Lifetime => !param.is_anonymous_lifetime(),
870 ty::GenericParamDefKind::Type { synthetic, .. } => {
871 if param.name == kw::SelfUpper {
872 debug_assert_eq!(param.index, 0);
873 return false;
874 }
875 if synthetic {
876 impl_trait.insert(param.index, vec![]);
877 return false;
878 }
879 true
880 }
881 ty::GenericParamDefKind::Const { .. } => true,
882 })
883 .map(|param| clean_generic_param_def(param, ParamDefaults::Yes, cx))
884 .collect();
885
886 let mut impl_trait_proj =
888 FxHashMap::<u32, Vec<(DefId, PathSegment, ty::Binder<'_, ty::Term<'_>>)>>::default();
889
890 let where_predicates = preds
891 .predicates
892 .iter()
893 .flat_map(|(pred, _)| {
894 let mut proj_pred = None;
895 let param_idx = {
896 let bound_p = pred.kind();
897 match bound_p.skip_binder() {
898 ty::ClauseKind::Trait(pred) if let ty::Param(param) = pred.self_ty().kind() => {
899 Some(param.index)
900 }
901 ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg))
902 if let ty::Param(param) = ty.kind() =>
903 {
904 Some(param.index)
905 }
906 ty::ClauseKind::Projection(p)
907 if let ty::Param(param) = p.projection_term.self_ty().kind() =>
908 {
909 proj_pred = Some(bound_p.rebind(p));
910 Some(param.index)
911 }
912 _ => None,
913 }
914 };
915
916 if let Some(param_idx) = param_idx
917 && let Some(bounds) = impl_trait.get_mut(¶m_idx)
918 {
919 let pred = clean_predicate(*pred, cx)?;
920
921 bounds.extend(pred.get_bounds().into_iter().flatten().cloned());
922
923 if let Some(pred) = proj_pred {
924 let lhs = clean_projection(pred.map_bound(|p| p.projection_term), cx, None);
925 impl_trait_proj.entry(param_idx).or_default().push((
926 lhs.trait_.unwrap().def_id(),
927 lhs.assoc,
928 pred.map_bound(|p| p.term),
929 ));
930 }
931
932 return None;
933 }
934
935 Some(pred)
936 })
937 .collect::<Vec<_>>();
938
939 for (idx, mut bounds) in impl_trait {
940 let mut has_sized = false;
941 bounds.retain(|b| {
942 if b.is_sized_bound(cx.tcx) {
943 has_sized = true;
944 false
945 } else if b.is_meta_sized_bound(cx.tcx) {
946 false
949 } else {
950 true
951 }
952 });
953 if !has_sized {
954 bounds.push(GenericBound::maybe_sized(cx));
955 }
956
957 bounds.sort_by_key(|b| !b.is_trait_bound());
959
960 if bounds.first().is_none_or(|b| !b.is_trait_bound()) {
963 bounds.insert(0, GenericBound::sized(cx));
964 }
965
966 if let Some(proj) = impl_trait_proj.remove(&idx) {
967 for (trait_did, name, rhs) in proj {
968 let rhs = clean_middle_term(rhs, cx);
969 simplify::merge_bounds(cx.tcx, &mut bounds, trait_did, name, &rhs);
970 }
971 }
972
973 cx.impl_trait_bounds.insert(idx.into(), bounds);
974 }
975
976 let where_predicates =
979 where_predicates.into_iter().flat_map(|p| clean_predicate(*p, cx)).collect();
980
981 let mut generics = Generics { params, where_predicates };
982 simplify::sized_bounds(cx, &mut generics);
983 generics.where_predicates = simplify::where_clauses(cx.tcx, generics.where_predicates);
984 generics
985}
986
987fn clean_ty_alias_inner_type<'tcx>(
988 ty: Ty<'tcx>,
989 cx: &mut DocContext<'tcx>,
990 ret: &mut Vec<Item>,
991) -> Option<TypeAliasInnerType> {
992 let ty::Adt(adt_def, args) = ty.kind() else {
993 return None;
994 };
995
996 if !adt_def.did().is_local() {
997 cx.with_param_env(adt_def.did(), |cx| {
998 inline::build_impls(cx, adt_def.did(), None, ret);
999 });
1000 }
1001
1002 Some(if adt_def.is_enum() {
1003 let variants: rustc_index::IndexVec<_, _> = adt_def
1004 .variants()
1005 .iter()
1006 .map(|variant| clean_variant_def_with_args(variant, args, cx))
1007 .collect();
1008
1009 if !adt_def.did().is_local() {
1010 inline::record_extern_fqn(cx, adt_def.did(), ItemType::Enum);
1011 }
1012
1013 TypeAliasInnerType::Enum {
1014 variants,
1015 is_non_exhaustive: adt_def.is_variant_list_non_exhaustive(),
1016 }
1017 } else {
1018 let variant = adt_def
1019 .variants()
1020 .iter()
1021 .next()
1022 .unwrap_or_else(|| bug!("a struct or union should always have one variant def"));
1023
1024 let fields: Vec<_> =
1025 clean_variant_def_with_args(variant, args, cx).kind.inner_items().cloned().collect();
1026
1027 if adt_def.is_struct() {
1028 if !adt_def.did().is_local() {
1029 inline::record_extern_fqn(cx, adt_def.did(), ItemType::Struct);
1030 }
1031 TypeAliasInnerType::Struct { ctor_kind: variant.ctor_kind(), fields }
1032 } else {
1033 if !adt_def.did().is_local() {
1034 inline::record_extern_fqn(cx, adt_def.did(), ItemType::Union);
1035 }
1036 TypeAliasInnerType::Union { fields }
1037 }
1038 })
1039}
1040
1041fn clean_proc_macro<'tcx>(
1042 item: &hir::Item<'tcx>,
1043 name: &mut Symbol,
1044 kind: MacroKind,
1045 tcx: TyCtxt<'tcx>,
1046) -> ItemKind {
1047 if kind != MacroKind::Derive {
1048 return ProcMacroItem(ProcMacro { kind, helpers: vec![] });
1049 }
1050 let attrs = tcx.hir_attrs(item.hir_id());
1051 let Some((trait_name, helper_attrs)) = find_attr!(attrs, ProcMacroDerive { trait_name, helper_attrs, ..} => (*trait_name, helper_attrs))
1052 else {
1053 return ProcMacroItem(ProcMacro { kind, helpers: vec![] });
1054 };
1055 *name = trait_name;
1056 let helpers = helper_attrs.iter().copied().collect();
1057
1058 ProcMacroItem(ProcMacro { kind, helpers })
1059}
1060
1061fn clean_fn_or_proc_macro<'tcx>(
1062 item: &hir::Item<'tcx>,
1063 sig: &hir::FnSig<'tcx>,
1064 generics: &hir::Generics<'tcx>,
1065 body_id: hir::BodyId,
1066 name: &mut Symbol,
1067 cx: &mut DocContext<'tcx>,
1068) -> ItemKind {
1069 let attrs = cx.tcx.hir_attrs(item.hir_id());
1070 let macro_kind = if find_attr!(attrs, ProcMacro(..)) {
1071 Some(MacroKind::Bang)
1072 } else if find_attr!(attrs, ProcMacroDerive { .. }) {
1073 Some(MacroKind::Derive)
1074 } else if find_attr!(attrs, ProcMacroAttribute(..)) {
1075 Some(MacroKind::Attr)
1076 } else {
1077 None
1078 };
1079
1080 match macro_kind {
1081 Some(kind) => clean_proc_macro(item, name, kind, cx.tcx),
1082 None => {
1083 let mut func = clean_function(cx, sig, generics, ParamsSrc::Body(body_id));
1084 clean_fn_decl_legacy_const_generics(&mut func, attrs);
1085 FunctionItem(func)
1086 }
1087 }
1088}
1089
1090fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[hir::Attribute]) {
1094 let Some(indexes) = find_attr!(attrs, RustcLegacyConstGenerics{fn_indexes,..} => fn_indexes)
1095 else {
1096 return;
1097 };
1098
1099 for (pos, (index, _)) in indexes.iter().enumerate() {
1100 let GenericParamDef { name, kind, .. } = func.generics.params.remove(0);
1101 if let GenericParamDefKind::Const { ty, .. } = kind {
1102 func.decl
1103 .inputs
1104 .insert(*index, Parameter { name: Some(name), type_: *ty, is_const: true });
1105 } else {
1106 panic!("unexpected non const in position {pos}");
1107 }
1108 }
1109}
1110
1111enum ParamsSrc<'tcx> {
1112 Body(hir::BodyId),
1113 Idents(&'tcx [Option<Ident>]),
1114}
1115
1116fn clean_function<'tcx>(
1117 cx: &mut DocContext<'tcx>,
1118 sig: &hir::FnSig<'tcx>,
1119 generics: &hir::Generics<'tcx>,
1120 params: ParamsSrc<'tcx>,
1121) -> Box<Function> {
1122 let (generics, decl) = enter_impl_trait(cx, |cx| {
1123 let generics = clean_generics(generics, cx);
1125 let params = match params {
1126 ParamsSrc::Body(body_id) => clean_params_via_body(cx, sig.decl.inputs, body_id),
1127 ParamsSrc::Idents(idents) => clean_params(cx, sig.decl.inputs, idents, |ident| {
1129 Some(ident.map_or(kw::Underscore, |ident| ident.name))
1130 }),
1131 };
1132 let decl = clean_fn_decl_with_params(cx, sig.decl, Some(&sig.header), params);
1133 (generics, decl)
1134 });
1135 Box::new(Function { decl, generics })
1136}
1137
1138fn clean_params<'tcx>(
1139 cx: &mut DocContext<'tcx>,
1140 types: &[hir::Ty<'tcx>],
1141 idents: &[Option<Ident>],
1142 postprocess: impl Fn(Option<Ident>) -> Option<Symbol>,
1143) -> Vec<Parameter> {
1144 types
1145 .iter()
1146 .enumerate()
1147 .map(|(i, ty)| Parameter {
1148 name: postprocess(idents[i]),
1149 type_: clean_ty(ty, cx),
1150 is_const: false,
1151 })
1152 .collect()
1153}
1154
1155fn clean_params_via_body<'tcx>(
1156 cx: &mut DocContext<'tcx>,
1157 types: &[hir::Ty<'tcx>],
1158 body_id: hir::BodyId,
1159) -> Vec<Parameter> {
1160 types
1161 .iter()
1162 .zip(cx.tcx.hir_body(body_id).params)
1163 .map(|(ty, param)| Parameter {
1164 name: Some(name_from_pat(param.pat)),
1165 type_: clean_ty(ty, cx),
1166 is_const: false,
1167 })
1168 .collect()
1169}
1170
1171fn clean_fn_decl_with_params<'tcx>(
1172 cx: &mut DocContext<'tcx>,
1173 decl: &hir::FnDecl<'tcx>,
1174 header: Option<&hir::FnHeader>,
1175 params: Vec<Parameter>,
1176) -> FnDecl {
1177 let mut output = match decl.output {
1178 hir::FnRetTy::Return(typ) => clean_ty(typ, cx),
1179 hir::FnRetTy::DefaultReturn(..) => Type::Tuple(Vec::new()),
1180 };
1181 if let Some(header) = header
1182 && header.is_async()
1183 {
1184 output = output.sugared_async_return_type();
1185 }
1186 FnDecl { inputs: params, output, c_variadic: decl.c_variadic() }
1187}
1188
1189fn clean_poly_fn_sig<'tcx>(
1190 cx: &mut DocContext<'tcx>,
1191 did: Option<DefId>,
1192 sig: ty::PolyFnSig<'tcx>,
1193) -> FnDecl {
1194 let mut output = clean_middle_ty(sig.output(), cx, None, None);
1195
1196 if let Some(did) = did
1200 && let Type::ImplTrait(_) = output
1201 && cx.tcx.asyncness(did).is_async()
1202 {
1203 output = output.sugared_async_return_type();
1204 }
1205
1206 let mut idents = did.map(|did| cx.tcx.fn_arg_idents(did)).unwrap_or_default().iter().copied();
1207
1208 let fallback = did.map(|_| kw::Underscore);
1213
1214 let params = sig
1215 .inputs()
1216 .iter()
1217 .map(|ty| Parameter {
1218 name: idents.next().flatten().map(|ident| ident.name).or(fallback),
1219 type_: clean_middle_ty(ty.map_bound(|ty| *ty), cx, None, None),
1220 is_const: false,
1221 })
1222 .collect();
1223
1224 FnDecl { inputs: params, output, c_variadic: sig.skip_binder().c_variadic() }
1225}
1226
1227fn clean_trait_ref<'tcx>(trait_ref: &hir::TraitRef<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
1228 let path = clean_path(trait_ref.path, cx);
1229 register_res(cx, path.res);
1230 path
1231}
1232
1233fn clean_poly_trait_ref<'tcx>(
1234 poly_trait_ref: &hir::PolyTraitRef<'tcx>,
1235 cx: &mut DocContext<'tcx>,
1236) -> PolyTrait {
1237 PolyTrait {
1238 trait_: clean_trait_ref(&poly_trait_ref.trait_ref, cx),
1239 generic_params: poly_trait_ref
1240 .bound_generic_params
1241 .iter()
1242 .filter(|p| !is_elided_lifetime(p))
1243 .map(|x| clean_generic_param(cx, None, x))
1244 .collect(),
1245 }
1246}
1247
1248fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
1249 let local_did = trait_item.owner_id.to_def_id();
1250 cx.with_param_env(local_did, |cx| {
1251 let inner = match trait_item.kind {
1252 hir::TraitItemKind::Const(ty, Some(default), _) => {
1253 ProvidedAssocConstItem(Box::new(Constant {
1254 generics: enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)),
1255 kind: clean_const_item_rhs(default, local_did),
1256 type_: clean_ty(ty, cx),
1257 }))
1258 }
1259 hir::TraitItemKind::Const(ty, None, _) => {
1260 let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
1261 RequiredAssocConstItem(generics, Box::new(clean_ty(ty, cx)))
1262 }
1263 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
1264 let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Body(body));
1265 MethodItem(m, Defaultness::from_trait_item(trait_item.defaultness))
1266 }
1267 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(idents)) => {
1268 let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Idents(idents));
1269 RequiredMethodItem(m, Defaultness::from_trait_item(trait_item.defaultness))
1270 }
1271 hir::TraitItemKind::Type(bounds, Some(default)) => {
1272 let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
1273 let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
1274 let item_type =
1275 clean_middle_ty(ty::Binder::dummy(lower_ty(cx.tcx, default)), cx, None, None);
1276 AssocTypeItem(
1277 Box::new(TypeAlias {
1278 type_: clean_ty(default, cx),
1279 generics,
1280 inner_type: None,
1281 item_type: Some(item_type),
1282 }),
1283 bounds,
1284 )
1285 }
1286 hir::TraitItemKind::Type(bounds, None) => {
1287 let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
1288 let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
1289 RequiredAssocTypeItem(generics, bounds)
1290 }
1291 };
1292 Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx.tcx)
1293 })
1294}
1295
1296pub(crate) fn clean_impl_item<'tcx>(
1297 impl_: &hir::ImplItem<'tcx>,
1298 cx: &mut DocContext<'tcx>,
1299) -> Item {
1300 let local_did = impl_.owner_id.to_def_id();
1301 cx.with_param_env(local_did, |cx| {
1302 let inner = match impl_.kind {
1303 hir::ImplItemKind::Const(ty, expr) => ImplAssocConstItem(Box::new(Constant {
1304 generics: clean_generics(impl_.generics, cx),
1305 kind: clean_const_item_rhs(expr, local_did),
1306 type_: clean_ty(ty, cx),
1307 })),
1308 hir::ImplItemKind::Fn(ref sig, body) => {
1309 let m = clean_function(cx, sig, impl_.generics, ParamsSrc::Body(body));
1310 let defaultness = match impl_.impl_kind {
1311 hir::ImplItemImplKind::Inherent { .. } => hir::Defaultness::Final,
1312 hir::ImplItemImplKind::Trait { defaultness, .. } => defaultness,
1313 };
1314 MethodItem(m, Defaultness::from_impl_item(defaultness))
1315 }
1316 hir::ImplItemKind::Type(hir_ty) => {
1317 let type_ = clean_ty(hir_ty, cx);
1318 let generics = clean_generics(impl_.generics, cx);
1319 let item_type =
1320 clean_middle_ty(ty::Binder::dummy(lower_ty(cx.tcx, hir_ty)), cx, None, None);
1321 AssocTypeItem(
1322 Box::new(TypeAlias {
1323 type_,
1324 generics,
1325 inner_type: None,
1326 item_type: Some(item_type),
1327 }),
1328 Vec::new(),
1329 )
1330 }
1331 };
1332
1333 Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx.tcx)
1334 })
1335}
1336
1337pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocContext<'_>) -> Item {
1338 let tcx = cx.tcx;
1339 let kind = match assoc_item.kind {
1340 ty::AssocKind::Const { .. } => {
1341 let ty = clean_middle_ty(
1342 ty::Binder::dummy(
1343 tcx.type_of(assoc_item.def_id).instantiate_identity().skip_norm_wip(),
1344 ),
1345 cx,
1346 Some(assoc_item.def_id),
1347 None,
1348 );
1349
1350 let mut generics = clean_ty_generics(cx, assoc_item.def_id);
1351 simplify::move_bounds_to_generic_parameters(&mut generics);
1352
1353 match assoc_item.container {
1354 ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {
1355 ImplAssocConstItem(Box::new(Constant {
1356 generics,
1357 kind: ConstantKind::Extern { def_id: assoc_item.def_id },
1358 type_: ty,
1359 }))
1360 }
1361 ty::AssocContainer::Trait => {
1362 if tcx.defaultness(assoc_item.def_id).has_value() {
1363 ProvidedAssocConstItem(Box::new(Constant {
1364 generics,
1365 kind: ConstantKind::Extern { def_id: assoc_item.def_id },
1366 type_: ty,
1367 }))
1368 } else {
1369 RequiredAssocConstItem(generics, Box::new(ty))
1370 }
1371 }
1372 }
1373 }
1374 ty::AssocKind::Fn { has_self, .. } => {
1375 let mut item = inline::build_function(cx, assoc_item.def_id);
1376
1377 if has_self {
1378 let self_ty = match assoc_item.container {
1379 ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => tcx
1380 .type_of(assoc_item.container_id(tcx))
1381 .instantiate_identity()
1382 .skip_norm_wip(),
1383 ty::AssocContainer::Trait => tcx.types.self_param,
1384 };
1385 let self_param_ty = tcx
1386 .fn_sig(assoc_item.def_id)
1387 .instantiate_identity()
1388 .skip_norm_wip()
1389 .input(0)
1390 .skip_binder();
1391 if self_param_ty == self_ty {
1392 item.decl.inputs[0].type_ = SelfTy;
1393 } else if let ty::Ref(_, ty, _) = *self_param_ty.kind()
1394 && ty == self_ty
1395 {
1396 match item.decl.inputs[0].type_ {
1397 BorrowedRef { ref mut type_, .. } => **type_ = SelfTy,
1398 _ => unreachable!(),
1399 }
1400 }
1401 }
1402
1403 let defaultness = assoc_item.defaultness(tcx);
1404 let (provided, defaultness) = match assoc_item.container {
1405 ty::AssocContainer::Trait => {
1406 (defaultness.has_value(), Defaultness::from_trait_item(defaultness))
1407 }
1408 ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {
1409 (true, Defaultness::from_impl_item(defaultness))
1410 }
1411 };
1412
1413 if provided {
1414 MethodItem(item, defaultness)
1415 } else {
1416 RequiredMethodItem(item, defaultness)
1417 }
1418 }
1419 ty::AssocKind::Type { .. } => {
1420 let my_name = assoc_item.name();
1421
1422 fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
1423 match (¶m.kind, arg) {
1424 (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty)))
1425 if *ty == param.name =>
1426 {
1427 true
1428 }
1429 (GenericParamDefKind::Lifetime { .. }, GenericArg::Lifetime(Lifetime(lt)))
1430 if *lt == param.name =>
1431 {
1432 true
1433 }
1434 (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &**c {
1435 ConstantKind::TyConst { expr } => **expr == *param.name.as_str(),
1436 _ => false,
1437 },
1438 _ => false,
1439 }
1440 }
1441
1442 let mut predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
1443 if let ty::AssocContainer::Trait = assoc_item.container {
1444 let bounds = tcx
1445 .explicit_item_bounds(assoc_item.def_id)
1446 .iter_identity_copied()
1447 .map(Unnormalized::skip_norm_wip);
1448 predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied()));
1449 }
1450 let mut generics = clean_ty_generics_inner(
1451 cx,
1452 tcx.generics_of(assoc_item.def_id),
1453 ty::GenericPredicates { parent: None, predicates },
1454 );
1455 simplify::move_bounds_to_generic_parameters(&mut generics);
1456
1457 if let ty::AssocContainer::Trait = assoc_item.container {
1458 let mut bounds: Vec<GenericBound> = Vec::new();
1463 generics.where_predicates.retain_mut(|pred| match *pred {
1464 WherePredicate::BoundPredicate {
1465 ty:
1466 QPath(box QPathData {
1467 ref assoc,
1468 ref self_type,
1469 trait_: Some(ref trait_),
1470 ..
1471 }),
1472 bounds: ref mut pred_bounds,
1473 ..
1474 } => {
1475 if assoc.name != my_name {
1476 return true;
1477 }
1478 if trait_.def_id() != assoc_item.container_id(tcx) {
1479 return true;
1480 }
1481 if *self_type != SelfTy {
1482 return true;
1483 }
1484 match &assoc.args {
1485 GenericArgs::AngleBracketed { args, constraints } => {
1486 if !constraints.is_empty()
1487 || generics
1488 .params
1489 .iter()
1490 .zip(args.iter())
1491 .any(|(param, arg)| !param_eq_arg(param, arg))
1492 {
1493 return true;
1494 }
1495 }
1496 GenericArgs::Parenthesized { .. } => {
1497 }
1500 GenericArgs::ReturnTypeNotation => {
1501 }
1503 }
1504 bounds.extend(mem::take(pred_bounds));
1505 false
1506 }
1507 _ => true,
1508 });
1509
1510 bounds.retain(|b| {
1511 !b.is_meta_sized_bound(tcx)
1514 });
1515
1516 match bounds.iter().position(|b| b.is_sized_bound(tcx)) {
1522 Some(i) => {
1523 bounds.remove(i);
1524 }
1525 None => bounds.push(GenericBound::maybe_sized(cx)),
1526 }
1527
1528 if tcx.defaultness(assoc_item.def_id).has_value() {
1529 AssocTypeItem(
1530 Box::new(TypeAlias {
1531 type_: clean_middle_ty(
1532 ty::Binder::dummy(
1533 tcx.type_of(assoc_item.def_id)
1534 .instantiate_identity()
1535 .skip_norm_wip(),
1536 ),
1537 cx,
1538 Some(assoc_item.def_id),
1539 None,
1540 ),
1541 generics,
1542 inner_type: None,
1543 item_type: None,
1544 }),
1545 bounds,
1546 )
1547 } else {
1548 RequiredAssocTypeItem(generics, bounds)
1549 }
1550 } else {
1551 AssocTypeItem(
1552 Box::new(TypeAlias {
1553 type_: clean_middle_ty(
1554 ty::Binder::dummy(
1555 tcx.type_of(assoc_item.def_id)
1556 .instantiate_identity()
1557 .skip_norm_wip(),
1558 ),
1559 cx,
1560 Some(assoc_item.def_id),
1561 None,
1562 ),
1563 generics,
1564 inner_type: None,
1565 item_type: None,
1566 }),
1567 Vec::new(),
1570 )
1571 }
1572 }
1573 };
1574
1575 Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name()), kind, tcx)
1576}
1577
1578fn first_non_private_clean_path<'tcx>(
1579 cx: &mut DocContext<'tcx>,
1580 path: &hir::Path<'tcx>,
1581 new_path_segments: &'tcx [hir::PathSegment<'tcx>],
1582 new_path_span: rustc_span::Span,
1583) -> Path {
1584 let new_hir_path =
1585 hir::Path { segments: new_path_segments, res: path.res, span: new_path_span };
1586 let mut new_clean_path = clean_path(&new_hir_path, cx);
1587 if let Some(path_last) = path.segments.last().as_ref()
1592 && let Some(new_path_last) = new_clean_path.segments[..].last_mut()
1593 && let Some(path_last_args) = path_last.args.as_ref()
1594 && path_last.args.is_some()
1595 {
1596 assert!(new_path_last.args.is_empty());
1597 new_path_last.args = clean_generic_args(None, path_last_args, cx);
1598 }
1599 new_clean_path
1600}
1601
1602fn first_non_private<'tcx>(
1607 cx: &mut DocContext<'tcx>,
1608 hir_id: hir::HirId,
1609 path: &hir::Path<'tcx>,
1610) -> Option<Path> {
1611 let target_def_id = path.res.opt_def_id()?;
1612 let (parent_def_id, ident) = match &path.segments {
1613 [] => return None,
1614 [leaf] => (cx.tcx.local_parent(hir_id.owner.def_id), leaf.ident),
1616 [parent, leaf] if parent.ident.name == kw::SelfLower => {
1618 (cx.tcx.local_parent(hir_id.owner.def_id), leaf.ident)
1619 }
1620 [parent, leaf] if matches!(parent.ident.name, kw::Crate | kw::PathRoot) => {
1622 (LOCAL_CRATE.as_def_id().as_local()?, leaf.ident)
1623 }
1624 [parent, leaf] if parent.ident.name == kw::Super => {
1625 let parent_mod = cx.tcx.parent_module(hir_id);
1626 if let Some(super_parent) = cx.tcx.opt_local_parent(parent_mod.to_local_def_id()) {
1627 (super_parent, leaf.ident)
1628 } else {
1629 (LOCAL_CRATE.as_def_id().as_local()?, leaf.ident)
1631 }
1632 }
1633 [.., parent, leaf] => (parent.res.opt_def_id()?.as_local()?, leaf.ident),
1635 };
1636 for child in
1638 cx.tcx.module_children_local(parent_def_id).iter().filter(move |c| c.ident == ident)
1639 {
1640 if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = child.res {
1641 continue;
1642 }
1643
1644 if let Some(def_id) = child.res.opt_def_id()
1645 && target_def_id == def_id
1646 {
1647 let mut last_path_res = None;
1648 'reexps: for reexp in child.reexport_chain.iter() {
1649 if let Some(use_def_id) = reexp.id()
1650 && let Some(local_use_def_id) = use_def_id.as_local()
1651 && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_use_def_id)
1652 && let hir::ItemKind::Use(path, hir::UseKind::Single(_)) = item.kind
1653 {
1654 for res in path.res.present_items() {
1655 if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
1656 continue;
1657 }
1658 if (cx.document_hidden() ||
1659 !cx.tcx.is_doc_hidden(use_def_id)) &&
1660 cx.tcx.local_visibility(local_use_def_id).is_public()
1664 {
1665 break 'reexps;
1666 }
1667 last_path_res = Some((path, res));
1668 continue 'reexps;
1669 }
1670 }
1671 }
1672 if !child.reexport_chain.is_empty() {
1673 if let Some((new_path, _)) = last_path_res {
1679 return Some(first_non_private_clean_path(
1680 cx,
1681 path,
1682 new_path.segments,
1683 new_path.span,
1684 ));
1685 }
1686 return None;
1691 }
1692 }
1693 }
1694 None
1695}
1696
1697fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
1698 let hir::Ty { hir_id, span, ref kind } = *hir_ty;
1699 let hir::TyKind::Path(qpath) = kind else { unreachable!() };
1700
1701 match qpath {
1702 hir::QPath::Resolved(None, path) => {
1703 if let Res::Def(DefKind::TyParam, did) = path.res {
1704 if let Some(new_ty) = cx.args.get(&did).and_then(|p| p.as_ty()).cloned() {
1705 return new_ty;
1706 }
1707 if let Some(bounds) = cx.impl_trait_bounds.remove(&did.into()) {
1708 return ImplTrait(bounds);
1709 }
1710 }
1711
1712 if let Some(expanded) = maybe_expand_private_type_alias(cx, path) {
1713 expanded
1714 } else {
1715 let path = if let Some(path) = first_non_private(cx, hir_id, path) {
1717 path
1718 } else {
1719 clean_path(path, cx)
1720 };
1721 resolve_type(cx, path)
1722 }
1723 }
1724 hir::QPath::Resolved(Some(qself), p) => {
1725 let ty = lower_ty(cx.tcx, hir_ty);
1727 if !ty.has_escaping_bound_vars()
1729 && let Some(normalized_value) = normalize(cx, ty::Binder::dummy(ty))
1730 {
1731 return clean_middle_ty(normalized_value, cx, None, None);
1732 }
1733
1734 let trait_segments = &p.segments[..p.segments.len() - 1];
1735 let trait_def = cx.tcx.parent(p.res.def_id());
1736 let trait_ = self::Path {
1737 res: Res::Def(DefKind::Trait, trait_def),
1738 segments: trait_segments.iter().map(|x| clean_path_segment(x, cx)).collect(),
1739 };
1740 register_res(cx, trait_.res);
1741 let self_def_id = DefId::local(qself.hir_id.owner.def_id.local_def_index);
1742 let self_type = clean_ty(qself, cx);
1743 let should_fully_qualify =
1744 should_fully_qualify_path(Some(self_def_id), &trait_, &self_type);
1745 Type::QPath(Box::new(QPathData {
1746 assoc: clean_path_segment(p.segments.last().expect("segments were empty"), cx),
1747 should_fully_qualify,
1748 self_type,
1749 trait_: Some(trait_),
1750 }))
1751 }
1752 hir::QPath::TypeRelative(qself, segment) => {
1753 let ty = lower_ty(cx.tcx, hir_ty);
1754 let self_type = clean_ty(qself, cx);
1755
1756 let (trait_, should_fully_qualify) = match ty.kind() {
1757 ty::Alias(proj @ ty::AliasTy { kind: ty::Projection { .. }, .. }) => {
1758 let res = Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id);
1759 let trait_ = clean_path(&hir::Path { span, res, segments: &[] }, cx);
1760 register_res(cx, trait_.res);
1761 let self_def_id = res.opt_def_id();
1762 let should_fully_qualify =
1763 should_fully_qualify_path(self_def_id, &trait_, &self_type);
1764
1765 (Some(trait_), should_fully_qualify)
1766 }
1767 ty::Alias(ty::AliasTy { kind: ty::Inherent { .. }, .. }) => (None, false),
1768 ty::Error(_) => return Type::Infer,
1770 _ => bug!("clean: expected associated type, found `{ty:?}`"),
1771 };
1772
1773 Type::QPath(Box::new(QPathData {
1774 assoc: clean_path_segment(segment, cx),
1775 should_fully_qualify,
1776 self_type,
1777 trait_,
1778 }))
1779 }
1780 }
1781}
1782
1783fn maybe_expand_private_type_alias<'tcx>(
1784 cx: &mut DocContext<'tcx>,
1785 path: &hir::Path<'tcx>,
1786) -> Option<Type> {
1787 let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
1788 let def_id = def_id.as_local()?;
1790 let alias = if !cx.cache.effective_visibilities.is_exported(cx.tcx, def_id.to_def_id())
1791 && !cx.current_type_aliases.contains_key(&def_id.to_def_id())
1792 {
1793 &cx.tcx.hir_expect_item(def_id).kind
1794 } else {
1795 return None;
1796 };
1797 let hir::ItemKind::TyAlias(_, generics, ty) = alias else { return None };
1798
1799 let final_seg = &path.segments.last().expect("segments were empty");
1800 let mut args = DefIdMap::default();
1801 let generic_args = final_seg.args();
1802
1803 let mut indices: hir::GenericParamCount = Default::default();
1804 for param in generics.params.iter() {
1805 match param.kind {
1806 hir::GenericParamKind::Lifetime { .. } => {
1807 let mut j = 0;
1808 let lifetime = generic_args.args.iter().find_map(|arg| match arg {
1809 hir::GenericArg::Lifetime(lt) => {
1810 if indices.lifetimes == j {
1811 return Some(lt);
1812 }
1813 j += 1;
1814 None
1815 }
1816 _ => None,
1817 });
1818 if let Some(lt) = lifetime {
1819 let lt = if !lt.is_anonymous() {
1820 clean_lifetime(lt, cx)
1821 } else {
1822 Lifetime::elided()
1823 };
1824 args.insert(param.def_id.to_def_id(), GenericArg::Lifetime(lt));
1825 }
1826 indices.lifetimes += 1;
1827 }
1828 hir::GenericParamKind::Type { ref default, .. } => {
1829 let mut j = 0;
1830 let type_ = generic_args.args.iter().find_map(|arg| match arg {
1831 hir::GenericArg::Type(ty) => {
1832 if indices.types == j {
1833 return Some(ty.as_unambig_ty());
1834 }
1835 j += 1;
1836 None
1837 }
1838 _ => None,
1839 });
1840 if let Some(ty) = type_.or(*default) {
1841 args.insert(param.def_id.to_def_id(), GenericArg::Type(clean_ty(ty, cx)));
1842 }
1843 indices.types += 1;
1844 }
1845 hir::GenericParamKind::Const { .. } => {}
1847 }
1848 }
1849
1850 Some(cx.enter_alias(args, def_id.to_def_id(), |cx| {
1851 cx.with_param_env(def_id.to_def_id(), |cx| clean_ty(ty, cx))
1852 }))
1853}
1854
1855pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
1856 use rustc_hir::*;
1857
1858 match ty.kind {
1859 TyKind::Never => Primitive(PrimitiveType::Never),
1860 TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(clean_ty(m.ty, cx))),
1861 TyKind::Ref(l, ref m) => {
1862 let lifetime = if l.is_anonymous() { None } else { Some(clean_lifetime(l, cx)) };
1863 BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) }
1864 }
1865 TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
1866 TyKind::Pat(inner_ty, pat) => {
1867 let pat = match lower_ty(cx.tcx, ty).kind() {
1870 ty::Pat(_, pat) => format!("{pat:?}").into_boxed_str(),
1871 _ => format!("{pat:?}").into(),
1872 };
1873 Type::Pat(Box::new(clean_ty(inner_ty, cx)), pat)
1874 }
1875 TyKind::FieldOf(ty, hir::TyFieldPath { variant, field }) => {
1876 let field_str = if let Some(variant) = variant {
1877 format!("{variant}.{field}")
1878 } else {
1879 format!("{field}")
1880 };
1881 Type::FieldOf(Box::new(clean_ty(ty, cx)), field_str.into())
1882 }
1883 TyKind::Array(ty, const_arg) => {
1884 let length = match const_arg.kind {
1892 hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => "_".to_string(),
1893 hir::ConstArgKind::Anon(hir::AnonConst { def_id, .. }) => {
1894 let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, cx.tcx.types.usize);
1895 let typing_env = ty::TypingEnv::post_analysis(cx.tcx, *def_id);
1896 let ct =
1897 cx.tcx.normalize_erasing_regions(typing_env, Unnormalized::new_wip(ct));
1898 print_const(cx.tcx, ct)
1899 }
1900 hir::ConstArgKind::Struct(..)
1901 | hir::ConstArgKind::Path(..)
1902 | hir::ConstArgKind::TupleCall(..)
1903 | hir::ConstArgKind::Tup(..)
1904 | hir::ConstArgKind::Array(..)
1905 | hir::ConstArgKind::Literal { .. } => {
1906 let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, cx.tcx.types.usize);
1907 print_const(cx.tcx, ct)
1908 }
1909 };
1910 Array(Box::new(clean_ty(ty, cx)), length.into())
1911 }
1912 TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
1913 TyKind::OpaqueDef(ty) => {
1914 ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
1915 }
1916 TyKind::Path(_) => clean_qpath(ty, cx),
1917 TyKind::TraitObject(bounds, lifetime) => {
1918 let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect();
1919 let lifetime = if !lifetime.is_elided() {
1920 Some(clean_lifetime(lifetime.pointer(), cx))
1921 } else {
1922 None
1923 };
1924 DynTrait(bounds, lifetime)
1925 }
1926 TyKind::FnPtr(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
1927 TyKind::UnsafeBinder(unsafe_binder_ty) => {
1928 UnsafeBinder(Box::new(clean_unsafe_binder_ty(unsafe_binder_ty, cx)))
1929 }
1930 TyKind::Infer(())
1932 | TyKind::Err(_)
1933 | TyKind::InferDelegation(..)
1934 | TyKind::TraitAscription(_) => Infer,
1935 }
1936}
1937
1938fn normalize<'tcx>(
1940 cx: &DocContext<'tcx>,
1941 ty: ty::Binder<'tcx, Ty<'tcx>>,
1942) -> Option<ty::Binder<'tcx, Ty<'tcx>>> {
1943 if !cx.tcx.sess.opts.unstable_opts.normalize_docs {
1945 return None;
1946 }
1947
1948 use rustc_middle::traits::ObligationCause;
1949 use rustc_trait_selection::infer::TyCtxtInferExt;
1950 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
1951
1952 let infcx = cx.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
1954 let normalized = infcx
1955 .at(&ObligationCause::dummy(), cx.param_env)
1956 .query_normalize(ty)
1957 .map(|resolved| infcx.resolve_vars_if_possible(resolved.value));
1958 match normalized {
1959 Ok(normalized_value) => {
1960 debug!("normalized {ty:?} to {normalized_value:?}");
1961 Some(normalized_value)
1962 }
1963 Err(err) => {
1964 debug!("failed to normalize {ty:?}: {err:?}");
1965 None
1966 }
1967 }
1968}
1969
1970fn clean_trait_object_lifetime_bound<'tcx>(
1971 region: ty::Region<'tcx>,
1972 container: Option<ContainerTy<'_, 'tcx>>,
1973 preds: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
1974 tcx: TyCtxt<'tcx>,
1975) -> Option<Lifetime> {
1976 if can_elide_trait_object_lifetime_bound(region, container, preds, tcx) {
1977 return None;
1978 }
1979
1980 match region.kind() {
1984 ty::ReStatic => Some(Lifetime::statik()),
1985 ty::ReEarlyParam(region) => Some(Lifetime(region.name)),
1986 ty::ReBound(_, ty::BoundRegion { kind: ty::BoundRegionKind::Named(def_id), .. }) => {
1987 Some(Lifetime(tcx.item_name(def_id)))
1988 }
1989 ty::ReBound(..)
1990 | ty::ReLateParam(_)
1991 | ty::ReVar(_)
1992 | ty::RePlaceholder(_)
1993 | ty::ReErased
1994 | ty::ReError(_) => None,
1995 }
1996}
1997
1998fn can_elide_trait_object_lifetime_bound<'tcx>(
1999 region: ty::Region<'tcx>,
2000 container: Option<ContainerTy<'_, 'tcx>>,
2001 preds: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
2002 tcx: TyCtxt<'tcx>,
2003) -> bool {
2004 let default = container
2009 .map_or(ObjectLifetimeDefault::Empty, |container| container.object_lifetime_default(tcx));
2010
2011 match default {
2014 ObjectLifetimeDefault::Static => return region.kind() == ty::ReStatic,
2015 ObjectLifetimeDefault::Arg(default) => {
2017 return region.get_name(tcx) == default.get_name(tcx);
2018 }
2019 ObjectLifetimeDefault::Ambiguous => return false,
2023 ObjectLifetimeDefault::Empty => {}
2025 }
2026
2027 match *object_region_bounds(tcx, preds) {
2029 [] => region.kind() == ty::ReStatic,
2037 [object_region] => object_region.get_name(tcx) == region.get_name(tcx),
2041 _ => false,
2045 }
2046}
2047
2048#[derive(Debug)]
2049pub(crate) enum ContainerTy<'a, 'tcx> {
2050 Ref(ty::Region<'tcx>),
2051 Regular {
2052 ty: DefId,
2053 args: ty::Binder<'tcx, &'a [ty::GenericArg<'tcx>]>,
2056 arg: usize,
2057 },
2058}
2059
2060impl<'tcx> ContainerTy<'_, 'tcx> {
2061 fn object_lifetime_default(self, tcx: TyCtxt<'tcx>) -> ObjectLifetimeDefault<'tcx> {
2062 match self {
2063 Self::Ref(region) => ObjectLifetimeDefault::Arg(region),
2064 Self::Regular { ty: container, args, arg: index } => {
2065 let (DefKind::Struct
2066 | DefKind::Union
2067 | DefKind::Enum
2068 | DefKind::TyAlias
2069 | DefKind::Trait) = tcx.def_kind(container)
2070 else {
2071 return ObjectLifetimeDefault::Empty;
2072 };
2073
2074 let generics = tcx.generics_of(container);
2075 debug_assert_eq!(generics.parent_count, 0);
2076
2077 let param = generics.own_params[index].def_id;
2078 let default = tcx.object_lifetime_default(param);
2079 match default {
2080 rbv::ObjectLifetimeDefault::Param(lifetime) => {
2081 let index = generics.param_def_id_to_index[&lifetime];
2084 let arg = args.skip_binder()[index as usize].expect_region();
2085 ObjectLifetimeDefault::Arg(arg)
2086 }
2087 rbv::ObjectLifetimeDefault::Empty => ObjectLifetimeDefault::Empty,
2088 rbv::ObjectLifetimeDefault::Static => ObjectLifetimeDefault::Static,
2089 rbv::ObjectLifetimeDefault::Ambiguous => ObjectLifetimeDefault::Ambiguous,
2090 }
2091 }
2092 }
2093 }
2094}
2095
2096#[derive(Debug, Clone, Copy)]
2097pub(crate) enum ObjectLifetimeDefault<'tcx> {
2098 Empty,
2099 Static,
2100 Ambiguous,
2101 Arg(ty::Region<'tcx>),
2102}
2103
2104#[instrument(level = "trace", skip(cx), ret)]
2105pub(crate) fn clean_middle_ty<'tcx>(
2106 bound_ty: ty::Binder<'tcx, Ty<'tcx>>,
2107 cx: &mut DocContext<'tcx>,
2108 parent_def_id: Option<DefId>,
2109 container: Option<ContainerTy<'_, 'tcx>>,
2110) -> Type {
2111 let bound_ty = normalize(cx, bound_ty).unwrap_or(bound_ty);
2112 match *bound_ty.skip_binder().kind() {
2113 ty::Never => Primitive(PrimitiveType::Never),
2114 ty::Bool => Primitive(PrimitiveType::Bool),
2115 ty::Char => Primitive(PrimitiveType::Char),
2116 ty::Int(int_ty) => Primitive(int_ty.into()),
2117 ty::Uint(uint_ty) => Primitive(uint_ty.into()),
2118 ty::Float(float_ty) => Primitive(float_ty.into()),
2119 ty::Str => Primitive(PrimitiveType::Str),
2120 ty::Slice(ty) => Slice(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None))),
2121 ty::Pat(ty, pat) => Type::Pat(
2122 Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)),
2123 format!("{pat:?}").into_boxed_str(),
2124 ),
2125 ty::Array(ty, n) => {
2126 let n = cx.tcx.normalize_erasing_regions(cx.typing_env(), Unnormalized::new_wip(n));
2127 let n = print_const(cx.tcx, n);
2128 Array(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), n.into())
2129 }
2130 ty::RawPtr(ty, mutbl) => {
2131 RawPointer(mutbl, Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)))
2132 }
2133 ty::Ref(r, ty, mutbl) => BorrowedRef {
2134 lifetime: clean_middle_region(r, cx.tcx),
2135 mutability: mutbl,
2136 type_: Box::new(clean_middle_ty(
2137 bound_ty.rebind(ty),
2138 cx,
2139 None,
2140 Some(ContainerTy::Ref(r)),
2141 )),
2142 },
2143 ty::FnDef(..) | ty::FnPtr(..) => {
2144 let sig = bound_ty.skip_binder().fn_sig(cx.tcx);
2146 let decl = clean_poly_fn_sig(cx, None, sig);
2147 let generic_params = clean_bound_vars(sig.bound_vars(), cx.tcx);
2148
2149 BareFunction(Box::new(BareFunctionDecl {
2150 safety: sig.safety(),
2151 generic_params,
2152 decl,
2153 abi: sig.abi(),
2154 }))
2155 }
2156 ty::UnsafeBinder(inner) => {
2157 let generic_params = clean_bound_vars(inner.bound_vars(), cx.tcx);
2158 let ty = clean_middle_ty(inner.into(), cx, None, None);
2159 UnsafeBinder(Box::new(UnsafeBinderTy { generic_params, ty }))
2160 }
2161 ty::Adt(def, args) => {
2162 let did = def.did();
2163 let kind = match def.adt_kind() {
2164 AdtKind::Struct => ItemType::Struct,
2165 AdtKind::Union => ItemType::Union,
2166 AdtKind::Enum => ItemType::Enum,
2167 };
2168 inline::record_extern_fqn(cx, did, kind);
2169 let path = clean_middle_path(cx, did, false, ThinVec::new(), bound_ty.rebind(args));
2170 Type::Path { path }
2171 }
2172 ty::Foreign(did) => {
2173 inline::record_extern_fqn(cx, did, ItemType::ForeignType);
2174 let path = clean_middle_path(
2175 cx,
2176 did,
2177 false,
2178 ThinVec::new(),
2179 ty::Binder::dummy(ty::GenericArgs::empty()),
2180 );
2181 Type::Path { path }
2182 }
2183 ty::Dynamic(obj, reg) => {
2184 let mut dids = obj.auto_traits();
2188 let did = obj
2189 .principal_def_id()
2190 .or_else(|| dids.next())
2191 .unwrap_or_else(|| panic!("found trait object `{bound_ty:?}` with no traits?"));
2192 let args = match obj.principal() {
2193 Some(principal) => principal.map_bound(|p| p.args),
2194 _ => ty::Binder::dummy(ty::GenericArgs::empty()),
2196 };
2197
2198 inline::record_extern_fqn(cx, did, ItemType::Trait);
2199
2200 let lifetime = clean_trait_object_lifetime_bound(reg, container, obj, cx.tcx);
2201
2202 let mut bounds = dids
2203 .map(|did| {
2204 let empty = ty::Binder::dummy(ty::GenericArgs::empty());
2205 let path = clean_middle_path(cx, did, false, ThinVec::new(), empty);
2206 inline::record_extern_fqn(cx, did, ItemType::Trait);
2207 PolyTrait { trait_: path, generic_params: Vec::new() }
2208 })
2209 .collect::<Vec<_>>();
2210
2211 let constraints = obj
2212 .projection_bounds()
2213 .map(|pb| AssocItemConstraint {
2214 assoc: projection_to_path_segment(
2215 pb.map_bound(|pb| {
2216 pb.with_self_ty(cx.tcx, cx.tcx.types.trait_object_dummy_self)
2217 .projection_term
2218 }),
2219 cx,
2220 ),
2221 kind: AssocItemConstraintKind::Equality {
2222 term: clean_middle_term(pb.map_bound(|pb| pb.term), cx),
2223 },
2224 })
2225 .collect();
2226
2227 let late_bound_regions: FxIndexSet<_> = obj
2228 .iter()
2229 .flat_map(|pred| pred.bound_vars())
2230 .filter_map(|var| match var {
2231 ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id)) => {
2232 let name = cx.tcx.item_name(def_id);
2233 if name != kw::UnderscoreLifetime {
2234 Some(GenericParamDef::lifetime(def_id, name))
2235 } else {
2236 None
2237 }
2238 }
2239 _ => None,
2240 })
2241 .collect();
2242 let late_bound_regions = late_bound_regions.into_iter().collect();
2243
2244 let path = clean_middle_path(cx, did, false, constraints, args);
2245 bounds.insert(0, PolyTrait { trait_: path, generic_params: late_bound_regions });
2246
2247 DynTrait(bounds, lifetime)
2248 }
2249 ty::Tuple(t) => {
2250 Tuple(t.iter().map(|t| clean_middle_ty(bound_ty.rebind(t), cx, None, None)).collect())
2251 }
2252
2253 ty::Alias(alias_ty @ ty::AliasTy { kind: ty::Projection { def_id }, args, .. }) => {
2254 if cx.tcx.is_impl_trait_in_trait(def_id) {
2255 clean_middle_opaque_bounds(cx, def_id, args)
2256 } else {
2257 Type::QPath(Box::new(clean_projection(
2258 bound_ty.rebind(alias_ty.into()),
2259 cx,
2260 parent_def_id,
2261 )))
2262 }
2263 }
2264
2265 ty::Alias(alias_ty @ ty::AliasTy { kind: ty::Inherent { def_id }, .. }) => {
2266 let alias_ty = bound_ty.rebind(alias_ty);
2267 let self_type = clean_middle_ty(alias_ty.map_bound(|ty| ty.self_ty()), cx, None, None);
2268
2269 Type::QPath(Box::new(QPathData {
2270 assoc: PathSegment {
2271 name: cx.tcx.item_name(def_id),
2272 args: GenericArgs::AngleBracketed {
2273 args: clean_middle_generic_args(
2274 cx,
2275 alias_ty.map_bound(|ty| ty.args.as_slice()),
2276 true,
2277 def_id,
2278 ),
2279 constraints: Default::default(),
2280 },
2281 },
2282 should_fully_qualify: false,
2283 self_type,
2284 trait_: None,
2285 }))
2286 }
2287
2288 ty::Alias(ty::AliasTy { kind: ty::Free { def_id }, args, .. }) => {
2289 if cx.tcx.features().lazy_type_alias() {
2290 let path =
2293 clean_middle_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(args));
2294 Type::Path { path }
2295 } else {
2296 let ty = cx.tcx.type_of(def_id).instantiate(cx.tcx, args).skip_norm_wip();
2297 clean_middle_ty(bound_ty.rebind(ty), cx, None, None)
2298 }
2299 }
2300
2301 ty::Param(ref p) => {
2302 if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
2303 ImplTrait(bounds)
2304 } else if p.name == kw::SelfUpper {
2305 SelfTy
2306 } else {
2307 Generic(p.name)
2308 }
2309 }
2310
2311 ty::Bound(_, ref ty) => match ty.kind {
2312 ty::BoundTyKind::Param(def_id) => Generic(cx.tcx.item_name(def_id)),
2313 ty::BoundTyKind::Anon => panic!("unexpected anonymous bound type variable"),
2314 },
2315
2316 ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
2317 if cx.current_type_aliases.contains_key(&def_id) {
2319 let path =
2320 clean_middle_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(args));
2321 Type::Path { path }
2322 } else {
2323 *cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
2324 let ty = clean_middle_opaque_bounds(cx, def_id, args);
2327 if let Some(count) = cx.current_type_aliases.get_mut(&def_id) {
2328 *count -= 1;
2329 if *count == 0 {
2330 cx.current_type_aliases.remove(&def_id);
2331 }
2332 }
2333 ty
2334 }
2335 }
2336
2337 ty::Closure(..) => panic!("Closure"),
2338 ty::CoroutineClosure(..) => panic!("CoroutineClosure"),
2339 ty::Coroutine(..) => panic!("Coroutine"),
2340 ty::Placeholder(..) => panic!("Placeholder"),
2341 ty::CoroutineWitness(..) => panic!("CoroutineWitness"),
2342 ty::Infer(..) => panic!("Infer"),
2343
2344 ty::Error(_) => FatalError.raise(),
2345 }
2346}
2347
2348fn clean_middle_opaque_bounds<'tcx>(
2349 cx: &mut DocContext<'tcx>,
2350 impl_trait_def_id: DefId,
2351 args: ty::GenericArgsRef<'tcx>,
2352) -> Type {
2353 let mut has_sized = false;
2354
2355 let bounds: Vec<_> = cx
2356 .tcx
2357 .explicit_item_bounds(impl_trait_def_id)
2358 .iter_instantiated_copied(cx.tcx, args)
2359 .map(Unnormalized::skip_norm_wip)
2360 .collect();
2361
2362 let mut bounds = bounds
2363 .iter()
2364 .filter_map(|(bound, _)| {
2365 let bound_predicate = bound.kind();
2366 let trait_ref = match bound_predicate.skip_binder() {
2367 ty::ClauseKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
2368 ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
2369 return clean_middle_region(reg, cx.tcx).map(GenericBound::Outlives);
2370 }
2371 _ => return None,
2372 };
2373
2374 if cx.tcx.is_lang_item(trait_ref.def_id(), LangItem::MetaSized) {
2377 return None;
2378 }
2379
2380 if let Some(sized) = cx.tcx.lang_items().sized_trait()
2381 && trait_ref.def_id() == sized
2382 {
2383 has_sized = true;
2384 return None;
2385 }
2386
2387 let bindings: ThinVec<_> = bounds
2388 .iter()
2389 .filter_map(|(bound, _)| {
2390 let bound = bound.kind();
2391 if let ty::ClauseKind::Projection(proj_pred) = bound.skip_binder()
2392 && proj_pred.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder()
2393 {
2394 return Some(AssocItemConstraint {
2395 assoc: projection_to_path_segment(
2396 bound.rebind(proj_pred.projection_term),
2397 cx,
2398 ),
2399 kind: AssocItemConstraintKind::Equality {
2400 term: clean_middle_term(bound.rebind(proj_pred.term), cx),
2401 },
2402 });
2403 }
2404 None
2405 })
2406 .collect();
2407
2408 Some(clean_poly_trait_ref_with_constraints(cx, trait_ref, bindings))
2409 })
2410 .collect::<Vec<_>>();
2411
2412 if !has_sized {
2413 bounds.push(GenericBound::maybe_sized(cx));
2414 }
2415
2416 bounds.sort_by_key(|b| !b.is_trait_bound());
2418
2419 if bounds.first().is_none_or(|b| !b.is_trait_bound()) {
2422 bounds.insert(0, GenericBound::sized(cx));
2423 }
2424
2425 if let Some(args) = cx.tcx.rendered_precise_capturing_args(impl_trait_def_id) {
2426 bounds.push(GenericBound::Use(
2427 args.iter()
2428 .map(|arg| match arg {
2429 hir::PreciseCapturingArgKind::Lifetime(lt) => {
2430 PreciseCapturingArg::Lifetime(Lifetime(*lt))
2431 }
2432 hir::PreciseCapturingArgKind::Param(param) => {
2433 PreciseCapturingArg::Param(*param)
2434 }
2435 })
2436 .collect(),
2437 ));
2438 }
2439
2440 ImplTrait(bounds)
2441}
2442
2443pub(crate) fn clean_field<'tcx>(field: &hir::FieldDef<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
2444 clean_field_with_def_id(
2445 field.def_id.to_def_id(),
2446 field.ident.name,
2447 clean_ty(field.ty, cx),
2448 cx.tcx,
2449 )
2450}
2451
2452pub(crate) fn clean_middle_field(field: &ty::FieldDef, cx: &mut DocContext<'_>) -> Item {
2453 clean_field_with_def_id(
2454 field.did,
2455 field.name,
2456 clean_middle_ty(
2457 ty::Binder::dummy(cx.tcx.type_of(field.did).instantiate_identity().skip_norm_wip()),
2458 cx,
2459 Some(field.did),
2460 None,
2461 ),
2462 cx.tcx,
2463 )
2464}
2465
2466pub(crate) fn clean_field_with_def_id(
2467 def_id: DefId,
2468 name: Symbol,
2469 ty: Type,
2470 tcx: TyCtxt<'_>,
2471) -> Item {
2472 Item::from_def_id_and_parts(def_id, Some(name), StructFieldItem(ty), tcx)
2473}
2474
2475pub(crate) fn clean_variant_def(variant: &ty::VariantDef, cx: &mut DocContext<'_>) -> Item {
2476 let discriminant = match variant.discr {
2477 ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
2478 ty::VariantDiscr::Relative(_) => None,
2479 };
2480
2481 let kind = match variant.ctor_kind() {
2482 Some(CtorKind::Const) => VariantKind::CLike,
2483 Some(CtorKind::Fn) => VariantKind::Tuple(
2484 variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
2485 ),
2486 None => VariantKind::Struct(VariantStruct {
2487 fields: variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
2488 }),
2489 };
2490
2491 Item::from_def_id_and_parts(
2492 variant.def_id,
2493 Some(variant.name),
2494 VariantItem(Variant { kind, discriminant }),
2495 cx.tcx,
2496 )
2497}
2498
2499pub(crate) fn clean_variant_def_with_args<'tcx>(
2500 variant: &ty::VariantDef,
2501 args: &GenericArgsRef<'tcx>,
2502 cx: &mut DocContext<'tcx>,
2503) -> Item {
2504 let discriminant = match variant.discr {
2505 ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
2506 ty::VariantDiscr::Relative(_) => None,
2507 };
2508
2509 use rustc_middle::traits::ObligationCause;
2510 use rustc_trait_selection::infer::TyCtxtInferExt;
2511 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
2512
2513 let infcx = cx.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
2514 let kind = match variant.ctor_kind() {
2515 Some(CtorKind::Const) => VariantKind::CLike,
2516 Some(CtorKind::Fn) => VariantKind::Tuple(
2517 variant
2518 .fields
2519 .iter()
2520 .map(|field| {
2521 let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args).skip_norm_wip();
2522
2523 let ty = infcx
2527 .at(&ObligationCause::dummy(), cx.param_env)
2528 .query_normalize(ty)
2529 .map(|normalized| normalized.value)
2530 .unwrap_or(ty);
2531
2532 clean_field_with_def_id(
2533 field.did,
2534 field.name,
2535 clean_middle_ty(ty::Binder::dummy(ty), cx, Some(field.did), None),
2536 cx.tcx,
2537 )
2538 })
2539 .collect(),
2540 ),
2541 None => VariantKind::Struct(VariantStruct {
2542 fields: variant
2543 .fields
2544 .iter()
2545 .map(|field| {
2546 let ty = cx.tcx.type_of(field.did).instantiate(cx.tcx, args).skip_norm_wip();
2547
2548 let ty = infcx
2552 .at(&ObligationCause::dummy(), cx.param_env)
2553 .query_normalize(ty)
2554 .map(|normalized| normalized.value)
2555 .unwrap_or(ty);
2556
2557 clean_field_with_def_id(
2558 field.did,
2559 field.name,
2560 clean_middle_ty(ty::Binder::dummy(ty), cx, Some(field.did), None),
2561 cx.tcx,
2562 )
2563 })
2564 .collect(),
2565 }),
2566 };
2567
2568 Item::from_def_id_and_parts(
2569 variant.def_id,
2570 Some(variant.name),
2571 VariantItem(Variant { kind, discriminant }),
2572 cx.tcx,
2573 )
2574}
2575
2576fn clean_variant_data<'tcx>(
2577 variant: &hir::VariantData<'tcx>,
2578 disr_expr: &Option<&hir::AnonConst>,
2579 cx: &mut DocContext<'tcx>,
2580) -> Variant {
2581 let discriminant = disr_expr
2582 .map(|disr| Discriminant { expr: Some(disr.body), value: disr.def_id.to_def_id() });
2583
2584 let kind = match variant {
2585 hir::VariantData::Struct { fields, .. } => VariantKind::Struct(VariantStruct {
2586 fields: fields.iter().map(|x| clean_field(x, cx)).collect(),
2587 }),
2588 hir::VariantData::Tuple(..) => {
2589 VariantKind::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
2590 }
2591 hir::VariantData::Unit(..) => VariantKind::CLike,
2592 };
2593
2594 Variant { discriminant, kind }
2595}
2596
2597fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
2598 Path {
2599 res: path.res,
2600 segments: path.segments.iter().map(|x| clean_path_segment(x, cx)).collect(),
2601 }
2602}
2603
2604fn clean_generic_args<'tcx>(
2605 trait_did: Option<DefId>,
2606 generic_args: &hir::GenericArgs<'tcx>,
2607 cx: &mut DocContext<'tcx>,
2608) -> GenericArgs {
2609 match generic_args.parenthesized {
2610 hir::GenericArgsParentheses::No => {
2611 let args = generic_args
2612 .args
2613 .iter()
2614 .map(|arg| match arg {
2615 hir::GenericArg::Lifetime(lt) if !lt.is_anonymous() => {
2616 GenericArg::Lifetime(clean_lifetime(lt, cx))
2617 }
2618 hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
2619 hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty.as_unambig_ty(), cx)),
2620 hir::GenericArg::Const(ct) => {
2621 GenericArg::Const(Box::new(clean_const(ct.as_unambig_ct())))
2622 }
2623 hir::GenericArg::Infer(_inf) => GenericArg::Infer,
2624 })
2625 .collect();
2626 let constraints = generic_args
2627 .constraints
2628 .iter()
2629 .map(|c| {
2630 clean_assoc_item_constraint(
2631 trait_did.expect("only trait ref has constraints"),
2632 c,
2633 cx,
2634 )
2635 })
2636 .collect::<ThinVec<_>>();
2637 GenericArgs::AngleBracketed { args, constraints }
2638 }
2639 hir::GenericArgsParentheses::ParenSugar => {
2640 let Some((inputs, output)) = generic_args.paren_sugar_inputs_output() else {
2641 bug!();
2642 };
2643 let inputs = inputs.iter().map(|x| clean_ty(x, cx)).collect();
2644 let output = match output.kind {
2645 hir::TyKind::Tup(&[]) => None,
2646 _ => Some(Box::new(clean_ty(output, cx))),
2647 };
2648 GenericArgs::Parenthesized { inputs, output }
2649 }
2650 hir::GenericArgsParentheses::ReturnTypeNotation => GenericArgs::ReturnTypeNotation,
2651 }
2652}
2653
2654fn clean_path_segment<'tcx>(
2655 path: &hir::PathSegment<'tcx>,
2656 cx: &mut DocContext<'tcx>,
2657) -> PathSegment {
2658 let trait_did = match path.res {
2659 hir::def::Res::Def(DefKind::Trait | DefKind::TraitAlias, did) => Some(did),
2660 _ => None,
2661 };
2662 PathSegment { name: path.ident.name, args: clean_generic_args(trait_did, path.args(), cx) }
2663}
2664
2665fn clean_bare_fn_ty<'tcx>(
2666 bare_fn: &hir::FnPtrTy<'tcx>,
2667 cx: &mut DocContext<'tcx>,
2668) -> BareFunctionDecl {
2669 let (generic_params, decl) = enter_impl_trait(cx, |cx| {
2670 let generic_params = bare_fn
2672 .generic_params
2673 .iter()
2674 .filter(|p| !is_elided_lifetime(p))
2675 .map(|x| clean_generic_param(cx, None, x))
2676 .collect();
2677 let filter = |ident: Option<Ident>| {
2681 ident.map(|ident| ident.name).filter(|&ident| ident != kw::Underscore)
2682 };
2683 let fallback =
2684 bare_fn.param_idents.iter().copied().find_map(filter).map(|_| kw::Underscore);
2685 let params = clean_params(cx, bare_fn.decl.inputs, bare_fn.param_idents, |ident| {
2686 filter(ident).or(fallback)
2687 });
2688 let decl = clean_fn_decl_with_params(cx, bare_fn.decl, None, params);
2689 (generic_params, decl)
2690 });
2691 BareFunctionDecl { safety: bare_fn.safety, abi: bare_fn.abi, decl, generic_params }
2692}
2693
2694fn clean_unsafe_binder_ty<'tcx>(
2695 unsafe_binder_ty: &hir::UnsafeBinderTy<'tcx>,
2696 cx: &mut DocContext<'tcx>,
2697) -> UnsafeBinderTy {
2698 let generic_params = unsafe_binder_ty
2699 .generic_params
2700 .iter()
2701 .filter(|p| !is_elided_lifetime(p))
2702 .map(|x| clean_generic_param(cx, None, x))
2703 .collect();
2704 let ty = clean_ty(unsafe_binder_ty.inner_ty, cx);
2705 UnsafeBinderTy { generic_params, ty }
2706}
2707
2708pub(crate) fn reexport_chain(
2709 tcx: TyCtxt<'_>,
2710 import_def_id: LocalDefId,
2711 target_def_id: DefId,
2712) -> &[Reexport] {
2713 for child in tcx.module_children_local(tcx.local_parent(import_def_id)) {
2714 if child.res.opt_def_id() == Some(target_def_id)
2715 && child.reexport_chain.first().and_then(|r| r.id()) == Some(import_def_id.to_def_id())
2716 {
2717 return &child.reexport_chain;
2718 }
2719 }
2720 &[]
2721}
2722
2723fn get_all_import_attributes<'hir>(
2725 cx: &mut DocContext<'hir>,
2726 import_def_id: LocalDefId,
2727 target_def_id: DefId,
2728 is_inline: bool,
2729) -> Vec<(Cow<'hir, hir::Attribute>, Option<DefId>)> {
2730 let mut attrs = Vec::new();
2731 let mut first = true;
2732 for def_id in reexport_chain(cx.tcx, import_def_id, target_def_id)
2733 .iter()
2734 .flat_map(|reexport| reexport.id())
2735 {
2736 let import_attrs = inline::load_attrs(cx.tcx, def_id);
2737 if first {
2738 attrs = import_attrs.iter().map(|attr| (Cow::Borrowed(attr), Some(def_id))).collect();
2740 first = false;
2741 } else if cx.document_hidden() || !cx.tcx.is_doc_hidden(def_id) {
2743 add_without_unwanted_attributes(&mut attrs, import_attrs, is_inline, Some(def_id));
2744 }
2745 }
2746 attrs
2747}
2748
2749fn add_without_unwanted_attributes<'hir>(
2770 attrs: &mut Vec<(Cow<'hir, hir::Attribute>, Option<DefId>)>,
2771 new_attrs: &'hir [hir::Attribute],
2772 is_inline: bool,
2773 import_parent: Option<DefId>,
2774) {
2775 for attr in new_attrs {
2776 match attr {
2777 hir::Attribute::Parsed(AttributeKind::DocComment { .. }) => {
2778 attrs.push((Cow::Borrowed(attr), import_parent));
2779 }
2780 hir::Attribute::Parsed(AttributeKind::Doc(box d)) => {
2781 let DocAttribute {
2783 first_span: _,
2784 aliases,
2785 hidden,
2786 inline,
2787 cfg,
2788 auto_cfg: _,
2789 auto_cfg_change: _,
2790 fake_variadic: _,
2791 keyword: _,
2792 attribute: _,
2793 masked: _,
2794 notable_trait: _,
2795 search_unbox: _,
2796 html_favicon_url: _,
2797 html_logo_url: _,
2798 html_playground_url: _,
2799 html_root_url: _,
2800 html_no_source: _,
2801 issue_tracker_base_url: _,
2802 rust_logo: _,
2803 test_attrs: _,
2804 no_crate_inject: _,
2805 } = d;
2806 let mut attr = DocAttribute::default();
2807 if is_inline {
2808 attr.cfg = cfg.clone();
2809 } else {
2810 attr.inline = inline.clone();
2811 attr.hidden = hidden.clone();
2812 }
2813 attr.aliases = aliases.clone();
2814 attrs.push((
2815 Cow::Owned(hir::Attribute::Parsed(AttributeKind::Doc(Box::new(attr)))),
2816 import_parent,
2817 ));
2818 }
2819
2820 hir::Attribute::Parsed(AttributeKind::CfgTrace(..)) if !is_inline => {}
2822 _ => {
2824 attrs.push((Cow::Borrowed(attr), import_parent));
2825 }
2826 }
2827 }
2828}
2829
2830fn clean_maybe_renamed_item<'tcx>(
2831 cx: &mut DocContext<'tcx>,
2832 item: &hir::Item<'tcx>,
2833 renamed: Option<Symbol>,
2834 import_ids: &[LocalDefId],
2835) -> Vec<Item> {
2836 use hir::ItemKind;
2837 fn get_name(tcx: TyCtxt<'_>, item: &hir::Item<'_>, renamed: Option<Symbol>) -> Option<Symbol> {
2838 renamed.or_else(|| tcx.hir_opt_name(item.hir_id()))
2839 }
2840
2841 let def_id = item.owner_id.to_def_id();
2842 cx.with_param_env(def_id, |cx| {
2843 match item.kind {
2846 ItemKind::Impl(ref impl_) => {
2847 return clean_impl(impl_, item.owner_id.def_id, cx, renamed.is_some());
2851 }
2852 ItemKind::Use(path, kind) => {
2853 return clean_use_statement(
2854 item,
2855 get_name(cx.tcx, item, renamed),
2856 path,
2857 kind,
2858 cx,
2859 &mut FxHashSet::default(),
2860 );
2861 }
2862 _ => {}
2863 }
2864
2865 let mut name = get_name(cx.tcx, item, renamed).unwrap();
2866
2867 let kind = match item.kind {
2868 ItemKind::Static(mutability, _, ty, body_id) => StaticItem(Static {
2869 type_: Box::new(clean_ty(ty, cx)),
2870 mutability,
2871 expr: Some(body_id),
2872 }),
2873 ItemKind::Const(_, generics, ty, rhs) => ConstantItem(Box::new(Constant {
2874 generics: clean_generics(generics, cx),
2875 type_: clean_ty(ty, cx),
2876 kind: clean_const_item_rhs(rhs, def_id),
2877 })),
2878 ItemKind::TyAlias(_, generics, ty) => {
2879 *cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
2880 let rustdoc_ty = clean_ty(ty, cx);
2881 let type_ =
2882 clean_middle_ty(ty::Binder::dummy(lower_ty(cx.tcx, ty)), cx, None, None);
2883 let generics = clean_generics(generics, cx);
2884 if let Some(count) = cx.current_type_aliases.get_mut(&def_id) {
2885 *count -= 1;
2886 if *count == 0 {
2887 cx.current_type_aliases.remove(&def_id);
2888 }
2889 }
2890
2891 let ty = cx.tcx.type_of(def_id).instantiate_identity().skip_norm_wip();
2892
2893 let mut ret = Vec::new();
2894 let inner_type = clean_ty_alias_inner_type(ty, cx, &mut ret);
2895
2896 ret.push(generate_item_with_correct_attrs(
2897 cx,
2898 TypeAliasItem(Box::new(TypeAlias {
2899 generics,
2900 inner_type,
2901 type_: rustdoc_ty,
2902 item_type: Some(type_),
2903 })),
2904 item.owner_id.def_id.to_def_id(),
2905 name,
2906 import_ids,
2907 renamed,
2908 ));
2909 return ret;
2910 }
2911 ItemKind::Enum(_, generics, def) => EnumItem(Enum {
2912 variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(),
2913 generics: clean_generics(generics, cx),
2914 }),
2915 ItemKind::TraitAlias(_, _, generics, bounds) => TraitAliasItem(TraitAlias {
2916 generics: clean_generics(generics, cx),
2917 bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
2918 }),
2919 ItemKind::Union(_, generics, variant_data) => UnionItem(Union {
2920 generics: clean_generics(generics, cx),
2921 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
2922 }),
2923 ItemKind::Struct(_, generics, variant_data) => StructItem(Struct {
2924 ctor_kind: variant_data.ctor_kind(),
2925 generics: clean_generics(generics, cx),
2926 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
2927 }),
2928 ItemKind::Macro(_, macro_def, MacroKinds::BANG) => MacroItem(Macro {
2931 source: display_macro_source(cx.tcx, name, macro_def),
2932 macro_rules: macro_def.macro_rules,
2933 }),
2934 ItemKind::Macro(_, _, MacroKinds::ATTR) => {
2935 clean_proc_macro(item, &mut name, MacroKind::Attr, cx.tcx)
2936 }
2937 ItemKind::Macro(_, _, MacroKinds::DERIVE) => {
2938 clean_proc_macro(item, &mut name, MacroKind::Derive, cx.tcx)
2939 }
2940 ItemKind::Macro(_, _, _) => todo!("Handle macros with multiple kinds"),
2941 ItemKind::Fn { ref sig, generics, body: body_id, .. } => {
2943 clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
2944 }
2945 ItemKind::Trait { generics, bounds, items: item_ids, .. } => {
2947 let items = item_ids
2948 .iter()
2949 .map(|&ti| clean_trait_item(cx.tcx.hir_trait_item(ti), cx))
2950 .collect();
2951
2952 TraitItem(Box::new(Trait {
2953 def_id,
2954 items,
2955 generics: clean_generics(generics, cx),
2956 bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
2957 }))
2958 }
2959 ItemKind::ExternCrate(orig_name, _) => {
2960 return clean_extern_crate(item, name, orig_name, cx);
2961 }
2962 _ => span_bug!(item.span, "not yet converted"),
2963 };
2964
2965 vec![generate_item_with_correct_attrs(
2966 cx,
2967 kind,
2968 item.owner_id.def_id.to_def_id(),
2969 name,
2970 import_ids,
2971 renamed,
2972 )]
2973 })
2974}
2975
2976fn clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
2977 let kind = VariantItem(clean_variant_data(&variant.data, &variant.disr_expr, cx));
2978 Item::from_def_id_and_parts(variant.def_id.to_def_id(), Some(variant.ident.name), kind, cx.tcx)
2979}
2980
2981fn clean_impl<'tcx>(
2982 impl_: &hir::Impl<'tcx>,
2983 def_id: LocalDefId,
2984 cx: &mut DocContext<'tcx>,
2985 is_inlined: bool,
2989) -> Vec<Item> {
2990 let tcx = cx.tcx;
2991 let mut ret = Vec::new();
2992 let trait_ = match impl_.of_trait {
2993 Some(t) => {
2994 if is_inlined {
2995 return vec![Item::from_def_id_and_parts(
2996 def_id.to_def_id(),
2997 None,
2998 PlaceholderImplItem,
2999 tcx,
3000 )];
3001 }
3002 Some(clean_trait_ref(&t.trait_ref, cx))
3003 }
3004 None => None,
3005 };
3006 let items = impl_
3007 .items
3008 .iter()
3009 .map(|&ii| clean_impl_item(tcx.hir_impl_item(ii), cx))
3010 .collect::<Vec<_>>();
3011
3012 if trait_.as_ref().is_some_and(|t| tcx.lang_items().deref_trait() == Some(t.def_id()))
3015 && tcx.impl_polarity(def_id) != ty::ImplPolarity::Negative
3016 {
3017 build_deref_target_impls(cx, &items, &mut ret);
3018 }
3019
3020 let for_ = clean_ty(impl_.self_ty, cx);
3021 let type_alias =
3022 for_.def_id(&cx.cache).and_then(|alias_def_id: DefId| match tcx.def_kind(alias_def_id) {
3023 DefKind::TyAlias => Some(clean_middle_ty(
3024 ty::Binder::dummy(tcx.type_of(def_id).instantiate_identity().skip_norm_wip()),
3025 cx,
3026 Some(def_id.to_def_id()),
3027 None,
3028 )),
3029 _ => None,
3030 });
3031 let is_deprecated = tcx
3032 .lookup_deprecation(def_id.to_def_id())
3033 .is_some_and(|deprecation| deprecation.is_in_effect());
3034 let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
3035 let kind = ImplItem(Box::new(Impl {
3036 safety: match impl_.of_trait {
3037 Some(of_trait) => of_trait.safety,
3038 None => hir::Safety::Safe,
3039 },
3040 generics: clean_generics(impl_.generics, cx),
3041 trait_,
3042 for_,
3043 items,
3044 polarity: if impl_.of_trait.is_some() {
3045 tcx.impl_polarity(def_id)
3046 } else {
3047 ty::ImplPolarity::Positive
3048 },
3049 kind: if utils::has_doc_flag(tcx, def_id.to_def_id(), |d| d.fake_variadic.is_some()) {
3050 ImplKind::FakeVariadic
3051 } else {
3052 ImplKind::Normal
3053 },
3054 is_deprecated,
3055 }));
3056 Item::from_def_id_and_parts(def_id.to_def_id(), None, kind, tcx)
3057 };
3058 if let Some(type_alias) = type_alias {
3059 ret.push(make_item(trait_.clone(), type_alias, items.clone()));
3060 }
3061 ret.push(make_item(trait_, for_, items));
3062 ret
3063}
3064
3065fn clean_extern_crate<'tcx>(
3066 krate: &hir::Item<'tcx>,
3067 name: Symbol,
3068 orig_name: Option<Symbol>,
3069 cx: &mut DocContext<'tcx>,
3070) -> Vec<Item> {
3071 let cnum = cx.tcx.extern_mod_stmt_cnum(krate.owner_id.def_id).unwrap_or(LOCAL_CRATE);
3073 let crate_def_id = cnum.as_def_id();
3075 let attrs = cx.tcx.hir_attrs(krate.hir_id());
3076 let ty_vis = cx.tcx.visibility(krate.owner_id);
3077 let please_inline = ty_vis.is_public()
3078 && attrs.iter().any(|a| {
3079 matches!(
3080 a,
3081 hir::Attribute::Parsed(AttributeKind::Doc(d))
3082 if d.inline.first().is_some_and(|(i, _)| *i == DocInline::Inline))
3083 })
3084 && !cx.is_json_output();
3085
3086 let krate_owner_def_id = krate.owner_id.def_id;
3087
3088 if please_inline
3089 && let Some(items) = inline::try_inline(
3090 cx,
3091 Res::Def(DefKind::Mod, crate_def_id),
3092 name,
3093 Some((attrs, Some(krate_owner_def_id))),
3094 &mut Default::default(),
3095 )
3096 {
3097 return items;
3098 }
3099
3100 vec![Item::from_def_id_and_parts(
3101 krate_owner_def_id.to_def_id(),
3102 Some(name),
3103 ExternCrateItem { src: orig_name },
3104 cx.tcx,
3105 )]
3106}
3107
3108fn clean_use_statement<'tcx>(
3109 import: &hir::Item<'tcx>,
3110 name: Option<Symbol>,
3111 path: &hir::UsePath<'tcx>,
3112 kind: hir::UseKind,
3113 cx: &mut DocContext<'tcx>,
3114 inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
3115) -> Vec<Item> {
3116 let mut items = Vec::new();
3117 let hir::UsePath { segments, ref res, span } = *path;
3118 for res in res.present_items() {
3119 let path = hir::Path { segments, res, span };
3120 items.append(&mut clean_use_statement_inner(import, name, &path, kind, cx, inlined_names));
3121 }
3122 items
3123}
3124
3125fn clean_use_statement_inner<'tcx>(
3126 import: &hir::Item<'tcx>,
3127 name: Option<Symbol>,
3128 path: &hir::Path<'tcx>,
3129 kind: hir::UseKind,
3130 cx: &mut DocContext<'tcx>,
3131 inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
3132) -> Vec<Item> {
3133 if should_ignore_res(path.res) {
3134 return Vec::new();
3135 }
3136 if import.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) {
3140 return Vec::new();
3141 }
3142
3143 let visibility = cx.tcx.visibility(import.owner_id);
3144 let attrs = cx.tcx.hir_attrs(import.hir_id());
3145 let inline_attr = find_attr!(
3146 attrs,
3147 Doc(d) if d.inline.first().is_some_and(|(i, _)| *i == DocInline::Inline) => d
3148 )
3149 .and_then(|d| d.inline.first());
3150 let pub_underscore = visibility.is_public() && name == Some(kw::Underscore);
3151 let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id);
3152 let import_def_id = import.owner_id.def_id;
3153
3154 let parent_mod = cx.tcx.parent_module_from_def_id(current_mod.to_local_def_id());
3158
3159 let is_visible_from_parent_mod =
3165 visibility.is_accessible_from(parent_mod, cx.tcx) && !current_mod.is_top_level_module();
3166
3167 if pub_underscore && let Some((_, inline_span)) = inline_attr {
3168 struct_span_code_err!(
3169 cx.tcx.dcx(),
3170 *inline_span,
3171 E0780,
3172 "anonymous imports cannot be inlined"
3173 )
3174 .with_span_label(import.span, "anonymous import")
3175 .emit();
3176 }
3177
3178 let mut denied = cx.is_json_output()
3183 || !(visibility.is_public() || (cx.document_private() && is_visible_from_parent_mod))
3184 || pub_underscore
3185 || attrs.iter().any(|a| matches!(
3186 a,
3187 hir::Attribute::Parsed(AttributeKind::Doc(d))
3188 if d.hidden.is_some() || d.inline.first().is_some_and(|(i, _)| *i == DocInline::NoInline)
3189 ));
3190
3191 let path = clean_path(path, cx);
3194 let inner = if kind == hir::UseKind::Glob {
3195 if !denied {
3196 let mut visited = DefIdSet::default();
3197 if let Some(items) = inline::try_inline_glob(
3198 cx,
3199 path.res,
3200 current_mod,
3201 &mut visited,
3202 inlined_names,
3203 import,
3204 ) {
3205 return items;
3206 }
3207 }
3208 Import::new_glob(resolve_use_source(cx, path), true)
3209 } else {
3210 let name = name.unwrap();
3211 if inline_attr.is_none()
3212 && let Res::Def(DefKind::Mod, did) = path.res
3213 && !did.is_local()
3214 && did.is_crate_root()
3215 {
3216 denied = true;
3219 }
3220 if !denied
3221 && let Some(mut items) = inline::try_inline(
3222 cx,
3223 path.res,
3224 name,
3225 Some((attrs, Some(import_def_id))),
3226 &mut Default::default(),
3227 )
3228 {
3229 items.push(Item::from_def_id_and_parts(
3230 import_def_id.to_def_id(),
3231 None,
3232 ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)),
3233 cx.tcx,
3234 ));
3235 return items;
3236 }
3237 Import::new_simple(name, resolve_use_source(cx, path), true)
3238 };
3239
3240 vec![Item::from_def_id_and_parts(import_def_id.to_def_id(), None, ImportItem(inner), cx.tcx)]
3241}
3242
3243fn clean_maybe_renamed_foreign_item<'tcx>(
3244 cx: &mut DocContext<'tcx>,
3245 item: &hir::ForeignItem<'tcx>,
3246 renamed: Option<Symbol>,
3247 import_id: Option<LocalDefId>,
3248) -> Item {
3249 let def_id = item.owner_id.to_def_id();
3250 cx.with_param_env(def_id, |cx| {
3251 let kind = match item.kind {
3252 hir::ForeignItemKind::Fn(sig, idents, generics) => ForeignFunctionItem(
3253 clean_function(cx, &sig, generics, ParamsSrc::Idents(idents)),
3254 sig.header.safety(),
3255 ),
3256 hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem(
3257 Static { type_: Box::new(clean_ty(ty, cx)), mutability, expr: None },
3258 safety,
3259 ),
3260 hir::ForeignItemKind::Type => ForeignTypeItem,
3261 };
3262
3263 generate_item_with_correct_attrs(
3264 cx,
3265 kind,
3266 item.owner_id.def_id.to_def_id(),
3267 item.ident.name,
3268 import_id.as_slice(),
3269 renamed,
3270 )
3271 })
3272}
3273
3274fn clean_assoc_item_constraint<'tcx>(
3275 trait_did: DefId,
3276 constraint: &hir::AssocItemConstraint<'tcx>,
3277 cx: &mut DocContext<'tcx>,
3278) -> AssocItemConstraint {
3279 AssocItemConstraint {
3280 assoc: PathSegment {
3281 name: constraint.ident.name,
3282 args: clean_generic_args(None, constraint.gen_args, cx),
3283 },
3284 kind: match constraint.kind {
3285 hir::AssocItemConstraintKind::Equality { ref term } => {
3286 let assoc_tag = match term {
3287 hir::Term::Ty(_) => ty::AssocTag::Type,
3288 hir::Term::Const(_) => ty::AssocTag::Const,
3289 };
3290 let assoc_item = cx
3291 .tcx
3292 .associated_items(trait_did)
3293 .find_by_ident_and_kind(cx.tcx, constraint.ident, assoc_tag, trait_did)
3294 .map(|item| item.def_id);
3295 AssocItemConstraintKind::Equality { term: clean_hir_term(assoc_item, term, cx) }
3296 }
3297 hir::AssocItemConstraintKind::Bound { bounds } => AssocItemConstraintKind::Bound {
3298 bounds: bounds.iter().filter_map(|b| clean_generic_bound(b, cx)).collect(),
3299 },
3300 },
3301 }
3302}
3303
3304fn clean_bound_vars<'tcx>(
3305 bound_vars: &ty::List<ty::BoundVariableKind<'tcx>>,
3306 tcx: TyCtxt<'tcx>,
3307) -> Vec<GenericParamDef> {
3308 bound_vars
3309 .into_iter()
3310 .filter_map(|var| match var {
3311 ty::BoundVariableKind::Region(ty::BoundRegionKind::Named(def_id)) => {
3312 let name = tcx.item_name(def_id);
3313 if name != kw::UnderscoreLifetime {
3314 Some(GenericParamDef::lifetime(def_id, name))
3315 } else {
3316 None
3317 }
3318 }
3319 ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id)) => {
3320 let name = tcx.item_name(def_id);
3321 Some(GenericParamDef {
3322 name,
3323 def_id,
3324 kind: GenericParamDefKind::Type {
3325 bounds: ThinVec::new(),
3326 default: None,
3327 synthetic: false,
3328 },
3329 })
3330 }
3331 ty::BoundVariableKind::Const => None,
3333 _ => None,
3334 })
3335 .collect()
3336}