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