Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustdoc: Strikethrough deprecated items in sidebar #113082

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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()
Expand Down
17 changes: 15 additions & 2 deletions src/librustdoc/html/render/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<String, Vec<String>> {
fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<SidebarEntry>> {
let tcx = self.tcx();

// BTreeMap instead of HashMap to get a sorted output
let mut map: BTreeMap<_, Vec<_>> = BTreeMap::new();
let mut inserted: FxHashMap<ItemType, FxHashSet<Symbol>> = FxHashMap::default();
Expand All @@ -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) });
}
}

Expand Down
129 changes: 85 additions & 44 deletions src/librustdoc/html/render/sidebar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Cow<'a, str>>, name: impl Into<Cow<'a, str>>) -> Self {
Self { href: href.into(), name: name.into() }
pub fn new(
href: impl Into<Cow<'a, str>>,
name: impl Into<Cow<'a, str>>,
deprecated: bool,
) -> Self {
Self { href: href.into(), name: name.into(), is_deprecated: deprecated }
}
pub fn empty() -> Link<'static> {
Link::new("", "")
Link::new("", "", false)
}
}

Expand Down Expand Up @@ -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<Link<'a>> {
fn get_struct_fields_name<'a>(fields: &'a [clean::Item], tcx: TyCtxt<'_>) -> Vec<Link<'a>> {
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::<Vec<Link<'a>>>();
fields.sort();
Expand All @@ -141,15 +149,15 @@ fn sidebar_struct<'a>(
it: &'a clean::Item,
s: &'a clean::Struct,
) -> Vec<LinkBlock<'a>> {
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"),
_ => None,
};
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
Expand All @@ -164,35 +172,39 @@ fn sidebar_trait<'a>(
items: &'a [clean::Item],
filt: impl Fn(&clean::Item) -> bool,
ty: &str,
tcx: TyCtxt<'_>,
) -> Vec<Link<'a>> {
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::<Vec<Link<'a>>>();
res.sort();
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();
}

Expand All @@ -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
}
Expand Down Expand Up @@ -241,8 +257,8 @@ fn sidebar_union<'a>(
it: &'a clean::Item,
u: &'a clean::Union,
) -> Vec<LinkBlock<'a>> {
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
}
Expand All @@ -253,6 +269,7 @@ fn sidebar_assoc_items<'a>(
it: &'a clean::Item,
links: &mut Vec<LinkBlock<'a>>,
) {
let tcx = cx.tcx();
let did = it.item_id.expect_def_id();
let cache = cx.cache();

Expand All @@ -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();
Expand Down Expand Up @@ -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]);
Expand All @@ -329,13 +349,16 @@ fn sidebar_deref_methods<'a>(
used_links: &mut FxHashSet<String>,
) {
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,
})
Expand All @@ -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(|| {
Expand All @@ -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::<Vec<_>>();
if !ret.is_empty() {
let id = if let Some(target_def_id) = real_target.def_id(c) {
Expand All @@ -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));
}
}

Expand All @@ -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)
})
{
Expand All @@ -413,14 +436,18 @@ fn sidebar_enum<'a>(
it: &'a clean::Item,
e: &'a clean::Enum,
) -> Vec<LinkBlock<'a>> {
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::<Vec<_>>();
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
}
Expand All @@ -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)
}
Expand Down Expand Up @@ -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();

Expand All @@ -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::<Vec<Link<'static>>>();
Expand All @@ -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,
),
]
}

Expand Down Expand Up @@ -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
Expand All @@ -544,13 +583,15 @@ fn get_methods<'a>(
fn get_associated_constants<'a>(
i: &'a clean::Impl,
used_links: &mut FxHashSet<String>,
tcx: TyCtxt<'_>,
) -> Vec<Link<'a>> {
i.items
.iter()
.filter_map(|item| match item.name {
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,
})
Expand Down
Loading