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