mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 15:01:51 +00:00
Rollup merge of #95316 - fmease:rustdoc-discr-req-prov-assoc-consts-tys, r=notriddle,GuillaumeGomez
Rustdoc: Discriminate required and provided associated constants and types Currently, rustdoc merely separates required and provided associated _functions_ (i.e. methods). This PR extends this to constants (fixes #94652) and types. This makes the documentation of all three kinds of associated items more alike and consistent. As an aside, associated types may actually be provided / have a default when users enable the unstable feature `associated_type_defaults`. | Before | After | |---|---| | ![image](https://user-images.githubusercontent.com/14913065/160631832-d5862d13-b395-4d86-b45c-3873ffd4cd4e.png) | ![image](https://user-images.githubusercontent.com/14913065/160631903-33909a03-b6ee-4d75-9cbc-d188f7f8602e.png) | | ![image](https://user-images.githubusercontent.com/14913065/160632173-040d4139-76f4-4410-851b-d8c1cef014d2.png) | ![image](https://user-images.githubusercontent.com/14913065/160632233-6fd3fe73-cadc-4291-b104-59d2e45366a6.png) | ### `clean::types::ItemKind` modification * `ItemKind::TypedefItem(.., true)` → `ItemKind::AssocTypeItem(..)` * `ItemKind::TypedefItem(.., false)` → `ItemKind::TypedefItem(..)` Further, I added `ItemKind::TyAssoc{Const,Type}Item`, the “required” variant of `ItemKind::Assoc{Const,Type}Item`, analogous to `ItemKind::TyMethodItem` with `ItemKind::MethodItem`. These new variants don't contain new information really, they are just the result of me getting rid of the `Option<_>` field in `AssocConstItem` and `AssocTypeItem`. **Goal**: Make associated items more consistent. Originally I thought modifying `ItemKind` was necessary to achieve the new functionality of this PR but in retrospect, it does not. If you don't like the changes to `ItemKind`, I think I _can_ get rid of them. This change is the root cause of those tiny changes in a lot of different files. ### Concerns and Open Questions * **breaking changes** to hyperlinks: Some heading IDs change: * `associated-const` (sic!) -> `{provided,required}-associated-consts` * `associated-types` -> `{provided,required}-associated-types` * **verbosity** of the headings _{Required,Provided} Associated {Constants,Types}_ * For some files, I am not sure if the changes I made are correct. So please take extra care when reviewing `conversions.rs` (conversion to JSON), `cache.rs`/`fold_item`, `stripper.rs`/`fold_item`, `check_doc_test_visibility.rs`/`should_have_doc_example`, `collect_intra_doc_links.rs`/`from_assoc_item` * JSON output: I still map `AssocTypeItem`s to `Typedef` etc. (FIXME)
This commit is contained in:
commit
0ec00c0ba3
@ -79,7 +79,7 @@ crate fn try_inline(
|
||||
Res::Def(DefKind::TyAlias, did) => {
|
||||
record_extern_fqn(cx, did, ItemType::Typedef);
|
||||
build_impls(cx, Some(parent_module), did, attrs, &mut ret);
|
||||
clean::TypedefItem(build_type_alias(cx, did), false)
|
||||
clean::TypedefItem(build_type_alias(cx, did))
|
||||
}
|
||||
Res::Def(DefKind::Enum, did) => {
|
||||
record_extern_fqn(cx, did, ItemType::Enum);
|
||||
|
@ -964,11 +964,11 @@ impl Clean<Item> for hir::TraitItem<'_> {
|
||||
let local_did = self.def_id.to_def_id();
|
||||
cx.with_param_env(local_did, |cx| {
|
||||
let inner = match self.kind {
|
||||
hir::TraitItemKind::Const(ref ty, default) => {
|
||||
let default =
|
||||
default.map(|e| ConstantKind::Local { def_id: local_did, body: e });
|
||||
AssocConstItem(ty.clean(cx), default)
|
||||
}
|
||||
hir::TraitItemKind::Const(ref ty, Some(default)) => AssocConstItem(
|
||||
ty.clean(cx),
|
||||
ConstantKind::Local { def_id: local_did, body: default },
|
||||
),
|
||||
hir::TraitItemKind::Const(ref ty, None) => TyAssocConstItem(ty.clean(cx)),
|
||||
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
|
||||
let m = clean_function(cx, sig, &self.generics, body);
|
||||
MethodItem(m, None)
|
||||
@ -983,11 +983,19 @@ impl Clean<Item> for hir::TraitItem<'_> {
|
||||
});
|
||||
TyMethodItem(Function { decl, generics })
|
||||
}
|
||||
hir::TraitItemKind::Type(bounds, ref default) => {
|
||||
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 default = default.map(|t| t.clean(cx));
|
||||
AssocTypeItem(Box::new(generics), bounds, default)
|
||||
let item_type = hir_ty_to_ty(cx.tcx, default).clean(cx);
|
||||
AssocTypeItem(
|
||||
Typedef { type_: default.clean(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 =
|
||||
@ -1004,7 +1012,7 @@ impl Clean<Item> for hir::ImplItem<'_> {
|
||||
cx.with_param_env(local_did, |cx| {
|
||||
let inner = match self.kind {
|
||||
hir::ImplItemKind::Const(ref ty, expr) => {
|
||||
let default = Some(ConstantKind::Local { def_id: local_did, body: expr });
|
||||
let default = ConstantKind::Local { def_id: local_did, body: expr };
|
||||
AssocConstItem(ty.clean(cx), default)
|
||||
}
|
||||
hir::ImplItemKind::Fn(ref sig, body) => {
|
||||
@ -1016,7 +1024,10 @@ impl Clean<Item> for hir::ImplItem<'_> {
|
||||
let type_ = hir_ty.clean(cx);
|
||||
let generics = self.generics.clean(cx);
|
||||
let item_type = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
|
||||
TypedefItem(Typedef { type_, generics, item_type: Some(item_type) }, true)
|
||||
AssocTypeItem(
|
||||
Typedef { type_, generics, item_type: Some(item_type) },
|
||||
Vec::new(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
@ -1041,13 +1052,17 @@ impl Clean<Item> for ty::AssocItem {
|
||||
let tcx = cx.tcx;
|
||||
let kind = match self.kind {
|
||||
ty::AssocKind::Const => {
|
||||
let ty = tcx.type_of(self.def_id);
|
||||
let default = if self.defaultness.has_value() {
|
||||
Some(ConstantKind::Extern { def_id: self.def_id })
|
||||
} else {
|
||||
None
|
||||
let ty = tcx.type_of(self.def_id).clean(cx);
|
||||
|
||||
let provided = match self.container {
|
||||
ty::ImplContainer(_) => true,
|
||||
ty::TraitContainer(_) => self.defaultness.has_value(),
|
||||
};
|
||||
AssocConstItem(ty.clean(cx), default)
|
||||
if provided {
|
||||
AssocConstItem(ty, ConstantKind::Extern { def_id: self.def_id })
|
||||
} else {
|
||||
TyAssocConstItem(ty)
|
||||
}
|
||||
}
|
||||
ty::AssocKind::Fn => {
|
||||
let generics = clean_ty_generics(
|
||||
@ -1181,23 +1196,28 @@ impl Clean<Item> for ty::AssocItem {
|
||||
None => bounds.push(GenericBound::maybe_sized(cx)),
|
||||
}
|
||||
|
||||
let ty = if self.defaultness.has_value() {
|
||||
Some(tcx.type_of(self.def_id))
|
||||
if self.defaultness.has_value() {
|
||||
AssocTypeItem(
|
||||
Typedef {
|
||||
type_: tcx.type_of(self.def_id).clean(cx),
|
||||
generics,
|
||||
// FIXME: should we obtain the Type from HIR and pass it on here?
|
||||
item_type: None,
|
||||
},
|
||||
bounds,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
AssocTypeItem(Box::new(generics), bounds, ty.map(|t| t.clean(cx)))
|
||||
TyAssocTypeItem(Box::new(generics), bounds)
|
||||
}
|
||||
} else {
|
||||
// FIXME: when could this happen? Associated items in inherent impls?
|
||||
let type_ = tcx.type_of(self.def_id).clean(cx);
|
||||
TypedefItem(
|
||||
AssocTypeItem(
|
||||
Typedef {
|
||||
type_,
|
||||
type_: tcx.type_of(self.def_id).clean(cx),
|
||||
generics: Generics { params: Vec::new(), where_predicates: Vec::new() },
|
||||
item_type: None,
|
||||
},
|
||||
true,
|
||||
Vec::new(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1837,14 +1857,11 @@ fn clean_maybe_renamed_item(
|
||||
ItemKind::TyAlias(hir_ty, ref generics) => {
|
||||
let rustdoc_ty = hir_ty.clean(cx);
|
||||
let ty = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
|
||||
TypedefItem(
|
||||
Typedef {
|
||||
type_: rustdoc_ty,
|
||||
generics: generics.clean(cx),
|
||||
item_type: Some(ty),
|
||||
},
|
||||
false,
|
||||
)
|
||||
TypedefItem(Typedef {
|
||||
type_: rustdoc_ty,
|
||||
generics: generics.clean(cx),
|
||||
item_type: Some(ty),
|
||||
})
|
||||
}
|
||||
ItemKind::Enum(ref def, ref generics) => EnumItem(Enum {
|
||||
variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
|
||||
|
@ -577,10 +577,16 @@ impl Item {
|
||||
self.type_() == ItemType::Variant
|
||||
}
|
||||
crate fn is_associated_type(&self) -> bool {
|
||||
self.type_() == ItemType::AssocType
|
||||
matches!(&*self.kind, AssocTypeItem(..) | StrippedItem(box AssocTypeItem(..)))
|
||||
}
|
||||
crate fn is_ty_associated_type(&self) -> bool {
|
||||
matches!(&*self.kind, TyAssocTypeItem(..) | StrippedItem(box TyAssocTypeItem(..)))
|
||||
}
|
||||
crate fn is_associated_const(&self) -> bool {
|
||||
self.type_() == ItemType::AssocConst
|
||||
matches!(&*self.kind, AssocConstItem(..) | StrippedItem(box AssocConstItem(..)))
|
||||
}
|
||||
crate fn is_ty_associated_const(&self) -> bool {
|
||||
matches!(&*self.kind, TyAssocConstItem(..) | StrippedItem(box TyAssocConstItem(..)))
|
||||
}
|
||||
crate fn is_method(&self) -> bool {
|
||||
self.type_() == ItemType::Method
|
||||
@ -726,17 +732,18 @@ crate enum ItemKind {
|
||||
EnumItem(Enum),
|
||||
FunctionItem(Function),
|
||||
ModuleItem(Module),
|
||||
TypedefItem(Typedef, bool /* is associated type */),
|
||||
TypedefItem(Typedef),
|
||||
OpaqueTyItem(OpaqueTy),
|
||||
StaticItem(Static),
|
||||
ConstantItem(Constant),
|
||||
TraitItem(Trait),
|
||||
TraitAliasItem(TraitAlias),
|
||||
ImplItem(Impl),
|
||||
/// A method signature only. Used for required methods in traits (ie,
|
||||
/// non-default-methods).
|
||||
/// A required method in a trait declaration meaning it's only a function signature.
|
||||
TyMethodItem(Function),
|
||||
/// A method with a body.
|
||||
/// A method in a trait impl or a provided method in a trait declaration.
|
||||
///
|
||||
/// Compared to [TyMethodItem], it also contains a method body.
|
||||
MethodItem(Function, Option<hir::Defaultness>),
|
||||
StructFieldItem(Type),
|
||||
VariantItem(Variant),
|
||||
@ -749,12 +756,16 @@ crate enum ItemKind {
|
||||
MacroItem(Macro),
|
||||
ProcMacroItem(ProcMacro),
|
||||
PrimitiveItem(PrimitiveType),
|
||||
AssocConstItem(Type, Option<ConstantKind>),
|
||||
/// An associated item in a trait or trait impl.
|
||||
/// A required associated constant in a trait declaration.
|
||||
TyAssocConstItem(Type),
|
||||
/// An associated associated constant in a trait impl or a provided one in a trait declaration.
|
||||
AssocConstItem(Type, ConstantKind),
|
||||
/// A required associated type in a trait declaration.
|
||||
///
|
||||
/// The bounds may be non-empty if there is a `where` clause.
|
||||
/// The `Option<Type>` is the default concrete type (e.g. `trait Trait { type Target = usize; }`)
|
||||
AssocTypeItem(Box<Generics>, Vec<GenericBound>, Option<Type>),
|
||||
TyAssocTypeItem(Box<Generics>, Vec<GenericBound>),
|
||||
/// An associated type in a trait impl or a provided one in a trait declaration.
|
||||
AssocTypeItem(Typedef, Vec<GenericBound>),
|
||||
/// An item that has been stripped by a rustdoc pass
|
||||
StrippedItem(Box<ItemKind>),
|
||||
KeywordItem(Symbol),
|
||||
@ -776,7 +787,7 @@ impl ItemKind {
|
||||
ExternCrateItem { .. }
|
||||
| ImportItem(_)
|
||||
| FunctionItem(_)
|
||||
| TypedefItem(_, _)
|
||||
| TypedefItem(_)
|
||||
| OpaqueTyItem(_)
|
||||
| StaticItem(_)
|
||||
| ConstantItem(_)
|
||||
@ -791,7 +802,9 @@ impl ItemKind {
|
||||
| MacroItem(_)
|
||||
| ProcMacroItem(_)
|
||||
| PrimitiveItem(_)
|
||||
| TyAssocConstItem(_)
|
||||
| AssocConstItem(_, _)
|
||||
| TyAssocTypeItem(..)
|
||||
| AssocTypeItem(..)
|
||||
| StrippedItem(_)
|
||||
| KeywordItem(_) => [].iter(),
|
||||
|
@ -178,7 +178,7 @@ crate fn build_deref_target_impls(cx: &mut DocContext<'_>, items: &[Item], ret:
|
||||
|
||||
for item in items {
|
||||
let target = match *item.kind {
|
||||
ItemKind::TypedefItem(ref t, true) => &t.type_,
|
||||
ItemKind::AssocTypeItem(ref t, _) => &t.type_,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
|
@ -71,7 +71,7 @@ crate trait DocFolder: Sized {
|
||||
ExternCrateItem { src: _ }
|
||||
| ImportItem(_)
|
||||
| FunctionItem(_)
|
||||
| TypedefItem(_, _)
|
||||
| TypedefItem(_)
|
||||
| OpaqueTyItem(_)
|
||||
| StaticItem(_)
|
||||
| ConstantItem(_)
|
||||
@ -85,7 +85,9 @@ crate trait DocFolder: Sized {
|
||||
| MacroItem(_)
|
||||
| ProcMacroItem(_)
|
||||
| PrimitiveItem(_)
|
||||
| AssocConstItem(_, _)
|
||||
| TyAssocConstItem(..)
|
||||
| AssocConstItem(..)
|
||||
| TyAssocTypeItem(..)
|
||||
| AssocTypeItem(..)
|
||||
| KeywordItem(_) => kind,
|
||||
}
|
||||
|
@ -242,14 +242,15 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
|
||||
if let Some(ref s) = item.name {
|
||||
let (parent, is_inherent_impl_item) = match *item.kind {
|
||||
clean::StrippedItem(..) => ((None, None), false),
|
||||
clean::AssocConstItem(..) | clean::TypedefItem(_, true)
|
||||
clean::AssocConstItem(..) | clean::AssocTypeItem(..)
|
||||
if self.cache.parent_is_trait_impl =>
|
||||
{
|
||||
// skip associated items in trait impls
|
||||
((None, None), false)
|
||||
}
|
||||
clean::AssocTypeItem(..)
|
||||
| clean::TyMethodItem(..)
|
||||
clean::TyMethodItem(..)
|
||||
| clean::TyAssocConstItem(..)
|
||||
| clean::TyAssocTypeItem(..)
|
||||
| clean::StructFieldItem(..)
|
||||
| clean::VariantItem(..) => (
|
||||
(
|
||||
@ -258,7 +259,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
|
||||
),
|
||||
false,
|
||||
),
|
||||
clean::MethodItem(..) | clean::AssocConstItem(..) => {
|
||||
clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => {
|
||||
if self.cache.parent_stack.is_empty() {
|
||||
((None, None), false)
|
||||
} else {
|
||||
@ -373,7 +374,9 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
|
||||
| clean::TyMethodItem(..)
|
||||
| clean::MethodItem(..)
|
||||
| clean::StructFieldItem(..)
|
||||
| clean::TyAssocConstItem(..)
|
||||
| clean::AssocConstItem(..)
|
||||
| clean::TyAssocTypeItem(..)
|
||||
| clean::AssocTypeItem(..)
|
||||
| clean::StrippedItem(..)
|
||||
| clean::KeywordItem(..) => {
|
||||
|
@ -14,7 +14,7 @@ use crate::clean;
|
||||
/// The search index uses item types encoded as smaller numbers which equal to
|
||||
/// discriminants. JavaScript then is used to decode them into the original value.
|
||||
/// Consequently, every change to this type should be synchronized to
|
||||
/// the `itemTypes` mapping table in `html/static/main.js`.
|
||||
/// the `itemTypes` mapping table in `html/static/js/search.js`.
|
||||
///
|
||||
/// In addition, code in `html::render` uses this enum to generate CSS classes, page prefixes, and
|
||||
/// module headings. If you are adding to this enum and want to ensure that the sidebar also prints
|
||||
@ -89,8 +89,8 @@ impl<'a> From<&'a clean::Item> for ItemType {
|
||||
clean::ForeignStaticItem(..) => ItemType::Static, // no ForeignStatic
|
||||
clean::MacroItem(..) => ItemType::Macro,
|
||||
clean::PrimitiveItem(..) => ItemType::Primitive,
|
||||
clean::AssocConstItem(..) => ItemType::AssocConst,
|
||||
clean::AssocTypeItem(..) => ItemType::AssocType,
|
||||
clean::TyAssocConstItem(..) | clean::AssocConstItem(..) => ItemType::AssocConst,
|
||||
clean::TyAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType,
|
||||
clean::ForeignTypeItem => ItemType::ForeignType,
|
||||
clean::KeywordItem(..) => ItemType::Keyword,
|
||||
clean::TraitAliasItem(..) => ItemType::TraitAlias,
|
||||
|
@ -527,6 +527,21 @@ crate enum HrefError {
|
||||
/// This item is known to rustdoc, but from a crate that does not have documentation generated.
|
||||
///
|
||||
/// This can only happen for non-local items.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Crate `a` defines a public trait and crate `b` – the target crate that depends on `a` –
|
||||
/// implements it for a local type.
|
||||
/// We document `b` but **not** `a` (we only _build_ the latter – with `rustc`):
|
||||
///
|
||||
/// ```sh
|
||||
/// rustc a.rs --crate-type=lib
|
||||
/// rustdoc b.rs --crate-type=lib --extern=a=liba.rlib
|
||||
/// ```
|
||||
///
|
||||
/// Now, the associated items in the trait impl want to link to the corresponding item in the
|
||||
/// trait declaration (see `html::render::assoc_href_attr`) but it's not available since their
|
||||
/// *documentation (was) not built*.
|
||||
DocumentationNotBuilt,
|
||||
/// This can only happen for non-local items when `--document-private-items` is not passed.
|
||||
Private,
|
||||
|
@ -1452,8 +1452,10 @@ fn init_id_map() -> FxHashMap<String, usize> {
|
||||
map.insert("trait-implementations".to_owned(), 1);
|
||||
map.insert("synthetic-implementations".to_owned(), 1);
|
||||
map.insert("blanket-implementations".to_owned(), 1);
|
||||
map.insert("associated-types".to_owned(), 1);
|
||||
map.insert("associated-const".to_owned(), 1);
|
||||
map.insert("required-associated-types".to_owned(), 1);
|
||||
map.insert("provided-associated-types".to_owned(), 1);
|
||||
map.insert("provided-associated-consts".to_owned(), 1);
|
||||
map.insert("required-associated-consts".to_owned(), 1);
|
||||
map.insert("required-methods".to_owned(), 1);
|
||||
map.insert("provided-methods".to_owned(), 1);
|
||||
map.insert("implementors".to_owned(), 1);
|
||||
|
@ -521,7 +521,7 @@ fn document_short(
|
||||
let mut summary_html = MarkdownSummaryLine(&s, &item.links(cx)).into_string();
|
||||
|
||||
if s.contains('\n') {
|
||||
let link = format!(r#" <a href="{}">Read more</a>"#, naive_assoc_href(item, link, cx));
|
||||
let link = format!(r#" <a{}>Read more</a>"#, assoc_href_attr(item, link, cx));
|
||||
|
||||
if let Some(idx) = summary_html.rfind("</p>") {
|
||||
summary_html.insert_str(idx, &link);
|
||||
@ -737,42 +737,82 @@ fn render_impls(
|
||||
w.write_str(&rendered_impls.join(""));
|
||||
}
|
||||
|
||||
fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String {
|
||||
use crate::formats::item_type::ItemType::*;
|
||||
/// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item.
|
||||
fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String {
|
||||
let name = it.name.unwrap();
|
||||
let item_type = it.type_();
|
||||
|
||||
let name = it.name.as_ref().unwrap();
|
||||
let ty = match it.type_() {
|
||||
Typedef | AssocType => AssocType,
|
||||
s => s,
|
||||
let href = match link {
|
||||
AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{}", id)),
|
||||
AssocItemLink::Anchor(None) => Some(format!("#{}.{}", item_type, name)),
|
||||
AssocItemLink::GotoSource(did, provided_methods) => {
|
||||
// We're creating a link from the implementation of an associated item to its
|
||||
// declaration in the trait declaration.
|
||||
let item_type = match item_type {
|
||||
// For historical but not technical reasons, the item type of methods in
|
||||
// trait declarations depends on whether the method is required (`TyMethod`) or
|
||||
// provided (`Method`).
|
||||
ItemType::Method | ItemType::TyMethod => {
|
||||
if provided_methods.contains(&name) {
|
||||
ItemType::Method
|
||||
} else {
|
||||
ItemType::TyMethod
|
||||
}
|
||||
}
|
||||
// For associated types and constants, no such distinction exists.
|
||||
item_type => item_type,
|
||||
};
|
||||
|
||||
match href(did.expect_def_id(), cx) {
|
||||
Ok((url, ..)) => Some(format!("{}#{}.{}", url, item_type, name)),
|
||||
// The link is broken since it points to an external crate that wasn't documented.
|
||||
// Do not create any link in such case. This is better than falling back to a
|
||||
// dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item
|
||||
// (that used to happen in older versions). Indeed, in most cases this dummy would
|
||||
// coincide with the `id`. However, it would not always do so.
|
||||
// In general, this dummy would be incorrect:
|
||||
// If the type with the trait impl also had an inherent impl with an assoc. item of
|
||||
// the *same* name as this impl item, the dummy would link to that one even though
|
||||
// those two items are distinct!
|
||||
// In this scenario, the actual `id` of this impl item would be
|
||||
// `#{item_type}.{name}-{n}` for some number `n` (a disambiguator).
|
||||
Err(HrefError::DocumentationNotBuilt) => None,
|
||||
Err(_) => Some(format!("#{}.{}", item_type, name)),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let anchor = format!("#{}.{}", ty, name);
|
||||
match link {
|
||||
AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
|
||||
AssocItemLink::Anchor(None) => anchor,
|
||||
AssocItemLink::GotoSource(did, _) => {
|
||||
href(did.expect_def_id(), cx).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
|
||||
}
|
||||
}
|
||||
// If there is no `href` for the reason explained above, simply do not render it which is valid:
|
||||
// https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements
|
||||
href.map(|href| format!(" href=\"{}\"", href)).unwrap_or_default()
|
||||
}
|
||||
|
||||
fn assoc_const(
|
||||
w: &mut Buffer,
|
||||
it: &clean::Item,
|
||||
ty: &clean::Type,
|
||||
default: Option<&clean::ConstantKind>,
|
||||
link: AssocItemLink<'_>,
|
||||
extra: &str,
|
||||
cx: &Context<'_>,
|
||||
) {
|
||||
write!(
|
||||
w,
|
||||
"{}{}const <a href=\"{}\" class=\"constant\">{}</a>: {}",
|
||||
extra,
|
||||
it.visibility.print_with_space(it.def_id, cx),
|
||||
naive_assoc_href(it, link, cx),
|
||||
it.name.as_ref().unwrap(),
|
||||
ty.print(cx)
|
||||
"{extra}{vis}const <a{href} class=\"constant\">{name}</a>: {ty}",
|
||||
extra = extra,
|
||||
vis = it.visibility.print_with_space(it.def_id, cx),
|
||||
href = assoc_href_attr(it, link, cx),
|
||||
name = it.name.as_ref().unwrap(),
|
||||
ty = ty.print(cx),
|
||||
);
|
||||
if let Some(default) = default {
|
||||
// FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
|
||||
// hood which adds noisy underscores and a type suffix to number literals.
|
||||
// This hurts readability in this context especially when more complex expressions
|
||||
// are involved and it doesn't add much of value.
|
||||
// Find a way to print constants here without all that jazz.
|
||||
write!(w, " = {}", default.value(cx.tcx()).unwrap_or_else(|| default.expr(cx.tcx())));
|
||||
}
|
||||
}
|
||||
|
||||
fn assoc_type(
|
||||
@ -787,9 +827,9 @@ fn assoc_type(
|
||||
) {
|
||||
write!(
|
||||
w,
|
||||
"{indent}type <a href=\"{href}\" class=\"associatedtype\">{name}</a>{generics}",
|
||||
"{indent}type <a{href} class=\"associatedtype\">{name}</a>{generics}",
|
||||
indent = " ".repeat(indent),
|
||||
href = naive_assoc_href(it, link, cx),
|
||||
href = assoc_href_attr(it, link, cx),
|
||||
name = it.name.as_ref().unwrap(),
|
||||
generics = generics.print(cx),
|
||||
);
|
||||
@ -814,22 +854,6 @@ fn assoc_method(
|
||||
) {
|
||||
let header = meth.fn_header(cx.tcx()).expect("Trying to get header from a non-function item");
|
||||
let name = meth.name.as_ref().unwrap();
|
||||
let href = match link {
|
||||
AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{}", id)),
|
||||
AssocItemLink::Anchor(None) => Some(format!("#{}.{}", meth.type_(), name)),
|
||||
AssocItemLink::GotoSource(did, provided_methods) => {
|
||||
// We're creating a link from an impl-item to the corresponding
|
||||
// trait-item and need to map the anchored type accordingly.
|
||||
let ty =
|
||||
if provided_methods.contains(name) { ItemType::Method } else { ItemType::TyMethod };
|
||||
|
||||
match (href(did.expect_def_id(), cx), ty) {
|
||||
(Ok(p), ty) => Some(format!("{}#{}.{}", p.0, ty, name)),
|
||||
(Err(HrefError::DocumentationNotBuilt), ItemType::TyMethod) => None,
|
||||
(Err(_), ty) => Some(format!("#{}.{}", ty, name)),
|
||||
}
|
||||
}
|
||||
};
|
||||
let vis = meth.visibility.print_with_space(meth.def_id, cx).to_string();
|
||||
// FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
|
||||
// this condition.
|
||||
@ -843,6 +867,7 @@ fn assoc_method(
|
||||
let unsafety = header.unsafety.print_with_space();
|
||||
let defaultness = print_default_space(meth.is_default());
|
||||
let abi = print_abi_with_space(header.abi).to_string();
|
||||
let href = assoc_href_attr(meth, link, cx);
|
||||
|
||||
// NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
|
||||
let generics_len = format!("{:#}", g.print(cx)).len();
|
||||
@ -868,7 +893,7 @@ fn assoc_method(
|
||||
w.reserve(header_len + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len());
|
||||
write!(
|
||||
w,
|
||||
"{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a {href} class=\"fnname\">{name}</a>\
|
||||
"{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a{href} class=\"fnname\">{name}</a>\
|
||||
{generics}{decl}{notable_traits}{where_clause}",
|
||||
indent = indent_str,
|
||||
vis = vis,
|
||||
@ -877,8 +902,7 @@ fn assoc_method(
|
||||
unsafety = unsafety,
|
||||
defaultness = defaultness,
|
||||
abi = abi,
|
||||
// links without a href are valid - https://www.w3schools.com/tags/att_a_href.asp
|
||||
href = href.map(|href| format!("href=\"{}\"", href)).unwrap_or_else(|| "".to_string()),
|
||||
href = href,
|
||||
name = name,
|
||||
generics = g.print(cx),
|
||||
decl = d.full_print(header_len, indent, header.asyncness, cx),
|
||||
@ -968,23 +992,43 @@ fn render_assoc_item(
|
||||
cx: &Context<'_>,
|
||||
render_mode: RenderMode,
|
||||
) {
|
||||
match *item.kind {
|
||||
match &*item.kind {
|
||||
clean::StrippedItem(..) => {}
|
||||
clean::TyMethodItem(ref m) => {
|
||||
clean::TyMethodItem(m) => {
|
||||
assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
|
||||
}
|
||||
clean::MethodItem(ref m, _) => {
|
||||
clean::MethodItem(m, _) => {
|
||||
assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
|
||||
}
|
||||
clean::AssocConstItem(ref ty, _) => {
|
||||
assoc_const(w, item, ty, link, if parent == ItemType::Trait { " " } else { "" }, cx)
|
||||
}
|
||||
clean::AssocTypeItem(ref generics, ref bounds, ref default) => assoc_type(
|
||||
kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => assoc_const(
|
||||
w,
|
||||
item,
|
||||
ty,
|
||||
match kind {
|
||||
clean::TyAssocConstItem(_) => None,
|
||||
clean::AssocConstItem(_, default) => Some(default),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
link,
|
||||
if parent == ItemType::Trait { " " } else { "" },
|
||||
cx,
|
||||
),
|
||||
clean::TyAssocTypeItem(ref generics, ref bounds) => assoc_type(
|
||||
w,
|
||||
item,
|
||||
generics,
|
||||
bounds,
|
||||
default.as_ref(),
|
||||
None,
|
||||
link,
|
||||
if parent == ItemType::Trait { 4 } else { 0 },
|
||||
cx,
|
||||
),
|
||||
clean::AssocTypeItem(ref ty, ref bounds) => assoc_type(
|
||||
w,
|
||||
item,
|
||||
&ty.generics,
|
||||
bounds,
|
||||
Some(ty.item_type.as_ref().unwrap_or(&ty.type_)),
|
||||
link,
|
||||
if parent == ItemType::Trait { 4 } else { 0 },
|
||||
cx,
|
||||
@ -1205,7 +1249,7 @@ fn render_deref_methods(
|
||||
.items
|
||||
.iter()
|
||||
.find_map(|item| match *item.kind {
|
||||
clean::TypedefItem(ref t, true) => Some(match *t {
|
||||
clean::AssocTypeItem(ref t, _) => Some(match *t {
|
||||
clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
|
||||
_ => (&t.type_, &t.type_),
|
||||
}),
|
||||
@ -1291,7 +1335,7 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
|
||||
impl_.print(false, cx)
|
||||
);
|
||||
for it in &impl_.items {
|
||||
if let clean::TypedefItem(ref tydef, _) = *it.kind {
|
||||
if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
|
||||
out.push_str("<span class=\"where fmt-newline\"> ");
|
||||
let empty_set = FxHashSet::default();
|
||||
let src_link =
|
||||
@ -1300,7 +1344,7 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
|
||||
&mut out,
|
||||
it,
|
||||
&tydef.generics,
|
||||
&[],
|
||||
&[], // intentionally leaving out bounds
|
||||
Some(&tydef.type_),
|
||||
src_link,
|
||||
0,
|
||||
@ -1439,7 +1483,7 @@ fn render_impl(
|
||||
if item_type == ItemType::Method { " method-toggle" } else { "" };
|
||||
write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class);
|
||||
}
|
||||
match *item.kind {
|
||||
match &*item.kind {
|
||||
clean::MethodItem(..) | clean::TyMethodItem(_) => {
|
||||
// Only render when the method is not static or we allow static methods
|
||||
if render_method_item {
|
||||
@ -1471,30 +1515,7 @@ fn render_impl(
|
||||
w.write_str("</section>");
|
||||
}
|
||||
}
|
||||
clean::TypedefItem(ref tydef, _) => {
|
||||
let source_id = format!("{}.{}", ItemType::AssocType, name);
|
||||
let id = cx.derive_id(source_id.clone());
|
||||
write!(
|
||||
w,
|
||||
"<section id=\"{}\" class=\"{}{} has-srclink\">",
|
||||
id, item_type, in_trait_class
|
||||
);
|
||||
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
|
||||
w.write_str("<h4 class=\"code-header\">");
|
||||
assoc_type(
|
||||
w,
|
||||
item,
|
||||
&tydef.generics,
|
||||
&[],
|
||||
Some(&tydef.type_),
|
||||
link.anchor(if trait_.is_some() { &source_id } else { &id }),
|
||||
0,
|
||||
cx,
|
||||
);
|
||||
w.write_str("</h4>");
|
||||
w.write_str("</section>");
|
||||
}
|
||||
clean::AssocConstItem(ref ty, _) => {
|
||||
kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => {
|
||||
let source_id = format!("{}.{}", item_type, name);
|
||||
let id = cx.derive_id(source_id.clone());
|
||||
write!(
|
||||
@ -1509,6 +1530,11 @@ fn render_impl(
|
||||
w,
|
||||
item,
|
||||
ty,
|
||||
match kind {
|
||||
clean::TyAssocConstItem(_) => None,
|
||||
clean::AssocConstItem(_, default) => Some(default),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
link.anchor(if trait_.is_some() { &source_id } else { &id }),
|
||||
"",
|
||||
cx,
|
||||
@ -1516,10 +1542,10 @@ fn render_impl(
|
||||
w.write_str("</h4>");
|
||||
w.write_str("</section>");
|
||||
}
|
||||
clean::AssocTypeItem(ref generics, ref bounds, ref default) => {
|
||||
clean::TyAssocTypeItem(generics, bounds) => {
|
||||
let source_id = format!("{}.{}", item_type, name);
|
||||
let id = cx.derive_id(source_id.clone());
|
||||
write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
|
||||
write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
|
||||
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
|
||||
w.write_str("<h4 class=\"code-header\">");
|
||||
assoc_type(
|
||||
@ -1527,7 +1553,30 @@ fn render_impl(
|
||||
item,
|
||||
generics,
|
||||
bounds,
|
||||
default.as_ref(),
|
||||
None,
|
||||
link.anchor(if trait_.is_some() { &source_id } else { &id }),
|
||||
0,
|
||||
cx,
|
||||
);
|
||||
w.write_str("</h4>");
|
||||
w.write_str("</section>");
|
||||
}
|
||||
clean::AssocTypeItem(tydef, _bounds) => {
|
||||
let source_id = format!("{}.{}", item_type, name);
|
||||
let id = cx.derive_id(source_id.clone());
|
||||
write!(
|
||||
w,
|
||||
"<section id=\"{}\" class=\"{}{} has-srclink\">",
|
||||
id, item_type, in_trait_class
|
||||
);
|
||||
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
|
||||
w.write_str("<h4 class=\"code-header\">");
|
||||
assoc_type(
|
||||
w,
|
||||
item,
|
||||
&tydef.generics,
|
||||
&[], // intentionally leaving out bounds
|
||||
Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)),
|
||||
link.anchor(if trait_.is_some() { &source_id } else { &id }),
|
||||
0,
|
||||
cx,
|
||||
@ -1748,13 +1797,13 @@ pub(crate) fn render_impl_summary(
|
||||
write!(w, "{}", i.inner_impl().print(use_absolute, cx));
|
||||
if show_def_docs {
|
||||
for it in &i.inner_impl().items {
|
||||
if let clean::TypedefItem(ref tydef, _) = *it.kind {
|
||||
if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
|
||||
w.write_str("<span class=\"where fmt-newline\"> ");
|
||||
assoc_type(
|
||||
w,
|
||||
it,
|
||||
&tydef.generics,
|
||||
&[],
|
||||
&[], // intentionally leaving out bounds
|
||||
Some(&tydef.type_),
|
||||
AssocItemLink::Anchor(None),
|
||||
0,
|
||||
@ -1822,7 +1871,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
|
||||
clean::PrimitiveItem(_) => sidebar_primitive(cx, buffer, it),
|
||||
clean::UnionItem(ref u) => sidebar_union(cx, buffer, it, u),
|
||||
clean::EnumItem(ref e) => sidebar_enum(cx, buffer, it, e),
|
||||
clean::TypedefItem(_, _) => sidebar_typedef(cx, buffer, it),
|
||||
clean::TypedefItem(_) => sidebar_typedef(cx, buffer, it),
|
||||
clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items),
|
||||
clean::ForeignTypeItem => sidebar_foreign_type(cx, buffer, it),
|
||||
_ => {}
|
||||
@ -1917,7 +1966,7 @@ fn get_methods(
|
||||
if !for_deref || should_render_item(item, deref_mut, tcx) {
|
||||
Some(SidebarLink {
|
||||
name,
|
||||
url: get_next_url(used_links, format!("method.{}", name)),
|
||||
url: get_next_url(used_links, format!("{}.{}", ItemType::Method, name)),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@ -1937,7 +1986,7 @@ fn get_associated_constants(
|
||||
.filter_map(|item| match item.name {
|
||||
Some(name) if !name.is_empty() && item.is_associated_const() => Some(SidebarLink {
|
||||
name,
|
||||
url: get_next_url(used_links, format!("associatedconstant.{}", name)),
|
||||
url: get_next_url(used_links, format!("{}.{}", ItemType::AssocConst, name)),
|
||||
}),
|
||||
_ => None,
|
||||
})
|
||||
@ -2106,7 +2155,7 @@ fn sidebar_deref_methods(
|
||||
debug!("found Deref: {:?}", impl_);
|
||||
if let Some((target, real_target)) =
|
||||
impl_.inner_impl().items.iter().find_map(|item| match *item.kind {
|
||||
clean::TypedefItem(ref t, true) => Some(match *t {
|
||||
clean::AssocTypeItem(ref t, _) => Some(match *t {
|
||||
clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
|
||||
_ => (&t.type_, &t.type_),
|
||||
}),
|
||||
@ -2281,19 +2330,37 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean
|
||||
print_sidebar_section(
|
||||
buf,
|
||||
&t.items,
|
||||
"associated-types",
|
||||
"Associated Types",
|
||||
|m| m.is_associated_type(),
|
||||
|sym| format!("<a href=\"#associatedtype.{0}\">{0}</a>", sym),
|
||||
"required-associated-types",
|
||||
"Required Associated Types",
|
||||
|m| m.is_ty_associated_type(),
|
||||
|sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocType),
|
||||
);
|
||||
|
||||
print_sidebar_section(
|
||||
buf,
|
||||
&t.items,
|
||||
"associated-const",
|
||||
"Associated Constants",
|
||||
"provided-associated-types",
|
||||
"Provided Associated Types",
|
||||
|m| m.is_associated_type(),
|
||||
|sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocType),
|
||||
);
|
||||
|
||||
print_sidebar_section(
|
||||
buf,
|
||||
&t.items,
|
||||
"required-associated-consts",
|
||||
"Required Associated Constants",
|
||||
|m| m.is_ty_associated_const(),
|
||||
|sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocConst),
|
||||
);
|
||||
|
||||
print_sidebar_section(
|
||||
buf,
|
||||
&t.items,
|
||||
"provided-associated-consts",
|
||||
"Provided Associated Constants",
|
||||
|m| m.is_associated_const(),
|
||||
|sym| format!("<a href=\"#associatedconstant.{0}\">{0}</a>", sym),
|
||||
|sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocConst),
|
||||
);
|
||||
|
||||
print_sidebar_section(
|
||||
@ -2302,7 +2369,7 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean
|
||||
"required-methods",
|
||||
"Required Methods",
|
||||
|m| m.is_ty_method(),
|
||||
|sym| format!("<a href=\"#tymethod.{0}\">{0}</a>", sym),
|
||||
|sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::TyMethod),
|
||||
);
|
||||
|
||||
print_sidebar_section(
|
||||
@ -2311,7 +2378,7 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean
|
||||
"provided-methods",
|
||||
"Provided Methods",
|
||||
|m| m.is_method(),
|
||||
|sym| format!("<a href=\"#method.{0}\">{0}</a>", sym),
|
||||
|sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::Method),
|
||||
);
|
||||
|
||||
let cache = cx.cache();
|
||||
|
@ -141,7 +141,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer,
|
||||
|
||||
item_vars.render_into(buf).unwrap();
|
||||
|
||||
match *item.kind {
|
||||
match &*item.kind {
|
||||
clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
|
||||
clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => {
|
||||
item_function(buf, cx, item, f)
|
||||
@ -150,7 +150,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer,
|
||||
clean::StructItem(ref s) => item_struct(buf, cx, item, s),
|
||||
clean::UnionItem(ref s) => item_union(buf, cx, item, s),
|
||||
clean::EnumItem(ref e) => item_enum(buf, cx, item, e),
|
||||
clean::TypedefItem(ref t, is_associated) => item_typedef(buf, cx, item, t, is_associated),
|
||||
clean::TypedefItem(ref t) => item_typedef(buf, cx, item, t),
|
||||
clean::MacroItem(ref m) => item_macro(buf, cx, item, m),
|
||||
clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m),
|
||||
clean::PrimitiveItem(_) => item_primitive(buf, cx, item),
|
||||
@ -507,13 +507,15 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
|
||||
|
||||
fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) {
|
||||
let bounds = bounds(&t.bounds, false, cx);
|
||||
let types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
|
||||
let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
|
||||
let required = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>();
|
||||
let provided = t.items.iter().filter(|m| m.is_method()).collect::<Vec<_>>();
|
||||
let count_types = types.len();
|
||||
let count_consts = consts.len();
|
||||
let count_methods = required.len() + provided.len();
|
||||
let required_types = t.items.iter().filter(|m| m.is_ty_associated_type()).collect::<Vec<_>>();
|
||||
let provided_types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
|
||||
let required_consts = t.items.iter().filter(|m| m.is_ty_associated_const()).collect::<Vec<_>>();
|
||||
let provided_consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
|
||||
let required_methods = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>();
|
||||
let provided_methods = t.items.iter().filter(|m| m.is_method()).collect::<Vec<_>>();
|
||||
let count_types = required_types.len() + provided_types.len();
|
||||
let count_consts = required_consts.len() + provided_consts.len();
|
||||
let count_methods = required_methods.len() + provided_methods.len();
|
||||
|
||||
// Output the trait definition
|
||||
wrap_into_docblock(w, |w| {
|
||||
@ -554,16 +556,18 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
|
||||
),
|
||||
);
|
||||
}
|
||||
for t in &types {
|
||||
render_assoc_item(
|
||||
w,
|
||||
t,
|
||||
AssocItemLink::Anchor(None),
|
||||
ItemType::Trait,
|
||||
cx,
|
||||
RenderMode::Normal,
|
||||
);
|
||||
w.write_str(";\n");
|
||||
for types in [&required_types, &provided_types] {
|
||||
for t in types {
|
||||
render_assoc_item(
|
||||
w,
|
||||
t,
|
||||
AssocItemLink::Anchor(None),
|
||||
ItemType::Trait,
|
||||
cx,
|
||||
RenderMode::Normal,
|
||||
);
|
||||
w.write_str(";\n");
|
||||
}
|
||||
}
|
||||
// If there are too many associated constants, hide everything after them
|
||||
// We also do this if the types + consts is large because otherwise we could
|
||||
@ -582,28 +586,30 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
|
||||
),
|
||||
);
|
||||
}
|
||||
if !types.is_empty() && !consts.is_empty() {
|
||||
if count_types != 0 && (count_consts != 0 || count_methods != 0) {
|
||||
w.write_str("\n");
|
||||
}
|
||||
for t in &consts {
|
||||
render_assoc_item(
|
||||
w,
|
||||
t,
|
||||
AssocItemLink::Anchor(None),
|
||||
ItemType::Trait,
|
||||
cx,
|
||||
RenderMode::Normal,
|
||||
);
|
||||
w.write_str(";\n");
|
||||
for consts in [&required_consts, &provided_consts] {
|
||||
for c in consts {
|
||||
render_assoc_item(
|
||||
w,
|
||||
c,
|
||||
AssocItemLink::Anchor(None),
|
||||
ItemType::Trait,
|
||||
cx,
|
||||
RenderMode::Normal,
|
||||
);
|
||||
w.write_str(";\n");
|
||||
}
|
||||
}
|
||||
if !toggle && should_hide_fields(count_methods) {
|
||||
toggle = true;
|
||||
toggle_open(w, format_args!("{} methods", count_methods));
|
||||
}
|
||||
if !consts.is_empty() && !required.is_empty() {
|
||||
if count_consts != 0 && count_methods != 0 {
|
||||
w.write_str("\n");
|
||||
}
|
||||
for (pos, m) in required.iter().enumerate() {
|
||||
for (pos, m) in required_methods.iter().enumerate() {
|
||||
render_assoc_item(
|
||||
w,
|
||||
m,
|
||||
@ -614,14 +620,14 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
|
||||
);
|
||||
w.write_str(";\n");
|
||||
|
||||
if pos < required.len() - 1 {
|
||||
if pos < required_methods.len() - 1 {
|
||||
w.write_str("<span class=\"item-spacer\"></span>");
|
||||
}
|
||||
}
|
||||
if !required.is_empty() && !provided.is_empty() {
|
||||
if !required_methods.is_empty() && !provided_methods.is_empty() {
|
||||
w.write_str("\n");
|
||||
}
|
||||
for (pos, m) in provided.iter().enumerate() {
|
||||
for (pos, m) in provided_methods.iter().enumerate() {
|
||||
render_assoc_item(
|
||||
w,
|
||||
m,
|
||||
@ -640,7 +646,8 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
|
||||
w.write_str(" { ... }\n");
|
||||
}
|
||||
}
|
||||
if pos < provided.len() - 1 {
|
||||
|
||||
if pos < provided_methods.len() - 1 {
|
||||
w.write_str("<span class=\"item-spacer\"></span>");
|
||||
}
|
||||
}
|
||||
@ -703,53 +710,77 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
|
||||
}
|
||||
}
|
||||
|
||||
if !types.is_empty() {
|
||||
if !required_types.is_empty() {
|
||||
write_small_section_header(
|
||||
w,
|
||||
"associated-types",
|
||||
"Associated Types",
|
||||
"required-associated-types",
|
||||
"Required Associated Types",
|
||||
"<div class=\"methods\">",
|
||||
);
|
||||
for t in types {
|
||||
for t in required_types {
|
||||
trait_item(w, cx, t, it);
|
||||
}
|
||||
w.write_str("</div>");
|
||||
}
|
||||
if !provided_types.is_empty() {
|
||||
write_small_section_header(
|
||||
w,
|
||||
"provided-associated-types",
|
||||
"Provided Associated Types",
|
||||
"<div class=\"methods\">",
|
||||
);
|
||||
for t in provided_types {
|
||||
trait_item(w, cx, t, it);
|
||||
}
|
||||
w.write_str("</div>");
|
||||
}
|
||||
|
||||
if !consts.is_empty() {
|
||||
if !required_consts.is_empty() {
|
||||
write_small_section_header(
|
||||
w,
|
||||
"associated-const",
|
||||
"Associated Constants",
|
||||
"required-associated-consts",
|
||||
"Required Associated Constants",
|
||||
"<div class=\"methods\">",
|
||||
);
|
||||
for t in consts {
|
||||
for t in required_consts {
|
||||
trait_item(w, cx, t, it);
|
||||
}
|
||||
w.write_str("</div>");
|
||||
}
|
||||
if !provided_consts.is_empty() {
|
||||
write_small_section_header(
|
||||
w,
|
||||
"provided-associated-consts",
|
||||
"Provided Associated Constants",
|
||||
"<div class=\"methods\">",
|
||||
);
|
||||
for t in provided_consts {
|
||||
trait_item(w, cx, t, it);
|
||||
}
|
||||
w.write_str("</div>");
|
||||
}
|
||||
|
||||
// Output the documentation for each function individually
|
||||
if !required.is_empty() {
|
||||
if !required_methods.is_empty() {
|
||||
write_small_section_header(
|
||||
w,
|
||||
"required-methods",
|
||||
"Required methods",
|
||||
"Required Methods",
|
||||
"<div class=\"methods\">",
|
||||
);
|
||||
for m in required {
|
||||
for m in required_methods {
|
||||
trait_item(w, cx, m, it);
|
||||
}
|
||||
w.write_str("</div>");
|
||||
}
|
||||
if !provided.is_empty() {
|
||||
if !provided_methods.is_empty() {
|
||||
write_small_section_header(
|
||||
w,
|
||||
"provided-methods",
|
||||
"Provided methods",
|
||||
"Provided Methods",
|
||||
"<div class=\"methods\">",
|
||||
);
|
||||
for m in provided {
|
||||
for m in provided_methods {
|
||||
trait_item(w, cx, m, it);
|
||||
}
|
||||
w.write_str("</div>");
|
||||
@ -933,25 +964,11 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean:
|
||||
render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All)
|
||||
}
|
||||
|
||||
fn item_typedef(
|
||||
w: &mut Buffer,
|
||||
cx: &Context<'_>,
|
||||
it: &clean::Item,
|
||||
t: &clean::Typedef,
|
||||
is_associated: bool,
|
||||
) {
|
||||
fn write_content(
|
||||
w: &mut Buffer,
|
||||
cx: &Context<'_>,
|
||||
it: &clean::Item,
|
||||
t: &clean::Typedef,
|
||||
is_associated: bool,
|
||||
) {
|
||||
fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
|
||||
fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
|
||||
wrap_item(w, "typedef", |w| {
|
||||
render_attributes_in_pre(w, it, "");
|
||||
if !is_associated {
|
||||
write!(w, "{}", it.visibility.print_with_space(it.def_id, cx));
|
||||
}
|
||||
write!(w, "{}", it.visibility.print_with_space(it.def_id, cx));
|
||||
write!(
|
||||
w,
|
||||
"type {}{}{where_clause} = {type_};",
|
||||
@ -963,14 +980,7 @@ fn item_typedef(
|
||||
});
|
||||
}
|
||||
|
||||
// If this is an associated typedef, we don't want to wrap it into a docblock.
|
||||
if is_associated {
|
||||
write_content(w, cx, it, t, is_associated);
|
||||
} else {
|
||||
wrap_into_docblock(w, |w| {
|
||||
write_content(w, cx, it, t, is_associated);
|
||||
});
|
||||
}
|
||||
wrap_into_docblock(w, |w| write_content(w, cx, it, t));
|
||||
|
||||
document(w, cx, it, None, HeadingOffset::H2);
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
(function() {
|
||||
// This mapping table should match the discriminants of
|
||||
// `rustdoc::html::item_type::ItemType` type in Rust.
|
||||
// `rustdoc::formats::item_type::ItemType` type in Rust.
|
||||
var itemTypes = [
|
||||
"mod",
|
||||
"externcrate",
|
||||
|
@ -219,20 +219,23 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
|
||||
StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
|
||||
ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
|
||||
ForeignTypeItem => ItemEnum::ForeignType,
|
||||
TypedefItem(t, _) => ItemEnum::Typedef(t.into_tcx(tcx)),
|
||||
TypedefItem(t) => ItemEnum::Typedef(t.into_tcx(tcx)),
|
||||
OpaqueTyItem(t) => ItemEnum::OpaqueTy(t.into_tcx(tcx)),
|
||||
ConstantItem(c) => ItemEnum::Constant(c.into_tcx(tcx)),
|
||||
MacroItem(m) => ItemEnum::Macro(m.source),
|
||||
ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_tcx(tcx)),
|
||||
PrimitiveItem(p) => ItemEnum::PrimitiveType(p.as_sym().to_string()),
|
||||
TyAssocConstItem(ty) => ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: None },
|
||||
AssocConstItem(ty, default) => {
|
||||
ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: default.map(|c| c.expr(tcx)) }
|
||||
ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: Some(default.expr(tcx)) }
|
||||
}
|
||||
AssocTypeItem(g, b, t) => ItemEnum::AssocType {
|
||||
TyAssocTypeItem(g, b) => ItemEnum::AssocType {
|
||||
generics: (*g).into_tcx(tcx),
|
||||
bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
|
||||
default: t.map(|x| x.into_tcx(tcx)),
|
||||
default: None,
|
||||
},
|
||||
// FIXME: do not map to Typedef but to a custom variant
|
||||
AssocTypeItem(t, _) => ItemEnum::Typedef(t.into_tcx(tcx)),
|
||||
// `convert_item` early returns `None` for striped items
|
||||
StrippedItem(_) => unreachable!(),
|
||||
KeywordItem(_) => {
|
||||
|
@ -61,9 +61,9 @@ crate fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> boo
|
||||
*item.kind,
|
||||
clean::StructFieldItem(_)
|
||||
| clean::VariantItem(_)
|
||||
| clean::AssocConstItem(_, _)
|
||||
| clean::AssocConstItem(..)
|
||||
| clean::AssocTypeItem(..)
|
||||
| clean::TypedefItem(_, _)
|
||||
| clean::TypedefItem(_)
|
||||
| clean::StaticItem(_)
|
||||
| clean::ConstantItem(_)
|
||||
| clean::ExternCrateItem { .. }
|
||||
|
@ -93,7 +93,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
|
||||
let target = items
|
||||
.iter()
|
||||
.find_map(|item| match *item.kind {
|
||||
TypedefItem(ref t, true) => Some(&t.type_),
|
||||
AssocTypeItem(ref t, _) => Some(&t.type_),
|
||||
_ => None,
|
||||
})
|
||||
.expect("Deref impl without Target type");
|
||||
|
@ -41,6 +41,7 @@ impl<'a> DocFolder for Stripper<'a> {
|
||||
| clean::ConstantItem(..)
|
||||
| clean::UnionItem(..)
|
||||
| clean::AssocConstItem(..)
|
||||
| clean::AssocTypeItem(..)
|
||||
| clean::TraitAliasItem(..)
|
||||
| clean::MacroItem(..)
|
||||
| clean::ForeignTypeItem => {
|
||||
@ -72,8 +73,8 @@ impl<'a> DocFolder for Stripper<'a> {
|
||||
|
||||
clean::ImplItem(..) => {}
|
||||
|
||||
// tymethods have no control over privacy
|
||||
clean::TyMethodItem(..) => {}
|
||||
// tymethods etc. have no control over privacy
|
||||
clean::TyMethodItem(..) | clean::TyAssocConstItem(..) | clean::TyAssocTypeItem(..) => {}
|
||||
|
||||
// Proc-macros are always public
|
||||
clean::ProcMacroItem(..) => {}
|
||||
@ -81,9 +82,6 @@ impl<'a> DocFolder for Stripper<'a> {
|
||||
// Primitives are never stripped
|
||||
clean::PrimitiveItem(..) => {}
|
||||
|
||||
// Associated types are never stripped
|
||||
clean::AssocTypeItem(..) => {}
|
||||
|
||||
// Keywords are never stripped
|
||||
clean::KeywordItem(..) => {}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ crate trait DocVisitor: Sized {
|
||||
ExternCrateItem { src: _ }
|
||||
| ImportItem(_)
|
||||
| FunctionItem(_)
|
||||
| TypedefItem(_, _)
|
||||
| TypedefItem(_)
|
||||
| OpaqueTyItem(_)
|
||||
| StaticItem(_)
|
||||
| ConstantItem(_)
|
||||
@ -40,7 +40,9 @@ crate trait DocVisitor: Sized {
|
||||
| MacroItem(_)
|
||||
| ProcMacroItem(_)
|
||||
| PrimitiveItem(_)
|
||||
| AssocConstItem(_, _)
|
||||
| TyAssocConstItem(..)
|
||||
| AssocConstItem(..)
|
||||
| TyAssocTypeItem(..)
|
||||
| AssocTypeItem(..)
|
||||
| KeywordItem(_) => {}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
pub trait Foo {
|
||||
// @has assoc_consts/trait.Foo.html '//*[@class="rust trait"]' \
|
||||
// 'const FOO: usize;'
|
||||
// 'const FOO: usize = 13usize;'
|
||||
// @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
|
||||
const FOO: usize = 12;
|
||||
const FOO: usize = 12 + 1;
|
||||
// @has - '//*[@id="associatedconstant.FOO_NO_DEFAULT"]' 'const FOO_NO_DEFAULT: bool'
|
||||
const FOO_NO_DEFAULT: bool;
|
||||
// @!has - FOO_HIDDEN
|
||||
|
@ -0,0 +1 @@
|
||||
<a class="fnname">provided</a>(&self)
|
@ -1,9 +1,23 @@
|
||||
// aux-build:rustdoc-extern-default-method.rs
|
||||
// ignore-cross-compile
|
||||
// ignore-tidy-linelength
|
||||
|
||||
extern crate rustdoc_extern_default_method as ext;
|
||||
|
||||
// For this test, the dependency is compiled but not documented.
|
||||
//
|
||||
// Still, the struct from the external crate and its impl should be documented since
|
||||
// the struct is re-exported from this crate.
|
||||
// However, the method in the trait impl should *not* have a link (an `href` attribute) to
|
||||
// its corresponding item in the trait declaration since it would otherwise be broken.
|
||||
//
|
||||
// In older versions of rustdoc, the impl item (`a[@class="fnname"]`) used to link to
|
||||
// `#method.provided` – i.e. "to itself". Put in quotes since that was actually incorrect in
|
||||
// general: If the type `Struct` also had an inherent method called `provided`, the impl item
|
||||
// would link to that one even though those two methods are distinct items!
|
||||
|
||||
// @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]' 1
|
||||
// @has extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="fnname"]/@href' #method.provided
|
||||
// @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="fnname"]' 1
|
||||
// @snapshot no_href_on_anchor - '//*[@id="method.provided"]//a[@class="fnname"]'
|
||||
// @has extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="anchor"]/@href' #method.provided
|
||||
pub use ext::Struct;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#![feature(no_core)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(inherent_associated_types)]
|
||||
#![feature(lang_items)]
|
||||
#![no_core]
|
||||
|
||||
/// [Self::f]
|
||||
@ -35,3 +36,6 @@ pub struct S;
|
||||
impl S {
|
||||
pub fn f() {}
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
pub trait Sized {}
|
||||
|
@ -1,3 +1,4 @@
|
||||
#![feature(associated_type_defaults)]
|
||||
#![crate_name = "foo"]
|
||||
|
||||
// @has foo/trait.Foo.html
|
||||
@ -5,12 +6,18 @@
|
||||
// @has - '//*[@class="sidebar-elems"]//section//a' 'bar'
|
||||
// @has - '//*[@class="sidebar-title"]/a[@href="#provided-methods"]' 'Provided Methods'
|
||||
// @has - '//*[@class="sidebar-elems"]//section//a' 'foo'
|
||||
// @has - '//*[@class="sidebar-title"]/a[@href="#associated-const"]' 'Associated Constants'
|
||||
// @has - '//*[@class="sidebar-title"]/a[@href="#required-associated-consts"]' 'Required Associated Constants'
|
||||
// @has - '//*[@class="sidebar-elems"]//section//a' 'FOO'
|
||||
// @has - '//*[@class="sidebar-title"]/a[@href="#provided-associated-consts"]' 'Provided Associated Constants'
|
||||
// @has - '//*[@class="sidebar-elems"]//section//a' 'BAR'
|
||||
// @has - '//*[@class="sidebar-title"]/a[@href="#associated-types"]' 'Associated Types'
|
||||
// @has - '//*[@class="sidebar-title"]/a[@href="#required-associated-types"]' 'Required Associated Types'
|
||||
// @has - '//*[@class="sidebar-elems"]//section//a' 'Output'
|
||||
// @has - '//*[@class="sidebar-title"]/a[@href="#provided-associated-types"]' 'Provided Associated Types'
|
||||
// @has - '//*[@class="sidebar-elems"]//section//a' 'Extra'
|
||||
pub trait Foo {
|
||||
const FOO: usize;
|
||||
const BAR: u32 = 0;
|
||||
type Extra: Copy = ();
|
||||
type Output: ?Sized;
|
||||
|
||||
fn foo() {}
|
||||
|
Loading…
Reference in New Issue
Block a user