rustdoc: use more precise relative URLS

Instead of using a depth counter and adding "../" to get to the top,
this commit makes rustdoc actually compare the path of what it's
linking from to the path that it's linking to. This makes the resulting
HTML shorter.

Here's a comparison of one of the largest (non-source) files in the
Rust standard library docs (about 4% improvement before gzipping).

    $ wc -c struct.Wrapping.old.html struct.Wrapping.new.html
    2387389 struct.Wrapping.old.html
    2298538 struct.Wrapping.new.html

Most if it can be efficiently gzipped away.

    $ wc -c struct.Wrapping.old.html.gz struct.Wrapping.new.html.gz
    70679 struct.Wrapping.old.html.gz
    70050 struct.Wrapping.new.html.gz

But it also makes a difference in the final DOM size, reducing it from 91MiB to 82MiB.
This commit is contained in:
Michael Howell
2021-03-17 11:41:01 -07:00
parent 03301ef1d8
commit 6516f9408e
47 changed files with 613 additions and 577 deletions

View File

@@ -2284,6 +2284,13 @@ impl Clean<Item> for (&hir::MacroDef<'_>, Option<Symbol>) {
let vis = item.vis.clean(cx); let vis = item.vis.clean(cx);
let def_id = item.def_id.to_def_id(); let def_id = item.def_id.to_def_id();
// Since this occurs in `clean()`, there are no cache entries for vis.print_with_space,
// so no links can be made.
//
// It's important that we maintain this invariant, because this is supposed to generate
// source code, not HTML.
assert!(cx.cache.paths.is_empty());
if matchers.len() <= 1 { if matchers.len() <= 1 {
format!( format!(
"{}macro {}{} {{\n ...\n}}", "{}macro {}{} {{\n ...\n}}",

View File

@@ -41,6 +41,7 @@ use crate::core::DocContext;
use crate::formats::cache::Cache; use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType; use crate::formats::item_type::ItemType;
use crate::html::render::cache::ExternalLocation; use crate::html::render::cache::ExternalLocation;
use crate::html::render::Context;
use self::FnRetTy::*; use self::FnRetTy::*;
use self::ItemKind::*; use self::ItemKind::*;
@@ -193,19 +194,18 @@ impl Item {
self.attrs.collapsed_doc_value() self.attrs.collapsed_doc_value()
} }
crate fn links(&self, cache: &Cache) -> Vec<RenderedLink> { crate fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
use crate::html::format::href; use crate::html::format::href;
use crate::html::render::CURRENT_DEPTH;
cache cx.cache()
.intra_doc_links .intra_doc_links
.get(&self.def_id) .get(&self.def_id)
.map_or(&[][..], |v| v.as_slice()) .map_or(&[][..], |v| v.as_slice())
.iter() .iter()
.filter_map(|ItemLink { link: s, link_text, did, fragment }| { .filter_map(|ItemLink { link: s, link_text, did, ref fragment }| {
match *did { match *did {
Some(did) => { Some(did) => {
if let Some((mut href, ..)) = href(did, cache) { if let Some((mut href, ..)) = href(did, cx) {
if let Some(ref fragment) = *fragment { if let Some(ref fragment) = *fragment {
href.push('#'); href.push('#');
href.push_str(fragment); href.push_str(fragment);
@@ -219,16 +219,26 @@ impl Item {
None None
} }
} }
// FIXME(83083): using fragments as a side-channel for
// primitive names is very unfortunate
None => { None => {
let relative_to = &cx.current;
if let Some(ref fragment) = *fragment { if let Some(ref fragment) = *fragment {
let url = match cache.extern_locations.get(&self.def_id.krate) { let url = match cx.cache().extern_locations.get(&self.def_id.krate) {
Some(&(_, _, ExternalLocation::Local)) => { Some(&(_, _, ExternalLocation::Local)) => {
let depth = CURRENT_DEPTH.with(|l| l.get()); if relative_to[0] == "std" {
let depth = relative_to.len() - 1;
"../".repeat(depth) "../".repeat(depth)
} else {
let depth = relative_to.len();
format!("{}std/", "../".repeat(depth))
}
}
Some(&(_, _, ExternalLocation::Remote(ref s))) => {
format!("{}/std/", s.trim_end_matches('/'))
} }
Some(&(_, _, ExternalLocation::Remote(ref s))) => s.to_string(),
Some(&(_, _, ExternalLocation::Unknown)) | None => format!( Some(&(_, _, ExternalLocation::Unknown)) | None => format!(
"https://doc.rust-lang.org/{}", "https://doc.rust-lang.org/{}/std/",
crate::doc_rust_lang_org_channel(), crate::doc_rust_lang_org_channel(),
), ),
}; };
@@ -238,9 +248,8 @@ impl Item {
original_text: s.clone(), original_text: s.clone(),
new_text: link_text.clone(), new_text: link_text.clone(),
href: format!( href: format!(
"{}{}std/primitive.{}.html{}", "{}primitive.{}.html{}",
url, url,
if !url.ends_with('/') { "/" } else { "" },
&fragment[..tail], &fragment[..tail],
&fragment[tail..] &fragment[tail..]
), ),

File diff suppressed because it is too large Load Diff

View File

@@ -8,3 +8,6 @@ crate mod render;
crate mod sources; crate mod sources;
crate mod static_files; crate mod static_files;
crate mod toc; crate mod toc;
#[cfg(test)]
mod tests;

View File

@@ -40,7 +40,7 @@ use crate::html::{layout, sources};
crate struct Context<'tcx> { crate struct Context<'tcx> {
/// Current hierarchy of components leading down to what's currently being /// Current hierarchy of components leading down to what's currently being
/// rendered /// rendered
pub(super) current: Vec<String>, pub(crate) current: Vec<String>,
/// The current destination folder of where HTML artifacts should be placed. /// The current destination folder of where HTML artifacts should be placed.
/// This changes as the context descends into the module hierarchy. /// This changes as the context descends into the module hierarchy.
pub(super) dst: PathBuf, pub(super) dst: PathBuf,
@@ -144,10 +144,14 @@ impl SharedContext<'_> {
} }
impl<'tcx> Context<'tcx> { impl<'tcx> Context<'tcx> {
pub(super) fn tcx(&self) -> TyCtxt<'tcx> { pub(crate) fn tcx(&self) -> TyCtxt<'tcx> {
self.shared.tcx self.shared.tcx
} }
pub(crate) fn cache(&self) -> &Cache {
&self.cache
}
fn sess(&self) -> &'tcx Session { fn sess(&self) -> &'tcx Session {
&self.shared.tcx.sess &self.shared.tcx.sess
} }

View File

@@ -51,7 +51,6 @@ use rustc_hir::def::CtorKind;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::Mutability; use rustc_hir::Mutability;
use rustc_middle::middle::stability; use rustc_middle::middle::stability;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::symbol::{kw, sym, Symbol};
use serde::ser::SerializeSeq; use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer}; use serde::{Serialize, Serializer};
@@ -61,7 +60,7 @@ use crate::docfs::PathError;
use crate::error::Error; use crate::error::Error;
use crate::formats::cache::Cache; use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType; use crate::formats::item_type::ItemType;
use crate::formats::{AssocItemRender, FormatRenderer, Impl, RenderMode}; use crate::formats::{AssocItemRender, Impl, RenderMode};
use crate::html::escape::Escape; use crate::html::escape::Escape;
use crate::html::format::{ use crate::html::format::{
href, print_abi_with_space, print_default_space, print_generic_bounds, print_where_clause, href, print_abi_with_space, print_default_space, print_generic_bounds, print_where_clause,
@@ -560,11 +559,10 @@ fn document_short(
return; return;
} }
if let Some(s) = item.doc_value() { if let Some(s) = item.doc_value() {
let mut summary_html = MarkdownSummaryLine(&s, &item.links(&cx.cache)).into_string(); let mut summary_html = MarkdownSummaryLine(&s, &item.links(cx)).into_string();
if s.contains('\n') { if s.contains('\n') {
let link = let link = format!(r#" <a href="{}">Read more</a>"#, naive_assoc_href(item, link, cx));
format!(r#" <a href="{}">Read more</a>"#, naive_assoc_href(item, link, cx.cache()));
if let Some(idx) = summary_html.rfind("</p>") { if let Some(idx) = summary_html.rfind("</p>") {
summary_html.insert_str(idx, &link); summary_html.insert_str(idx, &link);
@@ -599,7 +597,7 @@ fn document_full(
) { ) {
if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) { if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) {
debug!("Doc block: =====\n{}\n=====", s); debug!("Doc block: =====\n{}\n=====", s);
render_markdown(w, cx, &*s, item.links(&cx.cache), prefix, is_hidden); render_markdown(w, cx, &*s, item.links(cx), prefix, is_hidden);
} else if !prefix.is_empty() { } else if !prefix.is_empty() {
if is_hidden { if is_hidden {
w.write_str("<div class=\"docblock hidden\">"); w.write_str("<div class=\"docblock hidden\">");
@@ -785,7 +783,7 @@ fn render_impls(
w.write_str(&impls.join("")); w.write_str(&impls.join(""));
} }
fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cache: &Cache) -> String { fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String {
use crate::formats::item_type::ItemType::*; use crate::formats::item_type::ItemType::*;
let name = it.name.as_ref().unwrap(); let name = it.name.as_ref().unwrap();
@@ -799,7 +797,7 @@ fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cache: &Cache) ->
AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id), AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
AssocItemLink::Anchor(None) => anchor, AssocItemLink::Anchor(None) => anchor,
AssocItemLink::GotoSource(did, _) => { AssocItemLink::GotoSource(did, _) => {
href(did, cache).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor) href(did, cx).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
} }
} }
} }
@@ -813,16 +811,14 @@ fn assoc_const(
extra: &str, extra: &str,
cx: &Context<'_>, cx: &Context<'_>,
) { ) {
let cache = cx.cache();
let tcx = cx.tcx();
write!( write!(
w, w,
"{}{}const <a href=\"{}\" class=\"constant\"><b>{}</b></a>: {}", "{}{}const <a href=\"{}\" class=\"constant\"><b>{}</b></a>: {}",
extra, extra,
it.visibility.print_with_space(tcx, it.def_id, cache), it.visibility.print_with_space(cx, it.def_id),
naive_assoc_href(it, link, cache), naive_assoc_href(it, link, cx),
it.name.as_ref().unwrap(), it.name.as_ref().unwrap(),
ty.print(cache, tcx) ty.print(cx)
); );
} }
@@ -833,21 +829,20 @@ fn assoc_type(
default: Option<&clean::Type>, default: Option<&clean::Type>,
link: AssocItemLink<'_>, link: AssocItemLink<'_>,
extra: &str, extra: &str,
cache: &Cache, cx: &Context<'_>,
tcx: TyCtxt<'_>,
) { ) {
write!( write!(
w, w,
"{}type <a href=\"{}\" class=\"type\">{}</a>", "{}type <a href=\"{}\" class=\"type\">{}</a>",
extra, extra,
naive_assoc_href(it, link, cache), naive_assoc_href(it, link, cx),
it.name.as_ref().unwrap() it.name.as_ref().unwrap()
); );
if !bounds.is_empty() { if !bounds.is_empty() {
write!(w, ": {}", print_generic_bounds(bounds, cache, tcx)) write!(w, ": {}", print_generic_bounds(cx, bounds))
} }
if let Some(default) = default { if let Some(default) = default {
write!(w, " = {}", default.print(cache, tcx)) write!(w, " = {}", default.print(cx))
} }
} }
@@ -897,8 +892,6 @@ fn render_assoc_item(
parent: ItemType, parent: ItemType,
cx: &Context<'_>, cx: &Context<'_>,
) { ) {
let cache = cx.cache();
let tcx = cx.tcx();
let name = meth.name.as_ref().unwrap(); let name = meth.name.as_ref().unwrap();
let href = match link { let href = match link {
AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id), AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
@@ -912,19 +905,19 @@ fn render_assoc_item(
ItemType::TyMethod ItemType::TyMethod
}; };
href(did, cache) href(did, cx)
.map(|p| format!("{}#{}.{}", p.0, ty, name)) .map(|p| format!("{}#{}.{}", p.0, ty, name))
.unwrap_or_else(|| format!("#{}.{}", ty, name)) .unwrap_or_else(|| format!("#{}.{}", ty, name))
} }
}; };
let vis = meth.visibility.print_with_space(tcx, meth.def_id, cache).to_string(); let vis = meth.visibility.print_with_space(cx, meth.def_id).to_string();
let constness = header.constness.print_with_space(); let constness = header.constness.print_with_space();
let asyncness = header.asyncness.print_with_space(); let asyncness = header.asyncness.print_with_space();
let unsafety = header.unsafety.print_with_space(); let unsafety = header.unsafety.print_with_space();
let defaultness = print_default_space(meth.is_default()); let defaultness = print_default_space(meth.is_default());
let abi = print_abi_with_space(header.abi).to_string(); let abi = print_abi_with_space(header.abi).to_string();
// NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`. // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
let generics_len = format!("{:#}", g.print(cache, tcx)).len(); let generics_len = format!("{:#}", g.print(cx)).len();
let mut header_len = "fn ".len() let mut header_len = "fn ".len()
+ vis.len() + vis.len()
+ constness.len() + constness.len()
@@ -958,10 +951,10 @@ fn render_assoc_item(
abi, abi,
href = href, href = href,
name = name, name = name,
generics = g.print(cache, tcx), generics = g.print(cx),
decl = d.full_print(cache, tcx, header_len, indent, header.asyncness), decl = d.full_print(cx, header_len, indent, header.asyncness),
notable_traits = notable_traits_decl(&d, cache, tcx), notable_traits = notable_traits_decl(&d, cx),
where_clause = print_where_clause(g, cache, tcx, indent, end_newline), where_clause = print_where_clause(g, cx, indent, end_newline),
) )
} }
match *item.kind { match *item.kind {
@@ -988,8 +981,7 @@ fn render_assoc_item(
default.as_ref(), default.as_ref(),
link, link,
if parent == ItemType::Trait { " " } else { "" }, if parent == ItemType::Trait { " " } else { "" },
cx.cache(), cx,
cx.tcx(),
), ),
_ => panic!("render_assoc_item called on non-associated-item"), _ => panic!("render_assoc_item called on non-associated-item"),
} }
@@ -1076,11 +1068,9 @@ fn render_assoc_items(
RenderMode::Normal RenderMode::Normal
} }
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
let id = cx.derive_id(small_url_encode(format!( let id =
"deref-methods-{:#}", cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
type_.print(cache, tcx) debug!("Adding {} to deref id map", type_.print(cx));
)));
debug!("Adding {} to deref id map", type_.print(cache, tcx));
cx.deref_id_map.borrow_mut().insert(type_.def_id_full(cache).unwrap(), id.clone()); cx.deref_id_map.borrow_mut().insert(type_.def_id_full(cache).unwrap(), id.clone());
write!( write!(
w, w,
@@ -1089,8 +1079,8 @@ fn render_assoc_items(
<a href=\"#{id}\" class=\"anchor\"></a>\ <a href=\"#{id}\" class=\"anchor\"></a>\
</h2>", </h2>",
id = id, id = id,
trait_ = trait_.print(cache, tcx), trait_ = trait_.print(cx),
type_ = type_.print(cache, tcx), type_ = type_.print(cx),
); );
RenderMode::ForDeref { mut_: deref_mut_ } RenderMode::ForDeref { mut_: deref_mut_ }
} }
@@ -1242,36 +1232,34 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, cache: &Cache) -> bo
} }
} }
fn notable_traits_decl(decl: &clean::FnDecl, cache: &Cache, tcx: TyCtxt<'_>) -> String { fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
let mut out = Buffer::html(); let mut out = Buffer::html();
let mut trait_ = String::new(); let mut trait_ = String::new();
if let Some(did) = decl.output.def_id_full(cache) { if let Some(did) = decl.output.def_id_full(cx.cache()) {
if let Some(impls) = cache.impls.get(&did) { if let Some(impls) = cx.cache().impls.get(&did) {
for i in impls { for i in impls {
let impl_ = i.inner_impl(); let impl_ = i.inner_impl();
if impl_ if impl_.trait_.def_id().map_or(false, |d| {
.trait_ cx.cache().traits.get(&d).map(|t| t.is_notable).unwrap_or(false)
.def_id() }) {
.map_or(false, |d| cache.traits.get(&d).map(|t| t.is_notable).unwrap_or(false))
{
if out.is_empty() { if out.is_empty() {
write!( write!(
&mut out, &mut out,
"<h3 class=\"notable\">Notable traits for {}</h3>\ "<h3 class=\"notable\">Notable traits for {}</h3>\
<code class=\"content\">", <code class=\"content\">",
impl_.for_.print(cache, tcx) impl_.for_.print(cx)
); );
trait_.push_str(&impl_.for_.print(cache, tcx).to_string()); trait_.push_str(&impl_.for_.print(cx).to_string());
} }
//use the "where" class here to make it small //use the "where" class here to make it small
write!( write!(
&mut out, &mut out,
"<span class=\"where fmt-newline\">{}</span>", "<span class=\"where fmt-newline\">{}</span>",
impl_.print(cache, false, tcx) impl_.print(false, cx)
); );
let t_did = impl_.trait_.def_id_full(cache).unwrap(); let t_did = impl_.trait_.def_id_full(cx.cache()).unwrap();
for it in &impl_.items { for it in &impl_.items {
if let clean::TypedefItem(ref tydef, _) = *it.kind { if let clean::TypedefItem(ref tydef, _) = *it.kind {
out.push_str("<span class=\"where fmt-newline\"> "); out.push_str("<span class=\"where fmt-newline\"> ");
@@ -1282,8 +1270,7 @@ fn notable_traits_decl(decl: &clean::FnDecl, cache: &Cache, tcx: TyCtxt<'_>) ->
Some(&tydef.type_), Some(&tydef.type_),
AssocItemLink::GotoSource(t_did, &FxHashSet::default()), AssocItemLink::GotoSource(t_did, &FxHashSet::default()),
"", "",
cache, cx,
tcx,
); );
out.push_str(";</span>"); out.push_str(";</span>");
} }
@@ -1322,18 +1309,18 @@ fn render_impl(
// in documentation pages for trait with automatic implementations like "Send" and "Sync". // in documentation pages for trait with automatic implementations like "Send" and "Sync".
aliases: &[String], aliases: &[String],
) { ) {
let traits = &cx.cache.traits;
let tcx = cx.tcx(); let tcx = cx.tcx();
let cache = cx.cache(); let cache = cx.cache();
let traits = &cache.traits;
let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]); let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]);
if render_mode == RenderMode::Normal { if render_mode == RenderMode::Normal {
let id = cx.derive_id(match i.inner_impl().trait_ { let id = cx.derive_id(match i.inner_impl().trait_ {
Some(ref t) => { Some(ref t) => {
if is_on_foreign_type { if is_on_foreign_type {
get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cache, tcx) get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
} else { } else {
format!("impl-{}", small_url_encode(format!("{:#}", t.print(cache, tcx)))) format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
} }
} }
None => "impl".to_string(), None => "impl".to_string(),
@@ -1345,7 +1332,7 @@ fn render_impl(
}; };
if let Some(use_absolute) = use_absolute { if let Some(use_absolute) = use_absolute {
write!(w, "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">", id, aliases); write!(w, "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">", id, aliases);
write!(w, "{}", i.inner_impl().print(cache, use_absolute, tcx)); write!(w, "{}", i.inner_impl().print(use_absolute, cx));
if show_def_docs { if show_def_docs {
for it in &i.inner_impl().items { for it in &i.inner_impl().items {
if let clean::TypedefItem(ref tydef, _) = *it.kind { if let clean::TypedefItem(ref tydef, _) = *it.kind {
@@ -1357,8 +1344,7 @@ fn render_impl(
Some(&tydef.type_), Some(&tydef.type_),
AssocItemLink::Anchor(None), AssocItemLink::Anchor(None),
"", "",
cache, cx,
tcx,
); );
w.write_str(";</span>"); w.write_str(";</span>");
} }
@@ -1371,7 +1357,7 @@ fn render_impl(
"<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>", "<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>",
id, id,
aliases, aliases,
i.inner_impl().print(cache, false, tcx) i.inner_impl().print(false, cx)
); );
} }
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
@@ -1398,7 +1384,7 @@ fn render_impl(
"<div class=\"docblock\">{}</div>", "<div class=\"docblock\">{}</div>",
Markdown( Markdown(
&*dox, &*dox,
&i.impl_item.links(&cx.cache), &i.impl_item.links(cx),
&mut ids, &mut ids,
cx.shared.codes, cx.shared.codes,
cx.shared.edition, cx.shared.edition,
@@ -1495,8 +1481,7 @@ fn render_impl(
Some(&tydef.type_), Some(&tydef.type_),
link.anchor(if trait_.is_some() { &source_id } else { &id }), link.anchor(if trait_.is_some() { &source_id } else { &id }),
"", "",
cx.cache(), cx,
tcx,
); );
w.write_str("</code>"); w.write_str("</code>");
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
@@ -1546,8 +1531,7 @@ fn render_impl(
default.as_ref(), default.as_ref(),
link.anchor(if trait_.is_some() { &source_id } else { &id }), link.anchor(if trait_.is_some() { &source_id } else { &id }),
"", "",
cx.cache(), cx,
tcx,
); );
w.write_str("</code>"); w.write_str("</code>");
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
@@ -1853,7 +1837,6 @@ fn small_url_encode(s: String) -> String {
fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) { fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
if let Some(v) = cx.cache.impls.get(&it.def_id) { if let Some(v) = cx.cache.impls.get(&it.def_id) {
let mut used_links = FxHashSet::default(); let mut used_links = FxHashSet::default();
let tcx = cx.tcx();
let cache = cx.cache(); let cache = cx.cache();
{ {
@@ -1888,9 +1871,9 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
.iter() .iter()
.filter_map(|it| { .filter_map(|it| {
if let Some(ref i) = it.inner_impl().trait_ { if let Some(ref i) = it.inner_impl().trait_ {
let i_display = format!("{:#}", i.print(cache, tcx)); let i_display = format!("{:#}", i.print(cx));
let out = Escape(&i_display); let out = Escape(&i_display);
let encoded = small_url_encode(format!("{:#}", i.print(cache, tcx))); let encoded = small_url_encode(format!("{:#}", i.print(cx)));
let generated = format!( let generated = format!(
"<a href=\"#impl-{}\">{}{}</a>", "<a href=\"#impl-{}\">{}{}</a>",
encoded, encoded,
@@ -1962,7 +1945,6 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &Vec<Impl>) { fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &Vec<Impl>) {
let c = cx.cache(); let c = cx.cache();
let tcx = cx.tcx();
debug!("found Deref: {:?}", impl_); debug!("found Deref: {:?}", impl_);
if let Some((target, real_target)) = if let Some((target, real_target)) =
@@ -2011,11 +1993,8 @@ fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &V
out, out,
"<a class=\"sidebar-title\" href=\"#{}\">Methods from {}&lt;Target={}&gt;</a>", "<a class=\"sidebar-title\" href=\"#{}\">Methods from {}&lt;Target={}&gt;</a>",
id, id,
Escape(&format!( Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
"{:#}", Escape(&format!("{:#}", real_target.print(cx))),
impl_.inner_impl().trait_.as_ref().unwrap().print(c, tcx)
)),
Escape(&format!("{:#}", real_target.print(c, tcx))),
); );
// We want links' order to be reproducible so we don't use unstable sort. // We want links' order to be reproducible so we don't use unstable sort.
ret.sort(); ret.sort();
@@ -2071,27 +2050,20 @@ fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clea
fn get_id_for_impl_on_foreign_type( fn get_id_for_impl_on_foreign_type(
for_: &clean::Type, for_: &clean::Type,
trait_: &clean::Type, trait_: &clean::Type,
cache: &Cache, cx: &Context<'_>,
tcx: TyCtxt<'_>,
) -> String { ) -> String {
small_url_encode(format!( small_url_encode(format!("impl-{:#}-for-{:#}", trait_.print(cx), for_.print(cx),))
"impl-{:#}-for-{:#}",
trait_.print(cache, tcx),
for_.print(cache, tcx)
))
} }
fn extract_for_impl_name( fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
item: &clean::Item,
cache: &Cache,
tcx: TyCtxt<'_>,
) -> Option<(String, String)> {
match *item.kind { match *item.kind {
clean::ItemKind::ImplItem(ref i) => { clean::ItemKind::ImplItem(ref i) => {
if let Some(ref trait_) = i.trait_ { if let Some(ref trait_) = i.trait_ {
// Alternative format produces no URLs,
// so this parameter does nothing.
Some(( Some((
format!("{:#}", i.for_.print(cache, tcx)), format!("{:#}", i.for_.print(cx)),
get_id_for_impl_on_foreign_type(&i.for_, trait_, cache, tcx), get_id_for_impl_on_foreign_type(&i.for_, trait_, cx),
)) ))
} else { } else {
None None
@@ -2172,7 +2144,6 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean
if let Some(implementors) = cx.cache.implementors.get(&it.def_id) { if let Some(implementors) = cx.cache.implementors.get(&it.def_id) {
let cache = cx.cache(); let cache = cx.cache();
let tcx = cx.tcx();
let mut res = implementors let mut res = implementors
.iter() .iter()
.filter(|i| { .filter(|i| {
@@ -2181,7 +2152,7 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean
.def_id_full(cache) .def_id_full(cache)
.map_or(false, |d| !cx.cache.paths.contains_key(&d)) .map_or(false, |d| !cx.cache.paths.contains_key(&d))
}) })
.filter_map(|i| extract_for_impl_name(&i.impl_item, cache, tcx)) .filter_map(|i| extract_for_impl_name(&i.impl_item, cx))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if !res.is_empty() { if !res.is_empty() {

View File

@@ -15,9 +15,8 @@ use super::{
render_impl, render_stability_since_raw, write_srclink, AssocItemLink, Context, render_impl, render_stability_since_raw, write_srclink, AssocItemLink, Context,
}; };
use crate::clean::{self, GetDefId}; use crate::clean::{self, GetDefId};
use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType; use crate::formats::item_type::ItemType;
use crate::formats::{AssocItemRender, FormatRenderer, Impl, RenderMode}; use crate::formats::{AssocItemRender, Impl, RenderMode};
use crate::html::escape::Escape; use crate::html::escape::Escape;
use crate::html::format::{print_abi_with_space, print_where_clause, Buffer, PrintWithSpace}; use crate::html::format::{print_abi_with_space, print_where_clause, Buffer, PrintWithSpace};
use crate::html::highlight; use crate::html::highlight;
@@ -268,15 +267,15 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
Some(ref src) => write!( Some(ref src) => write!(
w, w,
"<tr><td><code>{}extern crate {} as {};", "<tr><td><code>{}extern crate {} as {};",
myitem.visibility.print_with_space(cx.tcx(), myitem.def_id, cx.cache()), myitem.visibility.print_with_space(cx, myitem.def_id),
anchor(myitem.def_id, &*src.as_str(), cx.cache()), anchor(myitem.def_id, &*src.as_str(), cx),
myitem.name.as_ref().unwrap(), myitem.name.as_ref().unwrap(),
), ),
None => write!( None => write!(
w, w,
"<tr><td><code>{}extern crate {};", "<tr><td><code>{}extern crate {};",
myitem.visibility.print_with_space(cx.tcx(), myitem.def_id, cx.cache()), myitem.visibility.print_with_space(cx, myitem.def_id),
anchor(myitem.def_id, &*myitem.name.as_ref().unwrap().as_str(), cx.cache()), anchor(myitem.def_id, &*myitem.name.as_ref().unwrap().as_str(), cx),
), ),
} }
w.write_str("</code></td></tr>"); w.write_str("</code></td></tr>");
@@ -286,8 +285,8 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
write!( write!(
w, w,
"<tr><td><code>{}{}</code></td></tr>", "<tr><td><code>{}{}</code></td></tr>",
myitem.visibility.print_with_space(cx.tcx(), myitem.def_id, cx.cache()), myitem.visibility.print_with_space(cx, myitem.def_id),
import.print(cx.cache(), cx.tcx()), import.print(cx),
); );
} }
@@ -318,7 +317,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
</tr>", </tr>",
name = *myitem.name.as_ref().unwrap(), name = *myitem.name.as_ref().unwrap(),
stab_tags = extra_info_tags(myitem, item, cx.tcx()), stab_tags = extra_info_tags(myitem, item, cx.tcx()),
docs = MarkdownSummaryLine(&doc_value, &myitem.links(&cx.cache)).into_string(), docs = MarkdownSummaryLine(&doc_value, &myitem.links(cx)).into_string(),
class = myitem.type_(), class = myitem.type_(),
add = add, add = add,
stab = stab.unwrap_or_else(String::new), stab = stab.unwrap_or_else(String::new),
@@ -387,13 +386,13 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) ->
fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) { fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) {
let header_len = format!( let header_len = format!(
"{}{}{}{}{:#}fn {}{:#}", "{}{}{}{}{:#}fn {}{:#}",
it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()), it.visibility.print_with_space(cx, it.def_id),
f.header.constness.print_with_space(), f.header.constness.print_with_space(),
f.header.asyncness.print_with_space(), f.header.asyncness.print_with_space(),
f.header.unsafety.print_with_space(), f.header.unsafety.print_with_space(),
print_abi_with_space(f.header.abi), print_abi_with_space(f.header.abi),
it.name.as_ref().unwrap(), it.name.as_ref().unwrap(),
f.generics.print(cx.cache(), cx.tcx()) f.generics.print(cx),
) )
.len(); .len();
w.write_str("<pre class=\"rust fn\">"); w.write_str("<pre class=\"rust fn\">");
@@ -402,22 +401,22 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
w, w,
"{vis}{constness}{asyncness}{unsafety}{abi}fn \ "{vis}{constness}{asyncness}{unsafety}{abi}fn \
{name}{generics}{decl}{notable_traits}{where_clause}</pre>", {name}{generics}{decl}{notable_traits}{where_clause}</pre>",
vis = it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()), vis = it.visibility.print_with_space(cx, it.def_id),
constness = f.header.constness.print_with_space(), constness = f.header.constness.print_with_space(),
asyncness = f.header.asyncness.print_with_space(), asyncness = f.header.asyncness.print_with_space(),
unsafety = f.header.unsafety.print_with_space(), unsafety = f.header.unsafety.print_with_space(),
abi = print_abi_with_space(f.header.abi), abi = print_abi_with_space(f.header.abi),
name = it.name.as_ref().unwrap(), name = it.name.as_ref().unwrap(),
generics = f.generics.print(cx.cache(), cx.tcx()), generics = f.generics.print(cx),
where_clause = print_where_clause(&f.generics, cx.cache(), cx.tcx(), 0, true), where_clause = print_where_clause(&f.generics, cx, 0, true),
decl = f.decl.full_print(cx.cache(), cx.tcx(), header_len, 0, f.header.asyncness), decl = f.decl.full_print(cx, header_len, 0, f.header.asyncness),
notable_traits = notable_traits_decl(&f.decl, cx.cache(), cx.tcx()), notable_traits = notable_traits_decl(&f.decl, cx),
); );
document(w, cx, it, None) document(w, cx, it, None)
} }
fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) { fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) {
let bounds = bounds(&t.bounds, false, cx.cache(), cx.tcx()); let bounds = bounds(&t.bounds, false, cx);
let types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>(); let types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>(); let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
let required = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>(); let required = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>();
@@ -430,16 +429,16 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
write!( write!(
w, w,
"{}{}{}trait {}{}{}", "{}{}{}trait {}{}{}",
it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()), it.visibility.print_with_space(cx, it.def_id),
t.unsafety.print_with_space(), t.unsafety.print_with_space(),
if t.is_auto { "auto " } else { "" }, if t.is_auto { "auto " } else { "" },
it.name.as_ref().unwrap(), it.name.as_ref().unwrap(),
t.generics.print(cx.cache(), cx.tcx()), t.generics.print(cx),
bounds bounds
); );
if !t.generics.where_predicates.is_empty() { if !t.generics.where_predicates.is_empty() {
write!(w, "{}", print_where_clause(&t.generics, cx.cache(), cx.tcx(), 0, true)); write!(w, "{}", print_where_clause(&t.generics, cx, 0, true));
} else { } else {
w.write_str(" "); w.write_str(" ");
} }
@@ -634,8 +633,8 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) = let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
local.iter().partition(|i| i.inner_impl().synthetic); local.iter().partition(|i| i.inner_impl().synthetic);
synthetic.sort_by(|a, b| compare_impl(a, b, cx.cache(), cx.tcx())); synthetic.sort_by(|a, b| compare_impl(a, b, cx));
concrete.sort_by(|a, b| compare_impl(a, b, cx.cache(), cx.tcx())); concrete.sort_by(|a, b| compare_impl(a, b, cx));
if !foreign.is_empty() { if !foreign.is_empty() {
write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", ""); write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", "");
@@ -740,9 +739,9 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea
w, w,
"trait {}{}{} = {};</pre>", "trait {}{}{} = {};</pre>",
it.name.as_ref().unwrap(), it.name.as_ref().unwrap(),
t.generics.print(cx.cache(), cx.tcx()), t.generics.print(cx),
print_where_clause(&t.generics, cx.cache(), cx.tcx(), 0, true), print_where_clause(&t.generics, cx, 0, true),
bounds(&t.bounds, true, cx.cache(), cx.tcx()) bounds(&t.bounds, true, cx)
); );
document(w, cx, it, None); document(w, cx, it, None);
@@ -761,9 +760,9 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean:
w, w,
"type {}{}{where_clause} = impl {bounds};</pre>", "type {}{}{where_clause} = impl {bounds};</pre>",
it.name.as_ref().unwrap(), it.name.as_ref().unwrap(),
t.generics.print(cx.cache(), cx.tcx()), t.generics.print(cx),
where_clause = print_where_clause(&t.generics, cx.cache(), cx.tcx(), 0, true), where_clause = print_where_clause(&t.generics, cx, 0, true),
bounds = bounds(&t.bounds, false, cx.cache(), cx.tcx()), bounds = bounds(&t.bounds, false, cx),
); );
document(w, cx, it, None); document(w, cx, it, None);
@@ -782,9 +781,9 @@ fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::T
w, w,
"type {}{}{where_clause} = {type_};</pre>", "type {}{}{where_clause} = {type_};</pre>",
it.name.as_ref().unwrap(), it.name.as_ref().unwrap(),
t.generics.print(cx.cache(), cx.tcx()), t.generics.print(cx),
where_clause = print_where_clause(&t.generics, cx.cache(), cx.tcx(), 0, true), where_clause = print_where_clause(&t.generics, cx, 0, true),
type_ = t.type_.print(cx.cache(), cx.tcx()), type_ = t.type_.print(cx),
); );
document(w, cx, it, None); document(w, cx, it, None);
@@ -831,7 +830,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
id = id, id = id,
name = name, name = name,
shortty = ItemType::StructField, shortty = ItemType::StructField,
ty = ty.print(cx.cache(), cx.tcx()), ty = ty.print(cx),
); );
if let Some(stability_class) = field.stability_class(cx.tcx()) { if let Some(stability_class) = field.stability_class(cx.tcx()) {
write!(w, "<span class=\"stab {stab}\"></span>", stab = stability_class); write!(w, "<span class=\"stab {stab}\"></span>", stab = stability_class);
@@ -849,10 +848,10 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
write!( write!(
w, w,
"{}enum {}{}{}", "{}enum {}{}{}",
it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()), it.visibility.print_with_space(cx, it.def_id),
it.name.as_ref().unwrap(), it.name.as_ref().unwrap(),
e.generics.print(cx.cache(), cx.tcx()), e.generics.print(cx),
print_where_clause(&e.generics, cx.cache(), cx.tcx(), 0, true), print_where_clause(&e.generics, cx, 0, true),
); );
if e.variants.is_empty() && !e.variants_stripped { if e.variants.is_empty() && !e.variants_stripped {
w.write_str(" {}"); w.write_str(" {}");
@@ -874,7 +873,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
if i > 0 { if i > 0 {
w.write_str(",&nbsp;") w.write_str(",&nbsp;")
} }
write!(w, "{}", ty.print(cx.cache(), cx.tcx())); write!(w, "{}", ty.print(cx));
} }
w.write_str(")"); w.write_str(")");
} }
@@ -924,7 +923,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
if i > 0 { if i > 0 {
w.write_str(",&nbsp;"); w.write_str(",&nbsp;");
} }
write!(w, "{}", ty.print(cx.cache(), cx.tcx())); write!(w, "{}", ty.print(cx));
} }
w.write_str(")"); w.write_str(")");
} }
@@ -961,7 +960,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
</span>", </span>",
id = id, id = id,
f = field.name.as_ref().unwrap(), f = field.name.as_ref().unwrap(),
t = ty.print(cx.cache(), cx.tcx()) t = ty.print(cx)
); );
document(w, cx, field, Some(variant)); document(w, cx, field, Some(variant));
} }
@@ -1030,9 +1029,9 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::
write!( write!(
w, w,
"{vis}const {name}: {typ}", "{vis}const {name}: {typ}",
vis = it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()), vis = it.visibility.print_with_space(cx, it.def_id),
name = it.name.as_ref().unwrap(), name = it.name.as_ref().unwrap(),
typ = c.type_.print(cx.cache(), cx.tcx()), typ = c.type_.print(cx),
); );
let value = c.value(cx.tcx()); let value = c.value(cx.tcx());
@@ -1102,7 +1101,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
item_type = ItemType::StructField, item_type = ItemType::StructField,
id = id, id = id,
name = field.name.as_ref().unwrap(), name = field.name.as_ref().unwrap(),
ty = ty.print(cx.cache(), cx.tcx()) ty = ty.print(cx)
); );
document(w, cx, field, Some(it)); document(w, cx, field, Some(it));
} }
@@ -1117,10 +1116,10 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
write!( write!(
w, w,
"{vis}static {mutability}{name}: {typ}</pre>", "{vis}static {mutability}{name}: {typ}</pre>",
vis = it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()), vis = it.visibility.print_with_space(cx, it.def_id),
mutability = s.mutability.print_with_space(), mutability = s.mutability.print_with_space(),
name = it.name.as_ref().unwrap(), name = it.name.as_ref().unwrap(),
typ = s.type_.print(cx.cache(), cx.tcx()) typ = s.type_.print(cx)
); );
document(w, cx, it, None) document(w, cx, it, None)
} }
@@ -1131,7 +1130,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
write!( write!(
w, w,
" {}type {};\n}}</pre>", " {}type {};\n}}</pre>",
it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()), it.visibility.print_with_space(cx, it.def_id),
it.name.as_ref().unwrap(), it.name.as_ref().unwrap(),
); );
@@ -1195,12 +1194,7 @@ pub(super) fn item_path(ty: ItemType, name: &str) -> String {
} }
} }
fn bounds( fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool, cx: &Context<'_>) -> String {
t_bounds: &[clean::GenericBound],
trait_alias: bool,
cache: &Cache,
tcx: TyCtxt<'_>,
) -> String {
let mut bounds = String::new(); let mut bounds = String::new();
if !t_bounds.is_empty() { if !t_bounds.is_empty() {
if !trait_alias { if !trait_alias {
@@ -1210,7 +1204,7 @@ fn bounds(
if i > 0 { if i > 0 {
bounds.push_str(" + "); bounds.push_str(" + ");
} }
bounds.push_str(&p.print(cache, tcx).to_string()); bounds.push_str(&p.print(cx).to_string());
} }
} }
bounds bounds
@@ -1240,17 +1234,12 @@ fn render_stability_since(
) )
} }
fn compare_impl<'a, 'b>( fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl, cx: &Context<'_>) -> Ordering {
lhs: &'a &&Impl, let lhss = format!("{}", lhs.inner_impl().print(false, cx));
rhs: &'b &&Impl, let rhss = format!("{}", rhs.inner_impl().print(false, cx));
cache: &Cache,
tcx: TyCtxt<'_>,
) -> Ordering {
let lhs = format!("{}", lhs.inner_impl().print(cache, false, tcx));
let rhs = format!("{}", rhs.inner_impl().print(cache, false, tcx));
// lhs and rhs are formatted as HTML, which may be unnecessary // lhs and rhs are formatted as HTML, which may be unnecessary
compare_names(&lhs, &rhs) compare_names(&lhss, &rhss)
} }
fn render_implementor( fn render_implementor(
@@ -1300,13 +1289,13 @@ fn render_union(
write!( write!(
w, w,
"{}{}{}", "{}{}{}",
it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()), it.visibility.print_with_space(cx, it.def_id),
if structhead { "union " } else { "" }, if structhead { "union " } else { "" },
it.name.as_ref().unwrap() it.name.as_ref().unwrap()
); );
if let Some(g) = g { if let Some(g) = g {
write!(w, "{}", g.print(cx.cache(), cx.tcx())); write!(w, "{}", g.print(cx));
write!(w, "{}", print_where_clause(&g, cx.cache(), cx.tcx(), 0, true)); write!(w, "{}", print_where_clause(&g, cx, 0, true));
} }
write!(w, " {{\n{}", tab); write!(w, " {{\n{}", tab);
@@ -1322,9 +1311,9 @@ fn render_union(
write!( write!(
w, w,
" {}{}: {},\n{}", " {}{}: {},\n{}",
field.visibility.print_with_space(cx.tcx(), field.def_id, cx.cache()), field.visibility.print_with_space(cx, field.def_id),
field.name.as_ref().unwrap(), field.name.as_ref().unwrap(),
ty.print(cx.cache(), cx.tcx()), ty.print(cx),
tab tab
); );
} }
@@ -1352,17 +1341,17 @@ fn render_struct(
write!( write!(
w, w,
"{}{}{}", "{}{}{}",
it.visibility.print_with_space(cx.tcx(), it.def_id, cx.cache()), it.visibility.print_with_space(cx, it.def_id),
if structhead { "struct " } else { "" }, if structhead { "struct " } else { "" },
it.name.as_ref().unwrap() it.name.as_ref().unwrap()
); );
if let Some(g) = g { if let Some(g) = g {
write!(w, "{}", g.print(cx.cache(), cx.tcx())) write!(w, "{}", g.print(cx))
} }
match ty { match ty {
CtorKind::Fictive => { CtorKind::Fictive => {
if let Some(g) = g { if let Some(g) = g {
write!(w, "{}", print_where_clause(g, cx.cache(), cx.tcx(), 0, true),) write!(w, "{}", print_where_clause(g, cx, 0, true),)
} }
w.write_str(" {"); w.write_str(" {");
let count_fields = let count_fields =
@@ -1378,9 +1367,9 @@ fn render_struct(
w, w,
"\n{} {}{}: {},", "\n{} {}{}: {},",
tab, tab,
field.visibility.print_with_space(cx.tcx(), field.def_id, cx.cache()), field.visibility.print_with_space(cx, field.def_id),
field.name.as_ref().unwrap(), field.name.as_ref().unwrap(),
ty.print(cx.cache(), cx.tcx()), ty.print(cx),
); );
} }
} }
@@ -1412,8 +1401,8 @@ fn render_struct(
write!( write!(
w, w,
"{}{}", "{}{}",
field.visibility.print_with_space(cx.tcx(), field.def_id, cx.cache()), field.visibility.print_with_space(cx, field.def_id),
ty.print(cx.cache(), cx.tcx()), ty.print(cx),
) )
} }
_ => unreachable!(), _ => unreachable!(),
@@ -1421,14 +1410,14 @@ fn render_struct(
} }
w.write_str(")"); w.write_str(")");
if let Some(g) = g { if let Some(g) = g {
write!(w, "{}", print_where_clause(g, cx.cache(), cx.tcx(), 0, false),) write!(w, "{}", print_where_clause(g, cx, 0, false),)
} }
w.write_str(";"); w.write_str(";");
} }
CtorKind::Const => { CtorKind::Const => {
// Needed for PhantomData. // Needed for PhantomData.
if let Some(g) = g { if let Some(g) = g {
write!(w, "{}", print_where_clause(g, cx.cache(), cx.tcx(), 0, false),) write!(w, "{}", print_where_clause(g, cx, 0, false),)
} }
w.write_str(";"); w.write_str(";");
} }

