Add new "hide deprecated items" setting in rustdoc

This commit is contained in:
Guillaume Gomez 2026-01-14 00:45:16 +01:00
parent 1b39278a31
commit 4ded6397b3
12 changed files with 107 additions and 23 deletions

View file

@ -126,6 +126,7 @@ fn synthesize_auto_trait_impl<'tcx>(
items: Vec::new(),
polarity,
kind: clean::ImplKind::Auto,
is_deprecated: false,
})),
item_id: clean::ItemId::Auto { trait_: trait_def_id, for_: item_def_id },
cfg: None,

View file

@ -117,6 +117,9 @@ pub(crate) fn synthesize_blanket_impls(
None,
None,
))),
is_deprecated: tcx
.lookup_deprecation(impl_def_id)
.is_some_and(|deprecation| deprecation.is_in_effect()),
})),
cfg: None,
inline_stmt_id: None,

View file

@ -645,6 +645,9 @@ pub(crate) fn build_impl(
} else {
ImplKind::Normal
},
is_deprecated: tcx
.lookup_deprecation(did)
.is_some_and(|deprecation| deprecation.is_in_effect()),
})),
merged_attrs,
cfg,

View file

@ -2882,6 +2882,9 @@ fn clean_impl<'tcx>(
)),
_ => None,
});
let is_deprecated = tcx
.lookup_deprecation(def_id.to_def_id())
.is_some_and(|deprecation| deprecation.is_in_effect());
let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
let kind = ImplItem(Box::new(Impl {
safety: match impl_.of_trait {
@ -2902,6 +2905,7 @@ fn clean_impl<'tcx>(
} else {
ImplKind::Normal
},
is_deprecated,
}));
Item::from_def_id_and_parts(def_id.to_def_id(), None, kind, cx)
};

View file

