Skip to content

rustdoc: cleanups relating to allocations #141573

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

Merged
merged 10 commits into from
May 30, 2025
Merged
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
22 changes: 8 additions & 14 deletions src/librustdoc/clean/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ impl From<DefId> for ItemId {
}

/// The crate currently being documented.
#[derive(Clone, Debug)]
#[derive(Debug)]
pub(crate) struct Crate {
pub(crate) module: Item,
/// Only here so that they can be filtered through the rustdoc passes.
Expand Down Expand Up @@ -1601,9 +1601,7 @@ impl Type {
a.def_id() == b.def_id()
&& a.generics()
.zip(b.generics())
.map(|(ag, bg)| {
ag.iter().zip(bg.iter()).all(|(at, bt)| at.is_doc_subtype_of(bt, cache))
})
.map(|(ag, bg)| ag.zip(bg).all(|(at, bt)| at.is_doc_subtype_of(bt, cache)))
.unwrap_or(true)
}
// Other cases, such as primitives, just use recursion.
Expand Down Expand Up @@ -1676,7 +1674,7 @@ impl Type {
}
}

pub(crate) fn generics(&self) -> Option<Vec<&Type>> {
pub(crate) fn generics<'a>(&'a self) -> Option<impl Iterator<Item = &'a Type>> {
match self {
Type::Path { path, .. } => path.generics(),
_ => None,
Expand Down Expand Up @@ -2234,17 +2232,13 @@ impl Path {
self.segments.last().map(|seg| &seg.args)
}

pub(crate) fn generics(&self) -> Option<Vec<&Type>> {
pub(crate) fn generics<'a>(&'a self) -> Option<impl Iterator<Item = &'a Type>> {
self.segments.last().and_then(|seg| {
if let GenericArgs::AngleBracketed { ref args, .. } = seg.args {
Some(
args.iter()
.filter_map(|arg| match arg {
GenericArg::Type(ty) => Some(ty),
_ => None,
})
.collect(),
)
Some(args.iter().filter_map(|arg| match arg {
GenericArg::Type(ty) => Some(ty),
_ => None,
}))
} else {
None
}
Expand Down
142 changes: 67 additions & 75 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@
//! some of them support an alternate format that emits text, but that should
//! not be used external to this module.

use std::borrow::Cow;
use std::cmp::Ordering;
use std::fmt::{self, Display, Write};
use std::iter::{self, once};
use std::slice;

use itertools::Either;
use itertools::{Either, Itertools};
use rustc_abi::ExternAbi;
use rustc_attr_data_structures::{ConstStability, StabilityLevel, StableSince};
use rustc_data_structures::fx::FxHashSet;
Expand Down Expand Up @@ -483,12 +482,12 @@ fn generate_item_def_id_path(
let mut is_remote = false;

let url_parts = url_parts(cx.cache(), def_id, module_fqp, &cx.current, &mut is_remote)?;
let (url_parts, shortty, fqp) = make_href(root_path, shortty, url_parts, &fqp, is_remote)?;
if def_id == original_def_id {
return Ok((url_parts, shortty, fqp));
}
let kind = ItemType::from_def_kind(original_def_kind, Some(def_kind));
Ok((format!("{url_parts}#{kind}.{}", tcx.item_name(original_def_id)), shortty, fqp))
let mut url_parts = make_href(root_path, shortty, url_parts, &fqp, is_remote);
if def_id != original_def_id {
let kind = ItemType::from_def_kind(original_def_kind, Some(def_kind));
url_parts = format!("{url_parts}#{kind}.{}", tcx.item_name(original_def_id))
};
Ok((url_parts, shortty, fqp))
}

fn to_module_fqp(shortty: ItemType, fqp: &[Symbol]) -> &[Symbol] {
Expand All @@ -510,7 +509,7 @@ fn url_parts(
builder.extend(module_fqp.iter().copied());
Ok(builder)
}
ExternalLocation::Local => Ok(href_relative_parts(module_fqp, relative_to).collect()),
ExternalLocation::Local => Ok(href_relative_parts(module_fqp, relative_to)),
ExternalLocation::Unknown => Err(HrefError::DocumentationNotBuilt),
}
}
Expand All @@ -521,7 +520,7 @@ fn make_href(
mut url_parts: UrlPartsBuilder,
fqp: &[Symbol],
is_remote: bool,
) -> Result<(String, ItemType, Vec<Symbol>), HrefError> {
) -> String {
if !is_remote && let Some(root_path) = root_path {
let root = root_path.trim_end_matches('/');
url_parts.push_front(root);
Expand All @@ -536,7 +535,7 @@ fn make_href(
url_parts.push_fmt(format_args!("{shortty}.{last}.html"));
}
}
Ok((url_parts.finish(), shortty, fqp.to_vec()))
url_parts.finish()
}

pub(crate) fn href_with_root_path(
Expand Down Expand Up @@ -587,7 +586,7 @@ pub(crate) fn href_with_root_path(
Some(&(ref fqp, shortty)) => (fqp, shortty, {
let module_fqp = to_module_fqp(shortty, fqp.as_slice());
debug!(?fqp, ?shortty, ?module_fqp);
href_relative_parts(module_fqp, relative_to).collect()
href_relative_parts(module_fqp, relative_to)
}),
None => {
// Associated items are handled differently with "jump to def". The anchor is generated
Expand All @@ -606,7 +605,8 @@ pub(crate) fn href_with_root_path(
}
}
};
make_href(root_path, shortty, url_parts, fqp, is_remote)
let url_parts = make_href(root_path, shortty, url_parts, &fqp, is_remote);
Ok((url_parts, shortty, fqp.clone()))
}

pub(crate) fn href(
Expand All @@ -619,34 +619,30 @@ pub(crate) fn href(
/// Both paths should only be modules.
/// This is because modules get their own directories; that is, `std::vec` and `std::vec::Vec` will
/// both need `../iter/trait.Iterator.html` to get at the iterator trait.
pub(crate) fn href_relative_parts<'fqp>(
fqp: &'fqp [Symbol],
relative_to_fqp: &[Symbol],
) -> Box<dyn Iterator<Item = Symbol> + 'fqp> {
pub(crate) fn href_relative_parts(fqp: &[Symbol], relative_to_fqp: &[Symbol]) -> UrlPartsBuilder {
for (i, (f, r)) in fqp.iter().zip(relative_to_fqp.iter()).enumerate() {
// e.g. linking to std::iter from std::vec (`dissimilar_part_count` will be 1)
if f != r {
let dissimilar_part_count = relative_to_fqp.len() - i;
let fqp_module = &fqp[i..];
return Box::new(
iter::repeat_n(sym::dotdot, dissimilar_part_count)
.chain(fqp_module.iter().copied()),
);
return iter::repeat_n(sym::dotdot, dissimilar_part_count)
.chain(fqp_module.iter().copied())
.collect();
}
}
match relative_to_fqp.len().cmp(&fqp.len()) {
Ordering::Less => {
// e.g. linking to std::sync::atomic from std::sync
Box::new(fqp[relative_to_fqp.len()..fqp.len()].iter().copied())
fqp[relative_to_fqp.len()..fqp.len()].iter().copied().collect()
}
Ordering::Greater => {
// e.g. linking to std::sync from std::sync::atomic
let dissimilar_part_count = relative_to_fqp.len() - fqp.len();
Box::new(iter::repeat_n(sym::dotdot, dissimilar_part_count))
iter::repeat_n(sym::dotdot, dissimilar_part_count).collect()
}
Ordering::Equal => {
// linking to the same module
Box::new(iter::empty())
UrlPartsBuilder::new()
}
}
}
Expand Down Expand Up @@ -708,13 +704,13 @@ fn resolved_path(
f,
"{path}::{anchor}",
path = join_with_double_colon(&fqp[..fqp.len() - 1]),
anchor = anchor(did, *fqp.last().unwrap(), cx)
anchor = print_anchor(did, *fqp.last().unwrap(), cx)
)
} else {
write!(f, "{}", last.name)
}
} else {
write!(f, "{}", anchor(did, last.name, cx))
write!(f, "{}", print_anchor(did, last.name, cx))
}
});
write!(w, "{path}{args}", args = last.args.print(cx))?;
Expand Down Expand Up @@ -800,7 +796,7 @@ fn primitive_link_fragment(
Ok(())
}

