rustdoc: seperate methods and associated functions in sidebar

This commit is contained in:
binarycat
2026-03-31 12:51:12 -05:00
parent cf7da0b727
commit 9bdf217810
6 changed files with 103 additions and 54 deletions
+9
View File
@@ -465,6 +465,15 @@ pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
.unwrap_or(false)
}
/// Returns true if item is an associated function with a `self` parameter.
pub(crate) fn has_self_param(&self) -> bool {
if let ItemKind::MethodItem(box Function { decl, .. }, _) = &self.inner.kind {
decl.receiver_type().is_some()
} else {
false
}
}
pub(crate) fn span(&self, tcx: TyCtxt<'_>) -> Option<Span> {
let kind = match &self.kind {
ItemKind::StrippedItem(k) => k,
+82 -50
View File
@@ -433,6 +433,7 @@ fn sidebar_assoc_items<'a>(
let mut assoc_consts = Vec::new();
let mut assoc_types = Vec::new();
let mut assoc_fns = Vec::new();
let mut methods = Vec::new();
if let Some(v) = cache.impls.get(&did) {
let mut used_links = FxHashSet::default();
@@ -443,7 +444,12 @@ fn sidebar_assoc_items<'a>(
for impl_ in v.iter().map(|i| i.inner_impl()).filter(|i| i.trait_.is_none()) {
assoc_consts.extend(get_associated_constants(impl_, used_links_bor));
assoc_types.extend(get_associated_types(impl_, used_links_bor));
methods.extend(get_methods(impl_, false, used_links_bor, false, cx.tcx()));
methods.extend(get_methods(
impl_,
GetMethodsMode::AlsoCollectAssocFns { assoc_fns: &mut assoc_fns },
used_links_bor,
cx.tcx(),
));
}
// We want links' order to be reproducible so we don't use unstable sort.
assoc_consts.sort();
@@ -462,6 +468,11 @@ fn sidebar_assoc_items<'a>(
"associatedtype",
assoc_types,
),
LinkBlock::new(
Link::new("implementations", "Associated Functions"),
"method",
assoc_fns,
),
LinkBlock::new(Link::new("implementations", "Methods"), "method", methods),
];
@@ -546,7 +557,15 @@ fn sidebar_deref_methods<'a>(
i.inner_impl().trait_.is_none()
&& real_target.is_doc_subtype_of(&i.inner_impl().for_, c)
})
.flat_map(|i| get_methods(i.inner_impl(), true, used_links, deref_mut, cx.tcx()))
.flat_map(|i| {
get_methods(
i.inner_impl(),
GetMethodsMode::Deref { deref_mut },
used_links,
cx.tcx(),
)
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
if !ret.is_empty() {
let id = if let Some(target_def_id) = real_target.def_id(c) {
@@ -734,69 +753,82 @@ fn get_next_url(used_links: &mut FxHashSet<String>, url: String) -> String {
format!("{url}-{add}")
}
enum GetMethodsMode<'r, 'l> {
Deref { deref_mut: bool },
AlsoCollectAssocFns { assoc_fns: &'r mut Vec<Link<'l>> },
}
fn get_methods<'a>(
i: &'a clean::Impl,
for_deref: bool,
mut mode: GetMethodsMode<'_, 'a>,
used_links: &mut FxHashSet<String>,
deref_mut: bool,
tcx: TyCtxt<'_>,
) -> Vec<Link<'a>> {
i.items
.iter()
.filter_map(|item| {
if let Some(ref name) = item.name
&& item.is_method()
&& (!for_deref || super::should_render_item(item, deref_mut, tcx))
{
Some(Link::new(
) -> impl Iterator<Item = Link<'a>> {
i.items.iter().filter_map(move |item| {
if let Some(ref name) = item.name
&& item.is_method()
{
let mut build_link = || {
Link::new(
get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::Method)),
name.as_str(),
))
} else {
None
)
};
match &mut mode {
&mut GetMethodsMode::Deref { deref_mut } => {
if super::should_render_item(item, deref_mut, tcx) {
Some(build_link())
} else {
None
}
}
GetMethodsMode::AlsoCollectAssocFns { assoc_fns } => {
if item.has_self_param() {
Some(build_link())
} else {
assoc_fns.push(build_link());
None
}
}
}
})
.collect()
} else {
None
}
})
}
fn get_associated_constants<'a>(
i: &'a clean::Impl,
used_links: &mut FxHashSet<String>,
) -> Vec<Link<'a>> {
i.items
.iter()
.filter_map(|item| {
if let Some(ref name) = item.name
&& item.is_associated_const()
{
Some(Link::new(
get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocConst)),
name.as_str(),
))
} else {
None
}
})
.collect()
) -> impl Iterator<Item = Link<'a>> {
i.items.iter().filter_map(|item| {
if let Some(ref name) = item.name
&& item.is_associated_const()
{
Some(Link::new(
get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocConst)),
name.as_str(),
))
} else {
None
}
})
}
fn get_associated_types<'a>(
i: &'a clean::Impl,
used_links: &mut FxHashSet<String>,
) -> Vec<Link<'a>> {
i.items
.iter()
.filter_map(|item| {
if let Some(ref name) = item.name
&& item.is_associated_type()
{
Some(Link::new(
get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocType)),
name.as_str(),
))
} else {
None
}
})
.collect()
) -> impl Iterator<Item = Link<'a>> {
i.items.iter().filter_map(|item| {
if let Some(ref name) = item.name
&& item.is_associated_type()
{
Some(Link::new(
get_next_url(used_links, format!("{typ}.{name}", typ = ItemType::AssocType)),
name.as_str(),
))
} else {
None
}
})
}
+2 -2
View File
@@ -5,7 +5,7 @@ assert-attribute: ("#blanket-implementations-list > details:nth-child(2)", {"ope
// We first check that the impl block is open by default.
assert-attribute: ("#implementations-list details", {"open": ""})
// To ensure that we will click on the currently hidden method.
assert-text: (".sidebar-elems section .block li > a", "must_use")
click: ".sidebar-elems section .block li > a"
assert-text: (".sidebar-elems section ul:nth-of-type(2) li > a", "must_use")
click: ".sidebar-elems ul:nth-of-type(2) li > a"
// We check that the impl block was opened as expected so that we can see the method.
assert-attribute: ("#implementations-list > details", {"open": ""})
+1 -1
View File
@@ -48,7 +48,7 @@ assert-property: ("rustdoc-topbar", {"clientHeight": "45"})
// Check that clicking an element from the sidebar scrolls to the right place
// so the target is not obscured by the topbar.
click: ".sidebar-menu-toggle"
click: ".sidebar-elems section .block li > a"
click: ".sidebar-elems section ul:nth-of-type(2) li > a"
assert-position: ("#method\.must_use", {"y": 45})
// Check that the bottom-most item on the sidebar menu can be scrolled fully into view.
@@ -42,6 +42,14 @@ pub struct Bar {
waza: u32,
}
//@ has foo/struct.Bar.html
//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#implementations"]' 'Associated Functions'
//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#implementations"]' 'Methods'
impl Bar {
pub fn method(&self) {}
pub fn assoc_fn() {}
}
//@ has foo/enum.En.html
//@ has - '//div[@class="sidebar-elems"]//h3/a[@href="#variants"]' 'Variants'
//@ has - '//*[@class="sidebar-elems"]//section//a' 'Foo'
+1 -1
View File
@@ -13,7 +13,7 @@ pub fn method_on_mystruct() {}
//@ has - '//*[@class="impl"]//h3[@class="code-header"]' 'impl MyTrait for MyAlias'
//@ hasraw - 'Alias docstring'
//@ has - '//*[@class="sidebar"]//*[@class="location"]' 'MyAlias'
//@ has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods'
//@ has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Associated Functions'
//@ has - '//*[@class="sidebar"]//a[@href="#trait-implementations"]' 'Trait Implementations'
/// Alias docstring
pub type MyAlias = MyStruct;