@ -427,6 +427,10 @@ impl Item {
})
}
pub(crate) fn is_deprecated(&self, tcx: TyCtxt<'_>) -> bool {
self.deprecation(tcx).is_some_and(|deprecation| deprecation.is_in_effect())
}
pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool {
self.item_id.as_def_id().map(|did| inner_docs(tcx.get_all_attrs(did))).unwrap_or(false)
}
@ -1270,6 +1274,9 @@ impl Trait {
pub(crate) fn is_dyn_compatible(&self, tcx: TyCtxt<'_>) -> bool {
tcx.is_dyn_compatible(self.def_id)
}
pub(crate) fn is_deprecated(&self, tcx: TyCtxt<'_>) -> bool {
tcx.lookup_deprecation(self.def_id).is_some_and(|deprecation| deprecation.is_in_effect())
}
}
#[derive(Clone, Debug)]
@ -2254,6 +2261,7 @@ pub(crate) struct Impl {
pub(crate) items: Vec<Item>,
pub(crate) polarity: ty::ImplPolarity,
pub(crate) kind: ImplKind,
pub(crate) is_deprecated: bool,
}
impl Impl {

View file

@ -1794,12 +1794,14 @@ fn render_impl(
let mut info_buffer = String::new();
let mut short_documented = true;
let mut trait_item_deprecated = false;
if render_method_item {
if !is_default_item {
if let Some(t) = trait_ {
// The trait item may have been stripped so we might not
// find any documentation or stability for it.
if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
trait_item_deprecated = it.is_deprecated(cx.tcx());
// We need the stability of the item from the trait
// because impls can't have a stability.
if !item.doc_value().is_empty() {
@ -1839,10 +1841,20 @@ fn render_impl(
Either::Right(boring)
};
let mut deprecation_class = if trait_item_deprecated || item.is_deprecated(cx.tcx()) {
" deprecated"
} else {
""
};
let toggled = !doc_buffer.is_empty();
if toggled {
let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>")?;
write!(
w,
"<details class=\"toggle{method_toggle_class}{deprecation_class}\" open><summary>"
)?;
deprecation_class = "";
}
match &item.kind {
clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
@ -1859,7 +1871,7 @@ fn render_impl(
.map(|item| format!("{}.{name}", item.type_()));
write!(
w,
"<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
"<section id=\"{id}\" class=\"{item_type}{in_trait_class}{deprecation_class}\">\
{}",
render_rightside(cx, item, render_mode)
)?;
@ -1885,7 +1897,7 @@ fn render_impl(
let id = cx.derive_id(&source_id);
write!(
w,
"<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
"<section id=\"{id}\" class=\"{item_type}{in_trait_class}{deprecation_class}\">\
{}",
render_rightside(cx, item, render_mode)
)?;
@ -1912,7 +1924,7 @@ fn render_impl(
let id = cx.derive_id(&source_id);
write!(
w,
"<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
"<section id=\"{id}\" class=\"{item_type}{in_trait_class}{deprecation_class}\">\
{}",
render_rightside(cx, item, render_mode),
)?;
@ -1944,7 +1956,7 @@ fn render_impl(
let id = cx.derive_id(&source_id);
write!(
w,
"<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
"<section id=\"{id}\" class=\"{item_type}{in_trait_class}{deprecation_class}\">\
{}",
render_rightside(cx, item, render_mode),
)?;
@ -1971,7 +1983,7 @@ fn render_impl(
let id = cx.derive_id(&source_id);
write!(
w,
"<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
"<section id=\"{id}\" class=\"{item_type}{in_trait_class}{deprecation_class}\">\
{}",
render_rightside(cx, item, render_mode),
)?;
@ -2143,11 +2155,18 @@ fn render_impl(
}
if render_mode == RenderMode::Normal {
let toggled = !(impl_items.is_empty() && default_impl_items.is_empty());
let deprecation_attr = if impl_.is_deprecated
|| trait_.is_some_and(|trait_| trait_.is_deprecated(cx.tcx()))
{
" deprecated"
} else {
""
};
if toggled {
close_tags.push("</details>");
write!(
w,
"<details class=\"toggle implementors-toggle\"{}>\
"<details class=\"toggle implementors-toggle{deprecation_attr}\"{}>\
<summary>",
if rendering_params.toggle_open_by_default { " open" } else { "" }
)?;

View file

@ -217,6 +217,10 @@ fn toggle_close(mut w: impl fmt::Write) {
}
fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> impl fmt::Display {
fn deprecation_class_attr(is_deprecated: bool) -> &'static str {
if is_deprecated { " class=\"deprecated\"" } else { "" }
}
fmt::from_fn(|w| {
write!(w, "{}", document(cx, item, None, HeadingOffset::H2))?;
@ -370,11 +374,18 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i
write!(w, "</code></dt>")?
}
clean::ImportItem(ref import) => {
let stab_tags =
import.source.did.map_or_else(String::new, |import_def_id| {
print_extra_info_tags(tcx, myitem, item, Some(import_def_id))
.to_string()
});
let (stab_tags, deprecation) = match import.source.did {
Some(import_def_id) => {
let stab_tags =
print_extra_info_tags(tcx, myitem, item, Some(import_def_id))
.to_string();
let deprecation = tcx
.lookup_deprecation(import_def_id)
.is_some_and(|deprecation| deprecation.is_in_effect());
(stab_tags, deprecation)
}
None => (String::new(), item.is_deprecated(tcx)),
};
let id = match import.kind {
clean::ImportKind::Simple(s) => {
format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}")))
@ -383,8 +394,8 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i
};
write!(
w,
"<dt{id}>\
<code>"
"<dt{id}{deprecation_attr}><code>",
deprecation_attr = deprecation_class_attr(deprecation)
)?;
render_attributes_in_code(w, myitem, "", cx)?;
write!(
@ -396,9 +407,7 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i
)?;
}
_ => {
if myitem.name.is_none() {
continue;
}
let Some(item_name) = myitem.name else { continue };
let unsafety_flag = match myitem.kind {
clean::FunctionItem(_) | clean::ForeignFunctionItem(..)
@ -431,9 +440,10 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i
.into_string();
let (docs_before, docs_after) =
if docs.is_empty() { ("", "") } else { ("<dd>", "</dd>") };
let deprecation_attr = deprecation_class_attr(myitem.is_deprecated(tcx));
write!(
w,
"<dt>\
"<dt{deprecation_attr}>\
<a class=\"{class}\" href=\"{href}\" title=\"{title1} {title2}\">\
{name}\
</a>\
@ -442,12 +452,12 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i
{stab_tags}\
</dt>\
{docs_before}{docs}{docs_after}",
name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
name = EscapeBodyTextWithWbr(item_name.as_str()),
visibility_and_hidden = visibility_and_hidden,
stab_tags = print_extra_info_tags(tcx, myitem, item, None),
class = type_,
unsafety_flag = unsafety_flag,
href = print_item_path(type_, myitem.name.unwrap().as_str()),
href = print_item_path(type_, item_name.as_str()),
title1 = myitem.type_(),
title2 = full_path(cx, myitem),
)?;
@ -778,15 +788,24 @@ fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt:
let content = document_full(m, cx, HeadingOffset::H5).to_string();
let mut deprecation_class =
if m.is_deprecated(cx.tcx()) { " deprecated" } else { "" };
let toggled = !content.is_empty();
if toggled {
let method_toggle_class =
if item_type.is_method() { " method-toggle" } else { "" };
write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>")?;
write!(
w,
"<details \
class=\"toggle{method_toggle_class}{deprecation_class}\" \
open><summary>"
)?;
deprecation_class = "";
}
write!(
w,
"<section id=\"{id}\" class=\"method\">\
"<section id=\"{id}\" class=\"method{deprecation_class}\">\
{}\
<h4 class=\"code-header\">{}</h4></section>",
render_rightside(cx, m, RenderMode::Normal),

View file

@ -2642,6 +2642,15 @@ However, it's not needed with smaller screen width because the doc/code block is
}
}
/* Items on module pages */
.hide-deprecated-items dt.deprecated,
.hide-deprecated-items dt.deprecated + dd,
/* Items on item pages */
.hide-deprecated-items .deprecated,
.hide-deprecated-items .deprecated + .item-info {
display: none;
}
/*
WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
If you update this line, then you also need to update the line with the same warning

View file

@ -4920,6 +4920,9 @@ async function addTab(results, query, display, finishedCallback, isTypeSearch) {
const link = document.createElement("a");
link.className = "result-" + type;
if (obj.item.deprecated) {
link.className += " deprecated";
}
link.href = obj.href;
const resultName = document.createElement("span");

View file

@ -78,6 +78,12 @@
removeClass(document.documentElement, "word-wrap-source-code");
}
break;
case "hide-deprecated-items":
if (value === true) {
addClass(document.documentElement, "hide-deprecated-items");
} else {
removeClass(document.documentElement, "hide-deprecated-items");
}
}
}
@ -274,6 +280,11 @@
"js_name": "word-wrap-source-code",
"default": false,
},
{
"name": "Hide deprecated items",
"js_name": "hide-deprecated-items",
"default": false,
},
];
// Then we build the DOM.

View file

@ -334,6 +334,9 @@ if (getSettingValue("sans-serif-fonts") === "true") {
if (getSettingValue("word-wrap-source-code") === "true") {
addClass(document.documentElement, "word-wrap-source-code");
}
if (getSettingValue("hide-deprecated-items") === "true") {
addClass(document.documentElement, "hide-deprecated-items");
}
function updateSidebarWidth() {
const desktopSidebarWidth = getSettingValue("desktop-sidebar-width");
if (desktopSidebarWidth && desktopSidebarWidth !== "null") {

View file

@ -711,7 +711,8 @@ impl FromClean<clean::PolyTrait> for PolyTrait {
impl FromClean<clean::Impl> for Impl {
fn from_clean(impl_: &clean::Impl, renderer: &JsonRenderer<'_>) -> Self {
let provided_trait_methods = impl_.provided_trait_methods(renderer.tcx);
let clean::Impl { safety, generics, trait_, for_, items, polarity, kind } = impl_;
let clean::Impl { safety, generics, trait_, for_, items, polarity, kind, is_deprecated: _ } =
impl_;
// FIXME: use something like ImplKind in JSON?
let (is_synthetic, blanket_impl) = match kind {
clean::ImplKind::Normal | clean::ImplKind::FakeVariadic => (false, None),