Skip to content
Merged
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,7 +7,6 @@
//! 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};
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(mut generics) = ty.generics()
&& let (Some(inner_type), None) = (generics.next(), generics.next())
{
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 @@ -1201,12 +1197,11 @@ impl clean::Impl {
fmt_type(&bare_fn.decl.output, f, use_absolute, cx)?;
}
} else if let clean::Type::Path { path } = type_
&& let Some(generics) = path.generics()
&& generics.len() == 1
&& let Some(mut generics) = path.generics()
&& let (Some(ty), None) = (generics.next(), generics.next())
&& 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