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