View File

@@ -16,7 +16,6 @@ use crate::clean::Crate;
use crate::config::{EmitType, RenderOptions}; use crate::config::{EmitType, RenderOptions};
use crate::docfs::PathError; use crate::docfs::PathError;
use crate::error::Error; use crate::error::Error;
use crate::formats::FormatRenderer;
use crate::html::{layout, static_files}; use crate::html::{layout, static_files};
crate static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| { crate static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
@@ -500,7 +499,7 @@ pub(super) fn write_shared(
None None
} else { } else {
Some(Implementor { Some(Implementor {
text: imp.inner_impl().print(cx.cache(), false, cx.tcx()).to_string(), text: imp.inner_impl().print(false, cx).to_string(),
synthetic: imp.inner_impl().synthetic, synthetic: imp.inner_impl().synthetic,
types: collect_paths_for_type(imp.inner_impl().for_.clone(), cx.cache()), types: collect_paths_for_type(imp.inner_impl().for_.clone(), cx.cache()),
}) })

View File

@@ -0,0 +1,44 @@
use crate::html::format::href_relative_parts;
fn assert_relative_path(expected: &[&str], relative_to_fqp: &[&str], fqp: &[&str]) {
let relative_to_fqp: Vec<String> = relative_to_fqp.iter().copied().map(String::from).collect();
let fqp: Vec<String> = fqp.iter().copied().map(String::from).collect();
assert_eq!(expected, href_relative_parts(&fqp, &relative_to_fqp));
}
#[test]
fn href_relative_parts_basic() {
let relative_to_fqp = &["std", "vec"];
let fqp = &["std", "iter"];
assert_relative_path(&["..", "iter"], relative_to_fqp, fqp);
}
#[test]
fn href_relative_parts_parent_module() {
let relative_to_fqp = &["std", "vec"];
let fqp = &["std"];
assert_relative_path(&[".."], relative_to_fqp, fqp);
}
#[test]
fn href_relative_parts_different_crate() {
let relative_to_fqp = &["std", "vec"];
let fqp = &["core", "iter"];
assert_relative_path(&["..", "..", "core", "iter"], relative_to_fqp, fqp);
}
#[test]
fn href_relative_parts_same_module() {
let relative_to_fqp = &["std", "vec"];
let fqp = &["std", "vec"];
assert_relative_path(&[], relative_to_fqp, fqp);
}
#[test]
fn href_relative_parts_child_module() {
let relative_to_fqp = &["std"];
let fqp = &["std", "vec"];
assert_relative_path(&["vec"], relative_to_fqp, fqp);
}
#[test]
fn href_relative_parts_root() {
let relative_to_fqp = &[];
let fqp = &["std"];
assert_relative_path(&["std"], relative_to_fqp, fqp);
}

View File

@@ -289,7 +289,13 @@ fn opts() -> Vec<RustcOptGroup> {
stable("cfg", |o| o.optmulti("", "cfg", "pass a --cfg to rustc", "")), stable("cfg", |o| o.optmulti("", "cfg", "pass a --cfg to rustc", "")),
stable("extern", |o| o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]")), stable("extern", |o| o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]")),
unstable("extern-html-root-url", |o| { unstable("extern-html-root-url", |o| {
o.optmulti("", "extern-html-root-url", "base URL to use for dependencies", "NAME=URL") o.optmulti(
"",
"extern-html-root-url",
"base URL to use for dependencies; for example, \
\"std=/doc\" links std::vec::Vec to /doc/std/vec/struct.Vec.html",
"NAME=URL",
)
}), }),
stable("plugin-path", |o| o.optmulti("", "plugin-path", "removed", "DIR")), stable("plugin-path", |o| o.optmulti("", "plugin-path", "removed", "DIR")),
stable("C", |o| { stable("C", |o| {

View File

@@ -6,14 +6,14 @@ pub trait Index<I: ?Sized> {
type Output: ?Sized; type Output: ?Sized;
// @has - '//*[@id="tymethod.index"]//code' \ // @has - '//*[@id="tymethod.index"]//code' \
// "fn index<'a>(&'a self, index: I) -> &'a Self::Output" // "fn index<'a>(&'a self, index: I) -> &'a Self::Output"
// @has - '//*[@id="tymethod.index"]//code//a[@href="../assoc_types/trait.Index.html#associatedtype.Output"]' \ // @has - '//*[@id="tymethod.index"]//code//a[@href="trait.Index.html#associatedtype.Output"]' \
// "Output" // "Output"
fn index<'a>(&'a self, index: I) -> &'a Self::Output; fn index<'a>(&'a self, index: I) -> &'a Self::Output;
} }
// @has assoc_types/fn.use_output.html // @has assoc_types/fn.use_output.html
// @has - '//*[@class="rust fn"]' '-> &T::Output' // @has - '//*[@class="rust fn"]' '-> &T::Output'
// @has - '//*[@class="rust fn"]//a[@href="../assoc_types/trait.Index.html#associatedtype.Output"]' 'Output' // @has - '//*[@class="rust fn"]//a[@href="trait.Index.html#associatedtype.Output"]' 'Output'
pub fn use_output<T: Index<usize>>(obj: &T, index: usize) -> &T::Output { pub fn use_output<T: Index<usize>>(obj: &T, index: usize) -> &T::Output {
obj.index(index) obj.index(index)
} }
@@ -24,12 +24,12 @@ pub trait Feed {
// @has assoc_types/fn.use_input.html // @has assoc_types/fn.use_input.html
// @has - '//*[@class="rust fn"]' 'T::Input' // @has - '//*[@class="rust fn"]' 'T::Input'
// @has - '//*[@class="rust fn"]//a[@href="../assoc_types/trait.Feed.html#associatedtype.Input"]' 'Input' // @has - '//*[@class="rust fn"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
pub fn use_input<T: Feed>(_feed: &T, _element: T::Input) { } pub fn use_input<T: Feed>(_feed: &T, _element: T::Input) { }
// @has assoc_types/fn.cmp_input.html // @has assoc_types/fn.cmp_input.html
// @has - '//*[@class="rust fn"]' 'where T::Input: PartialEq<U::Input>' // @has - '//*[@class="rust fn"]' 'where T::Input: PartialEq<U::Input>'
// @has - '//*[@class="rust fn"]//a[@href="../assoc_types/trait.Feed.html#associatedtype.Input"]' 'Input' // @has - '//*[@class="rust fn"]//a[@href="trait.Feed.html#associatedtype.Input"]' 'Input'
pub fn cmp_input<T: Feed, U: Feed>(a: &T::Input, b: &U::Input) -> bool pub fn cmp_input<T: Feed, U: Feed>(a: &T::Input, b: &U::Input) -> bool
where T::Input: PartialEq<U::Input> where T::Input: PartialEq<U::Input>
{ {

View File

@@ -0,0 +1,6 @@
// compile-flags: --crate-type lib --edition 2018
#[doc(primitive = "usize")]
/// This is the built-in type `usize`.
mod usize {
}

View File

@@ -2,7 +2,7 @@
pub struct Foo; pub struct Foo;
// @has foo/struct.Bar.html '//a[@href="../foo/struct.Foo.html"]' 'Foo' // @has foo/struct.Bar.html '//a[@href="struct.Foo.html"]' 'Foo'
/// Code-styled reference to [`Foo`]. /// Code-styled reference to [`Foo`].
pub struct Bar; pub struct Bar;

View File

@@ -0,0 +1,9 @@
// aux-build:primitive-doc.rs
// compile-flags: --extern-html-root-url=primitive_doc=../ -Z unstable-options
#![no_std]
extern crate primitive_doc;
// @has 'cross_crate_primitive_doc/fn.foo.html' '//a[@href="../primitive_doc/primitive.usize.html"]' 'usize'
pub fn foo() -> usize { 0 }

View File

@@ -1,7 +1,7 @@
#![crate_name = "foo"] #![crate_name = "foo"]
// @has foo/trait.Foo.html '//a[@href="../foo/trait.Foo.html#tymethod.req"]' 'req' // @has foo/trait.Foo.html '//a[@href="trait.Foo.html#tymethod.req"]' 'req'
// @has foo/trait.Foo.html '//a[@href="../foo/trait.Foo.html#method.prov"]' 'prov' // @has foo/trait.Foo.html '//a[@href="trait.Foo.html#method.prov"]' 'prov'
/// Always make sure to implement [`req`], but you don't have to implement [`prov`]. /// Always make sure to implement [`req`], but you don't have to implement [`prov`].
/// ///

View File

@@ -3,7 +3,7 @@
extern crate cross_crate_self; extern crate cross_crate_self;
// @has self/struct.S.html '//a[@href="../self/struct.S.html#method.f"]' "Self::f" // @has self/struct.S.html '//a[@href="struct.S.html#method.f"]' "Self::f"
// @has self/struct.S.html '//a[@href="../self/struct.S.html"]' "Self" // @has self/struct.S.html '//a[@href="struct.S.html"]' "Self"
// @has self/struct.S.html '//a[@href="../cross_crate_self/index.html"]' "crate" // @has self/struct.S.html '//a[@href="../cross_crate_self/index.html"]' "crate"
pub use cross_crate_self::S; pub use cross_crate_self::S;

View File

@@ -4,7 +4,7 @@
pub struct Something; pub struct Something;
// @has anchors/struct.SomeOtherType.html // @has anchors/struct.SomeOtherType.html
// @has - '//a/@href' '../anchors/struct.Something.html#Anchor!' // @has - '//a/@href' 'struct.Something.html#Anchor!'
/// I want... /// I want...
/// ///

View File

@@ -9,14 +9,14 @@ pub trait TraitWithDefault {
} }
/// Link to [UsesDefaults::T] and [UsesDefaults::f] /// Link to [UsesDefaults::T] and [UsesDefaults::f]
// @has 'associated_defaults/struct.UsesDefaults.html' '//a[@href="../associated_defaults/struct.UsesDefaults.html#associatedtype.T"]' 'UsesDefaults::T' // @has 'associated_defaults/struct.UsesDefaults.html' '//a[@href="struct.UsesDefaults.html#associatedtype.T"]' 'UsesDefaults::T'
// @has 'associated_defaults/struct.UsesDefaults.html' '//a[@href="../associated_defaults/struct.UsesDefaults.html#method.f"]' 'UsesDefaults::f' // @has 'associated_defaults/struct.UsesDefaults.html' '//a[@href="struct.UsesDefaults.html#method.f"]' 'UsesDefaults::f'
pub struct UsesDefaults; pub struct UsesDefaults;
impl TraitWithDefault for UsesDefaults {} impl TraitWithDefault for UsesDefaults {}
/// Link to [OverridesDefaults::T] and [OverridesDefaults::f] /// Link to [OverridesDefaults::T] and [OverridesDefaults::f]
// @has 'associated_defaults/struct.OverridesDefaults.html' '//a[@href="../associated_defaults/struct.OverridesDefaults.html#associatedtype.T"]' 'OverridesDefaults::T' // @has 'associated_defaults/struct.OverridesDefaults.html' '//a[@href="struct.OverridesDefaults.html#associatedtype.T"]' 'OverridesDefaults::T'
// @has 'associated_defaults/struct.OverridesDefaults.html' '//a[@href="../associated_defaults/struct.OverridesDefaults.html#method.f"]' 'OverridesDefaults::f' // @has 'associated_defaults/struct.OverridesDefaults.html' '//a[@href="struct.OverridesDefaults.html#method.f"]' 'OverridesDefaults::f'
pub struct OverridesDefaults; pub struct OverridesDefaults;
impl TraitWithDefault for OverridesDefaults { impl TraitWithDefault for OverridesDefaults {
type T = bool; type T = bool;

View File

@@ -9,10 +9,10 @@
pub fn foo() {} pub fn foo() {}
/// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input] /// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input]
// @has 'associated_items/struct.MyStruct.html' '//a[@href="../associated_items/struct.MyStruct.html"]' 'MyStruct' // @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html"]' 'MyStruct'
// @has 'associated_items/struct.MyStruct.html' '//a[@href="../associated_items/struct.MyStruct.html#method.method"]' 'link from struct' // @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.method"]' 'link from struct'
// @has 'associated_items/struct.MyStruct.html' '//a[@href="../associated_items/struct.MyStruct.html#method.clone"]' 'MyStruct::clone' // @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.clone"]' 'MyStruct::clone'
// @has 'associated_items/struct.MyStruct.html' '//a[@href="../associated_items/struct.MyStruct.html#associatedtype.Input"]' 'MyStruct::Input' // @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#associatedtype.Input"]' 'MyStruct::Input'
pub struct MyStruct { foo: () } pub struct MyStruct { foo: () }
impl Clone for MyStruct { impl Clone for MyStruct {
@@ -30,7 +30,7 @@ impl T for MyStruct {
type Input = usize; type Input = usize;
/// [link from method][MyStruct::method] on method /// [link from method][MyStruct::method] on method
// @has 'associated_items/struct.MyStruct.html' '//a[@href="../associated_items/struct.MyStruct.html#method.method"]' 'link from method' // @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.method"]' 'link from method'
fn method(i: usize) { fn method(i: usize) {
} }
} }

View File

@@ -1,21 +1,21 @@
// @has basic/index.html // @has basic/index.html
// @has - '//a/@href' '../basic/struct.ThisType.html' // @has - '//a/@href' 'struct.ThisType.html'
// @has - '//a/@href' '../basic/struct.ThisType.html#method.this_method' // @has - '//a/@href' 'struct.ThisType.html#method.this_method'
// @has - '//a/@href' '../basic/enum.ThisEnum.html' // @has - '//a/@href' 'enum.ThisEnum.html'
// @has - '//a/@href' '../basic/enum.ThisEnum.html#variant.ThisVariant' // @has - '//a/@href' 'enum.ThisEnum.html#variant.ThisVariant'
// @has - '//a/@href' '../basic/trait.ThisTrait.html' // @has - '//a/@href' 'trait.ThisTrait.html'
// @has - '//a/@href' '../basic/trait.ThisTrait.html#tymethod.this_associated_method' // @has - '//a/@href' 'trait.ThisTrait.html#tymethod.this_associated_method'
// @has - '//a/@href' '../basic/trait.ThisTrait.html#associatedtype.ThisAssociatedType' // @has - '//a/@href' 'trait.ThisTrait.html#associatedtype.ThisAssociatedType'
// @has - '//a/@href' '../basic/trait.ThisTrait.html#associatedconstant.THIS_ASSOCIATED_CONST' // @has - '//a/@href' 'trait.ThisTrait.html#associatedconstant.THIS_ASSOCIATED_CONST'
// @has - '//a/@href' '../basic/trait.ThisTrait.html' // @has - '//a/@href' 'trait.ThisTrait.html'
// @has - '//a/@href' '../basic/type.ThisAlias.html' // @has - '//a/@href' 'type.ThisAlias.html'
// @has - '//a/@href' '../basic/union.ThisUnion.html' // @has - '//a/@href' 'union.ThisUnion.html'
// @has - '//a/@href' '../basic/fn.this_function.html' // @has - '//a/@href' 'fn.this_function.html'
// @has - '//a/@href' '../basic/constant.THIS_CONST.html' // @has - '//a/@href' 'constant.THIS_CONST.html'
// @has - '//a/@href' '../basic/static.THIS_STATIC.html' // @has - '//a/@href' 'static.THIS_STATIC.html'
// @has - '//a/@href' '../basic/macro.this_macro.html' // @has - '//a/@href' 'macro.this_macro.html'
// @has - '//a/@href' '../basic/trait.SoAmbiguous.html' // @has - '//a/@href' 'trait.SoAmbiguous.html'
// @has - '//a/@href' '../basic/fn.SoAmbiguous.html' // @has - '//a/@href' 'fn.SoAmbiguous.html'
//! In this crate we would like to link to: //! In this crate we would like to link to:
//! //!
//! * [`ThisType`](ThisType) //! * [`ThisType`](ThisType)
@@ -46,7 +46,7 @@ macro_rules! this_macro {
() => {}; () => {};
} }
// @has basic/struct.ThisType.html '//a/@href' '../basic/macro.this_macro.html' // @has basic/struct.ThisType.html '//a/@href' 'macro.this_macro.html'
/// another link to [`this_macro!()`] /// another link to [`this_macro!()`]
pub struct ThisType; pub struct ThisType;
@@ -72,10 +72,10 @@ pub trait SoAmbiguous {}
pub fn SoAmbiguous() {} pub fn SoAmbiguous() {}
// @has basic/struct.SomeOtherType.html '//a/@href' '../basic/struct.ThisType.html' // @has basic/struct.SomeOtherType.html '//a/@href' 'struct.ThisType.html'
// @has - '//a/@href' '../basic/struct.ThisType.html#method.this_method' // @has - '//a/@href' 'struct.ThisType.html#method.this_method'
// @has - '//a/@href' '../basic/enum.ThisEnum.html' // @has - '//a/@href' 'enum.ThisEnum.html'
// @has - '//a/@href' '../basic/enum.ThisEnum.html#variant.ThisVariant' // @has - '//a/@href' 'enum.ThisEnum.html#variant.ThisVariant'
/// Shortcut links for: /// Shortcut links for:
/// * [`ThisType`] /// * [`ThisType`]
/// * [`ThisType::this_method`] /// * [`ThisType::this_method`]

View File

@@ -4,7 +4,7 @@
extern crate my_rand; extern crate my_rand;
// @has 'additional_doc/trait.Rng.html' '//a[@href="../additional_doc/trait.Rng.html"]' 'Rng' // @has 'additional_doc/trait.Rng.html' '//a[@href="trait.Rng.html"]' 'Rng'
// @has 'additional_doc/trait.Rng.html' '//a[@href="../my_rand/trait.RngCore.html"]' 'RngCore' // @has 'additional_doc/trait.Rng.html' '//a[@href="../my_rand/trait.RngCore.html"]' 'RngCore'
/// This is an [`Rng`]. /// This is an [`Rng`].
pub use my_rand::Rng; pub use my_rand::Rng;

View File

@@ -6,5 +6,5 @@
extern crate hidden_dep; extern crate hidden_dep;
// @has 'hidden/struct.Ready.html' '//a/@href' '../hidden/fn.ready.html' // @has 'hidden/struct.Ready.html' '//a/@href' 'fn.ready.html'
pub use hidden_dep::future::{ready, Ready}; pub use hidden_dep::future::{ready, Ready};

View File

@@ -11,6 +11,6 @@ pub mod bar {
// NOTE: we re-exported both `Foo` and `Bar` here, // NOTE: we re-exported both `Foo` and `Bar` here,
// NOTE: so they are inlined and therefore we link to the current module. // NOTE: so they are inlined and therefore we link to the current module.
// @has 'submodule_outer/trait.Foo.html' '//a[@href="../submodule_outer/bar/trait.Bar.html"]' 'Bar' // @has 'submodule_outer/trait.Foo.html' '//a[@href="bar/trait.Bar.html"]' 'Bar'
// @has 'submodule_outer/trait.Foo.html' '//a[@href="../submodule_outer/trait.Baz.html"]' 'Baz' // @has 'submodule_outer/trait.Foo.html' '//a[@href="trait.Baz.html"]' 'Baz'
pub use ::bar_::{Foo, Baz}; pub use ::bar_::{Foo, Baz};

View File

@@ -2,26 +2,26 @@
// first try backticks // first try backticks
/// Trait: [`trait@Name`], fn: [`fn@Name`], [`Name`][`macro@Name`] /// Trait: [`trait@Name`], fn: [`fn@Name`], [`Name`][`macro@Name`]
// @has disambiguators_removed/struct.AtDisambiguator.html // @has disambiguators_removed/struct.AtDisambiguator.html
// @has - '//a[@href="../disambiguators_removed/trait.Name.html"][code]' "Name" // @has - '//a[@href="trait.Name.html"][code]' "Name"
// @has - '//a[@href="../disambiguators_removed/fn.Name.html"][code]' "Name" // @has - '//a[@href="fn.Name.html"][code]' "Name"
// @has - '//a[@href="../disambiguators_removed/macro.Name.html"][code]' "Name" // @has - '//a[@href="macro.Name.html"][code]' "Name"
pub struct AtDisambiguator; pub struct AtDisambiguator;
/// fn: [`Name()`], macro: [`Name!`] /// fn: [`Name()`], macro: [`Name!`]
// @has disambiguators_removed/struct.SymbolDisambiguator.html // @has disambiguators_removed/struct.SymbolDisambiguator.html
// @has - '//a[@href="../disambiguators_removed/fn.Name.html"][code]' "Name()" // @has - '//a[@href="fn.Name.html"][code]' "Name()"
// @has - '//a[@href="../disambiguators_removed/macro.Name.html"][code]' "Name!" // @has - '//a[@href="macro.Name.html"][code]' "Name!"
pub struct SymbolDisambiguator; pub struct SymbolDisambiguator;
// Now make sure that backticks aren't added if they weren't already there // Now make sure that backticks aren't added if they weren't already there
/// [fn@Name] /// [fn@Name]
// @has disambiguators_removed/trait.Name.html // @has disambiguators_removed/trait.Name.html
// @has - '//a[@href="../disambiguators_removed/fn.Name.html"]' "Name" // @has - '//a[@href="fn.Name.html"]' "Name"
// @!has - '//a[@href="../disambiguators_removed/fn.Name.html"][code]' "Name" // @!has - '//a[@href="fn.Name.html"][code]' "Name"
// FIXME: this will turn !() into ! alone // FIXME: this will turn !() into ! alone
/// [Name!()] /// [Name!()]
// @has - '//a[@href="../disambiguators_removed/macro.Name.html"]' "Name!" // @has - '//a[@href="macro.Name.html"]' "Name!"
pub trait Name {} pub trait Name {}
#[allow(non_snake_case)] #[allow(non_snake_case)]
@@ -29,22 +29,22 @@ pub trait Name {}
// Try collapsed reference links // Try collapsed reference links
/// [macro@Name][] /// [macro@Name][]
// @has disambiguators_removed/fn.Name.html // @has disambiguators_removed/fn.Name.html
// @has - '//a[@href="../disambiguators_removed/macro.Name.html"]' "Name" // @has - '//a[@href="macro.Name.html"]' "Name"
// Try links that have the same text as a generated URL // Try links that have the same text as a generated URL
/// Weird URL aligned [../disambiguators_removed/macro.Name.html][trait@Name] /// Weird URL aligned [macro.Name.html][trait@Name]
// @has - '//a[@href="../disambiguators_removed/trait.Name.html"]' "../disambiguators_removed/macro.Name.html" // @has - '//a[@href="trait.Name.html"]' "macro.Name.html"
pub fn Name() {} pub fn Name() {}
#[macro_export] #[macro_export]
// Rustdoc doesn't currently handle links that have weird interspersing of inline code blocks. // Rustdoc doesn't currently handle links that have weird interspersing of inline code blocks.
/// [fn@Na`m`e] /// [fn@Na`m`e]
// @has disambiguators_removed/macro.Name.html // @has disambiguators_removed/macro.Name.html
// @has - '//a[@href="../disambiguators_removed/fn.Name.html"]' "fn@Name" // @has - '//a[@href="fn.Name.html"]' "fn@Name"
// It also doesn't handle any case where the code block isn't the whole link text: // It also doesn't handle any case where the code block isn't the whole link text:
/// [trait@`Name`] /// [trait@`Name`]
// @has - '//a[@href="../disambiguators_removed/trait.Name.html"]' "trait@Name" // @has - '//a[@href="trait.Name.html"]' "trait@Name"
macro_rules! Name { macro_rules! Name {
() => () () => ()
} }

View File

@@ -11,4 +11,4 @@ pub enum Foo {
/// I want [Foo::X::y]. /// I want [Foo::X::y].
pub fn foo() {} pub fn foo() {}
// @has foo/fn.foo.html '//a/@href' '../foo/enum.Foo.html#variant.X.field.y' // @has foo/fn.foo.html '//a/@href' 'enum.Foo.html#variant.X.field.y'

View File

@@ -12,6 +12,6 @@ impl ExternType {
// @has 'extern_type/foreigntype.ExternType.html' // @has 'extern_type/foreigntype.ExternType.html'
// @has 'extern_type/fn.links_to_extern_type.html' \ // @has 'extern_type/fn.links_to_extern_type.html' \
// 'href="../extern_type/foreigntype.ExternType.html#method.f"' // 'href="foreigntype.ExternType.html#method.f"'
/// See also [ExternType::f] /// See also [ExternType::f]
pub fn links_to_extern_type() {} pub fn links_to_extern_type() {}

View File

@@ -8,4 +8,4 @@ pub enum Foo {
}, },
} }
// @has foo/enum.Foo.html '//a/@href' '../foo/enum.Foo.html#variant.Bar.field.abc' // @has foo/enum.Foo.html '//a/@href' 'enum.Foo.html#variant.Bar.field.abc'

View File

@@ -6,11 +6,11 @@ pub fn foo() {
} }
pub mod foo {} pub mod foo {}
// @has mod_ambiguity/struct.A.html '//a/@href' '../mod_ambiguity/foo/index.html' // @has mod_ambiguity/struct.A.html '//a/@href' 'foo/index.html'
/// Module is [`module@foo`] /// Module is [`module@foo`]
pub struct A; pub struct A;
// @has mod_ambiguity/struct.B.html '//a/@href' '../mod_ambiguity/fn.foo.html' // @has mod_ambiguity/struct.B.html '//a/@href' 'fn.foo.html'
/// Function is [`fn@foo`] /// Function is [`fn@foo`]
pub struct B; pub struct B;

View File

@@ -11,6 +11,6 @@ pub mod char {
pub struct MyString; pub struct MyString;
/// See also [crate::char] and [mod@char] /// See also [crate::char] and [mod@char]
// @has prim_precedence/struct.MyString2.html '//*[@href="../prim_precedence/char/index.html"]' 'crate::char' // @has prim_precedence/struct.MyString2.html '//*[@href="char/index.html"]' 'crate::char'
// @has - '//*[@href="../prim_precedence/char/index.html"]' 'mod@char' // @has - '//*[@href="char/index.html"]' 'mod@char'
pub struct MyString2; pub struct MyString2;

View File

@@ -4,9 +4,9 @@
// make sure to update `rustdoc-ui/intra-doc/private.rs` if you update this file // make sure to update `rustdoc-ui/intra-doc/private.rs` if you update this file
/// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x] /// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
// @has private/struct.DocMe.html '//*a[@href="../private/struct.DontDocMe.html"]' 'DontDocMe' // @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html"]' 'DontDocMe'
// @has private/struct.DocMe.html '//*a[@href="../private/struct.DontDocMe.html#method.f"]' 'DontDocMe::f' // @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html#method.f"]' 'DontDocMe::f'
// @has private/struct.DocMe.html '//*a[@href="../private/struct.DontDocMe.html#structfield.x"]' 'DontDocMe::x' // @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html#structfield.x"]' 'DontDocMe::x'
pub struct DocMe; pub struct DocMe;
struct DontDocMe { struct DontDocMe {
x: usize, x: usize,

View File

@@ -9,17 +9,17 @@ pub use proc_macro_macro::{DeriveA, attr_a};
use proc_macro_macro::{DeriveB, attr_b}; use proc_macro_macro::{DeriveB, attr_b};
// @has proc_macro/struct.Foo.html // @has proc_macro/struct.Foo.html
// @has - '//a/@href' '../proc_macro/derive.DeriveA.html' // @has - '//a/@href' 'derive.DeriveA.html'
// @has - '//a/@href' '../proc_macro/attr.attr_a.html' // @has - '//a/@href' 'attr.attr_a.html'
// @has - '//a/@href' '../proc_macro/trait.DeriveTrait.html' // @has - '//a/@href' 'trait.DeriveTrait.html'
// @has - '//a/@href' '../proc_macro_macro/derive.DeriveB.html' // @has - '//a/@href' '../proc_macro_macro/derive.DeriveB.html'
// @has - '//a/@href' '../proc_macro_macro/attr.attr_b.html' // @has - '//a/@href' '../proc_macro_macro/attr.attr_b.html'
/// Link to [DeriveA], [attr_a], [DeriveB], [attr_b], [DeriveTrait] /// Link to [DeriveA], [attr_a], [DeriveB], [attr_b], [DeriveTrait]
pub struct Foo; pub struct Foo;
// @has proc_macro/struct.Bar.html // @has proc_macro/struct.Bar.html
// @has - '//a/@href' '../proc_macro/derive.DeriveA.html' // @has - '//a/@href' 'derive.DeriveA.html'
// @has - '//a/@href' '../proc_macro/attr.attr_a.html' // @has - '//a/@href' 'attr.attr_a.html'
/// Link to [deriveA](derive@DeriveA) [attr](macro@attr_a) /// Link to [deriveA](derive@DeriveA) [attr](macro@attr_a)
pub struct Bar; pub struct Bar;

View File

@@ -13,7 +13,7 @@ extern crate inner;
// @has outer/index.html // @has outer/index.html
// @ has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/fn.var.html"]' "std::env" // @ has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/fn.var.html"]' "std::env"
// @ has - '//a[@href="../outer/fn.f.html"]' "g" // @ has - '//a[@href="fn.f.html"]' "g"
pub use f as g; pub use f as g;
// FIXME: same as above // FIXME: same as above

View File

@@ -5,7 +5,7 @@ pub mod r#impl {
impl S { impl S {
/// See [Self::b]. /// See [Self::b].
// @has raw_ident_self/impl/struct.S.html // @has raw_ident_self/impl/struct.S.html
// @has - '//a[@href="../../raw_ident_self/impl/struct.S.html#method.b"]' 'Self::b' // @has - '//a[@href="struct.S.html#method.b"]' 'Self::b'
pub fn a() {} pub fn a() {}
pub fn b() {} pub fn b() {}

View File

@@ -3,13 +3,13 @@
#![crate_name = "foo"] #![crate_name = "foo"]
extern crate inner; extern crate inner;
// @has foo/struct.Inner.html '//a[@href="../foo/fn.with_code.html"]' 'crate::with_code' // @has foo/struct.Inner.html '//a[@href="fn.with_code.html"]' 'crate::with_code'
/// [crate::with_code] /// [crate::with_code]
// @has - '//a[@href="../foo/fn.with_code.html"]' 'different text' // @has - '//a[@href="fn.with_code.html"]' 'different text'
/// [different text][with_code] /// [different text][with_code]
// @has - '//a[@href="../foo/fn.me_too.html"]' 'me_too' // @has - '//a[@href="fn.me_too.html"]' 'me_too'
#[doc = "[me_too]"] #[doc = "[me_too]"]
// @has - '//a[@href="../foo/fn.me_three.html"]' 'reference link' // @has - '//a[@href="fn.me_three.html"]' 'reference link'
/// This [reference link] /// This [reference link]
#[doc = "has an attr in the way"] #[doc = "has an attr in the way"]
/// ///

View File

@@ -1,8 +1,8 @@
#![crate_name = "foo"] #![crate_name = "foo"]
// @has foo/index.html '//a/@href' '../foo/struct.Foo.html#method.new' // @has foo/index.html '//a/@href' 'struct.Foo.html#method.new'
// @has foo/struct.Foo.html '//a/@href' '../foo/struct.Foo.html#method.new' // @has foo/struct.Foo.html '//a/@href' 'struct.Foo.html#method.new'
/// Use [`new`] to create a new instance. /// Use [`new`] to create a new instance.
/// ///
@@ -15,8 +15,8 @@ impl Foo {
} }
} }
// @has foo/index.html '//a/@href' '../foo/struct.Bar.html#method.new2' // @has foo/index.html '//a/@href' 'struct.Bar.html#method.new2'
// @has foo/struct.Bar.html '//a/@href' '../foo/struct.Bar.html#method.new2' // @has foo/struct.Bar.html '//a/@href' 'struct.Bar.html#method.new2'
/// Use [`new2`] to create a new instance. /// Use [`new2`] to create a new instance.
/// ///
@@ -30,7 +30,7 @@ impl Bar {
} }
pub struct MyStruct { pub struct MyStruct {
// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#structfield.struct_field' // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#structfield.struct_field'
/// [`struct_field`] /// [`struct_field`]
/// ///
@@ -39,7 +39,7 @@ pub struct MyStruct {
} }
pub enum MyEnum { pub enum MyEnum {
// @has foo/enum.MyEnum.html '//a/@href' '../foo/enum.MyEnum.html#variant.EnumVariant' // @has foo/enum.MyEnum.html '//a/@href' 'enum.MyEnum.html#variant.EnumVariant'
/// [`EnumVariant`] /// [`EnumVariant`]
/// ///
@@ -48,7 +48,7 @@ pub enum MyEnum {
} }
pub union MyUnion { pub union MyUnion {
// @has foo/union.MyUnion.html '//a/@href' '../foo/union.MyUnion.html#structfield.union_field' // @has foo/union.MyUnion.html '//a/@href' 'union.MyUnion.html#structfield.union_field'
/// [`union_field`] /// [`union_field`]
/// ///
@@ -57,21 +57,21 @@ pub union MyUnion {
} }
pub trait MyTrait { pub trait MyTrait {
// @has foo/trait.MyTrait.html '//a/@href' '../foo/trait.MyTrait.html#associatedtype.AssoType' // @has foo/trait.MyTrait.html '//a/@href' 'trait.MyTrait.html#associatedtype.AssoType'
/// [`AssoType`] /// [`AssoType`]
/// ///
/// [`AssoType`]: Self::AssoType /// [`AssoType`]: Self::AssoType
type AssoType; type AssoType;
// @has foo/trait.MyTrait.html '//a/@href' '../foo/trait.MyTrait.html#associatedconstant.ASSO_CONST' // @has foo/trait.MyTrait.html '//a/@href' 'trait.MyTrait.html#associatedconstant.ASSO_CONST'
/// [`ASSO_CONST`] /// [`ASSO_CONST`]
/// ///
/// [`ASSO_CONST`]: Self::ASSO_CONST /// [`ASSO_CONST`]: Self::ASSO_CONST
const ASSO_CONST: i32 = 1; const ASSO_CONST: i32 = 1;
// @has foo/trait.MyTrait.html '//a/@href' '../foo/trait.MyTrait.html#method.asso_fn' // @has foo/trait.MyTrait.html '//a/@href' 'trait.MyTrait.html#method.asso_fn'
/// [`asso_fn`] /// [`asso_fn`]
/// ///
@@ -80,7 +80,7 @@ pub trait MyTrait {
} }
impl MyStruct { impl MyStruct {
// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#method.for_impl' // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#method.for_impl'
/// [`for_impl`] /// [`for_impl`]
/// ///
@@ -91,21 +91,21 @@ impl MyStruct {
} }
impl MyTrait for MyStruct { impl MyTrait for MyStruct {
// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#associatedtype.AssoType' // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedtype.AssoType'
/// [`AssoType`] /// [`AssoType`]
/// ///
/// [`AssoType`]: Self::AssoType /// [`AssoType`]: Self::AssoType
type AssoType = u32; type AssoType = u32;
// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#associatedconstant.ASSO_CONST' // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedconstant.ASSO_CONST'
/// [`ASSO_CONST`] /// [`ASSO_CONST`]
/// ///
/// [`ASSO_CONST`]: Self::ASSO_CONST /// [`ASSO_CONST`]: Self::ASSO_CONST
const ASSO_CONST: i32 = 10; const ASSO_CONST: i32 = 10;
// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#method.asso_fn' // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#method.asso_fn'
/// [`asso_fn`] /// [`asso_fn`]
/// ///

View File

@@ -5,21 +5,21 @@ pub struct MyStruct;
impl MyTrait for MyStruct { impl MyTrait for MyStruct {
// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#associatedtype.AssoType' // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedtype.AssoType'
/// [`AssoType`] /// [`AssoType`]
/// ///
/// [`AssoType`]: MyStruct::AssoType /// [`AssoType`]: MyStruct::AssoType
type AssoType = u32; type AssoType = u32;
// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#associatedconstant.ASSO_CONST' // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedconstant.ASSO_CONST'
/// [`ASSO_CONST`] /// [`ASSO_CONST`]
/// ///
/// [`ASSO_CONST`]: MyStruct::ASSO_CONST /// [`ASSO_CONST`]: MyStruct::ASSO_CONST
const ASSO_CONST: i32 = 10; const ASSO_CONST: i32 = 10;
// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#method.trait_fn' // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#method.trait_fn'
/// [`trait_fn`] /// [`trait_fn`]
/// ///

View File

@@ -2,7 +2,7 @@
/// Link to [S::assoc_fn()] /// Link to [S::assoc_fn()]
/// Link to [Default::default()] /// Link to [Default::default()]
// @has trait_item/struct.S.html '//*[@href="../trait_item/struct.S.html#method.assoc_fn"]' 'S::assoc_fn()' // @has trait_item/struct.S.html '//*[@href="struct.S.html#method.assoc_fn"]' 'S::assoc_fn()'
// @has - '//*[@href="https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default"]' 'Default::default()' // @has - '//*[@href="https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default"]' 'Default::default()'
pub struct S; pub struct S;

View File

@@ -1,12 +1,12 @@
#![crate_name = "foo"] #![crate_name = "foo"]
// @has foo/enum.E1.html '//a/@href' '../foo/enum.E1.html#variant.A' // @has foo/enum.E1.html '//a/@href' 'enum.E1.html#variant.A'
/// [Self::A::b] /// [Self::A::b]
pub enum E1 { pub enum E1 {
A { b: usize } A { b: usize }
} }
// @has foo/enum.E2.html '//a/@href' '../foo/enum.E2.html#variant.A' // @has foo/enum.E2.html '//a/@href' 'enum.E2.html#variant.A'
/// [Self::A::b] /// [Self::A::b]
pub enum E2 { pub enum E2 {

View File

@@ -23,9 +23,9 @@ impl Foo {
} }
impl Bar for Foo { impl Bar for Foo {
// @has - '//*[@href="../issue_28478/trait.Bar.html#associatedtype.Bar"]' 'Bar' // @has - '//*[@href="trait.Bar.html#associatedtype.Bar"]' 'Bar'
// @has - '//*[@href="../issue_28478/trait.Bar.html#associatedconstant.Baz"]' 'Baz' // @has - '//*[@href="trait.Bar.html#associatedconstant.Baz"]' 'Baz'
// @has - '//*[@href="../issue_28478/trait.Bar.html#tymethod.bar"]' 'bar' // @has - '//*[@href="trait.Bar.html#tymethod.bar"]' 'bar'
fn bar() {} fn bar() {}
// @has - '//*[@href="../issue_28478/trait.Bar.html#method.baz"]' 'baz' // @has - '//*[@href="trait.Bar.html#method.baz"]' 'baz'
} }

View File

@@ -2,19 +2,19 @@
// @has issue_55364/subone/index.html // @has issue_55364/subone/index.html
// These foo/bar links in the module's documentation should refer inside `subone` // These foo/bar links in the module's documentation should refer inside `subone`
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subone/fn.foo.html"]' 'foo' // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subone/fn.bar.html"]' 'bar' // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
pub mod subone { pub mod subone {
//! See either [foo] or [bar]. //! See either [foo] or [bar].
// This should refer to subone's `bar` // This should refer to subone's `bar`
// @has issue_55364/subone/fn.foo.html // @has issue_55364/subone/fn.foo.html
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subone/fn.bar.html"]' 'bar' // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
/// See [bar] /// See [bar]
pub fn foo() {} pub fn foo() {}
// This should refer to subone's `foo` // This should refer to subone's `foo`
// @has issue_55364/subone/fn.bar.html // @has issue_55364/subone/fn.bar.html
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subone/fn.foo.html"]' 'foo' // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
/// See [foo] /// See [foo]
pub fn bar() {} pub fn bar() {}
} }
@@ -23,11 +23,11 @@ pub mod subone {
// @has issue_55364/subtwo/index.html // @has issue_55364/subtwo/index.html
// These foo/bar links in the module's documentation should not reference inside `subtwo` // These foo/bar links in the module's documentation should not reference inside `subtwo`
// @!has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subtwo/fn.foo.html"]' 'foo' // @!has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
// @!has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subtwo/fn.bar.html"]' 'bar' // @!has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
// Instead it should be referencing the top level functions // Instead it should be referencing the top level functions
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/fn.foo.html"]' 'foo' // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo'
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/fn.bar.html"]' 'bar' // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar'
// Though there should be such links later // Though there should be such links later
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td/a[@class="fn"][@href="fn.foo.html"]' 'foo' // @has - '//section[@id="main"]/table//tr[@class="module-item"]/td/a[@class="fn"][@href="fn.foo.html"]' 'foo'
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td/a[@class="fn"][@href="fn.bar.html"]' 'bar' // @has - '//section[@id="main"]/table//tr[@class="module-item"]/td/a[@class="fn"][@href="fn.bar.html"]' 'bar'
@@ -37,13 +37,13 @@ pub mod subtwo {
// Despite the module's docs referring to the top level foo/bar, // Despite the module's docs referring to the top level foo/bar,
// this should refer to subtwo's `bar` // this should refer to subtwo's `bar`
// @has issue_55364/subtwo/fn.foo.html // @has issue_55364/subtwo/fn.foo.html
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subtwo/fn.bar.html"]' 'bar' // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.bar.html"]' 'bar'
/// See [bar] /// See [bar]
pub fn foo() {} pub fn foo() {}
// Despite the module's docs referring to the top level foo/bar, // Despite the module's docs referring to the top level foo/bar,
// this should refer to subtwo's `foo` // this should refer to subtwo's `foo`
// @has issue_55364/subtwo/fn.bar.html // @has issue_55364/subtwo/fn.bar.html
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subtwo/fn.foo.html"]' 'foo' // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="fn.foo.html"]' 'foo'
/// See [foo] /// See [foo]
pub fn bar() {} pub fn bar() {}
} }
@@ -59,8 +59,8 @@ pub fn bar() {}
// @has issue_55364/subthree/index.html // @has issue_55364/subthree/index.html
// This module should also refer to the top level foo/bar // This module should also refer to the top level foo/bar
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/fn.foo.html"]' 'foo' // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo'
// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/fn.bar.html"]' 'bar' // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar'
pub mod subthree { pub mod subthree {
//! See either [foo][super::foo] or [bar][super::bar] //! See either [foo][super::foo] or [bar][super::bar]
} }
@@ -68,8 +68,8 @@ pub mod subthree {
// Next we go *deeper* - In order to ensure it's not just "this or parent" // Next we go *deeper* - In order to ensure it's not just "this or parent"
// we test `crate::` and a `super::super::...` chain // we test `crate::` and a `super::super::...` chain
// @has issue_55364/subfour/subfive/subsix/subseven/subeight/index.html // @has issue_55364/subfour/subfive/subsix/subseven/subeight/index.html
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td[@class="docblock-short"]//a[@href="../../../../../../issue_55364/subone/fn.foo.html"]' 'other foo' // @has - '//section[@id="main"]/table//tr[@class="module-item"]/td[@class="docblock-short"]//a[@href="../../../../../subone/fn.foo.html"]' 'other foo'
// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td[@class="docblock-short"]//a[@href="../../../../../../issue_55364/subtwo/fn.bar.html"]' 'other bar' // @has - '//section[@id="main"]/table//tr[@class="module-item"]/td[@class="docblock-short"]//a[@href="../../../../../subtwo/fn.bar.html"]' 'other bar'
pub mod subfour { pub mod subfour {
pub mod subfive { pub mod subfive {
pub mod subsix { pub mod subsix {

View File

@@ -10,7 +10,7 @@ impl Body {
} }
impl Default for Body { impl Default for Body {
// @has foo/struct.Body.html '//a/@href' '../foo/struct.Body.html#method.empty' // @has foo/struct.Body.html '//a/@href' 'struct.Body.html#method.empty'
/// Returns [`Body::empty()`](Body::empty). /// Returns [`Body::empty()`](Body::empty).
fn default() -> Body { fn default() -> Body {

View File

@@ -1,7 +1,7 @@
#![crate_name = "foo"] #![crate_name = "foo"]
// @has foo/index.html '//a[@href="../foo/foo/constant.FIRSTCONST.html"]' 'foo::FIRSTCONST' // @has foo/index.html '//a[@href="foo/constant.FIRSTCONST.html"]' 'foo::FIRSTCONST'
// @has foo/index.html '//a[@href="../foo/struct.Bar.html#associatedconstant.CONST"]' 'Bar::CONST' // @has foo/index.html '//a[@href="struct.Bar.html#associatedconstant.CONST"]' 'Bar::CONST'
//! We have here [`foo::FIRSTCONST`] and [`Bar::CONST`]. //! We have here [`foo::FIRSTCONST`] and [`Bar::CONST`].

View File

@@ -61,12 +61,12 @@ pub fn some_derive(_item: TokenStream) -> TokenStream {
// @has some_macros/foo/index.html // @has some_macros/foo/index.html
mod foo { mod foo {
// @has - '//code' 'pub use some_proc_macro;' // @has - '//code' 'pub use some_proc_macro;'
// @has - '//a/@href' '../../some_macros/macro.some_proc_macro.html' // @has - '//a/@href' '../macro.some_proc_macro.html'
pub use some_proc_macro; pub use some_proc_macro;
// @has - '//code' 'pub use some_proc_attr;' // @has - '//code' 'pub use some_proc_attr;'
// @has - '//a/@href' '../../some_macros/attr.some_proc_attr.html' // @has - '//a/@href' '../attr.some_proc_attr.html'
pub use some_proc_attr; pub use some_proc_attr;
// @has - '//code' 'pub use some_derive;' // @has - '//code' 'pub use some_derive;'
// @has - '//a/@href' '../../some_macros/derive.SomeDerive.html' // @has - '//a/@href' '../derive.SomeDerive.html'
pub use some_derive; pub use some_derive;
} }

View File

@@ -8,13 +8,13 @@ pub mod internal {
/// ///
/// [name]: mod /// [name]: mod
/// [other name]: crate::internal::mod /// [other name]: crate::internal::mod
// @has 'raw_ident_eliminate_r_hashtag/internal/struct.B.html' '//*a[@href="../../raw_ident_eliminate_r_hashtag/internal/struct.mod.html"]' 'name' // @has 'raw_ident_eliminate_r_hashtag/internal/struct.B.html' '//*a[@href="struct.mod.html"]' 'name'
// @has 'raw_ident_eliminate_r_hashtag/internal/struct.B.html' '//*a[@href="../../raw_ident_eliminate_r_hashtag/internal/struct.mod.html"]' 'other name' // @has 'raw_ident_eliminate_r_hashtag/internal/struct.B.html' '//*a[@href="struct.mod.html"]' 'other name'
pub struct B; pub struct B;
} }
/// See [name]. /// See [name].
/// ///
/// [name]: internal::mod /// [name]: internal::mod
// @has 'raw_ident_eliminate_r_hashtag/struct.A.html' '//*a[@href="../raw_ident_eliminate_r_hashtag/internal/struct.mod.html"]' 'name' // @has 'raw_ident_eliminate_r_hashtag/struct.A.html' '//*a[@href="internal/struct.mod.html"]' 'name'
pub struct A; pub struct A;

View File

@@ -1,9 +1,9 @@
#![crate_name = "foo"] #![crate_name = "foo"]
// @has foo/index.html '//*[@class="docblock"]/p/a[@href="../foo/struct.Foo.html#structfield.bar"]' 'Foo::bar' // @has foo/index.html '//*[@class="docblock"]/p/a[@href="struct.Foo.html#structfield.bar"]' 'Foo::bar'
// @has foo/index.html '//*[@class="docblock"]/p/a[@href="../foo/union.Bar.html#structfield.foo"]' 'Bar::foo' // @has foo/index.html '//*[@class="docblock"]/p/a[@href="union.Bar.html#structfield.foo"]' 'Bar::foo'
// @has foo/index.html '//*[@class="docblock"]/p/a[@href="../foo/enum.Uniooon.html#variant.X"]' 'Uniooon::X' // @has foo/index.html '//*[@class="docblock"]/p/a[@href="enum.Uniooon.html#variant.X"]' 'Uniooon::X'
//! Test with [Foo::bar], [Bar::foo], [Uniooon::X] //! Test with [Foo::bar], [Bar::foo], [Uniooon::X]

View File

@@ -40,25 +40,25 @@ impl MyTrait for Vec<u8> {
impl MyTrait for MyStruct { impl MyTrait for MyStruct {
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="type"]/@href' #associatedtype.Assoc // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="type"]/@href' #associatedtype.Assoc
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3 // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="type"]/@href' ../trait_impl_items_links_and_anchors/trait.MyTrait.html#associatedtype.Assoc // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="type"]/@href' trait.MyTrait.html#associatedtype.Assoc
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc
type Assoc = bool; type Assoc = bool;
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="constant"]/@href' #associatedconstant.VALUE // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="constant"]/@href' #associatedconstant.VALUE
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3 // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' ../trait_impl_items_links_and_anchors/trait.MyTrait.html#associatedconstant.VALUE // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' trait.MyTrait.html#associatedconstant.VALUE
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE
const VALUE: u32 = 20; const VALUE: u32 = 20;
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="fnname"]/@href' #tymethod.trait_function // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="fnname"]/@href' #tymethod.trait_function
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="anchor"]/@href' #method.trait_function-2 // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="anchor"]/@href' #method.trait_function-2
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' ../trait_impl_items_links_and_anchors/trait.MyTrait.html#tymethod.trait_function // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' trait.MyTrait.html#tymethod.trait_function
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
fn trait_function(&self) {} fn trait_function(&self) {}
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="fnname"]/@href' #method.defaulted_override // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="fnname"]/@href' #method.defaulted_override
// @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="anchor"]/@href' #method.defaulted_override-3 // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="anchor"]/@href' #method.defaulted_override-3
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="fnname"]/@href' ../trait_impl_items_links_and_anchors/trait.MyTrait.html#method.defaulted_override // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted_override
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override
fn defaulted_override(&self) {} fn defaulted_override(&self) {}
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="fnname"]/@href' ../trait_impl_items_links_and_anchors/trait.MyTrait.html#method.defaulted // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted
// @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted
} }

View File

@@ -1,4 +1,4 @@
// @has trait_self_link/trait.Foo.html //a/@href ../trait_self_link/trait.Foo.html // @has trait_self_link/trait.Foo.html //a/@href trait.Foo.html
pub trait Foo {} pub trait Foo {}
pub struct Bar; pub struct Bar;