• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! This module contains the "cleaned" pieces of the AST, and the functions
2 //! that clean them.
3 
4 mod auto_trait;
5 mod blanket_impl;
6 pub(crate) mod cfg;
7 pub(crate) mod inline;
8 mod render_macro_matchers;
9 mod simplify;
10 pub(crate) mod types;
11 pub(crate) mod utils;
12 
13 use rustc_ast as ast;
14 use rustc_ast::token::{Token, TokenKind};
15 use rustc_ast::tokenstream::{TokenStream, TokenTree};
16 use rustc_attr as attr;
17 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry};
18 use rustc_hir as hir;
19 use rustc_hir::def::{CtorKind, DefKind, Res};
20 use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
21 use rustc_hir::PredicateOrigin;
22 use rustc_hir_analysis::hir_ty_to_ty;
23 use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
24 use rustc_middle::metadata::Reexport;
25 use rustc_middle::middle::resolve_bound_vars as rbv;
26 use rustc_middle::ty::fold::TypeFolder;
27 use rustc_middle::ty::InternalSubsts;
28 use rustc_middle::ty::TypeVisitableExt;
29 use rustc_middle::ty::{self, AdtKind, EarlyBinder, Ty, TyCtxt};
30 use rustc_middle::{bug, span_bug};
31 use rustc_span::hygiene::{AstPass, MacroKind};
32 use rustc_span::symbol::{kw, sym, Ident, Symbol};
33 use rustc_span::{self, ExpnKind};
34 use rustc_trait_selection::traits::wf::object_region_bounds;
35 
36 use std::borrow::Cow;
37 use std::collections::hash_map::Entry;
38 use std::collections::BTreeMap;
39 use std::hash::Hash;
40 use std::mem;
41 use thin_vec::ThinVec;
42 
43 use crate::core::{self, DocContext, ImplTraitParam};
44 use crate::formats::item_type::ItemType;
45 use crate::visit_ast::Module as DocModule;
46 
47 use utils::*;
48 
49 pub(crate) use self::types::*;
50 pub(crate) use self::utils::{get_auto_trait_and_blanket_impls, krate, register_res};
51 
clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item52 pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
53     let mut items: Vec<Item> = vec![];
54     let mut inserted = FxHashSet::default();
55     items.extend(doc.foreigns.iter().map(|(item, renamed)| {
56         let item = clean_maybe_renamed_foreign_item(cx, item, *renamed);
57         if let Some(name) = item.name && !item.is_doc_hidden() {
58             inserted.insert((item.type_(), name));
59         }
60         item
61     }));
62     items.extend(doc.mods.iter().filter_map(|x| {
63         if !inserted.insert((ItemType::Module, x.name)) {
64             return None;
65         }
66         let item = clean_doc_module(x, cx);
67         if item.is_doc_hidden() {
68             // Hidden modules are stripped at a later stage.
69             // If a hidden module has the same name as a visible one, we want
70             // to keep both of them around.
71             inserted.remove(&(ItemType::Module, x.name));
72         }
73         Some(item)
74     }));
75 
76     // Split up imports from all other items.
77     //
78     // This covers the case where somebody does an import which should pull in an item,
79     // but there's already an item with the same namespace and same name. Rust gives
80     // priority to the not-imported one, so we should, too.
81     items.extend(doc.items.values().flat_map(|(item, renamed, import_id)| {
82         // First, lower everything other than imports.
83         if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
84             return Vec::new();
85         }
86         let v = clean_maybe_renamed_item(cx, item, *renamed, *import_id);
87         for item in &v {
88             if let Some(name) = item.name && !item.is_doc_hidden() {
89                 inserted.insert((item.type_(), name));
90             }
91         }
92         v
93     }));
94     items.extend(doc.items.values().flat_map(|(item, renamed, _)| {
95         // Now we actually lower the imports, skipping everything else.
96         if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
97             let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
98             clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted)
99         } else {
100             // skip everything else
101             Vec::new()
102         }
103     }));
104 
105     // determine if we should display the inner contents or
106     // the outer `mod` item for the source code.
107 
108     let span = Span::new({
109         let where_outer = doc.where_outer(cx.tcx);
110         let sm = cx.sess().source_map();
111         let outer = sm.lookup_char_pos(where_outer.lo());
112         let inner = sm.lookup_char_pos(doc.where_inner.lo());
113         if outer.file.start_pos == inner.file.start_pos {
114             // mod foo { ... }
115             where_outer
116         } else {
117             // mod foo; (and a separate SourceFile for the contents)
118             doc.where_inner
119         }
120     });
121 
122     let kind = ModuleItem(Module { items, span });
123     generate_item_with_correct_attrs(cx, kind, doc.def_id, doc.name, doc.import_id, doc.renamed)
124 }
125 
generate_item_with_correct_attrs( cx: &mut DocContext<'_>, kind: ItemKind, local_def_id: LocalDefId, name: Symbol, import_id: Option<LocalDefId>, renamed: Option<Symbol>, ) -> Item126 fn generate_item_with_correct_attrs(
127     cx: &mut DocContext<'_>,
128     kind: ItemKind,
129     local_def_id: LocalDefId,
130     name: Symbol,
131     import_id: Option<LocalDefId>,
132     renamed: Option<Symbol>,
133 ) -> Item {
134     let def_id = local_def_id.to_def_id();
135     let target_attrs = inline::load_attrs(cx, def_id);
136     let attrs = if let Some(import_id) = import_id {
137         let is_inline = inline::load_attrs(cx, import_id.to_def_id())
138             .lists(sym::doc)
139             .get_word_attr(sym::inline)
140             .is_some();
141         let mut attrs = get_all_import_attributes(cx, import_id, local_def_id, is_inline);
142         add_without_unwanted_attributes(&mut attrs, target_attrs, is_inline, None);
143         attrs
144     } else {
145         // We only keep the item's attributes.
146         target_attrs.iter().map(|attr| (Cow::Borrowed(attr), None)).collect()
147     };
148 
149     let cfg = attrs.cfg(cx.tcx, &cx.cache.hidden_cfg);
150     let attrs = Attributes::from_ast_iter(attrs.iter().map(|(attr, did)| (&**attr, *did)), false);
151 
152     let name = renamed.or(Some(name));
153     let mut item = Item::from_def_id_and_attrs_and_parts(def_id, name, kind, Box::new(attrs), cfg);
154     item.inline_stmt_id = import_id.map(|local| local.to_def_id());
155     item
156 }
157 
clean_generic_bound<'tcx>( bound: &hir::GenericBound<'tcx>, cx: &mut DocContext<'tcx>, ) -> Option<GenericBound>158 fn clean_generic_bound<'tcx>(
159     bound: &hir::GenericBound<'tcx>,
160     cx: &mut DocContext<'tcx>,
161 ) -> Option<GenericBound> {
162     Some(match *bound {
163         hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
164         hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
165             let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
166 
167             let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(cx.tcx, def_id));
168 
169             let generic_args = clean_generic_args(generic_args, cx);
170             let GenericArgs::AngleBracketed { bindings, .. } = generic_args
171             else {
172                 bug!("clean: parenthesized `GenericBound::LangItemTrait`");
173             };
174 
175             let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, bindings);
176             GenericBound::TraitBound(
177                 PolyTrait { trait_, generic_params: vec![] },
178                 hir::TraitBoundModifier::None,
179             )
180         }
181         hir::GenericBound::Trait(ref t, modifier) => {
182             // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
183             if modifier == hir::TraitBoundModifier::MaybeConst
184                 && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap())
185             {
186                 return None;
187             }
188 
189             GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier)
190         }
191     })
192 }
193 
clean_trait_ref_with_bindings<'tcx>( cx: &mut DocContext<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, bindings: ThinVec<TypeBinding>, ) -> Path194 pub(crate) fn clean_trait_ref_with_bindings<'tcx>(
195     cx: &mut DocContext<'tcx>,
196     trait_ref: ty::PolyTraitRef<'tcx>,
197     bindings: ThinVec<TypeBinding>,
198 ) -> Path {
199     let kind = cx.tcx.def_kind(trait_ref.def_id()).into();
200     if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
201         span_bug!(cx.tcx.def_span(trait_ref.def_id()), "`TraitRef` had unexpected kind {:?}", kind);
202     }
203     inline::record_extern_fqn(cx, trait_ref.def_id(), kind);
204     let path =
205         external_path(cx, trait_ref.def_id(), true, bindings, trait_ref.map_bound(|tr| tr.substs));
206 
207     debug!(?trait_ref);
208 
209     path
210 }
211 
clean_poly_trait_ref_with_bindings<'tcx>( cx: &mut DocContext<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, bindings: ThinVec<TypeBinding>, ) -> GenericBound212 fn clean_poly_trait_ref_with_bindings<'tcx>(
213     cx: &mut DocContext<'tcx>,
214     poly_trait_ref: ty::PolyTraitRef<'tcx>,
215     bindings: ThinVec<TypeBinding>,
216 ) -> GenericBound {
217     // collect any late bound regions
218     let late_bound_regions: Vec<_> = cx
219         .tcx
220         .collect_referenced_late_bound_regions(&poly_trait_ref)
221         .into_iter()
222         .filter_map(|br| match br {
223             ty::BrNamed(_, name) if br.is_named() => Some(GenericParamDef::lifetime(name)),
224             _ => None,
225         })
226         .collect();
227 
228     let trait_ = clean_trait_ref_with_bindings(cx, poly_trait_ref, bindings);
229     GenericBound::TraitBound(
230         PolyTrait { trait_, generic_params: late_bound_regions },
231         hir::TraitBoundModifier::None,
232     )
233 }
234 
clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime235 fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> Lifetime {
236     let def = cx.tcx.named_bound_var(lifetime.hir_id);
237     if let Some(
238         rbv::ResolvedArg::EarlyBound(node_id)
239         | rbv::ResolvedArg::LateBound(_, _, node_id)
240         | rbv::ResolvedArg::Free(_, node_id),
241     ) = def
242     {
243         if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() {
244             return lt;
245         }
246     }
247     Lifetime(lifetime.ident.name)
248 }
249 
clean_const<'tcx>(constant: &hir::ConstArg, cx: &mut DocContext<'tcx>) -> Constant250 pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg, cx: &mut DocContext<'tcx>) -> Constant {
251     let def_id = cx.tcx.hir().body_owner_def_id(constant.value.body).to_def_id();
252     Constant {
253         type_: clean_middle_ty(
254             ty::Binder::dummy(cx.tcx.type_of(def_id).subst_identity()),
255             cx,
256             Some(def_id),
257             None,
258         ),
259         kind: ConstantKind::Anonymous { body: constant.value.body },
260     }
261 }
262 
clean_middle_const<'tcx>( constant: ty::Binder<'tcx, ty::Const<'tcx>>, cx: &mut DocContext<'tcx>, ) -> Constant263 pub(crate) fn clean_middle_const<'tcx>(
264     constant: ty::Binder<'tcx, ty::Const<'tcx>>,
265     cx: &mut DocContext<'tcx>,
266 ) -> Constant {
267     // FIXME: instead of storing the stringified expression, store `self` directly instead.
268     Constant {
269         type_: clean_middle_ty(constant.map_bound(|c| c.ty()), cx, None, None),
270         kind: ConstantKind::TyConst { expr: constant.skip_binder().to_string().into() },
271     }
272 }
273 
clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Lifetime>274 pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Lifetime> {
275     match *region {
276         ty::ReStatic => Some(Lifetime::statik()),
277         _ if !region.has_name() => None,
278         ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => {
279             Some(Lifetime(name))
280         }
281         ty::ReEarlyBound(ref data) => Some(Lifetime(data.name)),
282         ty::ReLateBound(..)
283         | ty::ReFree(..)
284         | ty::ReVar(..)
285         | ty::ReError(_)
286         | ty::RePlaceholder(..)
287         | ty::ReErased => {
288             debug!("cannot clean region {:?}", region);
289             None
290         }
291     }
292 }
293 
clean_where_predicate<'tcx>( predicate: &hir::WherePredicate<'tcx>, cx: &mut DocContext<'tcx>, ) -> Option<WherePredicate>294 fn clean_where_predicate<'tcx>(
295     predicate: &hir::WherePredicate<'tcx>,
296     cx: &mut DocContext<'tcx>,
297 ) -> Option<WherePredicate> {
298     if !predicate.in_where_clause() {
299         return None;
300     }
301     Some(match *predicate {
302         hir::WherePredicate::BoundPredicate(ref wbp) => {
303             let bound_params = wbp
304                 .bound_generic_params
305                 .iter()
306                 .map(|param| clean_generic_param(cx, None, param))
307                 .collect();
308             WherePredicate::BoundPredicate {
309                 ty: clean_ty(wbp.bounded_ty, cx),
310                 bounds: wbp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
311                 bound_params,
312             }
313         }
314 
315         hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
316             lifetime: clean_lifetime(wrp.lifetime, cx),
317             bounds: wrp.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
318         },
319 
320         hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
321             lhs: Box::new(clean_ty(wrp.lhs_ty, cx)),
322             rhs: Box::new(clean_ty(wrp.rhs_ty, cx).into()),
323             bound_params: Vec::new(),
324         },
325     })
326 }
327 
clean_predicate<'tcx>( predicate: ty::Clause<'tcx>, cx: &mut DocContext<'tcx>, ) -> Option<WherePredicate>328 pub(crate) fn clean_predicate<'tcx>(
329     predicate: ty::Clause<'tcx>,
330     cx: &mut DocContext<'tcx>,
331 ) -> Option<WherePredicate> {
332     let bound_predicate = predicate.kind();
333     match bound_predicate.skip_binder() {
334         ty::ClauseKind::Trait(pred) => clean_poly_trait_predicate(bound_predicate.rebind(pred), cx),
335         ty::ClauseKind::RegionOutlives(pred) => clean_region_outlives_predicate(pred),
336         ty::ClauseKind::TypeOutlives(pred) => {
337             clean_type_outlives_predicate(bound_predicate.rebind(pred), cx)
338         }
339         ty::ClauseKind::Projection(pred) => {
340             Some(clean_projection_predicate(bound_predicate.rebind(pred), cx))
341         }
342         // FIXME(generic_const_exprs): should this do something?
343         ty::ClauseKind::ConstEvaluatable(..)
344         | ty::ClauseKind::WellFormed(..)
345         | ty::ClauseKind::ConstArgHasType(..) => None,
346     }
347 }
348 
clean_poly_trait_predicate<'tcx>( pred: ty::PolyTraitPredicate<'tcx>, cx: &mut DocContext<'tcx>, ) -> Option<WherePredicate>349 fn clean_poly_trait_predicate<'tcx>(
350     pred: ty::PolyTraitPredicate<'tcx>,
351     cx: &mut DocContext<'tcx>,
352 ) -> Option<WherePredicate> {
353     // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
354     if pred.skip_binder().constness == ty::BoundConstness::ConstIfConst
355         && Some(pred.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait()
356     {
357         return None;
358     }
359 
360     let poly_trait_ref = pred.map_bound(|pred| pred.trait_ref);
361     Some(WherePredicate::BoundPredicate {
362         ty: clean_middle_ty(poly_trait_ref.self_ty(), cx, None, None),
363         bounds: vec![clean_poly_trait_ref_with_bindings(cx, poly_trait_ref, ThinVec::new())],
364         bound_params: Vec::new(),
365     })
366 }
367 
clean_region_outlives_predicate<'tcx>( pred: ty::RegionOutlivesPredicate<'tcx>, ) -> Option<WherePredicate>368 fn clean_region_outlives_predicate<'tcx>(
369     pred: ty::RegionOutlivesPredicate<'tcx>,
370 ) -> Option<WherePredicate> {
371     let ty::OutlivesPredicate(a, b) = pred;
372 
373     Some(WherePredicate::RegionPredicate {
374         lifetime: clean_middle_region(a).expect("failed to clean lifetime"),
375         bounds: vec![GenericBound::Outlives(
376             clean_middle_region(b).expect("failed to clean bounds"),
377         )],
378     })
379 }
380 
clean_type_outlives_predicate<'tcx>( pred: ty::Binder<'tcx, ty::TypeOutlivesPredicate<'tcx>>, cx: &mut DocContext<'tcx>, ) -> Option<WherePredicate>381 fn clean_type_outlives_predicate<'tcx>(
382     pred: ty::Binder<'tcx, ty::TypeOutlivesPredicate<'tcx>>,
383     cx: &mut DocContext<'tcx>,
384 ) -> Option<WherePredicate> {
385     let ty::OutlivesPredicate(ty, lt) = pred.skip_binder();
386 
387     Some(WherePredicate::BoundPredicate {
388         ty: clean_middle_ty(pred.rebind(ty), cx, None, None),
389         bounds: vec![GenericBound::Outlives(
390             clean_middle_region(lt).expect("failed to clean lifetimes"),
391         )],
392         bound_params: Vec::new(),
393     })
394 }
395 
clean_middle_term<'tcx>( term: ty::Binder<'tcx, ty::Term<'tcx>>, cx: &mut DocContext<'tcx>, ) -> Term396 fn clean_middle_term<'tcx>(
397     term: ty::Binder<'tcx, ty::Term<'tcx>>,
398     cx: &mut DocContext<'tcx>,
399 ) -> Term {
400     match term.skip_binder().unpack() {
401         ty::TermKind::Ty(ty) => Term::Type(clean_middle_ty(term.rebind(ty), cx, None, None)),
402         ty::TermKind::Const(c) => Term::Constant(clean_middle_const(term.rebind(c), cx)),
403     }
404 }
405 
clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term406 fn clean_hir_term<'tcx>(term: &hir::Term<'tcx>, cx: &mut DocContext<'tcx>) -> Term {
407     match term {
408         hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)),
409         hir::Term::Const(c) => Term::Constant(clean_middle_const(
410             ty::Binder::dummy(ty::Const::from_anon_const(cx.tcx, c.def_id)),
411             cx,
412         )),
413     }
414 }
415 
clean_projection_predicate<'tcx>( pred: ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>, cx: &mut DocContext<'tcx>, ) -> WherePredicate416 fn clean_projection_predicate<'tcx>(
417     pred: ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>,
418     cx: &mut DocContext<'tcx>,
419 ) -> WherePredicate {
420     let late_bound_regions = cx
421         .tcx
422         .collect_referenced_late_bound_regions(&pred)
423         .into_iter()
424         .filter_map(|br| match br {
425             ty::BrNamed(_, name) if br.is_named() => Some(GenericParamDef::lifetime(name)),
426             _ => None,
427         })
428         .collect();
429 
430     WherePredicate::EqPredicate {
431         lhs: Box::new(clean_projection(pred.map_bound(|p| p.projection_ty), cx, None)),
432         rhs: Box::new(clean_middle_term(pred.map_bound(|p| p.term), cx)),
433         bound_params: late_bound_regions,
434     }
435 }
436 
clean_projection<'tcx>( ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>, cx: &mut DocContext<'tcx>, def_id: Option<DefId>, ) -> Type437 fn clean_projection<'tcx>(
438     ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>,
439     cx: &mut DocContext<'tcx>,
440     def_id: Option<DefId>,
441 ) -> Type {
442     if cx.tcx.is_impl_trait_in_trait(ty.skip_binder().def_id) {
443         let bounds = cx
444             .tcx
445             .explicit_item_bounds(ty.skip_binder().def_id)
446             .subst_iter_copied(cx.tcx, ty.skip_binder().substs)
447             .map(|(pred, _)| pred)
448             .collect::<Vec<_>>();
449         return clean_middle_opaque_bounds(cx, bounds);
450     }
451 
452     let trait_ =
453         clean_trait_ref_with_bindings(cx, ty.map_bound(|ty| ty.trait_ref(cx.tcx)), ThinVec::new());
454     let self_type = clean_middle_ty(ty.map_bound(|ty| ty.self_ty()), cx, None, None);
455     let self_def_id = if let Some(def_id) = def_id {
456         cx.tcx.opt_parent(def_id).or(Some(def_id))
457     } else {
458         self_type.def_id(&cx.cache)
459     };
460     let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type);
461     Type::QPath(Box::new(QPathData {
462         assoc: projection_to_path_segment(ty, cx),
463         should_show_cast,
464         self_type,
465         trait_: Some(trait_),
466     }))
467 }
468 
compute_should_show_cast(self_def_id: Option<DefId>, trait_: &Path, self_type: &Type) -> bool469 fn compute_should_show_cast(self_def_id: Option<DefId>, trait_: &Path, self_type: &Type) -> bool {
470     !trait_.segments.is_empty()
471         && self_def_id
472             .zip(Some(trait_.def_id()))
473             .map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_)
474 }
475 
projection_to_path_segment<'tcx>( ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>, cx: &mut DocContext<'tcx>, ) -> PathSegment476 fn projection_to_path_segment<'tcx>(
477     ty: ty::Binder<'tcx, ty::AliasTy<'tcx>>,
478     cx: &mut DocContext<'tcx>,
479 ) -> PathSegment {
480     let item = cx.tcx.associated_item(ty.skip_binder().def_id);
481     let generics = cx.tcx.generics_of(ty.skip_binder().def_id);
482     PathSegment {
483         name: item.name,
484         args: GenericArgs::AngleBracketed {
485             args: substs_to_args(
486                 cx,
487                 ty.map_bound(|ty| &ty.substs[generics.parent_count..]),
488                 false,
489                 None,
490             )
491             .into(),
492             bindings: Default::default(),
493         },
494     }
495 }
496 
clean_generic_param_def<'tcx>( def: &ty::GenericParamDef, cx: &mut DocContext<'tcx>, ) -> GenericParamDef497 fn clean_generic_param_def<'tcx>(
498     def: &ty::GenericParamDef,
499     cx: &mut DocContext<'tcx>,
500 ) -> GenericParamDef {
501     let (name, kind) = match def.kind {
502         ty::GenericParamDefKind::Lifetime => {
503             (def.name, GenericParamDefKind::Lifetime { outlives: vec![] })
504         }
505         ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
506             let default = if has_default {
507                 Some(clean_middle_ty(
508                     ty::Binder::dummy(cx.tcx.type_of(def.def_id).subst_identity()),
509                     cx,
510                     Some(def.def_id),
511                     None,
512                 ))
513             } else {
514                 None
515             };
516             (
517                 def.name,
518                 GenericParamDefKind::Type {
519                     did: def.def_id,
520                     bounds: vec![], // These are filled in from the where-clauses.
521                     default: default.map(Box::new),
522                     synthetic,
523                 },
524             )
525         }
526         ty::GenericParamDefKind::Const { has_default } => (
527             def.name,
528             GenericParamDefKind::Const {
529                 ty: Box::new(clean_middle_ty(
530                     ty::Binder::dummy(
531                         cx.tcx
532                             .type_of(def.def_id)
533                             .no_bound_vars()
534                             .expect("const parameter types cannot be generic"),
535                     ),
536                     cx,
537                     Some(def.def_id),
538                     None,
539                 )),
540                 default: match has_default {
541                     true => Some(Box::new(
542                         cx.tcx.const_param_default(def.def_id).subst_identity().to_string(),
543                     )),
544                     false => None,
545                 },
546             },
547         ),
548     };
549 
550     GenericParamDef { name, kind }
551 }
552 
clean_generic_param<'tcx>( cx: &mut DocContext<'tcx>, generics: Option<&hir::Generics<'tcx>>, param: &hir::GenericParam<'tcx>, ) -> GenericParamDef553 fn clean_generic_param<'tcx>(
554     cx: &mut DocContext<'tcx>,
555     generics: Option<&hir::Generics<'tcx>>,
556     param: &hir::GenericParam<'tcx>,
557 ) -> GenericParamDef {
558     let (name, kind) = match param.kind {
559         hir::GenericParamKind::Lifetime { .. } => {
560             let outlives = if let Some(generics) = generics {
561                 generics
562                     .outlives_for_param(param.def_id)
563                     .filter(|bp| !bp.in_where_clause)
564                     .flat_map(|bp| bp.bounds)
565                     .map(|bound| match bound {
566                         hir::GenericBound::Outlives(lt) => clean_lifetime(lt, cx),
567                         _ => panic!(),
568                     })
569                     .collect()
570             } else {
571                 Vec::new()
572             };
573             (param.name.ident().name, GenericParamDefKind::Lifetime { outlives })
574         }
575         hir::GenericParamKind::Type { ref default, synthetic } => {
576             let bounds = if let Some(generics) = generics {
577                 generics
578                     .bounds_for_param(param.def_id)
579                     .filter(|bp| bp.origin != PredicateOrigin::WhereClause)
580                     .flat_map(|bp| bp.bounds)
581                     .filter_map(|x| clean_generic_bound(x, cx))
582                     .collect()
583             } else {
584                 Vec::new()
585             };
586             (
587                 param.name.ident().name,
588                 GenericParamDefKind::Type {
589                     did: param.def_id.to_def_id(),
590                     bounds,
591                     default: default.map(|t| clean_ty(t, cx)).map(Box::new),
592                     synthetic,
593                 },
594             )
595         }
596         hir::GenericParamKind::Const { ty, default } => (
597             param.name.ident().name,
598             GenericParamDefKind::Const {
599                 ty: Box::new(clean_ty(ty, cx)),
600                 default: default
601                     .map(|ct| Box::new(ty::Const::from_anon_const(cx.tcx, ct.def_id).to_string())),
602             },
603         ),
604     };
605 
606     GenericParamDef { name, kind }
607 }
608 
609 /// Synthetic type-parameters are inserted after normal ones.
610 /// In order for normal parameters to be able to refer to synthetic ones,
611 /// scans them first.
is_impl_trait(param: &hir::GenericParam<'_>) -> bool612 fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool {
613     match param.kind {
614         hir::GenericParamKind::Type { synthetic, .. } => synthetic,
615         _ => false,
616     }
617 }
618 
619 /// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
620 ///
621 /// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information.
is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool622 fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
623     matches!(param.kind, hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided })
624 }
625 
clean_generics<'tcx>( gens: &hir::Generics<'tcx>, cx: &mut DocContext<'tcx>, ) -> Generics626 pub(crate) fn clean_generics<'tcx>(
627     gens: &hir::Generics<'tcx>,
628     cx: &mut DocContext<'tcx>,
629 ) -> Generics {
630     let impl_trait_params = gens
631         .params
632         .iter()
633         .filter(|param| is_impl_trait(param))
634         .map(|param| {
635             let param = clean_generic_param(cx, Some(gens), param);
636             match param.kind {
637                 GenericParamDefKind::Lifetime { .. } => unreachable!(),
638                 GenericParamDefKind::Type { did, ref bounds, .. } => {
639                     cx.impl_trait_bounds.insert(did.into(), bounds.clone());
640                 }
641                 GenericParamDefKind::Const { .. } => unreachable!(),
642             }
643             param
644         })
645         .collect::<Vec<_>>();
646 
647     let mut bound_predicates = FxIndexMap::default();
648     let mut region_predicates = FxIndexMap::default();
649     let mut eq_predicates = ThinVec::default();
650     for pred in gens.predicates.iter().filter_map(|x| clean_where_predicate(x, cx)) {
651         match pred {
652             WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
653                 match bound_predicates.entry(ty) {
654                     IndexEntry::Vacant(v) => {
655                         v.insert((bounds, bound_params));
656                     }
657                     IndexEntry::Occupied(mut o) => {
658                         // we merge both bounds.
659                         for bound in bounds {
660                             if !o.get().0.contains(&bound) {
661                                 o.get_mut().0.push(bound);
662                             }
663                         }
664                         for bound_param in bound_params {
665                             if !o.get().1.contains(&bound_param) {
666                                 o.get_mut().1.push(bound_param);
667                             }
668                         }
669                     }
670                 }
671             }
672             WherePredicate::RegionPredicate { lifetime, bounds } => {
673                 match region_predicates.entry(lifetime) {
674                     IndexEntry::Vacant(v) => {
675                         v.insert(bounds);
676                     }
677                     IndexEntry::Occupied(mut o) => {
678                         // we merge both bounds.
679                         for bound in bounds {
680                             if !o.get().contains(&bound) {
681                                 o.get_mut().push(bound);
682                             }
683                         }
684                     }
685                 }
686             }
687             WherePredicate::EqPredicate { lhs, rhs, bound_params } => {
688                 eq_predicates.push(WherePredicate::EqPredicate { lhs, rhs, bound_params });
689             }
690         }
691     }
692 
693     let mut params = ThinVec::with_capacity(gens.params.len());
694     // In this loop, we gather the generic parameters (`<'a, B: 'a>`) and check if they have
695     // bounds in the where predicates. If so, we move their bounds into the where predicates
696     // while also preventing duplicates.
697     for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
698         let mut p = clean_generic_param(cx, Some(gens), p);
699         match &mut p.kind {
700             GenericParamDefKind::Lifetime { ref mut outlives } => {
701                 if let Some(region_pred) = region_predicates.get_mut(&Lifetime(p.name)) {
702                     // We merge bounds in the `where` clause.
703                     for outlive in outlives.drain(..) {
704                         let outlive = GenericBound::Outlives(outlive);
705                         if !region_pred.contains(&outlive) {
706                             region_pred.push(outlive);
707                         }
708                     }
709                 }
710             }
711             GenericParamDefKind::Type { bounds, synthetic: false, .. } => {
712                 if let Some(bound_pred) = bound_predicates.get_mut(&Type::Generic(p.name)) {
713                     // We merge bounds in the `where` clause.
714                     for bound in bounds.drain(..) {
715                         if !bound_pred.0.contains(&bound) {
716                             bound_pred.0.push(bound);
717                         }
718                     }
719                 }
720             }
721             GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
722                 // nothing to do here.
723             }
724         }
725         params.push(p);
726     }
727     params.extend(impl_trait_params);
728 
729     Generics {
730         params,
731         where_predicates: bound_predicates
732             .into_iter()
733             .map(|(ty, (bounds, bound_params))| WherePredicate::BoundPredicate {
734                 ty,
735                 bounds,
736                 bound_params,
737             })
738             .chain(
739                 region_predicates
740                     .into_iter()
741                     .map(|(lifetime, bounds)| WherePredicate::RegionPredicate { lifetime, bounds }),
742             )
743             .chain(eq_predicates.into_iter())
744             .collect(),
745     }
746 }
747 
clean_ty_generics<'tcx>( cx: &mut DocContext<'tcx>, gens: &ty::Generics, preds: ty::GenericPredicates<'tcx>, ) -> Generics748 fn clean_ty_generics<'tcx>(
749     cx: &mut DocContext<'tcx>,
750     gens: &ty::Generics,
751     preds: ty::GenericPredicates<'tcx>,
752 ) -> Generics {
753     // Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
754     // since `Clean for ty::Predicate` would consume them.
755     let mut impl_trait = BTreeMap::<ImplTraitParam, Vec<GenericBound>>::default();
756 
757     // Bounds in the type_params and lifetimes fields are repeated in the
758     // predicates field (see rustc_hir_analysis::collect::ty_generics), so remove
759     // them.
760     let stripped_params = gens
761         .params
762         .iter()
763         .filter_map(|param| match param.kind {
764             ty::GenericParamDefKind::Lifetime if param.is_anonymous_lifetime() => None,
765             ty::GenericParamDefKind::Lifetime => Some(clean_generic_param_def(param, cx)),
766             ty::GenericParamDefKind::Type { synthetic, .. } => {
767                 if param.name == kw::SelfUpper {
768                     assert_eq!(param.index, 0);
769                     return None;
770                 }
771                 if synthetic {
772                     impl_trait.insert(param.index.into(), vec![]);
773                     return None;
774                 }
775                 Some(clean_generic_param_def(param, cx))
776             }
777             ty::GenericParamDefKind::Const { .. } => Some(clean_generic_param_def(param, cx)),
778         })
779         .collect::<ThinVec<GenericParamDef>>();
780 
781     // param index -> [(trait DefId, associated type name & generics, term, higher-ranked params)]
782     let mut impl_trait_proj = FxHashMap::<
783         u32,
784         Vec<(DefId, PathSegment, ty::Binder<'_, ty::Term<'_>>, Vec<GenericParamDef>)>,
785     >::default();
786 
787     let where_predicates = preds
788         .predicates
789         .iter()
790         .flat_map(|(p, _)| {
791             let mut projection = None;
792             let param_idx = (|| {
793                 let bound_p = p.kind();
794                 match bound_p.skip_binder() {
795                     ty::ClauseKind::Trait(pred) => {
796                         if let ty::Param(param) = pred.self_ty().kind() {
797                             return Some(param.index);
798                         }
799                     }
800                     ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
801                         if let ty::Param(param) = ty.kind() {
802                             return Some(param.index);
803                         }
804                     }
805                     ty::ClauseKind::Projection(p) => {
806                         if let ty::Param(param) = p.projection_ty.self_ty().kind() {
807                             projection = Some(bound_p.rebind(p));
808                             return Some(param.index);
809                         }
810                     }
811                     _ => (),
812                 }
813 
814                 None
815             })();
816 
817             if let Some(param_idx) = param_idx
818                 && let Some(b) = impl_trait.get_mut(&param_idx.into())
819             {
820                 let p: WherePredicate = clean_predicate(*p, cx)?;
821 
822                 b.extend(
823                     p.get_bounds()
824                         .into_iter()
825                         .flatten()
826                         .cloned()
827                         .filter(|b| !b.is_sized_bound(cx)),
828                 );
829 
830                 let proj = projection.map(|p| {
831                     (
832                         clean_projection(p.map_bound(|p| p.projection_ty), cx, None),
833                         p.map_bound(|p| p.term),
834                     )
835                 });
836                 if let Some(((_, trait_did, name), rhs)) = proj
837                     .as_ref()
838                     .and_then(|(lhs, rhs): &(Type, _)| Some((lhs.projection()?, rhs)))
839                 {
840                     impl_trait_proj.entry(param_idx).or_default().push((
841                         trait_did,
842                         name,
843                         *rhs,
844                         p.get_bound_params()
845                             .into_iter()
846                             .flatten()
847                             .cloned()
848                             .collect(),
849                     ));
850                 }
851 
852                 return None;
853             }
854 
855             Some(p)
856         })
857         .collect::<Vec<_>>();
858 
859     for (param, mut bounds) in impl_trait {
860         // Move trait bounds to the front.
861         bounds.sort_by_key(|b| !matches!(b, GenericBound::TraitBound(..)));
862 
863         let crate::core::ImplTraitParam::ParamIndex(idx) = param else { unreachable!() };
864         if let Some(proj) = impl_trait_proj.remove(&idx) {
865             for (trait_did, name, rhs, bound_params) in proj {
866                 let rhs = clean_middle_term(rhs, cx);
867                 simplify::merge_bounds(cx, &mut bounds, bound_params, trait_did, name, &rhs);
868             }
869         }
870 
871         cx.impl_trait_bounds.insert(param, bounds);
872     }
873 
874     // Now that `cx.impl_trait_bounds` is populated, we can process
875     // remaining predicates which could contain `impl Trait`.
876     let mut where_predicates =
877         where_predicates.into_iter().flat_map(|p| clean_predicate(*p, cx)).collect::<Vec<_>>();
878 
879     // In the surface language, all type parameters except `Self` have an
880     // implicit `Sized` bound unless removed with `?Sized`.
881     // However, in the list of where-predicates below, `Sized` appears like a
882     // normal bound: It's either present (the type is sized) or
883     // absent (the type is unsized) but never *maybe* (i.e. `?Sized`).
884     //
885     // This is unsuitable for rendering.
886     // Thus, as a first step remove all `Sized` bounds that should be implicit.
887     //
888     // Note that associated types also have an implicit `Sized` bound but we
889     // don't actually know the set of associated types right here so that's
890     // handled when cleaning associated types.
891     let mut sized_params = FxHashSet::default();
892     where_predicates.retain(|pred| {
893         if let WherePredicate::BoundPredicate { ty: Generic(g), bounds, .. } = pred
894         && *g != kw::SelfUpper
895         && bounds.iter().any(|b| b.is_sized_bound(cx))
896         {
897             sized_params.insert(*g);
898             false
899         } else {
900             true
901         }
902     });
903 
904     // As a final step, go through the type parameters again and insert a
905     // `?Sized` bound for each one we didn't find to be `Sized`.
906     for tp in &stripped_params {
907         if let types::GenericParamDefKind::Type { .. } = tp.kind
908             && !sized_params.contains(&tp.name)
909         {
910             where_predicates.push(WherePredicate::BoundPredicate {
911                 ty: Type::Generic(tp.name),
912                 bounds: vec![GenericBound::maybe_sized(cx)],
913                 bound_params: Vec::new(),
914             })
915         }
916     }
917 
918     // It would be nice to collect all of the bounds on a type and recombine
919     // them if possible, to avoid e.g., `where T: Foo, T: Bar, T: Sized, T: 'a`
920     // and instead see `where T: Foo + Bar + Sized + 'a`
921 
922     Generics {
923         params: stripped_params,
924         where_predicates: simplify::where_clauses(cx, where_predicates),
925     }
926 }
927 
clean_proc_macro<'tcx>( item: &hir::Item<'tcx>, name: &mut Symbol, kind: MacroKind, cx: &mut DocContext<'tcx>, ) -> ItemKind928 fn clean_proc_macro<'tcx>(
929     item: &hir::Item<'tcx>,
930     name: &mut Symbol,
931     kind: MacroKind,
932     cx: &mut DocContext<'tcx>,
933 ) -> ItemKind {
934     let attrs = cx.tcx.hir().attrs(item.hir_id());
935     if kind == MacroKind::Derive &&
936         let Some(derive_name) = attrs
937             .lists(sym::proc_macro_derive)
938             .find_map(|mi| mi.ident())
939     {
940         *name = derive_name.name;
941     }
942 
943     let mut helpers = Vec::new();
944     for mi in attrs.lists(sym::proc_macro_derive) {
945         if !mi.has_name(sym::attributes) {
946             continue;
947         }
948 
949         if let Some(list) = mi.meta_item_list() {
950             for inner_mi in list {
951                 if let Some(ident) = inner_mi.ident() {
952                     helpers.push(ident.name);
953                 }
954             }
955         }
956     }
957     ProcMacroItem(ProcMacro { kind, helpers })
958 }
959 
clean_fn_or_proc_macro<'tcx>( item: &hir::Item<'tcx>, sig: &hir::FnSig<'tcx>, generics: &hir::Generics<'tcx>, body_id: hir::BodyId, name: &mut Symbol, cx: &mut DocContext<'tcx>, ) -> ItemKind960 fn clean_fn_or_proc_macro<'tcx>(
961     item: &hir::Item<'tcx>,
962     sig: &hir::FnSig<'tcx>,
963     generics: &hir::Generics<'tcx>,
964     body_id: hir::BodyId,
965     name: &mut Symbol,
966     cx: &mut DocContext<'tcx>,
967 ) -> ItemKind {
968     let attrs = cx.tcx.hir().attrs(item.hir_id());
969     let macro_kind = attrs.iter().find_map(|a| {
970         if a.has_name(sym::proc_macro) {
971             Some(MacroKind::Bang)
972         } else if a.has_name(sym::proc_macro_derive) {
973             Some(MacroKind::Derive)
974         } else if a.has_name(sym::proc_macro_attribute) {
975             Some(MacroKind::Attr)
976         } else {
977             None
978         }
979     });
980     match macro_kind {
981         Some(kind) => clean_proc_macro(item, name, kind, cx),
982         None => {
983             let mut func = clean_function(cx, sig, generics, FunctionArgs::Body(body_id));
984             clean_fn_decl_legacy_const_generics(&mut func, attrs);
985             FunctionItem(func)
986         }
987     }
988 }
989 
990 /// This is needed to make it more "readable" when documenting functions using
991 /// `rustc_legacy_const_generics`. More information in
992 /// <https://github.com/rust-lang/rust/issues/83167>.
clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attribute])993 fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attribute]) {
994     for meta_item_list in attrs
995         .iter()
996         .filter(|a| a.has_name(sym::rustc_legacy_const_generics))
997         .filter_map(|a| a.meta_item_list())
998     {
999         for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.lit()).enumerate() {
1000             match literal.kind {
1001                 ast::LitKind::Int(a, _) => {
1002                     let gen = func.generics.params.remove(0);
1003                     if let GenericParamDef { name, kind: GenericParamDefKind::Const { ty, .. } } =
1004                         gen
1005                     {
1006                         func.decl
1007                             .inputs
1008                             .values
1009                             .insert(a as _, Argument { name, type_: *ty, is_const: true });
1010                     } else {
1011                         panic!("unexpected non const in position {pos}");
1012                     }
1013                 }
1014                 _ => panic!("invalid arg index"),
1015             }
1016         }
1017     }
1018 }
1019 
1020 enum FunctionArgs<'tcx> {
1021     Body(hir::BodyId),
1022     Names(&'tcx [Ident]),
1023 }
1024 
clean_function<'tcx>( cx: &mut DocContext<'tcx>, sig: &hir::FnSig<'tcx>, generics: &hir::Generics<'tcx>, args: FunctionArgs<'tcx>, ) -> Box<Function>1025 fn clean_function<'tcx>(
1026     cx: &mut DocContext<'tcx>,
1027     sig: &hir::FnSig<'tcx>,
1028     generics: &hir::Generics<'tcx>,
1029     args: FunctionArgs<'tcx>,
1030 ) -> Box<Function> {
1031     let (generics, decl) = enter_impl_trait(cx, |cx| {
1032         // NOTE: generics must be cleaned before args
1033         let generics = clean_generics(generics, cx);
1034         let args = match args {
1035             FunctionArgs::Body(body_id) => {
1036                 clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id)
1037             }
1038             FunctionArgs::Names(names) => {
1039                 clean_args_from_types_and_names(cx, sig.decl.inputs, names)
1040             }
1041         };
1042         let mut decl = clean_fn_decl_with_args(cx, sig.decl, args);
1043         if sig.header.is_async() {
1044             decl.output = decl.sugared_async_return_type();
1045         }
1046         (generics, decl)
1047     });
1048     Box::new(Function { decl, generics })
1049 }
1050 
clean_args_from_types_and_names<'tcx>( cx: &mut DocContext<'tcx>, types: &[hir::Ty<'tcx>], names: &[Ident], ) -> Arguments1051 fn clean_args_from_types_and_names<'tcx>(
1052     cx: &mut DocContext<'tcx>,
1053     types: &[hir::Ty<'tcx>],
1054     names: &[Ident],
1055 ) -> Arguments {
1056     Arguments {
1057         values: types
1058             .iter()
1059             .enumerate()
1060             .map(|(i, ty)| Argument {
1061                 type_: clean_ty(ty, cx),
1062                 name: names
1063                     .get(i)
1064                     .map(|ident| ident.name)
1065                     .filter(|ident| !ident.is_empty())
1066                     .unwrap_or(kw::Underscore),
1067                 is_const: false,
1068             })
1069             .collect(),
1070     }
1071 }
1072 
clean_args_from_types_and_body_id<'tcx>( cx: &mut DocContext<'tcx>, types: &[hir::Ty<'tcx>], body_id: hir::BodyId, ) -> Arguments1073 fn clean_args_from_types_and_body_id<'tcx>(
1074     cx: &mut DocContext<'tcx>,
1075     types: &[hir::Ty<'tcx>],
1076     body_id: hir::BodyId,
1077 ) -> Arguments {
1078     let body = cx.tcx.hir().body(body_id);
1079 
1080     Arguments {
1081         values: types
1082             .iter()
1083             .enumerate()
1084             .map(|(i, ty)| Argument {
1085                 name: name_from_pat(body.params[i].pat),
1086                 type_: clean_ty(ty, cx),
1087                 is_const: false,
1088             })
1089             .collect(),
1090     }
1091 }
1092 
clean_fn_decl_with_args<'tcx>( cx: &mut DocContext<'tcx>, decl: &hir::FnDecl<'tcx>, args: Arguments, ) -> FnDecl1093 fn clean_fn_decl_with_args<'tcx>(
1094     cx: &mut DocContext<'tcx>,
1095     decl: &hir::FnDecl<'tcx>,
1096     args: Arguments,
1097 ) -> FnDecl {
1098     let output = match decl.output {
1099         hir::FnRetTy::Return(typ) => clean_ty(typ, cx),
1100         hir::FnRetTy::DefaultReturn(..) => Type::Tuple(Vec::new()),
1101     };
1102     FnDecl { inputs: args, output, c_variadic: decl.c_variadic }
1103 }
1104 
clean_fn_decl_from_did_and_sig<'tcx>( cx: &mut DocContext<'tcx>, did: Option<DefId>, sig: ty::PolyFnSig<'tcx>, ) -> FnDecl1105 fn clean_fn_decl_from_did_and_sig<'tcx>(
1106     cx: &mut DocContext<'tcx>,
1107     did: Option<DefId>,
1108     sig: ty::PolyFnSig<'tcx>,
1109 ) -> FnDecl {
1110     let mut names = did.map_or(&[] as &[_], |did| cx.tcx.fn_arg_names(did)).iter();
1111 
1112     // We assume all empty tuples are default return type. This theoretically can discard `-> ()`,
1113     // but shouldn't change any code meaning.
1114     let output = clean_middle_ty(sig.output(), cx, None, None);
1115 
1116     FnDecl {
1117         output,
1118         c_variadic: sig.skip_binder().c_variadic,
1119         inputs: Arguments {
1120             values: sig
1121                 .inputs()
1122                 .iter()
1123                 .map(|t| Argument {
1124                     type_: clean_middle_ty(t.map_bound(|t| *t), cx, None, None),
1125                     name: names
1126                         .next()
1127                         .map(|i| i.name)
1128                         .filter(|i| !i.is_empty())
1129                         .unwrap_or(kw::Underscore),
1130                     is_const: false,
1131                 })
1132                 .collect(),
1133         },
1134     }
1135 }
1136 
clean_trait_ref<'tcx>(trait_ref: &hir::TraitRef<'tcx>, cx: &mut DocContext<'tcx>) -> Path1137 fn clean_trait_ref<'tcx>(trait_ref: &hir::TraitRef<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
1138     let path = clean_path(trait_ref.path, cx);
1139     register_res(cx, path.res);
1140     path
1141 }
1142 
clean_poly_trait_ref<'tcx>( poly_trait_ref: &hir::PolyTraitRef<'tcx>, cx: &mut DocContext<'tcx>, ) -> PolyTrait1143 fn clean_poly_trait_ref<'tcx>(
1144     poly_trait_ref: &hir::PolyTraitRef<'tcx>,
1145     cx: &mut DocContext<'tcx>,
1146 ) -> PolyTrait {
1147     PolyTrait {
1148         trait_: clean_trait_ref(&poly_trait_ref.trait_ref, cx),
1149         generic_params: poly_trait_ref
1150             .bound_generic_params
1151             .iter()
1152             .filter(|p| !is_elided_lifetime(p))
1153             .map(|x| clean_generic_param(cx, None, x))
1154             .collect(),
1155     }
1156 }
1157 
clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext<'tcx>) -> Item1158 fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
1159     let local_did = trait_item.owner_id.to_def_id();
1160     cx.with_param_env(local_did, |cx| {
1161         let inner = match trait_item.kind {
1162             hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
1163                 clean_ty(ty, cx),
1164                 ConstantKind::Local { def_id: local_did, body: default },
1165             ),
1166             hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
1167             hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
1168                 let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body));
1169                 MethodItem(m, None)
1170             }
1171             hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
1172                 let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Names(names));
1173                 TyMethodItem(m)
1174             }
1175             hir::TraitItemKind::Type(bounds, Some(default)) => {
1176                 let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
1177                 let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
1178                 let item_type = clean_middle_ty(
1179                     ty::Binder::dummy(hir_ty_to_ty(cx.tcx, default)),
1180                     cx,
1181                     None,
1182                     None,
1183                 );
1184                 AssocTypeItem(
1185                     Box::new(Typedef {
1186                         type_: clean_ty(default, cx),
1187                         generics,
1188                         item_type: Some(item_type),
1189                     }),
1190                     bounds,
1191                 )
1192             }
1193             hir::TraitItemKind::Type(bounds, None) => {
1194                 let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
1195                 let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
1196                 TyAssocTypeItem(generics, bounds)
1197             }
1198         };
1199         Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx)
1200     })
1201 }
1202 
clean_impl_item<'tcx>( impl_: &hir::ImplItem<'tcx>, cx: &mut DocContext<'tcx>, ) -> Item1203 pub(crate) fn clean_impl_item<'tcx>(
1204     impl_: &hir::ImplItem<'tcx>,
1205     cx: &mut DocContext<'tcx>,
1206 ) -> Item {
1207     let local_did = impl_.owner_id.to_def_id();
1208     cx.with_param_env(local_did, |cx| {
1209         let inner = match impl_.kind {
1210             hir::ImplItemKind::Const(ty, expr) => {
1211                 let default = ConstantKind::Local { def_id: local_did, body: expr };
1212                 AssocConstItem(clean_ty(ty, cx), default)
1213             }
1214             hir::ImplItemKind::Fn(ref sig, body) => {
1215                 let m = clean_function(cx, sig, impl_.generics, FunctionArgs::Body(body));
1216                 let defaultness = cx.tcx.defaultness(impl_.owner_id);
1217                 MethodItem(m, Some(defaultness))
1218             }
1219             hir::ImplItemKind::Type(hir_ty) => {
1220                 let type_ = clean_ty(hir_ty, cx);
1221                 let generics = clean_generics(impl_.generics, cx);
1222                 let item_type = clean_middle_ty(
1223                     ty::Binder::dummy(hir_ty_to_ty(cx.tcx, hir_ty)),
1224                     cx,
1225                     None,
1226                     None,
1227                 );
1228                 AssocTypeItem(
1229                     Box::new(Typedef { type_, generics, item_type: Some(item_type) }),
1230                     Vec::new(),
1231                 )
1232             }
1233         };
1234 
1235         Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx)
1236     })
1237 }
1238 
clean_middle_assoc_item<'tcx>( assoc_item: &ty::AssocItem, cx: &mut DocContext<'tcx>, ) -> Item1239 pub(crate) fn clean_middle_assoc_item<'tcx>(
1240     assoc_item: &ty::AssocItem,
1241     cx: &mut DocContext<'tcx>,
1242 ) -> Item {
1243     let tcx = cx.tcx;
1244     let kind = match assoc_item.kind {
1245         ty::AssocKind::Const => {
1246             let ty = clean_middle_ty(
1247                 ty::Binder::dummy(tcx.type_of(assoc_item.def_id).subst_identity()),
1248                 cx,
1249                 Some(assoc_item.def_id),
1250                 None,
1251             );
1252 
1253             let provided = match assoc_item.container {
1254                 ty::ImplContainer => true,
1255                 ty::TraitContainer => tcx.defaultness(assoc_item.def_id).has_value(),
1256             };
1257             if provided {
1258                 AssocConstItem(ty, ConstantKind::Extern { def_id: assoc_item.def_id })
1259             } else {
1260                 TyAssocConstItem(ty)
1261             }
1262         }
1263         ty::AssocKind::Fn => {
1264             let sig = tcx.fn_sig(assoc_item.def_id).subst_identity();
1265 
1266             let late_bound_regions = sig.bound_vars().into_iter().filter_map(|var| match var {
1267                 ty::BoundVariableKind::Region(ty::BrNamed(_, name))
1268                     if name != kw::UnderscoreLifetime =>
1269                 {
1270                     Some(GenericParamDef::lifetime(name))
1271                 }
1272                 _ => None,
1273             });
1274 
1275             let mut generics = clean_ty_generics(
1276                 cx,
1277                 tcx.generics_of(assoc_item.def_id),
1278                 tcx.explicit_predicates_of(assoc_item.def_id),
1279             );
1280             // FIXME: This does not place parameters in source order (late-bound ones come last)
1281             generics.params.extend(late_bound_regions);
1282 
1283             let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(assoc_item.def_id), sig);
1284 
1285             if assoc_item.fn_has_self_parameter {
1286                 let self_ty = match assoc_item.container {
1287                     ty::ImplContainer => tcx.type_of(assoc_item.container_id(tcx)).subst_identity(),
1288                     ty::TraitContainer => tcx.types.self_param,
1289                 };
1290                 let self_arg_ty = sig.input(0).skip_binder();
1291                 if self_arg_ty == self_ty {
1292                     decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
1293                 } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
1294                     if ty == self_ty {
1295                         match decl.inputs.values[0].type_ {
1296                             BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper),
1297                             _ => unreachable!(),
1298                         }
1299                     }
1300                 }
1301             }
1302 
1303             let provided = match assoc_item.container {
1304                 ty::ImplContainer => true,
1305                 ty::TraitContainer => assoc_item.defaultness(tcx).has_value(),
1306             };
1307             if provided {
1308                 let defaultness = match assoc_item.container {
1309                     ty::ImplContainer => Some(assoc_item.defaultness(tcx)),
1310                     ty::TraitContainer => None,
1311                 };
1312                 MethodItem(Box::new(Function { generics, decl }), defaultness)
1313             } else {
1314                 TyMethodItem(Box::new(Function { generics, decl }))
1315             }
1316         }
1317         ty::AssocKind::Type => {
1318             let my_name = assoc_item.name;
1319 
1320             fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
1321                 match (&param.kind, arg) {
1322                     (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty)))
1323                         if *ty == param.name =>
1324                     {
1325                         true
1326                     }
1327                     (GenericParamDefKind::Lifetime { .. }, GenericArg::Lifetime(Lifetime(lt)))
1328                         if *lt == param.name =>
1329                     {
1330                         true
1331                     }
1332                     (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &c.kind {
1333                         ConstantKind::TyConst { expr } => **expr == *param.name.as_str(),
1334                         _ => false,
1335                     },
1336                     _ => false,
1337                 }
1338             }
1339 
1340             let mut predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates;
1341             if let ty::TraitContainer = assoc_item.container {
1342                 let bounds =
1343                     tcx.explicit_item_bounds(assoc_item.def_id).subst_identity_iter_copied();
1344                 predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied()));
1345             }
1346             let mut generics = clean_ty_generics(
1347                 cx,
1348                 tcx.generics_of(assoc_item.def_id),
1349                 ty::GenericPredicates { parent: None, predicates },
1350             );
1351             // Move bounds that are (likely) directly attached to the parameters of the
1352             // (generic) associated type from the where clause to the respective parameter.
1353             // There is no guarantee that this is what the user actually wrote but we have
1354             // no way of knowing.
1355             let mut where_predicates = ThinVec::new();
1356             for mut pred in generics.where_predicates {
1357                 if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
1358                     && let Some(GenericParamDef {
1359                         kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
1360                         ..
1361                     }) = generics.params.iter_mut().find(|param| &param.name == arg)
1362                 {
1363                     param_bounds.append(bounds);
1364                 } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
1365                     && let Some(GenericParamDef {
1366                         kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
1367                         ..
1368                     }) = generics.params.iter_mut().find(|param| &param.name == arg)
1369                 {
1370                     param_bounds.extend(bounds.drain(..).map(|bound| match bound {
1371                         GenericBound::Outlives(lifetime) => lifetime,
1372                         _ => unreachable!(),
1373                     }));
1374                 } else {
1375                     where_predicates.push(pred);
1376                 }
1377             }
1378             generics.where_predicates = where_predicates;
1379 
1380             if let ty::TraitContainer = assoc_item.container {
1381                 // Move bounds that are (likely) directly attached to the associated type
1382                 // from the where-clause to the associated type.
1383                 // There is no guarantee that this is what the user actually wrote but we have
1384                 // no way of knowing.
1385                 let mut bounds: Vec<GenericBound> = Vec::new();
1386                 generics.where_predicates.retain_mut(|pred| match *pred {
1387                     WherePredicate::BoundPredicate {
1388                         ty:
1389                             QPath(box QPathData {
1390                                 ref assoc,
1391                                 ref self_type,
1392                                 trait_: Some(ref trait_),
1393                                 ..
1394                             }),
1395                         bounds: ref mut pred_bounds,
1396                         ..
1397                     } => {
1398                         if assoc.name != my_name {
1399                             return true;
1400                         }
1401                         if trait_.def_id() != assoc_item.container_id(tcx) {
1402                             return true;
1403                         }
1404                         match *self_type {
1405                             Generic(ref s) if *s == kw::SelfUpper => {}
1406                             _ => return true,
1407                         }
1408                         match &assoc.args {
1409                             GenericArgs::AngleBracketed { args, bindings } => {
1410                                 if !bindings.is_empty()
1411                                     || generics
1412                                         .params
1413                                         .iter()
1414                                         .zip(args.iter())
1415                                         .any(|(param, arg)| !param_eq_arg(param, arg))
1416                                 {
1417                                     return true;
1418                                 }
1419                             }
1420                             GenericArgs::Parenthesized { .. } => {
1421                                 // The only time this happens is if we're inside the rustdoc for Fn(),
1422                                 // which only has one associated type, which is not a GAT, so whatever.
1423                             }
1424                         }
1425                         bounds.extend(mem::replace(pred_bounds, Vec::new()));
1426                         false
1427                     }
1428                     _ => true,
1429                 });
1430                 // Our Sized/?Sized bound didn't get handled when creating the generics
1431                 // because we didn't actually get our whole set of bounds until just now
1432                 // (some of them may have come from the trait). If we do have a sized
1433                 // bound, we remove it, and if we don't then we add the `?Sized` bound
1434                 // at the end.
1435                 match bounds.iter().position(|b| b.is_sized_bound(cx)) {
1436                     Some(i) => {
1437                         bounds.remove(i);
1438                     }
1439                     None => bounds.push(GenericBound::maybe_sized(cx)),
1440                 }
1441 
1442                 if tcx.defaultness(assoc_item.def_id).has_value() {
1443                     AssocTypeItem(
1444                         Box::new(Typedef {
1445                             type_: clean_middle_ty(
1446                                 ty::Binder::dummy(tcx.type_of(assoc_item.def_id).subst_identity()),
1447                                 cx,
1448                                 Some(assoc_item.def_id),
1449                                 None,
1450                             ),
1451                             generics,
1452                             item_type: None,
1453                         }),
1454                         bounds,
1455                     )
1456                 } else {
1457                     TyAssocTypeItem(generics, bounds)
1458                 }
1459             } else {
1460                 AssocTypeItem(
1461                     Box::new(Typedef {
1462                         type_: clean_middle_ty(
1463                             ty::Binder::dummy(tcx.type_of(assoc_item.def_id).subst_identity()),
1464                             cx,
1465                             Some(assoc_item.def_id),
1466                             None,
1467                         ),
1468                         generics,
1469                         item_type: None,
1470                     }),
1471                     // Associated types inside trait or inherent impls are not allowed to have
1472                     // item bounds. Thus we don't attempt to move any bounds there.
1473                     Vec::new(),
1474                 )
1475             }
1476         }
1477     };
1478 
1479     Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx)
1480 }
1481 
clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type1482 fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
1483     let hir::Ty { hir_id: _, span, ref kind } = *hir_ty;
1484     let hir::TyKind::Path(qpath) = kind else { unreachable!() };
1485 
1486     match qpath {
1487         hir::QPath::Resolved(None, path) => {
1488             if let Res::Def(DefKind::TyParam, did) = path.res {
1489                 if let Some(new_ty) = cx.substs.get(&did).and_then(|p| p.as_ty()).cloned() {
1490                     return new_ty;
1491                 }
1492                 if let Some(bounds) = cx.impl_trait_bounds.remove(&did.into()) {
1493                     return ImplTrait(bounds);
1494                 }
1495             }
1496 
1497             if let Some(expanded) = maybe_expand_private_type_alias(cx, path) {
1498                 expanded
1499             } else {
1500                 let path = clean_path(path, cx);
1501                 resolve_type(cx, path)
1502             }
1503         }
1504         hir::QPath::Resolved(Some(qself), p) => {
1505             // Try to normalize `<X as Y>::T` to a type
1506             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
1507             // `hir_to_ty` can return projection types with escaping vars for GATs, e.g. `<() as Trait>::Gat<'_>`
1508             if !ty.has_escaping_bound_vars()
1509                 && let Some(normalized_value) = normalize(cx, ty::Binder::dummy(ty))
1510             {
1511                 return clean_middle_ty(normalized_value, cx, None, None);
1512             }
1513 
1514             let trait_segments = &p.segments[..p.segments.len() - 1];
1515             let trait_def = cx.tcx.associated_item(p.res.def_id()).container_id(cx.tcx);
1516             let trait_ = self::Path {
1517                 res: Res::Def(DefKind::Trait, trait_def),
1518                 segments: trait_segments.iter().map(|x| clean_path_segment(x, cx)).collect(),
1519             };
1520             register_res(cx, trait_.res);
1521             let self_def_id = DefId::local(qself.hir_id.owner.def_id.local_def_index);
1522             let self_type = clean_ty(qself, cx);
1523             let should_show_cast = compute_should_show_cast(Some(self_def_id), &trait_, &self_type);
1524             Type::QPath(Box::new(QPathData {
1525                 assoc: clean_path_segment(p.segments.last().expect("segments were empty"), cx),
1526                 should_show_cast,
1527                 self_type,
1528                 trait_: Some(trait_),
1529             }))
1530         }
1531         hir::QPath::TypeRelative(qself, segment) => {
1532             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
1533             let self_type = clean_ty(qself, cx);
1534 
1535             let (trait_, should_show_cast) = match ty.kind() {
1536                 ty::Alias(ty::Projection, proj) => {
1537                     let res = Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id);
1538                     let trait_ = clean_path(&hir::Path { span, res, segments: &[] }, cx);
1539                     register_res(cx, trait_.res);
1540                     let self_def_id = res.opt_def_id();
1541                     let should_show_cast =
1542                         compute_should_show_cast(self_def_id, &trait_, &self_type);
1543 
1544                     (Some(trait_), should_show_cast)
1545                 }
1546                 ty::Alias(ty::Inherent, _) => (None, false),
1547                 // Rustdoc handles `ty::Error`s by turning them into `Type::Infer`s.
1548                 ty::Error(_) => return Type::Infer,
1549                 _ => bug!("clean: expected associated type, found `{ty:?}`"),
1550             };
1551 
1552             Type::QPath(Box::new(QPathData {
1553                 assoc: clean_path_segment(segment, cx),
1554                 should_show_cast,
1555                 self_type,
1556                 trait_,
1557             }))
1558         }
1559         hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"),
1560     }
1561 }
1562 
maybe_expand_private_type_alias<'tcx>( cx: &mut DocContext<'tcx>, path: &hir::Path<'tcx>, ) -> Option<Type>1563 fn maybe_expand_private_type_alias<'tcx>(
1564     cx: &mut DocContext<'tcx>,
1565     path: &hir::Path<'tcx>,
1566 ) -> Option<Type> {
1567     let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
1568     // Substitute private type aliases
1569     let def_id = def_id.as_local()?;
1570     let alias = if !cx.cache.effective_visibilities.is_exported(cx.tcx, def_id.to_def_id())
1571         && !cx.current_type_aliases.contains_key(&def_id.to_def_id())
1572     {
1573         &cx.tcx.hir().expect_item(def_id).kind
1574     } else {
1575         return None;
1576     };
1577     let hir::ItemKind::TyAlias(ty, generics) = alias else { return None };
1578 
1579     let provided_params = &path.segments.last().expect("segments were empty");
1580     let mut substs = DefIdMap::default();
1581     let generic_args = provided_params.args();
1582 
1583     let mut indices: hir::GenericParamCount = Default::default();
1584     for param in generics.params.iter() {
1585         match param.kind {
1586             hir::GenericParamKind::Lifetime { .. } => {
1587                 let mut j = 0;
1588                 let lifetime = generic_args.args.iter().find_map(|arg| match arg {
1589                     hir::GenericArg::Lifetime(lt) => {
1590                         if indices.lifetimes == j {
1591                             return Some(lt);
1592                         }
1593                         j += 1;
1594                         None
1595                     }
1596                     _ => None,
1597                 });
1598                 if let Some(lt) = lifetime {
1599                     let cleaned = if !lt.is_anonymous() {
1600                         clean_lifetime(lt, cx)
1601                     } else {
1602                         Lifetime::elided()
1603                     };
1604                     substs.insert(param.def_id.to_def_id(), SubstParam::Lifetime(cleaned));
1605                 }
1606                 indices.lifetimes += 1;
1607             }
1608             hir::GenericParamKind::Type { ref default, .. } => {
1609                 let mut j = 0;
1610                 let type_ = generic_args.args.iter().find_map(|arg| match arg {
1611                     hir::GenericArg::Type(ty) => {
1612                         if indices.types == j {
1613                             return Some(ty);
1614                         }
1615                         j += 1;
1616                         None
1617                     }
1618                     _ => None,
1619                 });
1620                 if let Some(ty) = type_ {
1621                     substs.insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(ty, cx)));
1622                 } else if let Some(default) = *default {
1623                     substs
1624                         .insert(param.def_id.to_def_id(), SubstParam::Type(clean_ty(default, cx)));
1625                 }
1626                 indices.types += 1;
1627             }
1628             hir::GenericParamKind::Const { .. } => {
1629                 let mut j = 0;
1630                 let const_ = generic_args.args.iter().find_map(|arg| match arg {
1631                     hir::GenericArg::Const(ct) => {
1632                         if indices.consts == j {
1633                             return Some(ct);
1634                         }
1635                         j += 1;
1636                         None
1637                     }
1638                     _ => None,
1639                 });
1640                 if let Some(ct) = const_ {
1641                     substs.insert(
1642                         param.def_id.to_def_id(),
1643                         SubstParam::Constant(clean_const(ct, cx)),
1644                     );
1645                 }
1646                 // FIXME(const_generics_defaults)
1647                 indices.consts += 1;
1648             }
1649         }
1650     }
1651 
1652     Some(cx.enter_alias(substs, def_id.to_def_id(), |cx| clean_ty(ty, cx)))
1653 }
1654 
clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type1655 pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
1656     use rustc_hir::*;
1657 
1658     match ty.kind {
1659         TyKind::Never => Primitive(PrimitiveType::Never),
1660         TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(clean_ty(m.ty, cx))),
1661         TyKind::Ref(ref l, ref m) => {
1662             let lifetime = if l.is_anonymous() { None } else { Some(clean_lifetime(*l, cx)) };
1663             BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) }
1664         }
1665         TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
1666         TyKind::Array(ty, ref length) => {
1667             let length = match length {
1668                 hir::ArrayLen::Infer(_, _) => "_".to_string(),
1669                 hir::ArrayLen::Body(anon_const) => {
1670                     // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
1671                     // as we currently do not supply the parent generics to anonymous constants
1672                     // but do allow `ConstKind::Param`.
1673                     //
1674                     // `const_eval_poly` tries to first substitute generic parameters which
1675                     // results in an ICE while manually constructing the constant and using `eval`
1676                     // does nothing for `ConstKind::Param`.
1677                     let ct = ty::Const::from_anon_const(cx.tcx, anon_const.def_id);
1678                     let param_env = cx.tcx.param_env(anon_const.def_id);
1679                     print_const(cx, ct.eval(cx.tcx, param_env))
1680                 }
1681             };
1682 
1683             Array(Box::new(clean_ty(ty, cx)), length.into())
1684         }
1685         TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
1686         TyKind::OpaqueDef(item_id, _, _) => {
1687             let item = cx.tcx.hir().item(item_id);
1688             if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
1689                 ImplTrait(ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect())
1690             } else {
1691                 unreachable!()
1692             }
1693         }
1694         TyKind::Path(_) => clean_qpath(ty, cx),
1695         TyKind::TraitObject(bounds, ref lifetime, _) => {
1696             let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect();
1697             let lifetime =
1698                 if !lifetime.is_elided() { Some(clean_lifetime(*lifetime, cx)) } else { None };
1699             DynTrait(bounds, lifetime)
1700         }
1701         TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
1702         // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
1703         TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) => Infer,
1704     }
1705 }
1706 
1707 /// Returns `None` if the type could not be normalized
normalize<'tcx>( cx: &mut DocContext<'tcx>, ty: ty::Binder<'tcx, Ty<'tcx>>, ) -> Option<ty::Binder<'tcx, Ty<'tcx>>>1708 fn normalize<'tcx>(
1709     cx: &mut DocContext<'tcx>,
1710     ty: ty::Binder<'tcx, Ty<'tcx>>,
1711 ) -> Option<ty::Binder<'tcx, Ty<'tcx>>> {
1712     // HACK: low-churn fix for #79459 while we wait for a trait normalization fix
1713     if !cx.tcx.sess.opts.unstable_opts.normalize_docs {
1714         return None;
1715     }
1716 
1717     use crate::rustc_trait_selection::infer::TyCtxtInferExt;
1718     use crate::rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
1719     use rustc_middle::traits::ObligationCause;
1720 
1721     // Try to normalize `<X as Y>::T` to a type
1722     let infcx = cx.tcx.infer_ctxt().build();
1723     let normalized = infcx
1724         .at(&ObligationCause::dummy(), cx.param_env)
1725         .query_normalize(ty)
1726         .map(|resolved| infcx.resolve_vars_if_possible(resolved.value));
1727     match normalized {
1728         Ok(normalized_value) => {
1729             debug!("normalized {:?} to {:?}", ty, normalized_value);
1730             Some(normalized_value)
1731         }
1732         Err(err) => {
1733             debug!("failed to normalize {:?}: {:?}", ty, err);
1734             None
1735         }
1736     }
1737 }
1738 
clean_trait_object_lifetime_bound<'tcx>( region: ty::Region<'tcx>, container: Option<ContainerTy<'tcx>>, preds: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, tcx: TyCtxt<'tcx>, ) -> Option<Lifetime>1739 fn clean_trait_object_lifetime_bound<'tcx>(
1740     region: ty::Region<'tcx>,
1741     container: Option<ContainerTy<'tcx>>,
1742     preds: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
1743     tcx: TyCtxt<'tcx>,
1744 ) -> Option<Lifetime> {
1745     if can_elide_trait_object_lifetime_bound(region, container, preds, tcx) {
1746         return None;
1747     }
1748 
1749     // Since there is a semantic difference between an implicitly elided (i.e. "defaulted") object
1750     // lifetime and an explicitly elided object lifetime (`'_`), we intentionally don't hide the
1751     // latter contrary to `clean_middle_region`.
1752     match *region {
1753         ty::ReStatic => Some(Lifetime::statik()),
1754         ty::ReEarlyBound(region) if region.name != kw::Empty => Some(Lifetime(region.name)),
1755         ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. })
1756             if name != kw::Empty =>
1757         {
1758             Some(Lifetime(name))
1759         }
1760         ty::ReEarlyBound(_)
1761         | ty::ReLateBound(..)
1762         | ty::ReFree(_)
1763         | ty::ReVar(_)
1764         | ty::RePlaceholder(_)
1765         | ty::ReErased
1766         | ty::ReError(_) => None,
1767     }
1768 }
1769 
can_elide_trait_object_lifetime_bound<'tcx>( region: ty::Region<'tcx>, container: Option<ContainerTy<'tcx>>, preds: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, tcx: TyCtxt<'tcx>, ) -> bool1770 fn can_elide_trait_object_lifetime_bound<'tcx>(
1771     region: ty::Region<'tcx>,
1772     container: Option<ContainerTy<'tcx>>,
1773     preds: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
1774     tcx: TyCtxt<'tcx>,
1775 ) -> bool {
1776     // Below we quote extracts from https://doc.rust-lang.org/reference/lifetime-elision.html#default-trait-object-lifetimes
1777 
1778     // > If the trait object is used as a type argument of a generic type then the containing type is
1779     // > first used to try to infer a bound.
1780     let default = container
1781         .map_or(ObjectLifetimeDefault::Empty, |container| container.object_lifetime_default(tcx));
1782 
1783     // > If there is a unique bound from the containing type then that is the default
1784     // If there is a default object lifetime and the given region is lexically equal to it, elide it.
1785     match default {
1786         ObjectLifetimeDefault::Static => return *region == ty::ReStatic,
1787         // FIXME(fmease): Don't compare lexically but respect de Bruijn indices etc. to handle shadowing correctly.
1788         ObjectLifetimeDefault::Arg(default) => return region.get_name() == default.get_name(),
1789         // > If there is more than one bound from the containing type then an explicit bound must be specified
1790         // Due to ambiguity there is no default trait-object lifetime and thus elision is impossible.
1791         // Don't elide the lifetime.
1792         ObjectLifetimeDefault::Ambiguous => return false,
1793         // There is no meaningful bound. Further processing is needed...
1794         ObjectLifetimeDefault::Empty => {}
1795     }
1796 
1797     // > If neither of those rules apply, then the bounds on the trait are used:
1798     match *object_region_bounds(tcx, preds) {
1799         // > If the trait has no lifetime bounds, then the lifetime is inferred in expressions
1800         // > and is 'static outside of expressions.
1801         // FIXME: If we are in an expression context (i.e. fn bodies and const exprs) then the default is
1802         // `'_` and not `'static`. Only if we are in a non-expression one, the default is `'static`.
1803         // Note however that at the time of this writing it should be fine to disregard this subtlety
1804         // as we neither render const exprs faithfully anyway (hiding them in some places or using `_` instead)
1805         // nor show the contents of fn bodies.
1806         [] => *region == ty::ReStatic,
1807         // > If the trait is defined with a single lifetime bound then that bound is used.
1808         // > If 'static is used for any lifetime bound then 'static is used.
1809         // FIXME(fmease): Don't compare lexically but respect de Bruijn indices etc. to handle shadowing correctly.
1810         [object_region] => object_region.get_name() == region.get_name(),
1811         // There are several distinct trait regions and none are `'static`.
1812         // Due to ambiguity there is no default trait-object lifetime and thus elision is impossible.
1813         // Don't elide the lifetime.
1814         _ => false,
1815     }
1816 }
1817 
1818 #[derive(Debug)]
1819 pub(crate) enum ContainerTy<'tcx> {
1820     Ref(ty::Region<'tcx>),
1821     Regular { ty: DefId, substs: ty::Binder<'tcx, &'tcx [ty::GenericArg<'tcx>]>, arg: usize },
1822 }
1823 
1824 impl<'tcx> ContainerTy<'tcx> {
object_lifetime_default(self, tcx: TyCtxt<'tcx>) -> ObjectLifetimeDefault<'tcx>1825     fn object_lifetime_default(self, tcx: TyCtxt<'tcx>) -> ObjectLifetimeDefault<'tcx> {
1826         match self {
1827             Self::Ref(region) => ObjectLifetimeDefault::Arg(region),
1828             Self::Regular { ty: container, substs, arg: index } => {
1829                 let (DefKind::Struct
1830                 | DefKind::Union
1831                 | DefKind::Enum
1832                 | DefKind::TyAlias
1833                 | DefKind::Trait
1834                 | DefKind::AssocTy
1835                 | DefKind::Variant) = tcx.def_kind(container)
1836                 else {
1837                     return ObjectLifetimeDefault::Empty;
1838                 };
1839 
1840                 let generics = tcx.generics_of(container);
1841                 let param = generics.params[index].def_id;
1842                 let default = tcx.object_lifetime_default(param);
1843 
1844                 match default {
1845                     rbv::ObjectLifetimeDefault::Param(lifetime) => {
1846                         let index = generics.param_def_id_to_index[&lifetime];
1847                         let arg = substs.skip_binder()[index as usize].expect_region();
1848                         ObjectLifetimeDefault::Arg(arg)
1849                     }
1850                     rbv::ObjectLifetimeDefault::Empty => ObjectLifetimeDefault::Empty,
1851                     rbv::ObjectLifetimeDefault::Static => ObjectLifetimeDefault::Static,
1852                     rbv::ObjectLifetimeDefault::Ambiguous => ObjectLifetimeDefault::Ambiguous,
1853                 }
1854             }
1855         }
1856     }
1857 }
1858 
1859 #[derive(Debug, Clone, Copy)]
1860 pub(crate) enum ObjectLifetimeDefault<'tcx> {
1861     Empty,
1862     Static,
1863     Ambiguous,
1864     Arg(ty::Region<'tcx>),
1865 }
1866 
1867 #[instrument(level = "trace", skip(cx), ret)]
clean_middle_ty<'tcx>( bound_ty: ty::Binder<'tcx, Ty<'tcx>>, cx: &mut DocContext<'tcx>, parent_def_id: Option<DefId>, container: Option<ContainerTy<'tcx>>, ) -> Type1868 pub(crate) fn clean_middle_ty<'tcx>(
1869     bound_ty: ty::Binder<'tcx, Ty<'tcx>>,
1870     cx: &mut DocContext<'tcx>,
1871     parent_def_id: Option<DefId>,
1872     container: Option<ContainerTy<'tcx>>,
1873 ) -> Type {
1874     let bound_ty = normalize(cx, bound_ty).unwrap_or(bound_ty);
1875     match *bound_ty.skip_binder().kind() {
1876         ty::Never => Primitive(PrimitiveType::Never),
1877         ty::Bool => Primitive(PrimitiveType::Bool),
1878         ty::Char => Primitive(PrimitiveType::Char),
1879         ty::Int(int_ty) => Primitive(int_ty.into()),
1880         ty::Uint(uint_ty) => Primitive(uint_ty.into()),
1881         ty::Float(float_ty) => Primitive(float_ty.into()),
1882         ty::Str => Primitive(PrimitiveType::Str),
1883         ty::Slice(ty) => Slice(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None))),
1884         ty::Array(ty, mut n) => {
1885             n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
1886             let n = print_const(cx, n);
1887             Array(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), n.into())
1888         }
1889         ty::RawPtr(mt) => {
1890             RawPointer(mt.mutbl, Box::new(clean_middle_ty(bound_ty.rebind(mt.ty), cx, None, None)))
1891         }
1892         ty::Ref(r, ty, mutbl) => BorrowedRef {
1893             lifetime: clean_middle_region(r),
1894             mutability: mutbl,
1895             type_: Box::new(clean_middle_ty(
1896                 bound_ty.rebind(ty),
1897                 cx,
1898                 None,
1899                 Some(ContainerTy::Ref(r)),
1900             )),
1901         },
1902         ty::FnDef(..) | ty::FnPtr(_) => {
1903             // FIXME: should we merge the outer and inner binders somehow?
1904             let sig = bound_ty.skip_binder().fn_sig(cx.tcx);
1905             let decl = clean_fn_decl_from_did_and_sig(cx, None, sig);
1906             BareFunction(Box::new(BareFunctionDecl {
1907                 unsafety: sig.unsafety(),
1908                 generic_params: Vec::new(),
1909                 decl,
1910                 abi: sig.abi(),
1911             }))
1912         }
1913         ty::Adt(def, substs) => {
1914             let did = def.did();
1915             let kind = match def.adt_kind() {
1916                 AdtKind::Struct => ItemType::Struct,
1917                 AdtKind::Union => ItemType::Union,
1918                 AdtKind::Enum => ItemType::Enum,
1919             };
1920             inline::record_extern_fqn(cx, did, kind);
1921             let path = external_path(cx, did, false, ThinVec::new(), bound_ty.rebind(substs));
1922             Type::Path { path }
1923         }
1924         ty::Foreign(did) => {
1925             inline::record_extern_fqn(cx, did, ItemType::ForeignType);
1926             let path = external_path(
1927                 cx,
1928                 did,
1929                 false,
1930                 ThinVec::new(),
1931                 ty::Binder::dummy(InternalSubsts::empty()),
1932             );
1933             Type::Path { path }
1934         }
1935         ty::Dynamic(obj, ref reg, _) => {
1936             // HACK: pick the first `did` as the `did` of the trait object. Someone
1937             // might want to implement "native" support for marker-trait-only
1938             // trait objects.
1939             let mut dids = obj.auto_traits();
1940             let did = obj
1941                 .principal_def_id()
1942                 .or_else(|| dids.next())
1943                 .unwrap_or_else(|| panic!("found trait object `{bound_ty:?}` with no traits?"));
1944             let substs = match obj.principal() {
1945                 Some(principal) => principal.map_bound(|p| p.substs),
1946                 // marker traits have no substs.
1947                 _ => ty::Binder::dummy(InternalSubsts::empty()),
1948             };
1949 
1950             inline::record_extern_fqn(cx, did, ItemType::Trait);
1951 
1952             let lifetime = clean_trait_object_lifetime_bound(*reg, container, obj, cx.tcx);
1953 
1954             let mut bounds = dids
1955                 .map(|did| {
1956                     let empty = ty::Binder::dummy(InternalSubsts::empty());
1957                     let path = external_path(cx, did, false, ThinVec::new(), empty);
1958                     inline::record_extern_fqn(cx, did, ItemType::Trait);
1959                     PolyTrait { trait_: path, generic_params: Vec::new() }
1960                 })
1961                 .collect::<Vec<_>>();
1962 
1963             let bindings = obj
1964                 .projection_bounds()
1965                 .map(|pb| TypeBinding {
1966                     assoc: projection_to_path_segment(
1967                         pb.map_bound(|pb| {
1968                             pb
1969                                 // HACK(compiler-errors): Doesn't actually matter what self
1970                                 // type we put here, because we're only using the GAT's substs.
1971                                 .with_self_ty(cx.tcx, cx.tcx.types.self_param)
1972                                 .projection_ty
1973                         }),
1974                         cx,
1975                     ),
1976                     kind: TypeBindingKind::Equality {
1977                         term: clean_middle_term(pb.map_bound(|pb| pb.term), cx),
1978                     },
1979                 })
1980                 .collect();
1981 
1982             let late_bound_regions: FxIndexSet<_> = obj
1983                 .iter()
1984                 .flat_map(|pb| pb.bound_vars())
1985                 .filter_map(|br| match br {
1986                     ty::BoundVariableKind::Region(ty::BrNamed(_, name))
1987                         if name != kw::UnderscoreLifetime =>
1988                     {
1989                         Some(GenericParamDef::lifetime(name))
1990                     }
1991                     _ => None,
1992                 })
1993                 .collect();
1994             let late_bound_regions = late_bound_regions.into_iter().collect();
1995 
1996             let path = external_path(cx, did, false, bindings, substs);
1997             bounds.insert(0, PolyTrait { trait_: path, generic_params: late_bound_regions });
1998 
1999             DynTrait(bounds, lifetime)
2000         }
2001         ty::Tuple(t) => {
2002             Tuple(t.iter().map(|t| clean_middle_ty(bound_ty.rebind(t), cx, None, None)).collect())
2003         }
2004 
2005         ty::Alias(ty::Projection, data) => {
2006             clean_projection(bound_ty.rebind(data), cx, parent_def_id)
2007         }
2008 
2009         ty::Alias(ty::Inherent, alias_ty) => {
2010             let alias_ty = bound_ty.rebind(alias_ty);
2011             let self_type = clean_middle_ty(alias_ty.map_bound(|ty| ty.self_ty()), cx, None, None);
2012 
2013             Type::QPath(Box::new(QPathData {
2014                 assoc: PathSegment {
2015                     name: cx.tcx.associated_item(alias_ty.skip_binder().def_id).name,
2016                     args: GenericArgs::AngleBracketed {
2017                         args: substs_to_args(
2018                             cx,
2019                             alias_ty.map_bound(|ty| ty.substs.as_slice()),
2020                             true,
2021                             None,
2022                         )
2023                         .into(),
2024                         bindings: Default::default(),
2025                     },
2026                 },
2027                 should_show_cast: false,
2028                 self_type,
2029                 trait_: None,
2030             }))
2031         }
2032 
2033         ty::Alias(ty::Weak, data) => {
2034             if cx.tcx.features().lazy_type_alias {
2035                 // Weak type alias `data` represents the `type X` in `type X = Y`. If we need `Y`,
2036                 // we need to use `type_of`.
2037                 let path = external_path(
2038                     cx,
2039                     data.def_id,
2040                     false,
2041                     ThinVec::new(),
2042                     bound_ty.rebind(data.substs),
2043                 );
2044                 Type::Path { path }
2045             } else {
2046                 let ty = cx.tcx.type_of(data.def_id).subst(cx.tcx, data.substs);
2047                 clean_middle_ty(bound_ty.rebind(ty), cx, None, None)
2048             }
2049         }
2050 
2051         ty::Param(ref p) => {
2052             if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
2053                 ImplTrait(bounds)
2054             } else {
2055                 Generic(p.name)
2056             }
2057         }
2058 
2059         ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
2060             // If it's already in the same alias, don't get an infinite loop.
2061             if cx.current_type_aliases.contains_key(&def_id) {
2062                 let path =
2063                     external_path(cx, def_id, false, ThinVec::new(), bound_ty.rebind(substs));
2064                 Type::Path { path }
2065             } else {
2066                 *cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
2067                 // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
2068                 // by looking up the bounds associated with the def_id.
2069                 let bounds = cx
2070                     .tcx
2071                     .explicit_item_bounds(def_id)
2072                     .subst_iter_copied(cx.tcx, substs)
2073                     .map(|(bound, _)| bound)
2074                     .collect::<Vec<_>>();
2075                 let ty = clean_middle_opaque_bounds(cx, bounds);
2076                 if let Some(count) = cx.current_type_aliases.get_mut(&def_id) {
2077                     *count -= 1;
2078                     if *count == 0 {
2079                         cx.current_type_aliases.remove(&def_id);
2080                     }
2081                 }
2082                 ty
2083             }
2084         }
2085 
2086         ty::Closure(..) => panic!("Closure"),
2087         ty::Generator(..) => panic!("Generator"),
2088         ty::Bound(..) => panic!("Bound"),
2089         ty::Placeholder(..) => panic!("Placeholder"),
2090         ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
2091         ty::GeneratorWitnessMIR(..) => panic!("GeneratorWitnessMIR"),
2092         ty::Infer(..) => panic!("Infer"),
2093         ty::Error(_) => rustc_errors::FatalError.raise(),
2094     }
2095 }
2096 
clean_middle_opaque_bounds<'tcx>( cx: &mut DocContext<'tcx>, bounds: Vec<ty::Clause<'tcx>>, ) -> Type2097 fn clean_middle_opaque_bounds<'tcx>(
2098     cx: &mut DocContext<'tcx>,
2099     bounds: Vec<ty::Clause<'tcx>>,
2100 ) -> Type {
2101     let mut regions = vec![];
2102     let mut has_sized = false;
2103     let mut bounds = bounds
2104         .iter()
2105         .filter_map(|bound| {
2106             let bound_predicate = bound.kind();
2107             let trait_ref = match bound_predicate.skip_binder() {
2108                 ty::ClauseKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
2109                 ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
2110                     if let Some(r) = clean_middle_region(reg) {
2111                         regions.push(GenericBound::Outlives(r));
2112                     }
2113                     return None;
2114                 }
2115                 _ => return None,
2116             };
2117 
2118             if let Some(sized) = cx.tcx.lang_items().sized_trait() && trait_ref.def_id() == sized {
2119                 has_sized = true;
2120                 return None;
2121             }
2122 
2123             let bindings: ThinVec<_> = bounds
2124                 .iter()
2125                 .filter_map(|bound| {
2126                     if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder() {
2127                         if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
2128                             Some(TypeBinding {
2129                                 assoc: projection_to_path_segment(
2130                                     bound.kind().rebind(proj.projection_ty),
2131                                     cx,
2132                                 ),
2133                                 kind: TypeBindingKind::Equality {
2134                                     term: clean_middle_term(bound.kind().rebind(proj.term), cx),
2135                                 },
2136                             })
2137                         } else {
2138                             None
2139                         }
2140                     } else {
2141                         None
2142                     }
2143                 })
2144                 .collect();
2145 
2146             Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings))
2147         })
2148         .collect::<Vec<_>>();
2149     bounds.extend(regions);
2150     if !has_sized && !bounds.is_empty() {
2151         bounds.insert(0, GenericBound::maybe_sized(cx));
2152     }
2153     ImplTrait(bounds)
2154 }
2155 
clean_field<'tcx>(field: &hir::FieldDef<'tcx>, cx: &mut DocContext<'tcx>) -> Item2156 pub(crate) fn clean_field<'tcx>(field: &hir::FieldDef<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
2157     clean_field_with_def_id(field.def_id.to_def_id(), field.ident.name, clean_ty(field.ty, cx), cx)
2158 }
2159 
clean_middle_field<'tcx>(field: &ty::FieldDef, cx: &mut DocContext<'tcx>) -> Item2160 pub(crate) fn clean_middle_field<'tcx>(field: &ty::FieldDef, cx: &mut DocContext<'tcx>) -> Item {
2161     clean_field_with_def_id(
2162         field.did,
2163         field.name,
2164         clean_middle_ty(
2165             ty::Binder::dummy(cx.tcx.type_of(field.did).subst_identity()),
2166             cx,
2167             Some(field.did),
2168             None,
2169         ),
2170         cx,
2171     )
2172 }
2173 
clean_field_with_def_id( def_id: DefId, name: Symbol, ty: Type, cx: &mut DocContext<'_>, ) -> Item2174 pub(crate) fn clean_field_with_def_id(
2175     def_id: DefId,
2176     name: Symbol,
2177     ty: Type,
2178     cx: &mut DocContext<'_>,
2179 ) -> Item {
2180     Item::from_def_id_and_parts(def_id, Some(name), StructFieldItem(ty), cx)
2181 }
2182 
clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item2183 pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item {
2184     let discriminant = match variant.discr {
2185         ty::VariantDiscr::Explicit(def_id) => Some(Discriminant { expr: None, value: def_id }),
2186         ty::VariantDiscr::Relative(_) => None,
2187     };
2188 
2189     let kind = match variant.ctor_kind() {
2190         Some(CtorKind::Const) => VariantKind::CLike,
2191         Some(CtorKind::Fn) => VariantKind::Tuple(
2192             variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
2193         ),
2194         None => VariantKind::Struct(VariantStruct {
2195             fields: variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
2196         }),
2197     };
2198 
2199     Item::from_def_id_and_parts(
2200         variant.def_id,
2201         Some(variant.name),
2202         VariantItem(Variant { kind, discriminant }),
2203         cx,
2204     )
2205 }
2206 
clean_variant_data<'tcx>( variant: &hir::VariantData<'tcx>, disr_expr: &Option<hir::AnonConst>, cx: &mut DocContext<'tcx>, ) -> Variant2207 fn clean_variant_data<'tcx>(
2208     variant: &hir::VariantData<'tcx>,
2209     disr_expr: &Option<hir::AnonConst>,
2210     cx: &mut DocContext<'tcx>,
2211 ) -> Variant {
2212     let discriminant = disr_expr
2213         .map(|disr| Discriminant { expr: Some(disr.body), value: disr.def_id.to_def_id() });
2214 
2215     let kind = match variant {
2216         hir::VariantData::Struct(..) => VariantKind::Struct(VariantStruct {
2217             fields: variant.fields().iter().map(|x| clean_field(x, cx)).collect(),
2218         }),
2219         hir::VariantData::Tuple(..) => {
2220             VariantKind::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
2221         }
2222         hir::VariantData::Unit(..) => VariantKind::CLike,
2223     };
2224 
2225     Variant { discriminant, kind }
2226 }
2227 
clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path2228 fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
2229     Path {
2230         res: path.res,
2231         segments: path.segments.iter().map(|x| clean_path_segment(x, cx)).collect(),
2232     }
2233 }
2234 
clean_generic_args<'tcx>( generic_args: &hir::GenericArgs<'tcx>, cx: &mut DocContext<'tcx>, ) -> GenericArgs2235 fn clean_generic_args<'tcx>(
2236     generic_args: &hir::GenericArgs<'tcx>,
2237     cx: &mut DocContext<'tcx>,
2238 ) -> GenericArgs {
2239     // FIXME(return_type_notation): Fix RTN parens rendering
2240     if generic_args.parenthesized == hir::GenericArgsParentheses::ParenSugar {
2241         let output = clean_ty(generic_args.bindings[0].ty(), cx);
2242         let output = if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
2243         let inputs =
2244             generic_args.inputs().iter().map(|x| clean_ty(x, cx)).collect::<Vec<_>>().into();
2245         GenericArgs::Parenthesized { inputs, output }
2246     } else {
2247         let args = generic_args
2248             .args
2249             .iter()
2250             .map(|arg| match arg {
2251                 hir::GenericArg::Lifetime(lt) if !lt.is_anonymous() => {
2252                     GenericArg::Lifetime(clean_lifetime(*lt, cx))
2253                 }
2254                 hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
2255                 hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
2256                 hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
2257                 hir::GenericArg::Infer(_inf) => GenericArg::Infer,
2258             })
2259             .collect::<Vec<_>>()
2260             .into();
2261         let bindings =
2262             generic_args.bindings.iter().map(|x| clean_type_binding(x, cx)).collect::<ThinVec<_>>();
2263         GenericArgs::AngleBracketed { args, bindings }
2264     }
2265 }
2266 
clean_path_segment<'tcx>( path: &hir::PathSegment<'tcx>, cx: &mut DocContext<'tcx>, ) -> PathSegment2267 fn clean_path_segment<'tcx>(
2268     path: &hir::PathSegment<'tcx>,
2269     cx: &mut DocContext<'tcx>,
2270 ) -> PathSegment {
2271     PathSegment { name: path.ident.name, args: clean_generic_args(path.args(), cx) }
2272 }
2273 
clean_bare_fn_ty<'tcx>( bare_fn: &hir::BareFnTy<'tcx>, cx: &mut DocContext<'tcx>, ) -> BareFunctionDecl2274 fn clean_bare_fn_ty<'tcx>(
2275     bare_fn: &hir::BareFnTy<'tcx>,
2276     cx: &mut DocContext<'tcx>,
2277 ) -> BareFunctionDecl {
2278     let (generic_params, decl) = enter_impl_trait(cx, |cx| {
2279         // NOTE: generics must be cleaned before args
2280         let generic_params = bare_fn
2281             .generic_params
2282             .iter()
2283             .filter(|p| !is_elided_lifetime(p))
2284             .map(|x| clean_generic_param(cx, None, x))
2285             .collect();
2286         let args = clean_args_from_types_and_names(cx, bare_fn.decl.inputs, bare_fn.param_names);
2287         let decl = clean_fn_decl_with_args(cx, bare_fn.decl, args);
2288         (generic_params, decl)
2289     });
2290     BareFunctionDecl { unsafety: bare_fn.unsafety, abi: bare_fn.abi, decl, generic_params }
2291 }
2292 
reexport_chain<'tcx>( tcx: TyCtxt<'tcx>, import_def_id: LocalDefId, target_def_id: LocalDefId, ) -> &'tcx [Reexport]2293 pub(crate) fn reexport_chain<'tcx>(
2294     tcx: TyCtxt<'tcx>,
2295     import_def_id: LocalDefId,
2296     target_def_id: LocalDefId,
2297 ) -> &'tcx [Reexport] {
2298     for child in tcx.module_children_local(tcx.local_parent(import_def_id)) {
2299         if child.res.opt_def_id() == Some(target_def_id.to_def_id())
2300             && child.reexport_chain.first().and_then(|r| r.id()) == Some(import_def_id.to_def_id())
2301         {
2302             return &child.reexport_chain;
2303         }
2304     }
2305     &[]
2306 }
2307 
2308 /// Collect attributes from the whole import chain.
get_all_import_attributes<'hir>( cx: &mut DocContext<'hir>, import_def_id: LocalDefId, target_def_id: LocalDefId, is_inline: bool, ) -> Vec<(Cow<'hir, ast::Attribute>, Option<DefId>)>2309 fn get_all_import_attributes<'hir>(
2310     cx: &mut DocContext<'hir>,
2311     import_def_id: LocalDefId,
2312     target_def_id: LocalDefId,
2313     is_inline: bool,
2314 ) -> Vec<(Cow<'hir, ast::Attribute>, Option<DefId>)> {
2315     let mut attrs = Vec::new();
2316     let mut first = true;
2317     for def_id in reexport_chain(cx.tcx, import_def_id, target_def_id)
2318         .iter()
2319         .flat_map(|reexport| reexport.id())
2320     {
2321         let import_attrs = inline::load_attrs(cx, def_id);
2322         if first {
2323             // This is the "original" reexport so we get all its attributes without filtering them.
2324             attrs = import_attrs.iter().map(|attr| (Cow::Borrowed(attr), Some(def_id))).collect();
2325             first = false;
2326         // We don't add attributes of an intermediate re-export if it has `#[doc(hidden)]`.
2327         } else if !cx.tcx.is_doc_hidden(def_id) {
2328             add_without_unwanted_attributes(&mut attrs, import_attrs, is_inline, Some(def_id));
2329         }
2330     }
2331     attrs
2332 }
2333 
filter_tokens_from_list( args_tokens: TokenStream, should_retain: impl Fn(&TokenTree) -> bool, ) -> Vec<TokenTree>2334 fn filter_tokens_from_list(
2335     args_tokens: TokenStream,
2336     should_retain: impl Fn(&TokenTree) -> bool,
2337 ) -> Vec<TokenTree> {
2338     let mut tokens = Vec::with_capacity(args_tokens.len());
2339     let mut skip_next_comma = false;
2340     for token in args_tokens.into_trees() {
2341         match token {
2342             TokenTree::Token(Token { kind: TokenKind::Comma, .. }, _) if skip_next_comma => {
2343                 skip_next_comma = false;
2344             }
2345             token if should_retain(&token) => {
2346                 skip_next_comma = false;
2347                 tokens.push(token);
2348             }
2349             _ => {
2350                 skip_next_comma = true;
2351             }
2352         }
2353     }
2354     tokens
2355 }
2356 
2357 /// When inlining items, we merge their attributes (and all the reexports attributes too) with the
2358 /// final reexport. For example:
2359 ///
2360 /// ```ignore (just an example)
2361 /// #[doc(hidden, cfg(feature = "foo"))]
2362 /// pub struct Foo;
2363 ///
2364 /// #[doc(cfg(feature = "bar"))]
2365 /// #[doc(hidden, no_inline)]
2366 /// pub use Foo as Foo1;
2367 ///
2368 /// #[doc(inline)]
2369 /// pub use Foo2 as Bar;
2370 /// ```
2371 ///
2372 /// So `Bar` at the end will have both `cfg(feature = "...")`. However, we don't want to merge all
2373 /// attributes so we filter out the following ones:
2374 /// * `doc(inline)`
2375 /// * `doc(no_inline)`
2376 /// * `doc(hidden)`
add_without_unwanted_attributes<'hir>( attrs: &mut Vec<(Cow<'hir, ast::Attribute>, Option<DefId>)>, new_attrs: &'hir [ast::Attribute], is_inline: bool, import_parent: Option<DefId>, )2377 fn add_without_unwanted_attributes<'hir>(
2378     attrs: &mut Vec<(Cow<'hir, ast::Attribute>, Option<DefId>)>,
2379     new_attrs: &'hir [ast::Attribute],
2380     is_inline: bool,
2381     import_parent: Option<DefId>,
2382 ) {
2383     // If it's not `#[doc(inline)]`, we don't want all attributes, otherwise we keep everything.
2384     if !is_inline {
2385         for attr in new_attrs {
2386             attrs.push((Cow::Borrowed(attr), import_parent));
2387         }
2388         return;
2389     }
2390     for attr in new_attrs {
2391         if matches!(attr.kind, ast::AttrKind::DocComment(..)) {
2392             attrs.push((Cow::Borrowed(attr), import_parent));
2393             continue;
2394         }
2395         let mut attr = attr.clone();
2396         match attr.kind {
2397             ast::AttrKind::Normal(ref mut normal) => {
2398                 if let [ident] = &*normal.item.path.segments &&
2399                     let ident = ident.ident.name &&
2400                     ident == sym::doc
2401                 {
2402                     match normal.item.args {
2403                         ast::AttrArgs::Delimited(ref mut args) => {
2404                             let tokens =
2405                                 filter_tokens_from_list(args.tokens.clone(), |token| {
2406                                     !matches!(
2407                                         token,
2408                                         TokenTree::Token(
2409                                             Token {
2410                                                 kind: TokenKind::Ident(
2411                                                     sym::hidden | sym::inline | sym::no_inline,
2412                                                     _,
2413                                                 ),
2414                                                 ..
2415                                             },
2416                                             _,
2417                                         ),
2418                                     )
2419                                 });
2420                             args.tokens = TokenStream::new(tokens);
2421                             attrs.push((Cow::Owned(attr), import_parent));
2422                         }
2423                         ast::AttrArgs::Empty | ast::AttrArgs::Eq(..) => {
2424                             attrs.push((Cow::Owned(attr), import_parent));
2425                         }
2426                     }
2427                 }
2428             }
2429             _ => unreachable!(),
2430         }
2431     }
2432 }
2433 
clean_maybe_renamed_item<'tcx>( cx: &mut DocContext<'tcx>, item: &hir::Item<'tcx>, renamed: Option<Symbol>, import_id: Option<LocalDefId>, ) -> Vec<Item>2434 fn clean_maybe_renamed_item<'tcx>(
2435     cx: &mut DocContext<'tcx>,
2436     item: &hir::Item<'tcx>,
2437     renamed: Option<Symbol>,
2438     import_id: Option<LocalDefId>,
2439 ) -> Vec<Item> {
2440     use hir::ItemKind;
2441 
2442     let def_id = item.owner_id.to_def_id();
2443     let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
2444     cx.with_param_env(def_id, |cx| {
2445         let kind = match item.kind {
2446             ItemKind::Static(ty, mutability, body_id) => {
2447                 StaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: Some(body_id) })
2448             }
2449             ItemKind::Const(ty, body_id) => ConstantItem(Constant {
2450                 type_: clean_ty(ty, cx),
2451                 kind: ConstantKind::Local { body: body_id, def_id },
2452             }),
2453             ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
2454                 bounds: ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
2455                 generics: clean_generics(ty.generics, cx),
2456             }),
2457             ItemKind::TyAlias(hir_ty, generics) => {
2458                 *cx.current_type_aliases.entry(def_id).or_insert(0) += 1;
2459                 let rustdoc_ty = clean_ty(hir_ty, cx);
2460                 let ty = clean_middle_ty(
2461                     ty::Binder::dummy(hir_ty_to_ty(cx.tcx, hir_ty)),
2462                     cx,
2463                     None,
2464                     None,
2465                 );
2466                 let generics = clean_generics(generics, cx);
2467                 if let Some(count) = cx.current_type_aliases.get_mut(&def_id) {
2468                     *count -= 1;
2469                     if *count == 0 {
2470                         cx.current_type_aliases.remove(&def_id);
2471                     }
2472                 }
2473                 TypedefItem(Box::new(Typedef { type_: rustdoc_ty, generics, item_type: Some(ty) }))
2474             }
2475             ItemKind::Enum(ref def, generics) => EnumItem(Enum {
2476                 variants: def.variants.iter().map(|v| clean_variant(v, cx)).collect(),
2477                 generics: clean_generics(generics, cx),
2478             }),
2479             ItemKind::TraitAlias(generics, bounds) => TraitAliasItem(TraitAlias {
2480                 generics: clean_generics(generics, cx),
2481                 bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
2482             }),
2483             ItemKind::Union(ref variant_data, generics) => UnionItem(Union {
2484                 generics: clean_generics(generics, cx),
2485                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
2486             }),
2487             ItemKind::Struct(ref variant_data, generics) => StructItem(Struct {
2488                 ctor_kind: variant_data.ctor_kind(),
2489                 generics: clean_generics(generics, cx),
2490                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
2491             }),
2492             ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
2493             ItemKind::Macro(ref macro_def, MacroKind::Bang) => {
2494                 let ty_vis = cx.tcx.visibility(def_id);
2495                 MacroItem(Macro {
2496                     source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
2497                 })
2498             }
2499             ItemKind::Macro(_, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx),
2500             // proc macros can have a name set by attributes
2501             ItemKind::Fn(ref sig, generics, body_id) => {
2502                 clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
2503             }
2504             ItemKind::Trait(_, _, generics, bounds, item_ids) => {
2505                 let items = item_ids
2506                     .iter()
2507                     .map(|ti| clean_trait_item(cx.tcx.hir().trait_item(ti.id), cx))
2508                     .collect();
2509 
2510                 TraitItem(Box::new(Trait {
2511                     def_id,
2512                     items,
2513                     generics: clean_generics(generics, cx),
2514                     bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
2515                 }))
2516             }
2517             ItemKind::ExternCrate(orig_name) => {
2518                 return clean_extern_crate(item, name, orig_name, cx);
2519             }
2520             ItemKind::Use(path, kind) => {
2521                 return clean_use_statement(item, name, path, kind, cx, &mut FxHashSet::default());
2522             }
2523             _ => unreachable!("not yet converted"),
2524         };
2525 
2526         vec![generate_item_with_correct_attrs(
2527             cx,
2528             kind,
2529             item.owner_id.def_id,
2530             name,
2531             import_id,
2532             renamed,
2533         )]
2534     })
2535 }
2536 
clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item2537 fn clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
2538     let kind = VariantItem(clean_variant_data(&variant.data, &variant.disr_expr, cx));
2539     Item::from_def_id_and_parts(variant.def_id.to_def_id(), Some(variant.ident.name), kind, cx)
2540 }
2541 
clean_impl<'tcx>( impl_: &hir::Impl<'tcx>, def_id: LocalDefId, cx: &mut DocContext<'tcx>, ) -> Vec<Item>2542 fn clean_impl<'tcx>(
2543     impl_: &hir::Impl<'tcx>,
2544     def_id: LocalDefId,
2545     cx: &mut DocContext<'tcx>,
2546 ) -> Vec<Item> {
2547     let tcx = cx.tcx;
2548     let mut ret = Vec::new();
2549     let trait_ = impl_.of_trait.as_ref().map(|t| clean_trait_ref(t, cx));
2550     let items = impl_
2551         .items
2552         .iter()
2553         .map(|ii| clean_impl_item(tcx.hir().impl_item(ii.id), cx))
2554         .collect::<Vec<_>>();
2555 
2556     // If this impl block is an implementation of the Deref trait, then we
2557     // need to try inlining the target's inherent impl blocks as well.
2558     if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() {
2559         build_deref_target_impls(cx, &items, &mut ret);
2560     }
2561 
2562     let for_ = clean_ty(impl_.self_ty, cx);
2563     let type_alias =
2564         for_.def_id(&cx.cache).and_then(|alias_def_id: DefId| match tcx.def_kind(alias_def_id) {
2565             DefKind::TyAlias => Some(clean_middle_ty(
2566                 ty::Binder::dummy(tcx.type_of(def_id).subst_identity()),
2567                 cx,
2568                 Some(def_id.to_def_id()),
2569                 None,
2570             )),
2571             _ => None,
2572         });
2573     let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
2574         let kind = ImplItem(Box::new(Impl {
2575             unsafety: impl_.unsafety,
2576             generics: clean_generics(impl_.generics, cx),
2577             trait_,
2578             for_,
2579             items,
2580             polarity: tcx.impl_polarity(def_id),
2581             kind: if utils::has_doc_flag(tcx, def_id.to_def_id(), sym::fake_variadic) {
2582                 ImplKind::FakeVariadic
2583             } else {
2584                 ImplKind::Normal
2585             },
2586         }));
2587         Item::from_def_id_and_parts(def_id.to_def_id(), None, kind, cx)
2588     };
2589     if let Some(type_alias) = type_alias {
2590         ret.push(make_item(trait_.clone(), type_alias, items.clone()));
2591     }
2592     ret.push(make_item(trait_, for_, items));
2593     ret
2594 }
2595 
clean_extern_crate<'tcx>( krate: &hir::Item<'tcx>, name: Symbol, orig_name: Option<Symbol>, cx: &mut DocContext<'tcx>, ) -> Vec<Item>2596 fn clean_extern_crate<'tcx>(
2597     krate: &hir::Item<'tcx>,
2598     name: Symbol,
2599     orig_name: Option<Symbol>,
2600     cx: &mut DocContext<'tcx>,
2601 ) -> Vec<Item> {
2602     // this is the ID of the `extern crate` statement
2603     let cnum = cx.tcx.extern_mod_stmt_cnum(krate.owner_id.def_id).unwrap_or(LOCAL_CRATE);
2604     // this is the ID of the crate itself
2605     let crate_def_id = cnum.as_def_id();
2606     let attrs = cx.tcx.hir().attrs(krate.hir_id());
2607     let ty_vis = cx.tcx.visibility(krate.owner_id);
2608     let please_inline = ty_vis.is_public()
2609         && attrs.iter().any(|a| {
2610             a.has_name(sym::doc)
2611                 && match a.meta_item_list() {
2612                     Some(l) => attr::list_contains_name(&l, sym::inline),
2613                     None => false,
2614                 }
2615         })
2616         && !cx.output_format.is_json();
2617 
2618     let krate_owner_def_id = krate.owner_id.to_def_id();
2619     if please_inline {
2620         if let Some(items) = inline::try_inline(
2621             cx,
2622             Res::Def(DefKind::Mod, crate_def_id),
2623             name,
2624             Some((attrs, Some(krate_owner_def_id))),
2625             &mut Default::default(),
2626         ) {
2627             return items;
2628         }
2629     }
2630 
2631     // FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason
2632     vec![Item {
2633         name: Some(name),
2634         attrs: Box::new(Attributes::from_ast(attrs)),
2635         item_id: crate_def_id.into(),
2636         kind: Box::new(ExternCrateItem { src: orig_name }),
2637         cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
2638         inline_stmt_id: Some(krate_owner_def_id),
2639     }]
2640 }
2641 
clean_use_statement<'tcx>( import: &hir::Item<'tcx>, name: Symbol, path: &hir::UsePath<'tcx>, kind: hir::UseKind, cx: &mut DocContext<'tcx>, inlined_names: &mut FxHashSet<(ItemType, Symbol)>, ) -> Vec<Item>2642 fn clean_use_statement<'tcx>(
2643     import: &hir::Item<'tcx>,
2644     name: Symbol,
2645     path: &hir::UsePath<'tcx>,
2646     kind: hir::UseKind,
2647     cx: &mut DocContext<'tcx>,
2648     inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
2649 ) -> Vec<Item> {
2650     let mut items = Vec::new();
2651     let hir::UsePath { segments, ref res, span } = *path;
2652     for &res in res {
2653         if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = res {
2654             continue;
2655         }
2656         let path = hir::Path { segments, res, span };
2657         items.append(&mut clean_use_statement_inner(import, name, &path, kind, cx, inlined_names));
2658     }
2659     items
2660 }
2661 
clean_use_statement_inner<'tcx>( import: &hir::Item<'tcx>, name: Symbol, path: &hir::Path<'tcx>, kind: hir::UseKind, cx: &mut DocContext<'tcx>, inlined_names: &mut FxHashSet<(ItemType, Symbol)>, ) -> Vec<Item>2662 fn clean_use_statement_inner<'tcx>(
2663     import: &hir::Item<'tcx>,
2664     name: Symbol,
2665     path: &hir::Path<'tcx>,
2666     kind: hir::UseKind,
2667     cx: &mut DocContext<'tcx>,
2668     inlined_names: &mut FxHashSet<(ItemType, Symbol)>,
2669 ) -> Vec<Item> {
2670     // We need this comparison because some imports (for std types for example)
2671     // are "inserted" as well but directly by the compiler and they should not be
2672     // taken into account.
2673     if import.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) {
2674         return Vec::new();
2675     }
2676 
2677     let visibility = cx.tcx.visibility(import.owner_id);
2678     let attrs = cx.tcx.hir().attrs(import.hir_id());
2679     let inline_attr = attrs.lists(sym::doc).get_word_attr(sym::inline);
2680     let pub_underscore = visibility.is_public() && name == kw::Underscore;
2681     let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id);
2682 
2683     // The parent of the module in which this import resides. This
2684     // is the same as `current_mod` if that's already the top
2685     // level module.
2686     let parent_mod = cx.tcx.parent_module_from_def_id(current_mod);
2687 
2688     // This checks if the import can be seen from a higher level module.
2689     // In other words, it checks if the visibility is the equivalent of
2690     // `pub(super)` or higher. If the current module is the top level
2691     // module, there isn't really a parent module, which makes the results
2692     // meaningless. In this case, we make sure the answer is `false`.
2693     let is_visible_from_parent_mod =
2694         visibility.is_accessible_from(parent_mod, cx.tcx) && !current_mod.is_top_level_module();
2695 
2696     if pub_underscore && let Some(ref inline) = inline_attr {
2697         rustc_errors::struct_span_err!(
2698             cx.tcx.sess,
2699             inline.span(),
2700             E0780,
2701             "anonymous imports cannot be inlined"
2702         )
2703         .span_label(import.span, "anonymous import")
2704         .emit();
2705     }
2706 
2707     // We consider inlining the documentation of `pub use` statements, but we
2708     // forcefully don't inline if this is not public or if the
2709     // #[doc(no_inline)] attribute is present.
2710     // Don't inline doc(hidden) imports so they can be stripped at a later stage.
2711     let mut denied = cx.output_format.is_json()
2712         || !(visibility.is_public()
2713             || (cx.render_options.document_private && is_visible_from_parent_mod))
2714         || pub_underscore
2715         || attrs.iter().any(|a| {
2716             a.has_name(sym::doc)
2717                 && match a.meta_item_list() {
2718                     Some(l) => {
2719                         attr::list_contains_name(&l, sym::no_inline)
2720                             || attr::list_contains_name(&l, sym::hidden)
2721                     }
2722                     None => false,
2723                 }
2724         });
2725 
2726     // Also check whether imports were asked to be inlined, in case we're trying to re-export a
2727     // crate in Rust 2018+
2728     let path = clean_path(path, cx);
2729     let inner = if kind == hir::UseKind::Glob {
2730         if !denied {
2731             let mut visited = DefIdSet::default();
2732             if let Some(items) =
2733                 inline::try_inline_glob(cx, path.res, current_mod, &mut visited, inlined_names)
2734             {
2735                 return items;
2736             }
2737         }
2738         Import::new_glob(resolve_use_source(cx, path), true)
2739     } else {
2740         if inline_attr.is_none()
2741             && let Res::Def(DefKind::Mod, did) = path.res
2742             && !did.is_local()
2743             && did.is_crate_root()
2744         {
2745             // if we're `pub use`ing an extern crate root, don't inline it unless we
2746             // were specifically asked for it
2747             denied = true;
2748         }
2749         if !denied {
2750             let import_def_id = import.owner_id.to_def_id();
2751             if let Some(mut items) = inline::try_inline(
2752                 cx,
2753                 path.res,
2754                 name,
2755                 Some((attrs, Some(import_def_id))),
2756                 &mut Default::default(),
2757             ) {
2758                 items.push(Item::from_def_id_and_parts(
2759                     import_def_id,
2760                     None,
2761                     ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)),
2762                     cx,
2763                 ));
2764                 return items;
2765             }
2766         }
2767         Import::new_simple(name, resolve_use_source(cx, path), true)
2768     };
2769 
2770     vec![Item::from_def_id_and_parts(import.owner_id.to_def_id(), None, ImportItem(inner), cx)]
2771 }
2772 
clean_maybe_renamed_foreign_item<'tcx>( cx: &mut DocContext<'tcx>, item: &hir::ForeignItem<'tcx>, renamed: Option<Symbol>, ) -> Item2773 fn clean_maybe_renamed_foreign_item<'tcx>(
2774     cx: &mut DocContext<'tcx>,
2775     item: &hir::ForeignItem<'tcx>,
2776     renamed: Option<Symbol>,
2777 ) -> Item {
2778     let def_id = item.owner_id.to_def_id();
2779     cx.with_param_env(def_id, |cx| {
2780         let kind = match item.kind {
2781             hir::ForeignItemKind::Fn(decl, names, generics) => {
2782                 let (generics, decl) = enter_impl_trait(cx, |cx| {
2783                     // NOTE: generics must be cleaned before args
2784                     let generics = clean_generics(generics, cx);
2785                     let args = clean_args_from_types_and_names(cx, decl.inputs, names);
2786                     let decl = clean_fn_decl_with_args(cx, decl, args);
2787                     (generics, decl)
2788                 });
2789                 ForeignFunctionItem(Box::new(Function { decl, generics }))
2790             }
2791             hir::ForeignItemKind::Static(ty, mutability) => {
2792                 ForeignStaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: None })
2793             }
2794             hir::ForeignItemKind::Type => ForeignTypeItem,
2795         };
2796 
2797         Item::from_def_id_and_parts(
2798             item.owner_id.def_id.to_def_id(),
2799             Some(renamed.unwrap_or(item.ident.name)),
2800             kind,
2801             cx,
2802         )
2803     })
2804 }
2805 
clean_type_binding<'tcx>( type_binding: &hir::TypeBinding<'tcx>, cx: &mut DocContext<'tcx>, ) -> TypeBinding2806 fn clean_type_binding<'tcx>(
2807     type_binding: &hir::TypeBinding<'tcx>,
2808     cx: &mut DocContext<'tcx>,
2809 ) -> TypeBinding {
2810     TypeBinding {
2811         assoc: PathSegment {
2812             name: type_binding.ident.name,
2813             args: clean_generic_args(type_binding.gen_args, cx),
2814         },
2815         kind: match type_binding.kind {
2816             hir::TypeBindingKind::Equality { ref term } => {
2817                 TypeBindingKind::Equality { term: clean_hir_term(term, cx) }
2818             }
2819             hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint {
2820                 bounds: bounds.iter().filter_map(|b| clean_generic_bound(b, cx)).collect(),
2821             },
2822         },
2823     }
2824 }
2825