Render final associated functions correctly in rustdoc
Co-authored-by: Michael Goulet <michael@errs.io>
This commit is contained in:
parent
f0e1c8f416
commit
f0a019bf90
9 changed files with 88 additions and 39 deletions
|
|
@ -1222,11 +1222,11 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
|
|||
}
|
||||
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
|
||||
let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Body(body));
|
||||
MethodItem(m, None)
|
||||
MethodItem(m, Defaultness::from_trait_item(trait_item.defaultness))
|
||||
}
|
||||
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(idents)) => {
|
||||
let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Idents(idents));
|
||||
RequiredMethodItem(m)
|
||||
RequiredMethodItem(m, Defaultness::from_trait_item(trait_item.defaultness))
|
||||
}
|
||||
hir::TraitItemKind::Type(bounds, Some(default)) => {
|
||||
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
|
||||
|
|
@ -1271,7 +1271,7 @@ pub(crate) fn clean_impl_item<'tcx>(
|
|||
hir::ImplItemImplKind::Inherent { .. } => hir::Defaultness::Final,
|
||||
hir::ImplItemImplKind::Trait { defaultness, .. } => defaultness,
|
||||
};
|
||||
MethodItem(m, Some(defaultness))
|
||||
MethodItem(m, Defaultness::from_impl_item(defaultness))
|
||||
}
|
||||
hir::ImplItemKind::Type(hir_ty) => {
|
||||
let type_ = clean_ty(hir_ty, cx);
|
||||
|
|
@ -1353,18 +1353,20 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
|
|||
}
|
||||
}
|
||||
|
||||
let provided = match assoc_item.container {
|
||||
ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true,
|
||||
ty::AssocContainer::Trait => assoc_item.defaultness(tcx).has_value(),
|
||||
let defaultness = assoc_item.defaultness(tcx);
|
||||
let (provided, defaultness) = match assoc_item.container {
|
||||
ty::AssocContainer::Trait => {
|
||||
(defaultness.has_value(), Defaultness::from_trait_item(defaultness))
|
||||
}
|
||||
ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {
|
||||
(true, Defaultness::from_impl_item(defaultness))
|
||||
}
|
||||
};
|
||||
|
||||
if provided {
|
||||
let defaultness = match assoc_item.container {
|
||||
ty::AssocContainer::TraitImpl(_) => Some(assoc_item.defaultness(tcx)),
|
||||
ty::AssocContainer::InherentImpl | ty::AssocContainer::Trait => None,
|
||||
};
|
||||
MethodItem(item, defaultness)
|
||||
} else {
|
||||
RequiredMethodItem(item)
|
||||
RequiredMethodItem(item, defaultness)
|
||||
}
|
||||
}
|
||||
ty::AssocKind::Type { .. } => {
|
||||
|
|
|
|||
|
|
@ -61,6 +61,29 @@ pub(crate) enum ItemId {
|
|||
Blanket { impl_id: DefId, for_: DefId },
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub(crate) enum Defaultness {
|
||||
Implicit,
|
||||
Default,
|
||||
Final,
|
||||
}
|
||||
|
||||
impl Defaultness {
|
||||
pub(crate) fn from_trait_item(defaultness: hir::Defaultness) -> Self {
|
||||
match defaultness {
|
||||
hir::Defaultness::Default { .. } => Self::Implicit,
|
||||
hir::Defaultness::Final => Self::Final,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_impl_item(defaultness: hir::Defaultness) -> Self {
|
||||
match defaultness {
|
||||
hir::Defaultness::Default { .. } => Self::Default,
|
||||
hir::Defaultness::Final => Self::Implicit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ItemId {
|
||||
#[inline]
|
||||
pub(crate) fn is_local(self) -> bool {
|
||||
|
|
@ -703,12 +726,12 @@ impl Item {
|
|||
ItemType::from(self)
|
||||
}
|
||||
|
||||
pub(crate) fn is_default(&self) -> bool {
|
||||
pub(crate) fn defaultness(&self) -> Option<Defaultness> {
|
||||
match self.kind {
|
||||
ItemKind::MethodItem(_, Some(defaultness)) => {
|
||||
defaultness.has_value() && !defaultness.is_final()
|
||||
ItemKind::MethodItem(_, defaultness) | ItemKind::RequiredMethodItem(_, defaultness) => {
|
||||
Some(defaultness)
|
||||
}
|
||||
_ => false,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -770,8 +793,8 @@ impl Item {
|
|||
}
|
||||
}
|
||||
ItemKind::FunctionItem(_)
|
||||
| ItemKind::MethodItem(_, _)
|
||||
| ItemKind::RequiredMethodItem(_) => {
|
||||
| ItemKind::MethodItem(..)
|
||||
| ItemKind::RequiredMethodItem(..) => {
|
||||
let def_id = self.def_id().unwrap();
|
||||
build_fn_header(def_id, tcx, tcx.asyncness(def_id))
|
||||
}
|
||||
|
|
@ -855,11 +878,11 @@ pub(crate) enum ItemKind {
|
|||
TraitAliasItem(TraitAlias),
|
||||
ImplItem(Box<Impl>),
|
||||
/// A required method in a trait declaration meaning it's only a function signature.
|
||||
RequiredMethodItem(Box<Function>),
|
||||
RequiredMethodItem(Box<Function>, Defaultness),
|
||||
/// A method in a trait impl or a provided method in a trait declaration.
|
||||
///
|
||||
/// Compared to [RequiredMethodItem], it also contains a method body.
|
||||
MethodItem(Box<Function>, Option<hir::Defaultness>),
|
||||
MethodItem(Box<Function>, Defaultness),
|
||||
StructFieldItem(Type),
|
||||
VariantItem(Variant),
|
||||
/// `fn`s from an extern block
|
||||
|
|
@ -917,8 +940,8 @@ impl ItemKind {
|
|||
| StaticItem(_)
|
||||
| ConstantItem(_)
|
||||
| TraitAliasItem(_)
|
||||
| RequiredMethodItem(_)
|
||||
| MethodItem(_, _)
|
||||
| RequiredMethodItem(..)
|
||||
| MethodItem(..)
|
||||
| StructFieldItem(_)
|
||||
| ForeignFunctionItem(_, _)
|
||||
| ForeignStaticItem(_, _)
|
||||
|
|
|
|||
|
|
@ -82,8 +82,8 @@ pub(crate) trait DocFolder: Sized {
|
|||
| StaticItem(_)
|
||||
| ConstantItem(..)
|
||||
| TraitAliasItem(_)
|
||||
| RequiredMethodItem(_)
|
||||
| MethodItem(_, _)
|
||||
| RequiredMethodItem(..)
|
||||
| MethodItem(..)
|
||||
| StructFieldItem(_)
|
||||
| ForeignFunctionItem(..)
|
||||
| ForeignStaticItem(..)
|
||||
|
|
|
|||
|
|
@ -1566,10 +1566,6 @@ pub(crate) fn print_abi_with_space(abi: ExternAbi) -> impl Display {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn print_default_space(v: bool) -> &'static str {
|
||||
if v { "default " } else { "" }
|
||||
}
|
||||
|
||||
fn print_generic_arg(generic_arg: &clean::GenericArg, cx: &Context<'_>) -> impl Display {
|
||||
fmt::from_fn(move |f| match generic_arg {
|
||||
clean::GenericArg::Lifetime(lt) => f.write_str(print_lifetime(lt)),
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ use tracing::{debug, info};
|
|||
pub(crate) use self::context::*;
|
||||
pub(crate) use self::span_map::{LinkFromSrc, collect_spans_and_sources};
|
||||
pub(crate) use self::write_shared::*;
|
||||
use crate::clean::{self, ItemId, RenderedLink};
|
||||
use crate::clean::{self, Defaultness, ItemId, RenderedLink};
|
||||
use crate::display::{Joined as _, MaybeDisplay as _};
|
||||
use crate::error::Error;
|
||||
use crate::formats::Impl;
|
||||
|
|
@ -75,8 +75,8 @@ use crate::formats::item_type::ItemType;
|
|||
use crate::html::escape::Escape;
|
||||
use crate::html::format::{
|
||||
Ending, HrefError, HrefInfo, PrintWithSpace, full_print_fn_decl, href, print_abi_with_space,
|
||||
print_constness_with_space, print_default_space, print_generic_bounds, print_generics,
|
||||
print_impl, print_path, print_type, print_where_clause, visibility_print_with_space,
|
||||
print_constness_with_space, print_generic_bounds, print_generics, print_impl, print_path,
|
||||
print_type, print_where_clause, visibility_print_with_space,
|
||||
};
|
||||
use crate::html::markdown::{
|
||||
HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine,
|
||||
|
|
@ -1109,7 +1109,11 @@ fn assoc_method(
|
|||
let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
|
||||
let name = meth.name.as_ref().unwrap();
|
||||
let vis = visibility_print_with_space(meth, cx).to_string();
|
||||
let defaultness = print_default_space(meth.is_default());
|
||||
let defaultness = match meth.defaultness().expect("Expected assoc method to have defaultness") {
|
||||
Defaultness::Implicit => "",
|
||||
Defaultness::Final => "final ",
|
||||
Defaultness::Default => "default ",
|
||||
};
|
||||
// FIXME: Once https://github.com/rust-lang/rust/issues/143874 is implemented, we can remove
|
||||
// this condition.
|
||||
let constness = match render_mode {
|
||||
|
|
@ -1260,7 +1264,7 @@ fn render_assoc_item(
|
|||
) -> impl fmt::Display {
|
||||
fmt::from_fn(move |f| match &item.kind {
|
||||
clean::StrippedItem(..) => Ok(()),
|
||||
clean::RequiredMethodItem(m) | clean::MethodItem(m, _) => {
|
||||
clean::RequiredMethodItem(m, _) | clean::MethodItem(m, _) => {
|
||||
assoc_method(item, &m.generics, &m.decl, link, parent, cx, render_mode).fmt(f)
|
||||
}
|
||||
clean::RequiredAssocConstItem(generics, ty) => assoc_const(
|
||||
|
|
@ -1585,7 +1589,7 @@ fn render_deref_methods(
|
|||
fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
|
||||
let self_type_opt = match item.kind {
|
||||
clean::MethodItem(ref method, _) => method.decl.receiver_type(),
|
||||
clean::RequiredMethodItem(ref method) => method.decl.receiver_type(),
|
||||
clean::RequiredMethodItem(ref method, _) => method.decl.receiver_type(),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
|
|
@ -1855,7 +1859,7 @@ fn render_impl(
|
|||
deprecation_class = "";
|
||||
}
|
||||
match &item.kind {
|
||||
clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
|
||||
clean::MethodItem(..) | clean::RequiredMethodItem(..) => {
|
||||
// Only render when the method is not static or we allow static methods
|
||||
if render_method_item {
|
||||
let id = cx.derive_id(format!("{item_type}.{name}"));
|
||||
|
|
@ -2033,7 +2037,9 @@ fn render_impl(
|
|||
if !impl_.is_negative_trait_impl() {
|
||||
for impl_item in &impl_.items {
|
||||
match impl_item.kind {
|
||||
clean::MethodItem(..) | clean::RequiredMethodItem(_) => methods.push(impl_item),
|
||||
clean::MethodItem(..) | clean::RequiredMethodItem(..) => {
|
||||
methods.push(impl_item)
|
||||
}
|
||||
clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => {
|
||||
assoc_types.push(impl_item)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1968,7 +1968,7 @@ pub(crate) fn get_function_type_for_search(
|
|||
clean::ForeignFunctionItem(ref f, _)
|
||||
| clean::FunctionItem(ref f)
|
||||
| clean::MethodItem(ref f, _)
|
||||
| clean::RequiredMethodItem(ref f) => {
|
||||
| clean::RequiredMethodItem(ref f, _) => {
|
||||
get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
|
||||
}
|
||||
clean::ConstantItem(ref c) => make_nullary_fn(&c.type_),
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum
|
|||
MethodItem(m, _) => {
|
||||
ItemEnum::Function(from_clean_function(m, true, header.unwrap(), renderer))
|
||||
}
|
||||
RequiredMethodItem(m) => {
|
||||
RequiredMethodItem(m, _) => {
|
||||
ItemEnum::Function(from_clean_function(m, false, header.unwrap(), renderer))
|
||||
}
|
||||
ImplItem(i) => ItemEnum::Impl(i.into_json(renderer)),
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ pub(crate) trait DocVisitor<'a>: Sized {
|
|||
| StaticItem(_)
|
||||
| ConstantItem(..)
|
||||
| TraitAliasItem(_)
|
||||
| RequiredMethodItem(_)
|
||||
| MethodItem(_, _)
|
||||
| RequiredMethodItem(..)
|
||||
| MethodItem(..)
|
||||
| StructFieldItem(_)
|
||||
| ForeignFunctionItem(..)
|
||||
| ForeignStaticItem(..)
|
||||
|
|
|
|||
22
tests/rustdoc-html/final-trait-method.rs
Normal file
22
tests/rustdoc-html/final-trait-method.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#![feature(final_associated_functions)]
|
||||
|
||||
//@ has final_trait_method/trait.Item.html
|
||||
pub trait Item {
|
||||
//@ has - '//*[@id="method.foo"]' 'final fn foo()'
|
||||
//@ !has - '//*[@id="method.foo"]' 'default fn foo()'
|
||||
final fn foo() {}
|
||||
|
||||
//@ has - '//*[@id="method.bar"]' 'fn bar()'
|
||||
//@ !has - '//*[@id="method.bar"]' 'default fn bar()'
|
||||
//@ !has - '//*[@id="method.bar"]' 'final fn bar()'
|
||||
fn bar() {}
|
||||
}
|
||||
|
||||
//@ has final_trait_method/struct.Foo.html
|
||||
pub struct Foo;
|
||||
impl Item for Foo {
|
||||
//@ has - '//*[@id="method.bar"]' 'fn bar()'
|
||||
//@ !has - '//*[@id="method.bar"]' 'final fn bar()'
|
||||
//@ !has - '//*[@id="method.bar"]' 'default fn bar()'
|
||||
fn bar() {}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue