rustdoc: discr. required+provided assoc consts+tys
This commit is contained in:
parent
2a83fbc42a
commit
8de453a8c6
22 changed files with 407 additions and 249 deletions
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue