rust/src/librustdoc/clean/mod.rs

2292 lines
89 KiB
Rust
Raw Normal View History

2013-08-15 20:28:54 +00:00
//! This module contains the "cleaned" pieces of the AST, and the functions
//! that clean them.
mod auto_trait;
mod blanket_impl;
pub(crate) mod cfg;
pub(crate) mod inline;
mod render_macro_matchers;
mod simplify;
pub(crate) mod types;
pub(crate) mod utils;
2020-04-27 17:56:11 +00:00
use rustc_ast as ast;
use rustc_attr as attr;
2019-12-24 04:02:53 +00:00
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::PredicateOrigin;
2020-01-06 22:31:06 +00:00
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
2020-03-29 14:41:09 +00:00
use rustc_middle::middle::resolve_lifetime as rl;
use rustc_middle::ty::fold::TypeFolder;
2020-06-30 21:41:57 +00:00
use rustc_middle::ty::subst::{InternalSubsts, Subst};
2022-05-08 05:17:58 +00:00
use rustc_middle::ty::{self, AdtKind, DefIdTree, EarlyBinder, Lift, Ty, TyCtxt};
2021-05-02 19:11:13 +00:00
use rustc_middle::{bug, span_bug};
use rustc_span::hygiene::{AstPass, MacroKind};
2020-04-19 11:00:18 +00:00
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{self, ExpnKind};
2019-12-22 22:42:04 +00:00
use rustc_typeck::hir_ty_to_ty;
use std::assert_matches::assert_matches;
Generate documentation for auto-trait impls A new section is added to both both struct and trait doc pages. On struct/enum pages, a new 'Auto Trait Implementations' section displays any synthetic implementations for auto traits. Currently, this is only done for Send and Sync. On trait pages, a new 'Auto Implementors' section displays all types which automatically implement the trait. Effectively, this is a list of all public types in the standard library. Synthesized impls for a particular auto trait ('synthetic impls') take into account generic bounds. For example, a type 'struct Foo<T>(T)' will have 'impl<T> Send for Foo<T> where T: Send' generated for it. Manual implementations of auto traits are also taken into account. If we have the following types: 'struct Foo<T>(T)' 'struct Wrapper<T>(Foo<T>)' 'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes this sound somehow Then Wrapper will have the following impl generated: 'impl<T> Send for Wrapper<T>' reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send' to hold Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are taken into account by synthetic impls However, if a type can *never* implement a particular auto trait (e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be generated (in this case, 'impl<T> !Send for MyStruct<T>') All of this means that a user should be able to copy-paste a synthetic impl into their code, without any observable changes in behavior (assuming the rest of the program remains unchanged).
2017-11-22 21:16:55 +00:00
use std::collections::hash_map::Entry;
use std::collections::BTreeMap;
use std::default::Default;
2019-12-22 22:42:04 +00:00
use std::hash::Hash;
use std::{mem, vec};
rustdoc: Generate hyperlinks between crates The general idea of hyperlinking between crates is that it should require as little configuration as possible, if any at all. In this vein, there are two separate ways to generate hyperlinks between crates: 1. When you're generating documentation for a crate 'foo' into folder 'doc', then if foo's external crate dependencies already have documented in the folder 'doc', then hyperlinks will be generated. This will work because all documentation is in the same folder, allowing links to work seamlessly both on the web and on the local filesystem browser. The rationale for this use case is a package with multiple libraries/crates that all want to link to one another, and you don't want to have to deal with going to the web. In theory this could be extended to have a RUST_PATH-style searching situtation, but I'm not sure that it would work seamlessly on the web as it does on the local filesystem, so I'm not attempting to explore this case in this pull request. I believe to fully realize this potential rustdoc would have to be acting as a server instead of a static site generator. 2. One of foo's external dependencies has a #[doc(html_root_url = "...")] attribute. This means that all hyperlinks to the dependency will be rooted at this url. This use case encompasses all packages using libstd/libextra. These two crates now have this attribute encoded (currently at the /doc/master url) and will be read by anything which has a dependency on libstd/libextra. This should also work for arbitrary crates in the wild that have online documentation. I don't like how the version is hard-wired into the url, but I think that this may be a case-by-case thing which doesn't end up being too bad in the long run. Closes #9539
2013-10-02 22:39:32 +00:00
use crate::core::{self, DocContext, ImplTraitParam};
use crate::formats::item_type::ItemType;
use crate::visit_ast::Module as DocModule;
2019-02-23 07:40:07 +00:00
2019-12-09 16:53:42 +00:00
use utils::*;
pub(crate) use self::types::*;
pub(crate) use self::utils::{get_auto_trait_and_blanket_impls, krate, register_res};
Generate documentation for auto-trait impls A new section is added to both both struct and trait doc pages. On struct/enum pages, a new 'Auto Trait Implementations' section displays any synthetic implementations for auto traits. Currently, this is only done for Send and Sync. On trait pages, a new 'Auto Implementors' section displays all types which automatically implement the trait. Effectively, this is a list of all public types in the standard library. Synthesized impls for a particular auto trait ('synthetic impls') take into account generic bounds. For example, a type 'struct Foo<T>(T)' will have 'impl<T> Send for Foo<T> where T: Send' generated for it. Manual implementations of auto traits are also taken into account. If we have the following types: 'struct Foo<T>(T)' 'struct Wrapper<T>(Foo<T>)' 'unsafe impl<T> Send for Wrapper<T>' // pretend that Wrapper<T> makes this sound somehow Then Wrapper will have the following impl generated: 'impl<T> Send for Wrapper<T>' reflecting the fact that 'T: Send' need not hold for 'Wrapper<T>: Send' to hold Lifetimes, HRTBS, and projections (e.g. '<T as Iterator>::Item') are taken into account by synthetic impls However, if a type can *never* implement a particular auto trait (e.g. 'struct MyStruct<T>(*const T)'), then a negative impl will be generated (in this case, 'impl<T> !Send for MyStruct<T>') All of this means that a user should be able to copy-paste a synthetic impl into their code, without any observable changes in behavior (assuming the rest of the program remains unchanged).
2017-11-22 21:16:55 +00:00
2022-05-22 19:40:26 +00:00
pub(crate) trait Clean<'tcx, T> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> T;
2013-08-15 20:28:54 +00:00
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
let mut items: Vec<Item> = vec![];
items.extend(
self.foreigns
.iter()
.map(|(item, renamed)| clean_maybe_renamed_foreign_item(cx, item, *renamed)),
);
items.extend(self.mods.iter().map(|x| x.clean(cx)));
// Split up imports from all other items.
//
// This covers the case where somebody does an import which should pull in an item,
// but there's already an item with the same namespace and same name. Rust gives
// priority to the not-imported one, so we should, too.
let mut inserted = FxHashSet::default();
items.extend(self.items.iter().flat_map(|(item, renamed)| {
// First, lower everything other than imports.
if matches!(item.kind, hir::ItemKind::Use(..)) {
return Vec::new();
}
let v = clean_maybe_renamed_item(cx, item, *renamed);
for item in &v {
if let Some(name) = item.name {
inserted.insert((item.type_(), name));
}
}
v
}));
items.extend(self.items.iter().flat_map(|(item, renamed)| {
// Now we actually lower the imports, skipping everything else.
if !matches!(item.kind, hir::ItemKind::Use(..)) {
return Vec::new();
}
let mut v = clean_maybe_renamed_item(cx, item, *renamed);
v.drain_filter(|item| {
if let Some(name) = item.name {
// If an item with the same type and name already exists,
// it takes priority over the inlined stuff.
!inserted.insert((item.type_(), name))
} else {
false
}
});
v
}));
// determine if we should display the inner contents or
// the outer `mod` item for the source code.
let span = Span::new({
let where_outer = self.where_outer(cx.tcx);
2020-02-22 14:07:05 +00:00
let sm = cx.sess().source_map();
let outer = sm.lookup_char_pos(where_outer.lo());
2020-02-22 14:07:05 +00:00
let inner = sm.lookup_char_pos(self.where_inner.lo());
if outer.file.start_pos == inner.file.start_pos {
// mod foo { ... }
where_outer
} else {
2018-08-18 10:13:52 +00:00
// mod foo; (and a separate SourceFile for the contents)
self.where_inner
}
});
Item::from_hir_id_and_parts(
self.id,
Some(self.name),
ModuleItem(Module { items, span }),
cx,
)
2013-08-15 20:28:54 +00:00
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Attributes> for [ast::Attribute] {
fn clean(&self, _cx: &mut DocContext<'_>) -> Attributes {
Attributes::from_ast(self, None)
2013-08-15 20:28:54 +00:00
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Option<GenericBound>> for hir::GenericBound<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<GenericBound> {
Some(match *self {
2018-06-14 11:23:46 +00:00
hir::GenericBound::Outlives(lt) => GenericBound::Outlives(lt.clean(cx)),
hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
2021-09-16 03:43:19 +00:00
let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder();
let generic_args = generic_args.clean(cx);
let GenericArgs::AngleBracketed { bindings, .. } = generic_args
else {
bug!("clean: parenthesized `GenericBound::LangItemTrait`");
};
let trait_ = clean_trait_ref_with_bindings(cx, trait_ref, &bindings);
GenericBound::TraitBound(
PolyTrait { trait_, generic_params: vec![] },
hir::TraitBoundModifier::None,
)
}
2018-06-14 11:23:46 +00:00
hir::GenericBound::Trait(ref t, modifier) => {
// `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
if modifier == hir::TraitBoundModifier::MaybeConst
2022-04-05 13:11:13 +00:00
&& cx.tcx.lang_items().destruct_trait()
== Some(t.trait_ref.trait_def_id().unwrap())
{
return None;
}
2018-06-14 11:23:46 +00:00
GenericBound::TraitBound(t.clean(cx), modifier)
}
})
2013-08-15 20:28:54 +00:00
}
}
2022-05-22 19:40:26 +00:00
fn clean_trait_ref_with_bindings<'tcx>(
cx: &mut DocContext<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
bindings: &[TypeBinding],
) -> Path {
let kind = cx.tcx.def_kind(trait_ref.def_id).into();
if !matches!(kind, ItemType::Trait | ItemType::TraitAlias) {
span_bug!(cx.tcx.def_span(trait_ref.def_id), "`TraitRef` had unexpected kind {:?}", kind);
}
inline::record_extern_fqn(cx, trait_ref.def_id, kind);
let path = external_path(cx, trait_ref.def_id, true, bindings.to_vec(), trait_ref.substs);
debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs);
path
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Path> for ty::TraitRef<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Path {
clean_trait_ref_with_bindings(cx, *self, &[])
}
}
2022-05-22 19:40:26 +00:00
fn clean_poly_trait_ref_with_bindings<'tcx>(
cx: &mut DocContext<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
2021-12-03 21:26:59 +00:00
bindings: &[TypeBinding],
) -> GenericBound {
let poly_trait_ref = poly_trait_ref.lift_to_tcx(cx.tcx).unwrap();
// collect any late bound regions
let late_bound_regions: Vec<_> = cx
.tcx
.collect_referenced_late_bound_regions(&poly_trait_ref)
.into_iter()
.filter_map(|br| match br {
ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => Some(GenericParamDef {
2021-12-03 21:26:59 +00:00
name,
kind: GenericParamDefKind::Lifetime { outlives: vec![] },
}),
_ => None,
})
.collect();
2021-12-03 21:26:59 +00:00
let trait_ = clean_trait_ref_with_bindings(cx, poly_trait_ref.skip_binder(), bindings);
GenericBound::TraitBound(
PolyTrait { trait_, generic_params: late_bound_regions },
hir::TraitBoundModifier::None,
)
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, GenericBound> for ty::PolyTraitRef<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericBound {
2021-12-03 21:26:59 +00:00
clean_poly_trait_ref_with_bindings(cx, *self, &[])
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Lifetime> for hir::Lifetime {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Lifetime {
2020-04-13 16:52:40 +00:00
let def = cx.tcx.named_region(self.hir_id);
2021-10-01 15:12:39 +00:00
if let Some(
2022-02-20 18:22:57 +00:00
rl::Region::EarlyBound(_, node_id)
| rl::Region::LateBound(_, _, node_id)
2021-10-01 15:12:39 +00:00
| rl::Region::Free(_, node_id),
) = def
{
if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() {
2021-10-01 15:12:39 +00:00
return lt;
2016-09-01 07:21:12 +00:00
}
}
Lifetime(self.name.ident().name)
2013-08-15 20:28:54 +00:00
}
}
pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg, cx: &mut DocContext<'tcx>) -> Constant {
let def_id = cx.tcx.hir().body_owner_def_id(constant.value.body).to_def_id();
Constant {
type_: clean_middle_ty(cx.tcx.type_of(def_id), cx, Some(def_id)),
kind: ConstantKind::Anonymous { body: constant.value.body },
}
}
pub(crate) fn clean_middle_const<'tcx>(
constant: ty::Const<'tcx>,
cx: &mut DocContext<'tcx>,
) -> Constant {
// FIXME: instead of storing the stringified expression, store `self` directly instead.
Constant {
type_: clean_middle_ty(constant.ty(), cx, None),
kind: ConstantKind::TyConst { expr: constant.to_string() },
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Option<Lifetime>> for ty::Region<'tcx> {
2020-12-17 00:14:21 +00:00
fn clean(&self, _cx: &mut DocContext<'_>) -> Option<Lifetime> {
match **self {
ty::ReStatic => Some(Lifetime::statik()),
ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => {
2022-06-04 09:53:34 +00:00
if name != kw::UnderscoreLifetime { Some(Lifetime(name)) } else { None }
}
ty::ReEarlyBound(ref data) => {
if data.name != kw::UnderscoreLifetime {
Some(Lifetime(data.name))
} else {
None
}
}
2019-12-22 22:42:04 +00:00
ty::ReLateBound(..)
| ty::ReFree(..)
| ty::ReVar(..)
| ty::RePlaceholder(..)
| ty::ReEmpty(_)
2019-12-22 22:42:04 +00:00
| ty::ReErased => {
debug!("cannot clean region {:?}", self);
None
}
}
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Option<WherePredicate>> for hir::WherePredicate<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
if !self.in_where_clause() {
return None;
}
Some(match *self {
hir::WherePredicate::BoundPredicate(ref wbp) => {
let bound_params = wbp
.bound_generic_params
2022-05-21 18:07:18 +00:00
.iter()
.map(|param| {
// Higher-ranked params must be lifetimes.
// Higher-ranked lifetimes can't have bounds.
assert_matches!(
param,
hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. }
);
Lifetime(param.name.ident().name)
})
.collect();
WherePredicate::BoundPredicate {
ty: clean_ty(wbp.bounded_ty, cx),
bounds: wbp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
bound_params,
}
}
2019-12-22 22:42:04 +00:00
hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
lifetime: wrp.lifetime.clean(cx),
bounds: wrp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
2019-12-22 22:42:04 +00:00
},
hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
lhs: clean_ty(wrp.lhs_ty, cx),
rhs: clean_ty(wrp.rhs_ty, cx).into(),
},
})
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::Predicate<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
2021-01-07 16:20:28 +00:00
let bound_predicate = self.kind();
2020-12-17 03:36:14 +00:00
match bound_predicate.skip_binder() {
ty::PredicateKind::Trait(pred) => bound_predicate.rebind(pred).clean(cx),
2021-01-07 16:20:28 +00:00
ty::PredicateKind::RegionOutlives(pred) => pred.clean(cx),
ty::PredicateKind::TypeOutlives(pred) => pred.clean(cx),
ty::PredicateKind::Projection(pred) => Some(pred.clean(cx)),
ty::PredicateKind::ConstEvaluatable(..) => None,
ty::PredicateKind::WellFormed(..) => None,
2021-01-07 16:20:28 +00:00
ty::PredicateKind::Subtype(..)
2020-11-21 12:06:16 +00:00
| ty::PredicateKind::Coerce(..)
2021-01-07 16:20:28 +00:00
| ty::PredicateKind::ObjectSafe(..)
| ty::PredicateKind::ClosureKind(..)
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(..) => panic!("not user writable"),
}
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Option<WherePredicate>> for ty::PolyTraitPredicate<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
// `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
if self.skip_binder().constness == ty::BoundConstness::ConstIfConst
&& Some(self.skip_binder().def_id()) == cx.tcx.lang_items().destruct_trait()
{
return None;
}
let poly_trait_ref = self.map_bound(|pred| pred.trait_ref);
Some(WherePredicate::BoundPredicate {
ty: clean_middle_ty(poly_trait_ref.skip_binder().self_ty(), cx, None),
bounds: vec![poly_trait_ref.clean(cx)],
bound_params: Vec::new(),
})
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Option<WherePredicate>>
2020-07-18 16:46:30 +00:00
for ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
2019-12-22 22:42:04 +00:00
{
2022-05-22 19:40:26 +00:00
fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
2020-07-18 16:46:30 +00:00
let ty::OutlivesPredicate(a, b) = self;
if a.is_empty() && b.is_empty() {
return None;
}
Some(WherePredicate::RegionPredicate {
2018-07-29 13:39:51 +00:00
lifetime: a.clean(cx).expect("failed to clean lifetime"),
2019-12-22 22:42:04 +00:00
bounds: vec![GenericBound::Outlives(b.clean(cx).expect("failed to clean bounds"))],
})
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Option<WherePredicate>>
for ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>
{
fn clean(&self, cx: &mut DocContext<'tcx>) -> Option<WherePredicate> {
2020-07-18 16:46:30 +00:00
let ty::OutlivesPredicate(ty, lt) = self;
if lt.is_empty() {
return None;
}
Some(WherePredicate::BoundPredicate {
ty: clean_middle_ty(*ty, cx, None),
2019-12-22 22:42:04 +00:00
bounds: vec![GenericBound::Outlives(lt.clean(cx).expect("failed to clean lifetimes"))],
bound_params: Vec::new(),
})
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Term> for ty::Term<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Term {
match self {
ty::Term::Ty(ty) => Term::Type(clean_middle_ty(*ty, cx, None)),
ty::Term::Const(c) => Term::Constant(clean_middle_const(*c, cx)),
}
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Term> for hir::Term<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Term {
match self {
hir::Term::Ty(ty) => Term::Type(clean_ty(ty, cx)),
hir::Term::Const(c) => {
let def_id = cx.tcx.hir().local_def_id(c.hir_id);
Term::Constant(clean_middle_const(ty::Const::from_anon_const(cx.tcx, def_id), cx))
}
}
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, WherePredicate> for ty::ProjectionPredicate<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> WherePredicate {
let ty::ProjectionPredicate { projection_ty, term } = self;
WherePredicate::EqPredicate {
lhs: clean_projection(*projection_ty, cx, None),
rhs: term.clean(cx),
}
}
}
fn clean_projection<'tcx>(
ty: ty::ProjectionTy<'tcx>,
2022-05-22 19:40:26 +00:00
cx: &mut DocContext<'tcx>,
def_id: Option<DefId>,
) -> Type {
let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
let trait_ = lifted.trait_ref(cx.tcx).clean(cx);
let self_type = clean_middle_ty(ty.self_ty(), cx, None);
let self_def_id = if let Some(def_id) = def_id {
cx.tcx.opt_parent(def_id).or(Some(def_id))
} else {
self_type.def_id(&cx.cache)
};
let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type);
Type::QPath {
assoc: Box::new(projection_to_path_segment(ty, cx)),
should_show_cast,
self_type: Box::new(self_type),
trait_,
}
}
fn compute_should_show_cast(self_def_id: Option<DefId>, trait_: &Path, self_type: &Type) -> bool {
!trait_.segments.is_empty()
&& self_def_id
.zip(Some(trait_.def_id()))
.map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_)
}
2022-05-22 19:40:26 +00:00
fn projection_to_path_segment<'tcx>(
ty: ty::ProjectionTy<'tcx>,
cx: &mut DocContext<'tcx>,
) -> PathSegment {
let item = cx.tcx.associated_item(ty.item_def_id);
let generics = cx.tcx.generics_of(ty.item_def_id);
PathSegment {
name: item.name,
args: GenericArgs::AngleBracketed {
args: substs_to_args(cx, &ty.substs[generics.parent_count..], false).into(),
bindings: Default::default(),
},
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, GenericParamDef> for ty::GenericParamDef {
fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericParamDef {
let (name, kind) = match self.kind {
ty::GenericParamDefKind::Lifetime => {
(self.name, GenericParamDefKind::Lifetime { outlives: vec![] })
}
ty::GenericParamDefKind::Type { has_default, synthetic, .. } => {
let default = if has_default {
Some(clean_middle_ty(cx.tcx.type_of(self.def_id), cx, Some(self.def_id)))
} else {
None
};
2019-12-22 22:42:04 +00:00
(
self.name,
2019-12-22 22:42:04 +00:00
GenericParamDefKind::Type {
did: self.def_id,
bounds: vec![], // These are filled in from the where-clauses.
default: default.map(Box::new),
2019-12-22 22:42:04 +00:00
synthetic,
},
)
}
2022-03-06 17:18:36 +00:00
ty::GenericParamDefKind::Const { has_default } => (
self.name,
2019-12-22 22:42:04 +00:00
GenericParamDefKind::Const {
did: self.def_id,
ty: Box::new(clean_middle_ty(
cx.tcx.type_of(self.def_id),
cx,
Some(self.def_id),
)),
default: match has_default {
true => Some(Box::new(cx.tcx.const_param_default(self.def_id).to_string())),
false => None,
},
2019-12-22 22:42:04 +00:00
},
),
};
2019-12-22 22:42:04 +00:00
GenericParamDef { name, kind }
2018-03-24 02:03:06 +00:00
}
}
2022-05-22 19:40:26 +00:00
fn clean_generic_param<'tcx>(
cx: &mut DocContext<'tcx>,
generics: Option<&hir::Generics<'tcx>>,
param: &hir::GenericParam<'tcx>,
) -> GenericParamDef {
let did = cx.tcx.hir().local_def_id(param.hir_id);
let (name, kind) = match param.kind {
hir::GenericParamKind::Lifetime { .. } => {
let outlives = if let Some(generics) = generics {
generics
.outlives_for_param(did)
.filter(|bp| !bp.in_where_clause)
.flat_map(|bp| bp.bounds)
.map(|bound| match bound {
hir::GenericBound::Outlives(lt) => lt.clean(cx),
2018-05-28 12:33:28 +00:00
_ => panic!(),
})
.collect()
} else {
Vec::new()
};
(param.name.ident().name, GenericParamDefKind::Lifetime { outlives })
}
hir::GenericParamKind::Type { ref default, synthetic } => {
let bounds = if let Some(generics) = generics {
generics
.bounds_for_param(did)
.filter(|bp| bp.origin != PredicateOrigin::WhereClause)
.flat_map(|bp| bp.bounds)
.filter_map(|x| x.clean(cx))
.collect()
} else {
Vec::new()
};
(
param.name.ident().name,
2019-12-22 22:42:04 +00:00
GenericParamDefKind::Type {
did: did.to_def_id(),
bounds,
default: default.map(|t| clean_ty(t, cx)).map(Box::new),
synthetic,
2019-12-22 22:42:04 +00:00
},
)
}
2022-05-21 18:07:18 +00:00
hir::GenericParamKind::Const { ty, default } => (
param.name.ident().name,
GenericParamDefKind::Const {
did: did.to_def_id(),
ty: Box::new(clean_ty(ty, cx)),
default: default.map(|ct| {
let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string())
}),
},
),
};
GenericParamDef { name, kind }
}
2022-06-04 09:53:34 +00:00
/// Synthetic type-parameters are inserted after normal ones.
/// In order for normal parameters to be able to refer to synthetic ones,
/// scans them first.
fn is_impl_trait(param: &hir::GenericParam<'_>) -> bool {
match param.kind {
hir::GenericParamKind::Type { synthetic, .. } => synthetic,
_ => false,
}
}
/// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
///
/// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information.
fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
matches!(param.kind, hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided })
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Generics> for hir::Generics<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Generics {
2019-12-22 22:42:04 +00:00
let impl_trait_params = self
.params
.iter()
.filter(|param| is_impl_trait(param))
.map(|param| {
let param = clean_generic_param(cx, Some(self), param);
match param.kind {
GenericParamDefKind::Lifetime { .. } => unreachable!(),
GenericParamDefKind::Type { did, ref bounds, .. } => {
cx.impl_trait_bounds.insert(did.into(), bounds.clone());
}
GenericParamDefKind::Const { .. } => unreachable!(),
}
param
})
.collect::<Vec<_>>();
2018-05-03 13:24:50 +00:00
let mut params = Vec::with_capacity(self.params.len());
for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
let p = clean_generic_param(cx, Some(self), p);
2018-05-03 13:24:50 +00:00
params.push(p);
}
params.extend(impl_trait_params);
2021-11-07 17:19:25 +00:00
let mut generics = Generics {
params,
where_predicates: self.predicates.iter().filter_map(|x| x.clean(cx)).collect(),
2021-11-07 17:19:25 +00:00
};
// Some duplicates are generated for ?Sized bounds between type params and where
// predicates. The point in here is to move the bounds definitions from type params
// to where predicates when such cases occur.
for where_pred in &mut generics.where_predicates {
match *where_pred {
WherePredicate::BoundPredicate {
ty: Generic(ref name), ref mut bounds, ..
} => {
2021-08-15 08:17:36 +00:00
if bounds.is_empty() {
for param in &mut generics.params {
match param.kind {
GenericParamDefKind::Lifetime { .. } => {}
GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
if &param.name == name {
mem::swap(bounds, ty_bounds);
2019-12-22 22:42:04 +00:00
break;
}
}
GenericParamDefKind::Const { .. } => {}
}
}
}
}
_ => continue,
}
2013-08-15 20:28:54 +00:00
}
generics
2013-08-15 20:28:54 +00:00
}
}
2022-05-22 19:40:26 +00:00
fn clean_ty_generics<'tcx>(
cx: &mut DocContext<'tcx>,
2021-12-03 21:34:46 +00:00
gens: &ty::Generics,
2022-05-22 19:40:26 +00:00
preds: ty::GenericPredicates<'tcx>,
2021-12-03 21:34:46 +00:00
) -> Generics {
// Don't populate `cx.impl_trait_bounds` before `clean`ning `where` clauses,
// since `Clean for ty::Predicate` would consume them.
let mut impl_trait = BTreeMap::<ImplTraitParam, Vec<GenericBound>>::default();
// Bounds in the type_params and lifetimes fields are repeated in the
// predicates field (see rustc_typeck::collect::ty_generics), so remove
// them.
let stripped_params = gens
.params
.iter()
.filter_map(|param| match param.kind {
ty::GenericParamDefKind::Lifetime if param.name == kw::UnderscoreLifetime => None,
ty::GenericParamDefKind::Lifetime => Some(param.clean(cx)),
2021-12-03 21:34:46 +00:00
ty::GenericParamDefKind::Type { synthetic, .. } => {
if param.name == kw::SelfUpper {
assert_eq!(param.index, 0);
return None;
}
2021-12-03 21:34:46 +00:00
if synthetic {
impl_trait.insert(param.index.into(), vec![]);
return None;
}
Some(param.clean(cx))
}
ty::GenericParamDefKind::Const { .. } => Some(param.clean(cx)),
})
.collect::<Vec<GenericParamDef>>();
// param index -> [(DefId of trait, associated type name and generics, type)]
let mut impl_trait_proj = FxHashMap::<u32, Vec<(DefId, PathSegment, Ty<'_>)>>::default();
2021-12-03 21:34:46 +00:00
let where_predicates = preds
.predicates
.iter()
.flat_map(|(p, _)| {
let mut projection = None;
let param_idx = (|| {
let bound_p = p.kind();
match bound_p.skip_binder() {
ty::PredicateKind::Trait(pred) => {
if let ty::Param(param) = pred.self_ty().kind() {
return Some(param.index);
}
2021-12-03 21:34:46 +00:00
}
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => {
if let ty::Param(param) = ty.kind() {
return Some(param.index);
}
}
2021-12-03 21:34:46 +00:00
ty::PredicateKind::Projection(p) => {
if let ty::Param(param) = p.projection_ty.self_ty().kind() {
projection = Some(bound_p.rebind(p));
return Some(param.index);
}
}
2021-12-03 21:34:46 +00:00
_ => (),
}
2021-12-03 21:34:46 +00:00
None
})();
if let Some(param_idx) = param_idx {
if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
let p: WherePredicate = p.clean(cx)?;
2021-12-03 21:34:46 +00:00
b.extend(
p.get_bounds()
.into_iter()
.flatten()
.cloned()
.filter(|b| !b.is_sized_bound(cx)),
);
let proj = projection.map(|p| {
(
clean_projection(p.skip_binder().projection_ty, cx, None),
p.skip_binder().term,
)
});
if let Some(((_, trait_did, name), rhs)) = proj
.as_ref()
.and_then(|(lhs, rhs): &(Type, _)| Some((lhs.projection()?, rhs)))
2021-12-03 21:34:46 +00:00
{
// FIXME(...): Remove this unwrap()
impl_trait_proj.entry(param_idx).or_default().push((
trait_did,
name,
rhs.ty().unwrap(),
));
2019-07-08 11:42:45 +00:00
}
2021-12-03 21:34:46 +00:00
return None;
2019-07-08 11:42:45 +00:00
}
}
2021-12-03 21:34:46 +00:00
Some(p)
})
.collect::<Vec<_>>();
2021-12-03 21:34:46 +00:00
for (param, mut bounds) in impl_trait {
// Move trait bounds to the front.
bounds.sort_by_key(|b| !matches!(b, GenericBound::TraitBound(..)));
if let crate::core::ImplTraitParam::ParamIndex(idx) = param {
if let Some(proj) = impl_trait_proj.remove(&idx) {
for (trait_did, name, rhs) in proj {
let rhs = clean_middle_ty(rhs, cx, None);
simplify::merge_bounds(cx, &mut bounds, trait_did, name, &Term::Type(rhs));
}
}
2021-12-03 21:34:46 +00:00
} else {
unreachable!();
}
2021-12-03 21:34:46 +00:00
cx.impl_trait_bounds.insert(param, bounds);
}
// Now that `cx.impl_trait_bounds` is populated, we can process
// remaining predicates which could contain `impl Trait`.
let mut where_predicates =
where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::<Vec<_>>();
// Type parameters have a Sized bound by default unless removed with
// ?Sized. Scan through the predicates and mark any type parameter with
// a Sized bound, removing the bounds as we find them.
//
// Note that associated types also have a sized bound by default, but we
// don't actually know the set of associated types right here so that's
// handled in cleaning associated types
let mut sized_params = FxHashSet::default();
where_predicates.retain(|pred| match *pred {
WherePredicate::BoundPredicate { ty: Generic(ref g), ref bounds, .. } => {
2021-12-03 21:34:46 +00:00
if bounds.iter().any(|b| b.is_sized_bound(cx)) {
sized_params.insert(*g);
false
} else {
true
}
}
2021-12-03 21:34:46 +00:00
_ => true,
});
2021-12-03 21:34:46 +00:00
// Run through the type parameters again and insert a ?Sized
// unbound for any we didn't find to be Sized.
for tp in &stripped_params {
if matches!(tp.kind, types::GenericParamDefKind::Type { .. })
&& !sized_params.contains(&tp.name)
{
where_predicates.push(WherePredicate::BoundPredicate {
2021-12-03 21:34:46 +00:00
ty: Type::Generic(tp.name),
bounds: vec![GenericBound::maybe_sized(cx)],
bound_params: Vec::new(),
})
}
}
2021-12-03 21:34:46 +00:00
// It would be nice to collect all of the bounds on a type and recombine
// them if possible, to avoid e.g., `where T: Foo, T: Bar, T: Sized, T: 'a`
// and instead see `where T: Foo + Bar + Sized + 'a`
Generics {
params: stripped_params,
where_predicates: simplify::where_clauses(cx, where_predicates),
}
}
2022-05-22 19:40:26 +00:00
fn clean_fn_or_proc_macro<'tcx>(
item: &hir::Item<'tcx>,
sig: &hir::FnSig<'tcx>,
generics: &hir::Generics<'tcx>,
2020-11-23 02:20:08 +00:00
body_id: hir::BodyId,
name: &mut Symbol,
2022-05-22 19:40:26 +00:00
cx: &mut DocContext<'tcx>,
2020-11-23 02:20:08 +00:00
) -> ItemKind {
2021-01-24 12:17:54 +00:00
let attrs = cx.tcx.hir().attrs(item.hir_id());
let macro_kind = attrs.iter().find_map(|a| {
2020-11-23 02:20:08 +00:00
if a.has_name(sym::proc_macro) {
Some(MacroKind::Bang)
} else if a.has_name(sym::proc_macro_derive) {
Some(MacroKind::Derive)
} else if a.has_name(sym::proc_macro_attribute) {
Some(MacroKind::Attr)
} else {
None
}
});
match macro_kind {
Some(kind) => {
if kind == MacroKind::Derive {
2021-01-24 12:17:54 +00:00
*name = attrs
2020-11-23 02:20:08 +00:00
.lists(sym::proc_macro_derive)
.find_map(|mi| mi.ident())
.expect("proc-macro derives require a name")
.name;
}
let mut helpers = Vec::new();
2021-01-24 12:17:54 +00:00
for mi in attrs.lists(sym::proc_macro_derive) {
2020-11-23 02:20:08 +00:00
if !mi.has_name(sym::attributes) {
continue;
}
if let Some(list) = mi.meta_item_list() {
for inner_mi in list {
if let Some(ident) = inner_mi.ident() {
helpers.push(ident.name);
}
}
}
}
ProcMacroItem(ProcMacro { kind, helpers })
2020-11-23 02:20:08 +00:00
}
None => {
2021-12-03 21:42:38 +00:00
let mut func = clean_function(cx, sig, generics, body_id);
clean_fn_decl_legacy_const_generics(&mut func, attrs);
2020-11-23 02:20:08 +00:00
FunctionItem(func)
}
}
}
/// This is needed to make it more "readable" when documenting functions using
/// `rustc_legacy_const_generics`. More information in
/// <https://github.com/rust-lang/rust/issues/83167>.
fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attribute]) {
for meta_item_list in attrs
.iter()
.filter(|a| a.has_name(sym::rustc_legacy_const_generics))
.filter_map(|a| a.meta_item_list())
{
for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.literal()).enumerate() {
match literal.kind {
ast::LitKind::Int(a, _) => {
let gen = func.generics.params.remove(0);
if let GenericParamDef { name, kind: GenericParamDefKind::Const { ty, .. } } =
gen
{
func.decl
.inputs
.values
.insert(a as _, Argument { name, type_: *ty, is_const: true });
} else {
panic!("unexpected non const in position {pos}");
}
}
_ => panic!("invalid arg index"),
}
}
}
}
2022-05-22 19:40:26 +00:00
fn clean_function<'tcx>(
cx: &mut DocContext<'tcx>,
sig: &hir::FnSig<'tcx>,
generics: &hir::Generics<'tcx>,
2021-12-03 21:42:38 +00:00
body_id: hir::BodyId,
) -> Function {
let (generics, decl) = enter_impl_trait(cx, |cx| {
// NOTE: generics must be cleaned before args
let generics = generics.clean(cx);
2021-12-03 21:46:19 +00:00
let args = clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id);
2021-12-03 21:42:38 +00:00
let decl = clean_fn_decl_with_args(cx, sig.decl, args);
(generics, decl)
});
Function { decl, generics }
2013-08-15 20:28:54 +00:00
}
2022-05-22 19:40:26 +00:00
fn clean_args_from_types_and_names<'tcx>(
cx: &mut DocContext<'tcx>,
types: &[hir::Ty<'tcx>],
2021-12-03 21:44:47 +00:00
names: &[Ident],
) -> Arguments {
Arguments {
values: types
.iter()
.enumerate()
.map(|(i, ty)| {
let mut name = names.get(i).map_or(kw::Empty, |ident| ident.name);
if name.is_empty() {
name = kw::Underscore;
}
Argument { name, type_: clean_ty(ty, cx), is_const: false }
2021-12-03 21:44:47 +00:00
})
.collect(),
}
}
2022-05-22 19:40:26 +00:00
fn clean_args_from_types_and_body_id<'tcx>(
cx: &mut DocContext<'tcx>,
types: &[hir::Ty<'tcx>],
2021-12-03 21:46:19 +00:00
body_id: hir::BodyId,
) -> Arguments {
let body = cx.tcx.hir().body(body_id);
Arguments {
values: types
.iter()
.enumerate()
.map(|(i, ty)| Argument {
name: name_from_pat(body.params[i].pat),
type_: clean_ty(ty, cx),
2021-12-03 21:46:19 +00:00
is_const: false,
})
.collect(),
}
}
2022-05-22 19:40:26 +00:00
fn clean_fn_decl_with_args<'tcx>(
cx: &mut DocContext<'tcx>,
decl: &hir::FnDecl<'tcx>,
args: Arguments,
) -> FnDecl {
FnDecl { inputs: args, output: decl.output.clean(cx), c_variadic: decl.c_variadic }
2013-08-15 20:28:54 +00:00
}
2022-05-22 19:40:26 +00:00
fn clean_fn_decl_from_did_and_sig<'tcx>(
cx: &mut DocContext<'tcx>,
did: Option<DefId>,
2022-05-22 19:40:26 +00:00
sig: ty::PolyFnSig<'tcx>,
2021-12-03 21:52:38 +00:00
) -> FnDecl {
let mut names = did.map_or(&[] as &[_], |did| cx.tcx.fn_arg_names(did)).iter();
2021-12-03 21:52:38 +00:00
// We assume all empty tuples are default return type. This theoretically can discard `-> ()`,
// but shouldn't change any code meaning.
let output = match clean_middle_ty(sig.skip_binder().output(), cx, None) {
2022-05-21 18:07:18 +00:00
Type::Tuple(inner) if inner.is_empty() => DefaultReturn,
ty => Return(ty),
};
2021-12-03 21:52:38 +00:00
FnDecl {
output,
2021-12-03 21:52:38 +00:00
c_variadic: sig.skip_binder().c_variadic,
inputs: Arguments {
values: sig
.skip_binder()
.inputs()
.iter()
.map(|t| Argument {
type_: clean_middle_ty(*t, cx, None),
2021-12-03 21:52:38 +00:00
name: names.next().map_or(kw::Empty, |i| i.name),
is_const: false,
})
.collect(),
},
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, FnRetTy> for hir::FnRetTy<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> FnRetTy {
2013-08-15 20:28:54 +00:00
match *self {
Self::Return(typ) => Return(clean_ty(typ, cx)),
2020-01-05 00:50:05 +00:00
Self::DefaultReturn(..) => DefaultReturn,
2013-08-15 20:28:54 +00:00
}
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, bool> for hir::IsAuto {
fn clean(&self, _: &mut DocContext<'tcx>) -> bool {
match *self {
hir::IsAuto::Yes => true,
hir::IsAuto::No => false,
}
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Path> for hir::TraitRef<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Path {
let path = self.path.clean(cx);
register_res(cx, path.res);
path
2013-08-15 20:28:54 +00:00
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, PolyTrait> for hir::PolyTraitRef<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> PolyTrait {
PolyTrait {
trait_: self.trait_ref.clean(cx),
generic_params: self
.bound_generic_params
.iter()
2022-06-04 09:53:34 +00:00
.filter(|p| !is_elided_lifetime(p))
.map(|x| clean_generic_param(cx, None, x))
.collect(),
}
2014-11-07 11:53:45 +00:00
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Item> for hir::TraitItem<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
let local_did = self.def_id.to_def_id();
cx.with_param_env(local_did, |cx| {
let inner = match self.kind {
2022-05-21 18:07:18 +00:00
hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
clean_ty(ty, cx),
ConstantKind::Local { def_id: local_did, body: default },
),
hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
2022-05-21 18:07:18 +00:00
let m = clean_function(cx, sig, self.generics, body);
MethodItem(m, None)
}
2021-10-01 15:12:39 +00:00
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
let (generics, decl) = enter_impl_trait(cx, |cx| {
// NOTE: generics must be cleaned before args
let generics = self.generics.clean(cx);
2021-12-03 21:44:47 +00:00
let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names);
let decl = clean_fn_decl_with_args(cx, sig.decl, args);
(generics, decl)
});
TyMethodItem(Function { decl, generics })
}
hir::TraitItemKind::Type(bounds, Some(default)) => {
let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx));
let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None);
AssocTypeItem(
Typedef {
type_: clean_ty(default, cx),
generics,
item_type: Some(item_type),
},
bounds,
)
}
hir::TraitItemKind::Type(bounds, None) => {
let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx));
let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
TyAssocTypeItem(Box::new(generics), bounds)
}
};
let what_rustc_thinks =
Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
// Trait items always inherit the trait's visibility -- we don't want to show `pub`.
Item { visibility: Inherited, ..what_rustc_thinks }
})
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
let local_did = self.def_id.to_def_id();
cx.with_param_env(local_did, |cx| {
let inner = match self.kind {
2022-05-21 18:07:18 +00:00
hir::ImplItemKind::Const(ty, expr) => {
let default = ConstantKind::Local { def_id: local_did, body: expr };
AssocConstItem(clean_ty(ty, cx), default)
}
hir::ImplItemKind::Fn(ref sig, body) => {
2022-05-21 18:07:18 +00:00
let m = clean_function(cx, sig, self.generics, body);
2022-02-02 11:44:51 +00:00
let defaultness = cx.tcx.associated_item(self.def_id).defaultness;
MethodItem(m, Some(defaultness))
}
2022-05-21 18:07:18 +00:00
hir::ImplItemKind::TyAlias(hir_ty) => {
let type_ = clean_ty(hir_ty, cx);
let generics = self.generics.clean(cx);
let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
AssocTypeItem(
Typedef { type_, generics, item_type: Some(item_type) },
Vec::new(),
)
}
};
2022-01-27 18:21:17 +00:00
let mut what_rustc_thinks =
Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
2022-01-27 18:21:17 +00:00
let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(self.def_id));
2022-01-27 18:21:17 +00:00
// Trait impl items always inherit the impl's visibility --
// we don't want to show `pub`.
if impl_ref.is_some() {
what_rustc_thinks.visibility = Inherited;
}
2022-01-27 18:21:17 +00:00
what_rustc_thinks
})
2013-08-15 20:28:54 +00:00
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
let tcx = cx.tcx;
let kind = match self.kind {
ty::AssocKind::Const => {
let ty = clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id));
let provided = match self.container {
ty::ImplContainer(_) => true,
ty::TraitContainer(_) => self.defaultness.has_value(),
};
if provided {
AssocConstItem(ty, ConstantKind::Extern { def_id: self.def_id })
} else {
TyAssocConstItem(ty)
}
2016-05-08 18:19:29 +00:00
}
ty::AssocKind::Fn => {
2021-12-03 21:34:46 +00:00
let generics = clean_ty_generics(
cx,
tcx.generics_of(self.def_id),
tcx.explicit_predicates_of(self.def_id),
);
let sig = tcx.fn_sig(self.def_id);
let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(self.def_id), sig);
if self.fn_has_self_parameter {
let self_ty = match self.container {
ty::ImplContainer(def_id) => tcx.type_of(def_id),
ty::TraitContainer(_) => tcx.types.self_param,
};
2020-06-24 21:40:33 +00:00
let self_arg_ty = sig.input(0).skip_binder();
if self_arg_ty == self_ty {
decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
} else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
if ty == self_ty {
match decl.inputs.values[0].type_ {
2019-12-22 22:42:04 +00:00
BorrowedRef { ref mut type_, .. } => {
**type_ = Generic(kw::SelfUpper)
}
_ => unreachable!(),
}
}
}
}
let provided = match self.container {
ty::ImplContainer(_) => true,
2019-12-22 22:42:04 +00:00
ty::TraitContainer(_) => self.defaultness.has_value(),
};
if provided {
let defaultness = match self.container {
ty::ImplContainer(_) => Some(self.defaultness),
ty::TraitContainer(_) => None,
};
MethodItem(Function { generics, decl }, defaultness)
} else {
TyMethodItem(Function { generics, decl })
2016-05-08 18:19:29 +00:00
}
}
ty::AssocKind::Type => {
let my_name = self.name;
fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
match (&param.kind, arg) {
(GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty)))
if *ty == param.name =>
{
true
}
(
GenericParamDefKind::Lifetime { .. },
GenericArg::Lifetime(Lifetime(lt)),
) if *lt == param.name => true,
(GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => {
match &c.kind {
ConstantKind::TyConst { expr } => expr == param.name.as_str(),
_ => false,
}
}
_ => false,
}
}
2020-06-30 21:41:57 +00:00
if let ty::TraitContainer(_) = self.container {
let bounds = tcx.explicit_item_bounds(self.def_id);
2020-06-30 21:41:57 +00:00
let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
2022-02-15 02:14:38 +00:00
let mut generics =
clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates);
// Filter out the bounds that are (likely?) directly attached to the associated type,
// as opposed to being located in the where clause.
2019-12-22 22:42:04 +00:00
let mut bounds = generics
.where_predicates
2022-02-15 02:14:38 +00:00
.drain_filter(|pred| match *pred {
WherePredicate::BoundPredicate {
ty: QPath { ref assoc, ref self_type, ref trait_, .. },
2022-02-15 02:14:38 +00:00
..
} => {
if assoc.name != my_name {
2022-02-15 02:14:38 +00:00
return false;
}
if trait_.def_id() != self.container.id() {
return false;
}
match **self_type {
Generic(ref s) if *s == kw::SelfUpper => {}
_ => return false,
}
match &assoc.args {
GenericArgs::AngleBracketed { args, bindings } => {
if !bindings.is_empty()
|| generics
.params
.iter()
.zip(args.iter())
2022-02-15 02:14:38 +00:00
.any(|(param, arg)| !param_eq_arg(param, arg))
{
return false;
}
}
GenericArgs::Parenthesized { .. } => {
// The only time this happens is if we're inside the rustdoc for Fn(),
// which only has one associated type, which is not a GAT, so whatever.
}
}
true
2019-12-22 22:42:04 +00:00
}
2022-02-15 02:14:38 +00:00
_ => false,
})
.flat_map(|pred| {
if let WherePredicate::BoundPredicate { bounds, .. } = pred {
bounds
} else {
unreachable!()
2019-12-22 22:42:04 +00:00
}
})
.collect::<Vec<_>>();
// Our Sized/?Sized bound didn't get handled when creating the generics
// because we didn't actually get our whole set of bounds until just now
// (some of them may have come from the trait). If we do have a sized
// bound, we remove it, and if we don't then we add the `?Sized` bound
// at the end.
match bounds.iter().position(|b| b.is_sized_bound(cx)) {
2019-12-22 22:42:04 +00:00
Some(i) => {
bounds.remove(i);
}
None => bounds.push(GenericBound::maybe_sized(cx)),
}
if self.defaultness.has_value() {
AssocTypeItem(
Typedef {
type_: clean_middle_ty(
tcx.type_of(self.def_id),
cx,
Some(self.def_id),
),
generics,
// FIXME: should we obtain the Type from HIR and pass it on here?
item_type: None,
},
bounds,
)
} else {
TyAssocTypeItem(Box::new(generics), bounds)
}
} else {
2021-02-14 12:18:17 +00:00
// FIXME: when could this happen? Associated items in inherent impls?
AssocTypeItem(
2019-12-22 22:42:04 +00:00
Typedef {
type_: clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id)),
2019-12-22 22:42:04 +00:00
generics: Generics { params: Vec::new(), where_predicates: Vec::new() },
2021-01-03 21:08:21 +00:00
item_type: None,
},
Vec::new(),
2019-12-22 22:42:04 +00:00
)
}
}
};
2022-01-27 18:21:17 +00:00
let mut what_rustc_thinks =
Item::from_def_id_and_parts(self.def_id, Some(self.name), kind, cx);
let impl_ref = tcx.impl_trait_ref(tcx.parent(self.def_id));
2022-01-27 18:21:17 +00:00
// Trait impl items always inherit the impl's visibility --
// we don't want to show `pub`.
if impl_ref.is_some() {
2022-01-27 18:21:17 +00:00
what_rustc_thinks.visibility = Visibility::Inherited;
}
2022-01-27 18:21:17 +00:00
what_rustc_thinks
}
}
2022-05-22 19:40:26 +00:00
fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
let hir::Ty { hir_id: _, span, ref kind } = *hir_ty;
let hir::TyKind::Path(qpath) = kind else { unreachable!() };
match qpath {
2022-05-21 18:07:18 +00:00
hir::QPath::Resolved(None, path) => {
if let Res::Def(DefKind::TyParam, did) = path.res {
if let Some(new_ty) = cx.substs.get(&did).and_then(|p| p.as_ty()).cloned() {
return new_ty;
}
if let Some(bounds) = cx.impl_trait_bounds.remove(&did.into()) {
return ImplTrait(bounds);
}
}
if let Some(expanded) = maybe_expand_private_type_alias(cx, path) {
expanded
} else {
let path = path.clean(cx);
resolve_type(cx, path)
}
}
2022-05-21 18:07:18 +00:00
hir::QPath::Resolved(Some(qself), p) => {
// Try to normalize `<X as Y>::T` to a type
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
if let Some(normalized_value) = normalize(cx, ty) {
return clean_middle_ty(normalized_value, cx, None);
}
let trait_segments = &p.segments[..p.segments.len() - 1];
let trait_def = cx.tcx.associated_item(p.res.def_id()).container.id();
let trait_ = self::Path {
res: Res::Def(DefKind::Trait, trait_def),
2021-11-07 17:19:25 +00:00
segments: trait_segments.iter().map(|x| x.clean(cx)).collect(),
};
register_res(cx, trait_.res);
let self_def_id = DefId::local(qself.hir_id.owner.local_def_index);
let self_type = clean_ty(qself, cx);
let should_show_cast = compute_should_show_cast(Some(self_def_id), &trait_, &self_type);
Type::QPath {
assoc: Box::new(p.segments.last().expect("segments were empty").clean(cx)),
should_show_cast,
self_type: Box::new(self_type),
trait_,
}
}
2022-05-21 18:07:18 +00:00
hir::QPath::TypeRelative(qself, segment) => {
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
let res = match ty.kind() {
ty::Projection(proj) => Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id),
// Rustdoc handles `ty::Error`s by turning them into `Type::Infer`s.
ty::Error(_) => return Type::Infer,
_ => bug!("clean: expected associated type, found `{:?}`", ty),
};
let trait_ = hir::Path { span, res, segments: &[] }.clean(cx);
register_res(cx, trait_.res);
let self_def_id = res.opt_def_id();
let self_type = clean_ty(qself, cx);
let should_show_cast = compute_should_show_cast(self_def_id, &trait_, &self_type);
Type::QPath {
assoc: Box::new(segment.clean(cx)),
should_show_cast,
self_type: Box::new(self_type),
trait_,
}
}
hir::QPath::LangItem(..) => bug!("clean: requiring documentation of lang item"),
}
}
2022-05-22 19:40:26 +00:00
fn maybe_expand_private_type_alias<'tcx>(
cx: &mut DocContext<'tcx>,
path: &hir::Path<'tcx>,
) -> Option<Type> {
2021-10-31 04:26:38 +00:00
let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
// Substitute private type aliases
2022-04-27 07:51:33 +00:00
let def_id = def_id.as_local()?;
2021-10-31 04:26:38 +00:00
let alias = if !cx.cache.access_levels.is_exported(def_id.to_def_id()) {
2021-10-20 20:38:10 +00:00
&cx.tcx.hir().expect_item(def_id).kind
2021-10-31 04:26:38 +00:00
} else {
return None;
};
2021-10-31 04:26:38 +00:00
let hir::ItemKind::TyAlias(ty, generics) = alias else { return None };
2021-10-31 04:26:38 +00:00
let provided_params = &path.segments.last().expect("segments were empty");
let mut substs = FxHashMap::default();
2021-10-31 04:26:38 +00:00
let generic_args = provided_params.args();
let mut indices: hir::GenericParamCount = Default::default();
for param in generics.params.iter() {
match param.kind {
hir::GenericParamKind::Lifetime { .. } => {
let mut j = 0;
let lifetime = generic_args.args.iter().find_map(|arg| match arg {
hir::GenericArg::Lifetime(lt) => {
if indices.lifetimes == j {
return Some(lt);
}
2021-10-31 04:26:38 +00:00
j += 1;
None
}
2021-10-31 04:26:38 +00:00
_ => None,
});
if let Some(lt) = lifetime.cloned() {
let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
let cleaned = if !lt.is_elided() { lt.clean(cx) } else { Lifetime::elided() };
substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned));
2021-10-31 04:26:38 +00:00
}
indices.lifetimes += 1;
}
hir::GenericParamKind::Type { ref default, .. } => {
let ty_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
let mut j = 0;
let type_ = generic_args.args.iter().find_map(|arg| match arg {
hir::GenericArg::Type(ty) => {
if indices.types == j {
return Some(ty);
}
2021-10-31 04:26:38 +00:00
j += 1;
None
}
2021-10-31 04:26:38 +00:00
_ => None,
});
if let Some(ty) = type_ {
substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(clean_ty(ty, cx)));
2021-10-31 04:26:38 +00:00
} else if let Some(default) = *default {
substs.insert(
ty_param_def_id.to_def_id(),
SubstParam::Type(clean_ty(default, cx)),
);
2021-10-31 04:26:38 +00:00
}
indices.types += 1;
}
hir::GenericParamKind::Const { .. } => {
let const_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
let mut j = 0;
let const_ = generic_args.args.iter().find_map(|arg| match arg {
hir::GenericArg::Const(ct) => {
if indices.consts == j {
return Some(ct);
}
2021-10-31 04:26:38 +00:00
j += 1;
None
}
2021-10-31 04:26:38 +00:00
_ => None,
});
if let Some(ct) = const_ {
substs.insert(
const_param_def_id.to_def_id(),
SubstParam::Constant(clean_const(ct, cx)),
);
}
2021-10-31 04:26:38 +00:00
// FIXME(const_generics_defaults)
indices.consts += 1;
}
}
}
2021-10-31 04:26:38 +00:00
Some(cx.enter_alias(substs, |cx| clean_ty(ty, cx)))
}
pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
use rustc_hir::*;
2021-12-23 09:01:59 +00:00
match ty.kind {
TyKind::Never => Primitive(PrimitiveType::Never),
TyKind::Ptr(ref m) => RawPointer(m.mutbl, Box::new(clean_ty(m.ty, cx))),
TyKind::Rptr(ref l, ref m) => {
// There are two times a `Fresh` lifetime can be created:
// 1. For `&'_ x`, written by the user. This corresponds to `lower_lifetime` in `rustc_ast_lowering`.
// 2. For `&x` as a parameter to an `async fn`. This corresponds to `elided_ref_lifetime in `rustc_ast_lowering`.
// See #59286 for more information.
// Ideally we would only hide the `'_` for case 2., but I don't know a way to distinguish it.
// Turning `fn f(&'_ self)` into `fn f(&self)` isn't the worst thing in the world, though;
// there's no case where it could cause the function to fail to compile.
let elided =
l.is_elided() || matches!(l.name, LifetimeName::Param(_, ParamName::Fresh));
let lifetime = if elided { None } else { Some(l.clean(cx)) };
BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) }
}
TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))),
TyKind::Array(ty, ref length) => {
let length = match length {
hir::ArrayLen::Infer(_, _) => "_".to_string(),
hir::ArrayLen::Body(anon_const) => {
let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id);
// NOTE(min_const_generics): We can't use `const_eval_poly` for constants
// as we currently do not supply the parent generics to anonymous constants
// but do allow `ConstKind::Param`.
//
// `const_eval_poly` tries to to first substitute generic parameters which
// results in an ICE while manually constructing the constant and using `eval`
// does nothing for `ConstKind::Param`.
let ct = ty::Const::from_anon_const(cx.tcx, def_id);
let param_env = cx.tcx.param_env(def_id);
print_const(cx, ct.eval(cx.tcx, param_env))
2018-10-02 10:31:05 +00:00
}
};
Array(Box::new(clean_ty(ty, cx)), length)
}
TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
TyKind::OpaqueDef(item_id, _) => {
let item = cx.tcx.hir().item(item_id);
if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
ImplTrait(ty.bounds.iter().filter_map(|x| x.clean(cx)).collect())
} else {
unreachable!()
2018-10-02 10:31:05 +00:00
}
}
TyKind::Path(_) => clean_qpath(ty, cx),
TyKind::TraitObject(bounds, ref lifetime, _) => {
let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect();
let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
DynTrait(bounds, lifetime)
}
TyKind::BareFn(barefn) => BareFunction(Box::new(barefn.clean(cx))),
// Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
TyKind::Infer | TyKind::Err => Infer,
TyKind::Typeof(..) => panic!("unimplemented type {:?}", ty.kind),
2013-08-15 20:28:54 +00:00
}
}
/// Returns `None` if the type could not be normalized
fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
// HACK: low-churn fix for #79459 while we wait for a trait normalization fix
if !cx.tcx.sess.opts.unstable_opts.normalize_docs {
return None;
}
2022-02-01 11:29:22 +00:00
use crate::rustc_trait_selection::infer::TyCtxtInferExt;
use crate::rustc_trait_selection::traits::query::normalize::AtExt;
use rustc_middle::traits::ObligationCause;
// Try to normalize `<X as Y>::T` to a type
let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
2022-02-01 11:29:22 +00:00
let normalized = cx.tcx.infer_ctxt().enter(|infcx| {
infcx
.at(&ObligationCause::dummy(), cx.param_env)
.normalize(lifted)
.map(|resolved| infcx.resolve_vars_if_possible(resolved.value))
});
match normalized {
Ok(normalized_value) => {
2022-02-01 11:29:22 +00:00
debug!("normalized {:?} to {:?}", ty, normalized_value);
Some(normalized_value)
}
Err(err) => {
2022-02-01 11:29:22 +00:00
debug!("failed to normalize {:?}: {:?}", ty, err);
None
}
}
}
pub(crate) fn clean_middle_ty<'tcx>(
this: Ty<'tcx>,
cx: &mut DocContext<'tcx>,
def_id: Option<DefId>,
) -> Type {
trace!("cleaning type: {:?}", this);
let ty = normalize(cx, this).unwrap_or(this);
match *ty.kind() {
ty::Never => Primitive(PrimitiveType::Never),
ty::Bool => Primitive(PrimitiveType::Bool),
ty::Char => Primitive(PrimitiveType::Char),
ty::Int(int_ty) => Primitive(int_ty.into()),
ty::Uint(uint_ty) => Primitive(uint_ty.into()),
ty::Float(float_ty) => Primitive(float_ty.into()),
ty::Str => Primitive(PrimitiveType::Str),
ty::Slice(ty) => Slice(Box::new(clean_middle_ty(ty, cx, None))),
ty::Array(ty, n) => {
let mut n = cx.tcx.lift(n).expect("array lift failed");
n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
let n = print_const(cx, n);
Array(Box::new(clean_middle_ty(ty, cx, None)), n)
}
ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(clean_middle_ty(mt.ty, cx, None))),
ty::Ref(r, ty, mutbl) => BorrowedRef {
lifetime: r.clean(cx),
mutability: mutbl,
type_: Box::new(clean_middle_ty(ty, cx, None)),
},
ty::FnDef(..) | ty::FnPtr(_) => {
let ty = cx.tcx.lift(this).expect("FnPtr lift failed");
let sig = ty.fn_sig(cx.tcx);
let decl = clean_fn_decl_from_did_and_sig(cx, None, sig);
BareFunction(Box::new(BareFunctionDecl {
unsafety: sig.unsafety(),
generic_params: Vec::new(),
decl,
abi: sig.abi(),
}))
}
ty::Adt(def, substs) => {
let did = def.did();
let kind = match def.adt_kind() {
AdtKind::Struct => ItemType::Struct,
AdtKind::Union => ItemType::Union,
AdtKind::Enum => ItemType::Enum,
};
inline::record_extern_fqn(cx, did, kind);
let path = external_path(cx, did, false, vec![], substs);
Type::Path { path }
}
ty::Foreign(did) => {
inline::record_extern_fqn(cx, did, ItemType::ForeignType);
let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
Type::Path { path }
}
ty::Dynamic(obj, ref reg) => {
// HACK: pick the first `did` as the `did` of the trait object. Someone
// might want to implement "native" support for marker-trait-only
// trait objects.
let mut dids = obj.principal_def_id().into_iter().chain(obj.auto_traits());
let did = dids
.next()
.unwrap_or_else(|| panic!("found trait object `{:?}` with no traits?", this));
let substs = match obj.principal() {
Some(principal) => principal.skip_binder().substs,
// marker traits have no substs.
_ => cx.tcx.intern_substs(&[]),
};
2018-12-15 15:35:55 +00:00
inline::record_extern_fqn(cx, did, ItemType::Trait);
let lifetime = reg.clean(cx);
let mut bounds = vec![];
for did in dids {
let empty = cx.tcx.intern_substs(&[]);
let path = external_path(cx, did, false, vec![], empty);
inline::record_extern_fqn(cx, did, ItemType::Trait);
let bound = PolyTrait { trait_: path, generic_params: Vec::new() };
bounds.push(bound);
}
let mut bindings = vec![];
for pb in obj.projection_bounds() {
bindings.push(TypeBinding {
assoc: projection_to_path_segment(
pb.skip_binder()
.lift_to_tcx(cx.tcx)
.unwrap()
// HACK(compiler-errors): Doesn't actually matter what self
// type we put here, because we're only using the GAT's substs.
.with_self_ty(cx.tcx, cx.tcx.types.self_param)
.projection_ty,
cx,
),
kind: TypeBindingKind::Equality { term: pb.skip_binder().term.clean(cx) },
});
}
let path = external_path(cx, did, false, bindings, substs);
bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() });
DynTrait(bounds, lifetime)
}
ty::Tuple(t) => Tuple(t.iter().map(|t| clean_middle_ty(t, cx, None)).collect()),
ty::Projection(ref data) => clean_projection(*data, cx, def_id),
ty::Param(ref p) => {
if let Some(bounds) = cx.impl_trait_bounds.remove(&p.index.into()) {
ImplTrait(bounds)
} else {
Generic(p.name)
}
}
ty::Opaque(def_id, substs) => {
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
// by looking up the bounds associated with the def_id.
let substs = cx.tcx.lift(substs).expect("Opaque lift failed");
let bounds = cx
.tcx
.explicit_item_bounds(def_id)
.iter()
.map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs))
.collect::<Vec<_>>();
let mut regions = vec![];
let mut has_sized = false;
let mut bounds = bounds
.iter()
.filter_map(|bound| {
let bound_predicate = bound.kind();
let trait_ref = match bound_predicate.skip_binder() {
ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
if let Some(r) = reg.clean(cx) {
regions.push(GenericBound::Outlives(r));
}
return None;
}
_ => return None,
};
if let Some(sized) = cx.tcx.lang_items().sized_trait() {
if trait_ref.def_id() == sized {
has_sized = true;
return None;
}
}
let bindings: Vec<_> = bounds
.iter()
.filter_map(|bound| {
if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder()
{
if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
Some(TypeBinding {
assoc: projection_to_path_segment(proj.projection_ty, cx),
kind: TypeBindingKind::Equality {
term: proj.term.clean(cx),
},
})
2019-12-22 22:42:04 +00:00
} else {
None
}
} else {
None
}
})
.collect();
2019-12-22 22:42:04 +00:00
Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, &bindings))
})
.collect::<Vec<_>>();
bounds.extend(regions);
if !has_sized && !bounds.is_empty() {
bounds.insert(0, GenericBound::maybe_sized(cx));
}
ImplTrait(bounds)
}
ty::Closure(..) => panic!("Closure"),
ty::Generator(..) => panic!("Generator"),
ty::Bound(..) => panic!("Bound"),
ty::Placeholder(..) => panic!("Placeholder"),
ty::GeneratorWitness(..) => panic!("GeneratorWitness"),
ty::Infer(..) => panic!("Infer"),
ty::Error(_) => panic!("Error"),
}
}
pub(crate) fn clean_field<'tcx>(field: &hir::FieldDef<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
let def_id = cx.tcx.hir().local_def_id(field.hir_id).to_def_id();
clean_field_with_def_id(def_id, field.ident.name, clean_ty(field.ty, cx), cx)
2013-08-15 20:28:54 +00:00
}
pub(crate) fn clean_middle_field<'tcx>(field: &ty::FieldDef, cx: &mut DocContext<'tcx>) -> Item {
clean_field_with_def_id(
field.did,
field.name,
clean_middle_ty(cx.tcx.type_of(field.did), cx, Some(field.did)),
cx,
)
}
pub(crate) fn clean_field_with_def_id(
def_id: DefId,
name: Symbol,
ty: Type,
cx: &mut DocContext<'_>,
) -> Item {
let what_rustc_thinks =
Item::from_def_id_and_parts(def_id, Some(name), StructFieldItem(ty), cx);
if is_field_vis_inherited(cx.tcx, def_id) {
// Variant fields inherit their enum's visibility.
Item { visibility: Visibility::Inherited, ..what_rustc_thinks }
} else {
what_rustc_thinks
}
}
fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
let parent = tcx.parent(def_id);
match tcx.def_kind(parent) {
DefKind::Struct | DefKind::Union => false,
DefKind::Variant => true,
parent_kind => panic!("unexpected parent kind: {:?}", parent_kind),
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Visibility> for ty::Visibility {
2020-12-17 00:14:21 +00:00
fn clean(&self, _cx: &mut DocContext<'_>) -> Visibility {
match *self {
ty::Visibility::Public => Visibility::Public,
// NOTE: this is not quite right: `ty` uses `Invisible` to mean 'private',
// while rustdoc really does mean inherited. That means that for enum variants, such as
// `pub enum E { V }`, `V` will be marked as `Public` by `ty`, but as `Inherited` by rustdoc.
// Various parts of clean override `tcx.visibility` explicitly to make sure this distinction is captured.
ty::Visibility::Invisible => Visibility::Inherited,
ty::Visibility::Restricted(module) => Visibility::Restricted(module),
}
2013-08-15 20:28:54 +00:00
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, VariantStruct> for rustc_hir::VariantData<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> VariantStruct {
2013-08-15 20:28:54 +00:00
VariantStruct {
struct_type: CtorKind::from_hir(self),
fields: self.fields().iter().map(|x| clean_field(x, cx)).collect(),
2013-08-15 20:28:54 +00:00
}
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Vec<Item>> for hir::VariantData<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Vec<Item> {
self.fields().iter().map(|x| clean_field(x, cx)).collect()
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Item> for ty::VariantDef {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
let kind = match self.ctor_kind {
CtorKind::Const => Variant::CLike,
CtorKind::Fn => Variant::Tuple(
self.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
),
CtorKind::Fictive => Variant::Struct(VariantStruct {
struct_type: CtorKind::Fictive,
fields: self.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
2019-12-22 22:42:04 +00:00
}),
2014-05-23 23:14:54 +00:00
};
let what_rustc_thinks =
Item::from_def_id_and_parts(self.def_id, Some(self.name), VariantItem(kind), cx);
// don't show `pub` for variants, which always inherit visibility
Item { visibility: Inherited, ..what_rustc_thinks }
2014-05-23 23:14:54 +00:00
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Variant> for hir::VariantData<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Variant {
match self {
hir::VariantData::Struct(..) => Variant::Struct(self.clean(cx)),
hir::VariantData::Tuple(..) => Variant::Tuple(self.clean(cx)),
hir::VariantData::Unit(..) => Variant::CLike,
}
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Path> for hir::Path<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Path {
2021-11-07 17:19:25 +00:00
Path { res: self.res, segments: self.segments.iter().map(|x| x.clean(cx)).collect() }
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericArgs {
if self.parenthesized {
let output = clean_ty(self.bindings[0].ty(), cx);
let output =
if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
let inputs = self.inputs().iter().map(|x| clean_ty(x, cx)).collect::<Vec<_>>().into();
2021-11-07 17:19:25 +00:00
GenericArgs::Parenthesized { inputs, output }
} else {
2021-11-07 17:19:25 +00:00
let args = self
.args
.iter()
.map(|arg| match arg {
hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
GenericArg::Lifetime(lt.clean(cx))
}
hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
2021-11-07 17:19:25 +00:00
hir::GenericArg::Infer(_inf) => GenericArg::Infer,
})
.collect::<Vec<_>>()
.into();
let bindings = self.bindings.iter().map(|x| x.clean(cx)).collect::<Vec<_>>().into();
2021-11-07 17:19:25 +00:00
GenericArgs::AngleBracketed { args, bindings }
}
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, PathSegment> for hir::PathSegment<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> PathSegment {
PathSegment { name: self.ident.name, args: self.args().clean(cx) }
2013-08-15 20:28:54 +00:00
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, BareFunctionDecl> for hir::BareFnTy<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> BareFunctionDecl {
let (generic_params, decl) = enter_impl_trait(cx, |cx| {
// NOTE: generics must be cleaned before args
2022-06-04 09:53:34 +00:00
let generic_params = self
.generic_params
.iter()
.filter(|p| !is_elided_lifetime(p))
.map(|x| clean_generic_param(cx, None, x))
.collect();
2021-12-03 21:44:47 +00:00
let args = clean_args_from_types_and_names(cx, self.decl.inputs, self.param_names);
let decl = clean_fn_decl_with_args(cx, self.decl, args);
2021-11-07 17:19:25 +00:00
(generic_params, decl)
2018-05-03 13:24:50 +00:00
});
2019-12-22 22:42:04 +00:00
BareFunctionDecl { unsafety: self.unsafety, abi: self.abi, decl, generic_params }
2013-08-15 20:28:54 +00:00
}
}
2022-05-22 19:40:26 +00:00
fn clean_maybe_renamed_item<'tcx>(
cx: &mut DocContext<'tcx>,
item: &hir::Item<'tcx>,
2021-12-03 21:55:59 +00:00
renamed: Option<Symbol>,
) -> Vec<Item> {
use hir::ItemKind;
let def_id = item.def_id.to_def_id();
let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
cx.with_param_env(def_id, |cx| {
let kind = match item.kind {
ItemKind::Static(ty, mutability, body_id) => {
StaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: Some(body_id) })
2021-12-03 21:55:59 +00:00
}
ItemKind::Const(ty, body_id) => ConstantItem(Constant {
type_: clean_ty(ty, cx),
2021-12-03 21:55:59 +00:00
kind: ConstantKind::Local { body: body_id, def_id },
}),
ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
bounds: ty.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
2021-12-03 21:55:59 +00:00
generics: ty.generics.clean(cx),
}),
2022-05-21 18:07:18 +00:00
ItemKind::TyAlias(hir_ty, generics) => {
let rustdoc_ty = clean_ty(hir_ty, cx);
let ty = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
TypedefItem(Typedef {
type_: rustdoc_ty,
generics: generics.clean(cx),
item_type: Some(ty),
})
2021-12-03 21:55:59 +00:00
}
2022-05-21 18:07:18 +00:00
ItemKind::Enum(ref def, generics) => EnumItem(Enum {
2021-12-03 21:55:59 +00:00
variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
generics: generics.clean(cx),
}),
2022-05-21 18:07:18 +00:00
ItemKind::TraitAlias(generics, bounds) => TraitAliasItem(TraitAlias {
2021-12-03 21:55:59 +00:00
generics: generics.clean(cx),
bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(),
2021-12-03 21:55:59 +00:00
}),
2022-05-21 18:07:18 +00:00
ItemKind::Union(ref variant_data, generics) => UnionItem(Union {
2021-12-03 21:55:59 +00:00
generics: generics.clean(cx),
fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
2021-12-03 21:55:59 +00:00
}),
2022-05-21 18:07:18 +00:00
ItemKind::Struct(ref variant_data, generics) => StructItem(Struct {
2021-12-03 21:55:59 +00:00
struct_type: CtorKind::from_hir(variant_data),
generics: generics.clean(cx),
fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
2021-12-03 21:55:59 +00:00
}),
2022-05-21 18:07:18 +00:00
ItemKind::Impl(impl_) => return clean_impl(impl_, item.hir_id(), cx),
2021-12-03 21:55:59 +00:00
// proc macros can have a name set by attributes
2022-05-21 18:07:18 +00:00
ItemKind::Fn(ref sig, generics, body_id) => {
2021-12-03 21:55:59 +00:00
clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
}
ItemKind::Macro(ref macro_def, _) => {
2021-12-03 21:55:59 +00:00
let ty_vis = cx.tcx.visibility(def_id).clean(cx);
MacroItem(Macro {
source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
})
}
ItemKind::Trait(_, _, generics, bounds, item_ids) => {
2021-12-03 21:55:59 +00:00
let items =
item_ids.iter().map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)).collect();
2021-12-03 21:55:59 +00:00
TraitItem(Trait {
def_id,
2021-12-03 21:55:59 +00:00
items,
2020-11-23 02:32:18 +00:00
generics: generics.clean(cx),
bounds: bounds.iter().filter_map(|x| x.clean(cx)).collect(),
2021-12-03 21:55:59 +00:00
})
}
ItemKind::ExternCrate(orig_name) => {
return clean_extern_crate(item, name, orig_name, cx);
}
ItemKind::Use(path, kind) => {
return clean_use_statement(item, name, path, kind, cx);
}
_ => unreachable!("not yet converted"),
};
2021-12-03 21:55:59 +00:00
vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)]
})
2013-08-15 20:28:54 +00:00
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, Item> for hir::Variant<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
let kind = VariantItem(self.data.clean(cx));
let what_rustc_thinks =
Item::from_hir_id_and_parts(self.id, Some(self.ident.name), kind, cx);
// don't show `pub` for variants, which are always public
Item { visibility: Inherited, ..what_rustc_thinks }
}
}
2022-05-22 19:40:26 +00:00
fn clean_impl<'tcx>(
impl_: &hir::Impl<'tcx>,
hir_id: hir::HirId,
cx: &mut DocContext<'tcx>,
) -> Vec<Item> {
let tcx = cx.tcx;
2020-11-22 18:34:06 +00:00
let mut ret = Vec::new();
2021-11-07 17:06:50 +00:00
let trait_ = impl_.of_trait.as_ref().map(|t| t.clean(cx));
let items =
impl_.items.iter().map(|ii| tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>();
let def_id = tcx.hir().local_def_id(hir_id);
2020-11-22 18:34:06 +00:00
// If this impl block is an implementation of the Deref trait, then we
// need to try inlining the target's inherent impl blocks as well.
if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() {
2020-11-22 18:34:06 +00:00
build_deref_target_impls(cx, &items, &mut ret);
}
let for_ = clean_ty(impl_.self_ty, cx);
let type_alias = for_.def_id(&cx.cache).and_then(|did| match tcx.def_kind(did) {
DefKind::TyAlias => Some(clean_middle_ty(tcx.type_of(did), cx, Some(did))),
2020-11-22 18:34:06 +00:00
_ => None,
});
let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
2020-11-22 18:34:06 +00:00
let kind = ImplItem(Impl {
unsafety: impl_.unsafety,
generics: impl_.generics.clean(cx),
2020-11-22 18:34:06 +00:00
trait_,
for_,
items,
polarity: tcx.impl_polarity(def_id),
kind: if utils::has_doc_flag(tcx, def_id.to_def_id(), sym::fake_variadic) {
ImplKind::FakeVaradic
} else {
ImplKind::Normal
},
2020-01-15 17:52:04 +00:00
});
Item::from_hir_id_and_parts(hir_id, None, kind, cx)
2020-11-22 18:34:06 +00:00
};
if let Some(type_alias) = type_alias {
ret.push(make_item(trait_.clone(), type_alias, items.clone()));
}
2020-11-22 18:34:06 +00:00
ret.push(make_item(trait_, for_, items));
ret
}
2022-05-22 19:40:26 +00:00
fn clean_extern_crate<'tcx>(
krate: &hir::Item<'tcx>,
2020-11-23 02:51:57 +00:00
name: Symbol,
orig_name: Option<Symbol>,
2022-05-22 19:40:26 +00:00
cx: &mut DocContext<'tcx>,
2020-11-23 02:51:57 +00:00
) -> Vec<Item> {
// this is the ID of the `extern crate` statement
let cnum = cx.tcx.extern_mod_stmt_cnum(krate.def_id).unwrap_or(LOCAL_CRATE);
2020-11-23 02:51:57 +00:00
// this is the ID of the crate itself
let crate_def_id = cnum.as_def_id();
2021-01-24 12:17:54 +00:00
let attrs = cx.tcx.hir().attrs(krate.hir_id());
let ty_vis = cx.tcx.visibility(krate.def_id);
let please_inline = ty_vis.is_public()
2021-01-24 12:17:54 +00:00
&& attrs.iter().any(|a| {
2020-11-23 02:51:57 +00:00
a.has_name(sym::doc)
&& match a.meta_item_list() {
Some(l) => attr::list_contains_name(&l, sym::inline),
None => false,
}
});
if please_inline {
let mut visited = FxHashSet::default();
2019-01-11 01:27:44 +00:00
2020-11-23 02:51:57 +00:00
let res = Res::Def(DefKind::Mod, crate_def_id);
if let Some(items) = inline::try_inline(
cx,
cx.tcx.parent_module(krate.hir_id()).to_def_id(),
2021-07-06 12:43:03 +00:00
Some(krate.def_id.to_def_id()),
2020-11-23 02:51:57 +00:00
res,
name,
2021-01-24 12:17:54 +00:00
Some(attrs),
2020-11-23 02:51:57 +00:00
&mut visited,
) {
return items;
}
}
2020-11-23 02:51:57 +00:00
// FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason
vec![Item {
name: Some(name),
attrs: Box::new(attrs.clean(cx)),
item_id: crate_def_id.into(),
visibility: ty_vis.clean(cx),
kind: box ExternCrateItem { src: orig_name },
cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
2020-11-23 02:51:57 +00:00
}]
2013-08-15 20:28:54 +00:00
}
2022-05-22 19:40:26 +00:00
fn clean_use_statement<'tcx>(
import: &hir::Item<'tcx>,
2021-01-14 19:49:58 +00:00
name: Symbol,
2022-05-22 19:40:26 +00:00
path: &hir::Path<'tcx>,
2021-01-14 19:49:58 +00:00
kind: hir::UseKind,
2022-05-22 19:40:26 +00:00
cx: &mut DocContext<'tcx>,
2021-01-14 19:49:58 +00:00
) -> Vec<Item> {
// We need this comparison because some imports (for std types for example)
// are "inserted" as well but directly by the compiler and they should not be
// taken into account.
if import.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) {
return Vec::new();
}
2021-11-08 03:54:19 +00:00
let visibility = cx.tcx.visibility(import.def_id);
2021-01-24 12:17:54 +00:00
let attrs = cx.tcx.hir().attrs(import.hir_id());
let inline_attr = attrs.lists(sym::doc).get_word_attr(sym::inline);
2021-11-08 03:54:19 +00:00
let pub_underscore = visibility.is_public() && name == kw::Underscore;
let current_mod = cx.tcx.parent_module_from_def_id(import.def_id);
// The parent of the module in which this import resides. This
// is the same as `current_mod` if that's already the top
// level module.
2021-11-08 03:54:19 +00:00
let parent_mod = cx.tcx.parent_module_from_def_id(current_mod);
2021-01-14 19:49:58 +00:00
// This checks if the import can be seen from a higher level module.
// In other words, it checks if the visibility is the equivalent of
// `pub(super)` or higher. If the current module is the top level
// module, there isn't really a parent module, which makes the results
// meaningless. In this case, we make sure the answer is `false`.
let is_visible_from_parent_mod = visibility.is_accessible_from(parent_mod.to_def_id(), cx.tcx)
&& !current_mod.is_top_level_module();
if pub_underscore {
if let Some(ref inline) = inline_attr {
rustc_errors::struct_span_err!(
cx.tcx.sess,
inline.span(),
E0780,
"anonymous imports cannot be inlined"
)
.span_label(import.span, "anonymous import")
.emit();
}
2021-01-14 19:49:58 +00:00
}
2021-01-14 19:49:58 +00:00
// We consider inlining the documentation of `pub use` statements, but we
// forcefully don't inline if this is not public or if the
// #[doc(no_inline)] attribute is present.
// Don't inline doc(hidden) imports so they can be stripped at a later stage.
2022-07-15 15:37:07 +00:00
let mut denied = cx.output_format.is_json()
|| !(visibility.is_public()
|| (cx.render_options.document_private && is_visible_from_parent_mod))
2021-01-14 19:49:58 +00:00
|| pub_underscore
2021-01-24 12:17:54 +00:00
|| attrs.iter().any(|a| {
2021-01-14 19:49:58 +00:00
a.has_name(sym::doc)
&& match a.meta_item_list() {
Some(l) => {
attr::list_contains_name(&l, sym::no_inline)
|| attr::list_contains_name(&l, sym::hidden)
2019-12-22 22:42:04 +00:00
}
2021-01-14 19:49:58 +00:00
None => false,
2018-06-15 23:16:43 +00:00
}
2021-01-14 19:49:58 +00:00
});
// Also check whether imports were asked to be inlined, in case we're trying to re-export a
// crate in Rust 2018+
let path = path.clean(cx);
let inner = if kind == hir::UseKind::Glob {
if !denied {
let mut visited = FxHashSet::default();
if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) {
return items;
2018-06-15 23:16:43 +00:00
}
2021-01-14 19:49:58 +00:00
}
Import::new_glob(resolve_use_source(cx, path), true)
} else {
if inline_attr.is_none() {
2021-01-14 19:49:58 +00:00
if let Res::Def(DefKind::Mod, did) = path.res {
if !did.is_local() && did.is_crate_root() {
2021-01-14 19:49:58 +00:00
// if we're `pub use`ing an extern crate root, don't inline it unless we
// were specifically asked for it
denied = true;
}
}
2021-01-14 19:49:58 +00:00
}
if !denied {
let mut visited = FxHashSet::default();
2021-07-06 12:43:03 +00:00
let import_def_id = import.def_id.to_def_id();
2021-01-14 19:49:58 +00:00
if let Some(mut items) = inline::try_inline(
cx,
cx.tcx.parent_module(import.hir_id()).to_def_id(),
2021-07-06 12:43:03 +00:00
Some(import_def_id),
2021-01-14 19:49:58 +00:00
path.res,
name,
2021-01-24 12:17:54 +00:00
Some(attrs),
2021-01-14 19:49:58 +00:00
&mut visited,
) {
items.push(Item::from_def_id_and_parts(
2021-07-06 12:43:03 +00:00
import_def_id,
2021-01-14 19:49:58 +00:00
None,
ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)),
cx,
2021-01-14 19:49:58 +00:00
));
return items;
}
2021-01-14 19:49:58 +00:00
}
Import::new_simple(name, resolve_use_source(cx, path), true)
};
2018-07-12 20:00:57 +00:00
vec![Item::from_def_id_and_parts(import.def_id.to_def_id(), None, ImportItem(inner), cx)]
2013-08-15 20:28:54 +00:00
}
2022-05-22 19:40:26 +00:00
fn clean_maybe_renamed_foreign_item<'tcx>(
cx: &mut DocContext<'tcx>,
item: &hir::ForeignItem<'tcx>,
renamed: Option<Symbol>,
) -> Item {
let def_id = item.def_id.to_def_id();
cx.with_param_env(def_id, |cx| {
let kind = match item.kind {
2022-05-21 18:07:18 +00:00
hir::ForeignItemKind::Fn(decl, names, generics) => {
let (generics, decl) = enter_impl_trait(cx, |cx| {
// NOTE: generics must be cleaned before args
let generics = generics.clean(cx);
let args = clean_args_from_types_and_names(cx, decl.inputs, names);
let decl = clean_fn_decl_with_args(cx, decl, args);
(generics, decl)
});
ForeignFunctionItem(Function { decl, generics })
}
2022-05-21 18:07:18 +00:00
hir::ForeignItemKind::Static(ty, mutability) => {
ForeignStaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: None })
}
hir::ForeignItemKind::Type => ForeignTypeItem,
};
2018-07-12 20:00:57 +00:00
Item::from_hir_id_and_parts(
item.hir_id(),
Some(renamed.unwrap_or(item.ident.name)),
kind,
cx,
)
})
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, TypeBinding> for hir::TypeBinding<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> TypeBinding {
TypeBinding {
assoc: PathSegment { name: self.ident.name, args: self.gen_args.clean(cx) },
kind: self.kind.clean(cx),
}
2019-05-08 19:57:06 +00:00
}
}
2022-05-22 19:40:26 +00:00
impl<'tcx> Clean<'tcx, TypeBindingKind> for hir::TypeBindingKind<'tcx> {
fn clean(&self, cx: &mut DocContext<'tcx>) -> TypeBindingKind {
2019-05-08 19:57:06 +00:00
match *self {
hir::TypeBindingKind::Equality { ref term } => {
TypeBindingKind::Equality { term: term.clean(cx) }
}
2022-05-21 18:07:18 +00:00
hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint {
bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(),
},
}
}
}