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(¶m_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 (¶m.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| ¶m.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| ¶m.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