From 4ded6397b376b0a005c26381ed92c944e3702019 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 14 Jan 2026 00:45:16 +0100 Subject: [PATCH] Add new "hide deprecated items" setting in rustdoc --- src/librustdoc/clean/auto_trait.rs | 1 + src/librustdoc/clean/blanket_impl.rs | 3 ++ src/librustdoc/clean/inline.rs | 3 ++ src/librustdoc/clean/mod.rs | 4 ++ src/librustdoc/clean/types.rs | 8 ++++ src/librustdoc/html/render/mod.rs | 33 +++++++++++---- src/librustdoc/html/render/print_item.rs | 49 +++++++++++++++------- src/librustdoc/html/static/css/rustdoc.css | 9 ++++ src/librustdoc/html/static/js/search.js | 3 ++ src/librustdoc/html/static/js/settings.js | 11 +++++ src/librustdoc/html/static/js/storage.js | 3 ++ src/librustdoc/json/conversions.rs | 3 +- 12 files changed, 107 insertions(+), 23 deletions(-) diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 6c67916571a4..847e688d03d0 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -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, diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index ddfce7aeb92d..de45922e856f 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -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, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index c86a655c083a..19974f4847d4 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -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, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 817eda4c52ec..0e970a042ff0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -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, for_: Type, items: Vec| { 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) }; diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c3bafd3db13a..93863ea41396 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -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, pub(crate) polarity: ty::ImplPolarity, pub(crate) kind: ImplKind, + pub(crate) is_deprecated: bool, } impl Impl { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 63de870f07f4..106aefa4626b 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -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, "
")?; + write!( + w, + "
" + )?; + deprecation_class = ""; } match &item.kind { clean::MethodItem(..) | clean::RequiredMethodItem(_) => { @@ -1859,7 +1871,7 @@ fn render_impl( .map(|item| format!("{}.{name}", item.type_())); write!( w, - "
\ + "
\ {}", render_rightside(cx, item, render_mode) )?; @@ -1885,7 +1897,7 @@ fn render_impl( let id = cx.derive_id(&source_id); write!( w, - "
\ + "
\ {}", render_rightside(cx, item, render_mode) )?; @@ -1912,7 +1924,7 @@ fn render_impl( let id = cx.derive_id(&source_id); write!( w, - "
\ + "
\ {}", render_rightside(cx, item, render_mode), )?; @@ -1944,7 +1956,7 @@ fn render_impl( let id = cx.derive_id(&source_id); write!( w, - "
\ + "
\ {}", render_rightside(cx, item, render_mode), )?; @@ -1971,7 +1983,7 @@ fn render_impl( let id = cx.derive_id(&source_id); write!( w, - "
\ + "
\ {}", 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("
"); write!( w, - "
\ + "
\ ", if rendering_params.toggle_open_by_default { " open" } else { "" } )?; diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 84e93a479b5b..55e36c462f96 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -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, "")? } 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, - "\ - " + "", + 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 { ("
", "
") }; + let deprecation_attr = deprecation_class_attr(myitem.is_deprecated(tcx)); write!( w, - "
\ + "\ \ {name}\ \ @@ -442,12 +452,12 @@ fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> i {stab_tags}\
\ {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, "
")?; + write!( + w, + "
" + )?; + deprecation_class = ""; } write!( w, - "
\ + "
\ {}\

{}

", render_rightside(cx, m, RenderMode::Normal), diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index b770a0e2a0e4..73eb260a2b8e 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -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 diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index b2880a2f4c2b..9961c1447ec2 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -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"); diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 347d3d0750ec..b28b76b0d2e7 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -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. diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 40ab8be03c93..7cc70374378b 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -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") { diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 892cc483dbd6..2edf7891be40 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -711,7 +711,8 @@ impl FromClean for PolyTrait { impl FromClean 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),