From 3fd362aafd70f45b412d8a1efe69ee0c7203e5b2 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Tue, 27 Jun 2023 00:23:57 -0400 Subject: [PATCH] rustdoc: Strikethrough deprecated items in sidebar --- src/librustdoc/clean/types.rs | 8 ++ src/librustdoc/html/render/context.rs | 17 ++- src/librustdoc/html/render/sidebar.rs | 129 ++++++++++++++------- src/librustdoc/html/static/js/main.js | 11 +- src/librustdoc/html/templates/sidebar.html | 8 +- 5 files changed, 124 insertions(+), 49 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 5f5cade67a2b7..31b78bbb1a40d 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -22,6 +22,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{BodyId, Mutability}; use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety; use rustc_index::IndexVec; +use rustc_middle::middle::stability; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, TyCtxt, Visibility}; use rustc_resolve::rustdoc::{add_doc_fragment, attrs_to_doc_fragments, inner_docs, DocFragment}; @@ -369,6 +370,13 @@ impl Item { self.def_id().and_then(|did| tcx.lookup_deprecation(did)) } + pub(crate) fn is_deprecated(&self, tcx: TyCtxt<'_>) -> bool { + match self.deprecation(tcx) { + Some(depr) => stability::deprecation_in_effect(&depr), + None => false, + } + } + pub(crate) fn inner_docs(&self, tcx: TyCtxt<'_>) -> bool { self.item_id .as_def_id() diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 4c47626363518..56233f29661b2 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -5,6 +5,8 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use std::sync::mpsc::{channel, Receiver}; +use serde::Serialize; + use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefIdMap, LOCAL_CRATE}; use rustc_middle::ty::TyCtxt; @@ -149,6 +151,13 @@ impl SharedContext<'_> { } } +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize)] +struct SidebarEntry { + name: String, + #[serde(skip_serializing_if = "std::ops::Not::not")] + is_deprecated: bool, +} + impl<'tcx> Context<'tcx> { pub(crate) fn tcx(&self) -> TyCtxt<'tcx> { self.shared.tcx @@ -273,7 +282,9 @@ impl<'tcx> Context<'tcx> { } /// Construct a map of items shown in the sidebar to a plain-text summary of their docs. - fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap> { + fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap> { + let tcx = self.tcx(); + // BTreeMap instead of HashMap to get a sorted output let mut map: BTreeMap<_, Vec<_>> = BTreeMap::new(); let mut inserted: FxHashMap> = FxHashMap::default(); @@ -291,7 +302,9 @@ impl<'tcx> Context<'tcx> { if inserted.entry(short).or_default().insert(myname) { let short = short.to_string(); let myname = myname.to_string(); - map.entry(short).or_default().push(myname); + map.entry(short) + .or_default() + .push(SidebarEntry { name: myname, is_deprecated: item.is_deprecated(tcx) }); } } diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 455b4e9aefe55..0ef5b8b8ecc9b 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -64,14 +64,20 @@ pub(crate) struct Link<'a> { name: Cow<'a, str>, /// The id of an anchor within the page (without a `#` prefix) href: Cow<'a, str>, + /// Whether the item is deprecated + is_deprecated: bool, } impl<'a> Link<'a> { - pub fn new(href: impl Into>, name: impl Into>) -> Self { - Self { href: href.into(), name: name.into() } + pub fn new( + href: impl Into>, + name: impl Into>, + deprecated: bool, + ) -> Self { + Self { href: href.into(), name: name.into(), is_deprecated: deprecated } } pub fn empty() -> Link<'static> { - Link::new("", "") + Link::new("", "", false) } } @@ -124,12 +130,14 @@ pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buf sidebar.render_into(buffer).unwrap(); } -fn get_struct_fields_name<'a>(fields: &'a [clean::Item]) -> Vec> { +fn get_struct_fields_name<'a>(fields: &'a [clean::Item], tcx: TyCtxt<'_>) -> Vec> { let mut fields = fields .iter() .filter(|f| matches!(*f.kind, clean::StructFieldItem(..))) .filter_map(|f| { - f.name.as_ref().map(|name| Link::new(format!("structfield.{name}"), name.as_str())) + f.name.as_ref().map(|name| { + Link::new(format!("structfield.{name}"), name.as_str(), f.is_deprecated(tcx)) + }) }) .collect::>>(); fields.sort(); @@ -141,7 +149,7 @@ fn sidebar_struct<'a>( it: &'a clean::Item, s: &'a clean::Struct, ) -> Vec> { - let fields = get_struct_fields_name(&s.fields); + let fields = get_struct_fields_name(&s.fields, cx.tcx()); let field_name = match s.ctor_kind { Some(CtorKind::Fn) => Some("Tuple Fields"), None => Some("Fields"), @@ -149,7 +157,7 @@ fn sidebar_struct<'a>( }; let mut items = vec![]; if let Some(name) = field_name { - items.push(LinkBlock::new(Link::new("fields", name), fields)); + items.push(LinkBlock::new(Link::new("fields", name, false), fields)); } sidebar_assoc_items(cx, it, &mut items); items @@ -164,11 +172,14 @@ fn sidebar_trait<'a>( items: &'a [clean::Item], filt: impl Fn(&clean::Item) -> bool, ty: &str, + tcx: TyCtxt<'_>, ) -> Vec> { let mut res = items .iter() .filter_map(|m: &clean::Item| match m.name { - Some(ref name) if filt(m) => Some(Link::new(format!("{ty}.{name}"), name.as_str())), + Some(ref name) if filt(m) => { + Some(Link::new(format!("{ty}.{name}"), name.as_str(), m.is_deprecated(tcx))) + } _ => None, }) .collect::>>(); @@ -176,23 +187,24 @@ fn sidebar_trait<'a>( res } - let req_assoc = filter_items(&t.items, |m| m.is_ty_associated_type(), "associatedtype"); - let prov_assoc = filter_items(&t.items, |m| m.is_associated_type(), "associatedtype"); + let tcx = cx.tcx(); + + let req_assoc = filter_items(&t.items, |m| m.is_ty_associated_type(), "associatedtype", tcx); + let prov_assoc = filter_items(&t.items, |m| m.is_associated_type(), "associatedtype", tcx); let req_assoc_const = - filter_items(&t.items, |m| m.is_ty_associated_const(), "associatedconstant"); + filter_items(&t.items, |m| m.is_ty_associated_const(), "associatedconstant", tcx); let prov_assoc_const = - filter_items(&t.items, |m| m.is_associated_const(), "associatedconstant"); - let req_method = filter_items(&t.items, |m| m.is_ty_method(), "tymethod"); - let prov_method = filter_items(&t.items, |m| m.is_method(), "method"); + filter_items(&t.items, |m| m.is_associated_const(), "associatedconstant", tcx); + let req_method = filter_items(&t.items, |m| m.is_ty_method(), "tymethod", tcx); + let prov_method = filter_items(&t.items, |m| m.is_method(), "method", tcx); let mut foreign_impls = vec![]; if let Some(implementors) = cx.cache().implementors.get(&it.item_id.expect_def_id()) { - foreign_impls.extend( - implementors - .iter() - .filter(|i| !i.is_on_local_type(cx)) - .filter_map(|i| super::extract_for_impl_name(&i.impl_item, cx)) - .map(|(name, id)| Link::new(id, name)), - ); + foreign_impls.extend(implementors.iter().filter(|i| !i.is_on_local_type(cx)).filter_map( + |i| { + super::extract_for_impl_name(&i.impl_item, cx) + .map(|(name, id)| Link::new(id, name, i.impl_item.is_deprecated(tcx))) + }, + )); foreign_impls.sort(); } @@ -206,12 +218,16 @@ fn sidebar_trait<'a>( ("foreign-impls", "Implementations on Foreign Types", foreign_impls), ] .into_iter() - .map(|(id, title, items)| LinkBlock::new(Link::new(id, title), items)) + .map(|(id, title, items)| LinkBlock::new(Link::new(id, title, false), items)) .collect(); sidebar_assoc_items(cx, it, &mut blocks); - blocks.push(LinkBlock::forced(Link::new("implementors", "Implementors"))); + blocks.push(LinkBlock::forced(Link::new("implementors", "Implementors", false))); if t.is_auto(cx.tcx()) { - blocks.push(LinkBlock::forced(Link::new("synthetic-implementors", "Auto Implementors"))); + blocks.push(LinkBlock::forced(Link::new( + "synthetic-implementors", + "Auto Implementors", + false, + ))); } blocks } @@ -241,8 +257,8 @@ fn sidebar_union<'a>( it: &'a clean::Item, u: &'a clean::Union, ) -> Vec> { - let fields = get_struct_fields_name(&u.fields); - let mut items = vec![LinkBlock::new(Link::new("fields", "Fields"), fields)]; + let fields = get_struct_fields_name(&u.fields, cx.tcx()); + let mut items = vec![LinkBlock::new(Link::new("fields", "Fields", false), fields)]; sidebar_assoc_items(cx, it, &mut items); items } @@ -253,6 +269,7 @@ fn sidebar_assoc_items<'a>( it: &'a clean::Item, links: &mut Vec>, ) { + let tcx = cx.tcx(); let did = it.item_id.expect_def_id(); let cache = cx.cache(); @@ -267,7 +284,7 @@ fn sidebar_assoc_items<'a>( assoc_consts.extend( v.iter() .filter(|i| i.inner_impl().trait_.is_none()) - .flat_map(|i| get_associated_constants(i.inner_impl(), used_links_bor)), + .flat_map(|i| get_associated_constants(i.inner_impl(), used_links_bor, tcx)), ); // We want links' order to be reproducible so we don't use unstable sort. assoc_consts.sort(); @@ -311,8 +328,11 @@ fn sidebar_assoc_items<'a>( }; let mut blocks = vec![ - LinkBlock::new(Link::new("implementations", "Associated Constants"), assoc_consts), - LinkBlock::new(Link::new("implementations", "Methods"), methods), + LinkBlock::new( + Link::new("implementations", "Associated Constants", false), + assoc_consts, + ), + LinkBlock::new(Link::new("implementations", "Methods", false), methods), ]; blocks.append(&mut deref_methods); blocks.extend([concrete, synthetic, blanket]); @@ -329,13 +349,16 @@ fn sidebar_deref_methods<'a>( used_links: &mut FxHashSet, ) { let c = cx.cache(); + let tcx = cx.tcx(); debug!("found Deref: {:?}", impl_); - if let Some((target, real_target)) = + if let Some((target, real_target, target_is_deprecated)) = impl_.inner_impl().items.iter().find_map(|item| match *item.kind { clean::AssocTypeItem(box ref t, _) => Some(match *t { - clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_), - _ => (&t.type_, &t.type_), + clean::Typedef { item_type: Some(ref type_), .. } => { + (type_, &t.type_, item.is_deprecated(tcx)) + } + _ => (&t.type_, &t.type_, item.is_deprecated(tcx)), }), _ => None, }) @@ -349,7 +372,7 @@ fn sidebar_deref_methods<'a>( // Avoid infinite cycles return; } - let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait()); + let deref_mut = v.iter().any(|i| i.trait_did() == tcx.lang_items().deref_mut_trait()); let inner_impl = target .def_id(c) .or_else(|| { @@ -361,7 +384,7 @@ fn sidebar_deref_methods<'a>( let mut ret = impls .iter() .filter(|i| i.inner_impl().trait_.is_none()) - .flat_map(|i| get_methods(i.inner_impl(), true, used_links, deref_mut, cx.tcx())) + .flat_map(|i| get_methods(i.inner_impl(), true, used_links, deref_mut, tcx)) .collect::>(); if !ret.is_empty() { let id = if let Some(target_def_id) = real_target.def_id(c) { @@ -381,7 +404,7 @@ fn sidebar_deref_methods<'a>( ); // We want links' order to be reproducible so we don't use unstable sort. ret.sort(); - out.push(LinkBlock::new(Link::new(id, title), ret)); + out.push(LinkBlock::new(Link::new(id, title, target_is_deprecated), ret)); } } @@ -392,7 +415,7 @@ fn sidebar_deref_methods<'a>( i.inner_impl() .trait_ .as_ref() - .map(|t| Some(t.def_id()) == cx.tcx().lang_items().deref_trait()) + .map(|t| Some(t.def_id()) == tcx.lang_items().deref_trait()) .unwrap_or(false) }) { @@ -413,14 +436,18 @@ fn sidebar_enum<'a>( it: &'a clean::Item, e: &'a clean::Enum, ) -> Vec> { + let tcx = cx.tcx(); let mut variants = e .variants() - .filter_map(|v| v.name) - .map(|name| Link::new(format!("variant.{name}"), name.to_string())) + .filter_map(|v| { + v.name.map(|name| { + Link::new(format!("variant.{name}"), name.to_string(), v.is_deprecated(tcx)) + }) + }) .collect::>(); variants.sort_unstable(); - let mut items = vec![LinkBlock::new(Link::new("variants", "Variants"), variants)]; + let mut items = vec![LinkBlock::new(Link::new("variants", "Variants", false), variants)]; sidebar_assoc_items(cx, it, &mut items); items } @@ -432,7 +459,7 @@ pub(crate) fn sidebar_module_like( .iter() .copied() .filter(|sec| item_sections_in_use.contains(sec)) - .map(|sec| Link::new(sec.id(), sec.name())) + .map(|sec| Link::new(sec.id(), sec.name(), false)) .collect(); LinkBlock::new(Link::empty(), item_sections) } @@ -470,6 +497,7 @@ fn sidebar_render_assoc_items( synthetic: Vec<&Impl>, blanket_impl: Vec<&Impl>, ) -> [LinkBlock<'static>; 3] { + let tcx = cx.tcx(); let format_impls = |impls: Vec<&Impl>, id_map: &mut IdMap| { let mut links = FxHashSet::default(); @@ -484,7 +512,11 @@ fn sidebar_render_assoc_items( ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "", ty::ImplPolarity::Negative => "!", }; - let generated = Link::new(encoded, format!("{prefix}{:#}", trait_.print(cx))); + let generated = Link::new( + encoded, + format!("{prefix}{:#}", trait_.print(cx)), + it.impl_item.is_deprecated(tcx), + ); if links.insert(generated.clone()) { Some(generated) } else { None } }) .collect::>>(); @@ -496,12 +528,18 @@ fn sidebar_render_assoc_items( let synthetic = format_impls(synthetic, id_map); let blanket = format_impls(blanket_impl, id_map); [ - LinkBlock::new(Link::new("trait-implementations", "Trait Implementations"), concrete), LinkBlock::new( - Link::new("synthetic-implementations", "Auto Trait Implementations"), + Link::new("trait-implementations", "Trait Implementations", false), + concrete, + ), + LinkBlock::new( + Link::new("synthetic-implementations", "Auto Trait Implementations", false), synthetic, ), - LinkBlock::new(Link::new("blanket-implementations", "Blanket Implementations"), blanket), + LinkBlock::new( + Link::new("blanket-implementations", "Blanket Implementations", false), + blanket, + ), ] } @@ -531,6 +569,7 @@ fn get_methods<'a>( Some(Link::new( get_next_url(used_links, format!("{}.{}", ItemType::Method, name)), name.as_str(), + item.is_deprecated(tcx), )) } else { None @@ -544,6 +583,7 @@ fn get_methods<'a>( fn get_associated_constants<'a>( i: &'a clean::Impl, used_links: &mut FxHashSet, + tcx: TyCtxt<'_>, ) -> Vec> { i.items .iter() @@ -551,6 +591,7 @@ fn get_associated_constants<'a>( Some(ref name) if !name.is_empty() && item.is_associated_const() => Some(Link::new( get_next_url(used_links, format!("{}.{}", ItemType::AssocConst, name)), name.as_str(), + item.is_deprecated(tcx), )), _ => None, }) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 254b0d8bf5a43..ccc9f5b29a295 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -466,7 +466,8 @@ function preLoadCss(cssUrl) { const ul = document.createElement("ul"); ul.className = "block " + shortty; - for (const name of filtered) { + for (const entry of filtered) { + const name = entry.name; let path; if (shortty === "mod") { path = name + "/index.html"; @@ -479,7 +480,13 @@ function preLoadCss(cssUrl) { if (path === current_page) { link.className = "current"; } - link.textContent = name; + if (entry.is_deprecated) { + const s = document.createElement("s"); + s.textContent = name; + link.appendChild(s); + } else { + link.textContent = name; + } const li = document.createElement("li"); li.appendChild(link); ul.appendChild(li); diff --git a/src/librustdoc/html/templates/sidebar.html b/src/librustdoc/html/templates/sidebar.html index 01d476ad29f2f..5c3eacd936d7d 100644 --- a/src/librustdoc/html/templates/sidebar.html +++ b/src/librustdoc/html/templates/sidebar.html @@ -23,7 +23,13 @@

{{block.heading.name}}

{% if !block.links.is_empty() %} {% endif %}