fn tybounds(
fn print_tybounds(
bounds: &[clean::PolyTrait],
lt: &Option<clean::Lifetime>,
cx: &Context<'_>,
Expand Down Expand Up @@ -832,7 +828,7 @@ fn print_higher_ranked_params_with_space(
})
}

pub(crate) fn anchor(did: DefId, text: Symbol, cx: &Context<'_>) -> impl Display {
pub(crate) fn print_anchor(did: DefId, text: Symbol, cx: &Context<'_>) -> impl Display {
fmt::from_fn(move |f| {
let parts = href(did, cx);
if let Ok((url, short_ty, fqp)) = parts {
Expand Down Expand Up @@ -866,7 +862,7 @@ fn fmt_type(
}
clean::DynTrait(bounds, lt) => {
f.write_str("dyn ")?;
tybounds(bounds, lt, cx).fmt(f)
print_tybounds(bounds, lt, cx).fmt(f)
}
clean::Infer => write!(f, "_"),
clean::Primitive(clean::PrimitiveType::Never) => {
Expand Down Expand Up @@ -1122,16 +1118,16 @@ impl clean::Impl {
write!(f, "!")?;
}
if self.kind.is_fake_variadic()
&& let generics = ty.generics()
&& let &[inner_type] = generics.as_ref().map_or(&[][..], |v| &v[..])
&& let Some(generics) = ty.generics()
&& let Ok(inner_type) = generics.exactly_one()
{
let last = ty.last();
if f.alternate() {
write!(f, "{}<", last)?;
self.print_type(inner_type, f, use_absolute, cx)?;
write!(f, ">")?;
} else {
write!(f, "{}&lt;", anchor(ty.def_id(), last, cx))?;
write!(f, "{}&lt;", print_anchor(ty.def_id(), last, cx))?;
self.print_type(inner_type, f, use_absolute, cx)?;
write!(f, "&gt;")?;
}
Expand Down Expand Up @@ -1202,11 +1198,10 @@ impl clean::Impl {
}
} else if let clean::Type::Path { path } = type_
&& let Some(generics) = path.generics()
&& generics.len() == 1
&& let Ok(ty) = generics.exactly_one()
&& self.kind.is_fake_variadic()
{
let ty = generics[0];
let wrapper = anchor(path.def_id(), path.last(), cx);
let wrapper = print_anchor(path.def_id(), path.last(), cx);
if f.alternate() {
write!(f, "{wrapper:#}&lt;")?;
} else {
Expand Down Expand Up @@ -1394,50 +1389,47 @@ impl clean::FnDecl {
}

pub(crate) fn visibility_print_with_space(item: &clean::Item, cx: &Context<'_>) -> impl Display {
use std::fmt::Write as _;
let vis: Cow<'static, str> = match item.visibility(cx.tcx()) {
None => "".into(),
Some(ty::Visibility::Public) => "pub ".into(),
Some(ty::Visibility::Restricted(vis_did)) => {
// FIXME(camelid): This may not work correctly if `item_did` is a module.
// However, rustdoc currently never displays a module's
// visibility, so it shouldn't matter.
let parent_module = find_nearest_parent_module(cx.tcx(), item.item_id.expect_def_id());

if vis_did.is_crate_root() {
"pub(crate) ".into()
} else if parent_module == Some(vis_did) {
// `pub(in foo)` where `foo` is the parent module
// is the same as no visibility modifier
"".into()
} else if parent_module.and_then(|parent| find_nearest_parent_module(cx.tcx(), parent))
== Some(vis_did)
{
"pub(super) ".into()
} else {
let path = cx.tcx().def_path(vis_did);
debug!("path={path:?}");
// modified from `resolved_path()` to work with `DefPathData`
let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
let anchor = anchor(vis_did, last_name, cx);

let mut s = "pub(in ".to_owned();
for seg in &path.data[..path.data.len() - 1] {
let _ = write!(s, "{}::", seg.data.get_opt_name().unwrap());
}
let _ = write!(s, "{anchor}) ");
s.into()
}
}
};

let is_doc_hidden = item.is_doc_hidden();
fmt::from_fn(move |f| {
if is_doc_hidden {
if item.is_doc_hidden() {
f.write_str("#[doc(hidden)] ")?;
}

f.write_str(&vis)
match item.visibility(cx.tcx()) {
None => {}
Some(ty::Visibility::Public) => f.write_str("pub ")?,
Some(ty::Visibility::Restricted(vis_did)) => {
// FIXME(camelid): This may not work correctly if `item_did` is a module.
// However, rustdoc currently never displays a module's
// visibility, so it shouldn't matter.
let parent_module =
find_nearest_parent_module(cx.tcx(), item.item_id.expect_def_id());

if vis_did.is_crate_root() {
f.write_str("pub(crate) ")?;
} else if parent_module == Some(vis_did) {
// `pub(in foo)` where `foo` is the parent module
// is the same as no visibility modifier; do nothing
} else if parent_module
.and_then(|parent| find_nearest_parent_module(cx.tcx(), parent))
== Some(vis_did)
{
f.write_str("pub(super) ")?;
} else {
let path = cx.tcx().def_path(vis_did);
debug!("path={path:?}");
// modified from `resolved_path()` to work with `DefPathData`
let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
let anchor = print_anchor(vis_did, last_name, cx);

f.write_str("pub(in ")?;
for seg in &path.data[..path.data.len() - 1] {
write!(f, "{}::", seg.data.get_opt_name().unwrap())?;
}
write!(f, "{anchor}) ")?;
}
}
}
Ok(())
})
}

Expand Down
1 change: 0 additions & 1 deletion src/librustdoc/html/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use super::static_files::{STATIC_FILES, StaticFiles};
use crate::externalfiles::ExternalHtml;
use crate::html::render::{StylePath, ensure_trailing_slash};

#[derive(Clone)]
pub(crate) struct Layout {
pub(crate) logo: String,
pub(crate) favicon: String,
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ fn slugify(c: char) -> Option<char> {
}
}

#[derive(Clone, Debug)]
#[derive(Debug)]
pub struct Playground {
pub crate_name: Option<Symbol>,
pub url: String,
Expand Down
8 changes: 4 additions & 4 deletions src/librustdoc/html/render/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use rustc_span::edition::Edition;
use rustc_span::{FileName, Symbol, sym};
use tracing::info;

use super::print_item::{full_path, item_path, print_item};
use super::print_item::{full_path, print_item, print_item_path};
use super::sidebar::{ModuleLike, Sidebar, print_sidebar, sidebar_module_like};
use super::{AllTypes, LinkFromSrc, StylePath, collect_spans_and_sources, scrape_examples_help};
use crate::clean::types::ExternalLocation;
Expand Down Expand Up @@ -266,7 +266,7 @@ impl<'tcx> Context<'tcx> {
for name in &names[..names.len() - 1] {
write!(f, "{name}/")?;
}
write!(f, "{}", item_path(ty, names.last().unwrap().as_str()))
write!(f, "{}", print_item_path(ty, names.last().unwrap().as_str()))
});
match self.shared.redirections {
Some(ref redirections) => {
Expand All @@ -278,7 +278,7 @@ impl<'tcx> Context<'tcx> {
let _ = write!(
current_path,
"{}",
item_path(ty, names.last().unwrap().as_str())
print_item_path(ty, names.last().unwrap().as_str())
);
redirections.borrow_mut().insert(current_path, path.to_string());
}
Expand Down Expand Up @@ -847,7 +847,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
if !buf.is_empty() {
let name = item.name.as_ref().unwrap();
let item_type = item.type_();
let file_name = item_path(item_type, name.as_str()).to_string();
let file_name = print_item_path(item_type, name.as_str()).to_string();
self.shared.ensure_dir(&self.dst)?;
let joint_dst = self.dst.join(&file_name);
self.shared.fs.write(joint_dst, buf)?;
Expand Down
Loading
Loading