diff options
Diffstat (limited to 'src/librustdoc/html/render')
-rw-r--r-- | src/librustdoc/html/render/context.rs | 33 | ||||
-rw-r--r-- | src/librustdoc/html/render/mod.rs | 35 | ||||
-rw-r--r-- | src/librustdoc/html/render/print_item.rs | 91 | ||||
-rw-r--r-- | src/librustdoc/html/render/search_index.rs | 92 | ||||
-rw-r--r-- | src/librustdoc/html/render/write_shared.rs | 64 |
5 files changed, 188 insertions, 127 deletions
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 73690c86f..5cefe9475 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -309,7 +309,7 @@ impl<'tcx> Context<'tcx> { pub(crate) fn href_from_span(&self, span: clean::Span, with_lines: bool) -> Option<String> { let mut root = self.root_path(); - let mut path = String::new(); + let mut path: String; let cnum = span.cnum(self.sess()); // We can safely ignore synthetic `SourceFile`s. @@ -340,10 +340,24 @@ impl<'tcx> Context<'tcx> { ExternalLocation::Unknown => return None, }; - sources::clean_path(&src_root, file, false, |component| { - path.push_str(&component.to_string_lossy()); + let href = RefCell::new(PathBuf::new()); + sources::clean_path( + &src_root, + file, + |component| { + href.borrow_mut().push(component); + }, + || { + href.borrow_mut().pop(); + }, + ); + + path = href.into_inner().to_string_lossy().to_string(); + + if let Some(c) = path.as_bytes().last() && *c != b'/' { path.push('/'); - }); + } + let mut fname = file.file_name().expect("source has no filename").to_os_string(); fname.push(".html"); path.push_str(&fname.to_string_lossy()); @@ -450,8 +464,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { // If user passed in `--playground-url` arg, we fill in crate name here let mut playground = None; if let Some(url) = playground_url { - playground = - Some(markdown::Playground { crate_name: Some(krate.name(tcx).to_string()), url }); + playground = Some(markdown::Playground { crate_name: Some(krate.name(tcx)), url }); } let mut layout = layout::Layout { logo: String::new(), @@ -477,7 +490,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { } (sym::html_playground_url, Some(s)) => { playground = Some(markdown::Playground { - crate_name: Some(krate.name(tcx).to_string()), + crate_name: Some(krate.name(tcx)), url: s.to_string(), }); } @@ -625,7 +638,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { write!( buf, "<div class=\"main-heading\">\ - <h1 class=\"fqn\">Rustdoc settings</h1>\ + <h1>Rustdoc settings</h1>\ <span class=\"out-of-band\">\ <a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\ Back\ @@ -637,7 +650,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { You need to enable Javascript be able to update your settings.\ </section>\ </noscript>\ - <link rel=\"stylesheet\" type=\"text/css\" \ + <link rel=\"stylesheet\" \ href=\"{static_root_path}{settings_css}\">\ <script defer src=\"{static_root_path}{settings_js}\"></script>", static_root_path = page.get_static_root_path(), @@ -663,7 +676,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { write!( buf, "<div class=\"main-heading\">\ - <h1 class=\"fqn\">Rustdoc help</h1>\ + <h1>Rustdoc help</h1>\ <span class=\"out-of-band\">\ <a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\ Back\ diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 36d15ec3b..4fa33e890 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -100,7 +100,7 @@ pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ { #[derive(Debug)] pub(crate) struct IndexItem { pub(crate) ty: ItemType, - pub(crate) name: String, + pub(crate) name: Symbol, pub(crate) path: String, pub(crate) desc: String, pub(crate) parent: Option<DefId>, @@ -364,7 +364,7 @@ impl AllTypes { } } - f.write_str("<h1 class=\"fqn\">List of all items</h1>"); + f.write_str("<h1>List of all items</h1>"); // Note: print_entries does not escape the title, because we know the current set of titles // doesn't require escaping. print_entries(f, &self.structs, ItemSection::Structs); @@ -394,7 +394,7 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String { let mut ids = IdMap::default(); format!( "<div class=\"main-heading\">\ - <h1 class=\"fqn\">About scraped examples</h1>\ + <h1>About scraped examples</h1>\ </div>\ <div>{}</div>", Markdown { @@ -467,9 +467,10 @@ fn document_short( return; } if let Some(s) = item.doc_value() { - let mut summary_html = MarkdownSummaryLine(&s, &item.links(cx)).into_string(); + let (mut summary_html, has_more_content) = + MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content(); - if s.contains('\n') { + if has_more_content { let link = format!(r#" <a{}>Read more</a>"#, assoc_href_attr(item, link, cx)); if let Some(idx) = summary_html.rfind("</p>") { @@ -512,7 +513,7 @@ fn document_full_inner( debug!("Doc block: =====\n{}\n=====", s); if is_collapsible { w.write_str( - "<details class=\"rustdoc-toggle top-doc\" open>\ + "<details class=\"toggle top-doc\" open>\ <summary class=\"hideme\">\ <span>Expand description</span>\ </summary>", @@ -1342,7 +1343,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { write!( &mut out, "<h3>Notable traits for <code>{}</code></h3>\ - <pre class=\"content\"><code>", + <pre><code>", impl_.for_.print(cx) ); } @@ -1512,9 +1513,8 @@ fn render_impl( let toggled = !doc_buffer.is_empty(); if toggled { - let method_toggle_class = - if item_type == ItemType::Method { " method-toggle" } else { "" }; - write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class); + let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; + write!(w, "<details class=\"toggle{}\" open><summary>", method_toggle_class); } match &*item.kind { clean::MethodItem(..) | clean::TyMethodItem(_) => { @@ -1730,7 +1730,7 @@ fn render_impl( close_tags.insert_str(0, "</details>"); write!( w, - "<details class=\"rustdoc-toggle implementors-toggle\"{}>", + "<details class=\"toggle implementors-toggle\"{}>", if rendering_params.toggle_open_by_default { " open" } else { "" } ); write!(w, "<summary>") @@ -2769,8 +2769,8 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> { let mut work = VecDeque::new(); let mut process_path = |did: DefId| { - let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone()); - let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern); + let get_extern = || cache.external_paths.get(&did).map(|s| &s.0); + let fqp = cache.exact_paths.get(&did).or_else(get_extern); if let Some(path) = fqp { out.push(join_with_double_colon(&path)); @@ -2921,7 +2921,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite // Look for the example file in the source map if it exists, otherwise return a dummy span let file_span = (|| { let source_map = tcx.sess.source_map(); - let crate_src = tcx.sess.local_crate_source_file.as_ref()?; + let crate_src = tcx.sess.local_crate_source_file()?; let abs_crate_src = crate_src.canonicalize().ok()?; let crate_root = abs_crate_src.parent()?.parent()?; let rel_path = path.strip_prefix(crate_root).ok()?; @@ -2999,14 +2999,13 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite if it.peek().is_some() { write!( w, - "<details class=\"rustdoc-toggle more-examples-toggle\">\ + "<details class=\"toggle more-examples-toggle\">\ <summary class=\"hideme\">\ <span>More examples</span>\ </summary>\ <div class=\"hide-more\">Hide additional examples</div>\ <div class=\"more-scraped-examples\">\ - <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>\ - <div class=\"more-scraped-examples-inner\">" + <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>" ); // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could @@ -3030,7 +3029,7 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite write!(w, "</ul></div>"); } - write!(w, "</div></div></details>"); + write!(w, "</div></details>"); } write!(w, "</div>"); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index acbe3f228..f824c9e3a 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -204,7 +204,7 @@ fn should_hide_fields(n_fields: usize) -> bool { fn toggle_open(w: &mut Buffer, text: impl fmt::Display) { write!( w, - "<details class=\"rustdoc-toggle type-contents-toggle\">\ + "<details class=\"toggle type-contents-toggle\">\ <summary class=\"hideme\">\ <span>Show {}</span>\ </summary>", @@ -531,7 +531,7 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx)); wrap_into_item_decl(w, |w| { - wrap_item(w, "fn", |w| { + wrap_item(w, |w| { render_attributes_in_pre(w, it, ""); w.reserve(header_len); write!( @@ -570,7 +570,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: // Output the trait definition wrap_into_item_decl(w, |w| { - wrap_item(w, "trait", |w| { + wrap_item(w, |w| { render_attributes_in_pre(w, it, ""); write!( w, @@ -732,7 +732,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: document(&mut content, cx, m, Some(t), HeadingOffset::H5); let toggled = !content.is_empty(); if toggled { - write!(w, "<details class=\"rustdoc-toggle method-toggle\" open><summary>"); + let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; + write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>"); } write!(w, "<section id=\"{}\" class=\"method has-srclink\">", id); render_rightside(w, cx, m, t, RenderMode::Normal); @@ -1026,8 +1027,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: .chain(std::iter::once("implementors")) .collect(); if let Some(did) = it.item_id.as_def_id() && - let get_extern = { || cache.external_paths.get(&did).map(|s| s.0.clone()) } && - let Some(fqp) = cache.exact_paths.get(&did).cloned().or_else(get_extern) { + let get_extern = { || cache.external_paths.get(&did).map(|s| &s.0) } && + let Some(fqp) = cache.exact_paths.get(&did).or_else(get_extern) { js_src_path.extend(fqp[..fqp.len() - 1].iter().copied()); js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), fqp.last().unwrap())); } else { @@ -1050,7 +1051,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::TraitAlias) { wrap_into_item_decl(w, |w| { - wrap_item(w, "trait-alias", |w| { + wrap_item(w, |w| { render_attributes_in_pre(w, it, ""); write!( w, @@ -1074,7 +1075,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: & fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::OpaqueTy) { wrap_into_item_decl(w, |w| { - wrap_item(w, "opaque", |w| { + wrap_item(w, |w| { render_attributes_in_pre(w, it, ""); write!( w, @@ -1098,7 +1099,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &cl fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Typedef) { fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) { - wrap_item(w, "typedef", |w| { + wrap_item(w, |w| { render_attributes_in_pre(w, it, ""); write!(w, "{}", visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx)); write!( @@ -1127,7 +1128,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Union) { wrap_into_item_decl(w, |w| { - wrap_item(w, "union", |w| { + wrap_item(w, |w| { render_attributes_in_pre(w, it, ""); render_union(w, it, Some(&s.generics), &s.fields, "", cx); }); @@ -1192,7 +1193,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: let tcx = cx.tcx(); let count_variants = e.variants().count(); wrap_into_item_decl(w, |w| { - wrap_item(w, "enum", |w| { + wrap_item(w, |w| { render_attributes_in_pre(w, it, ""); write!( w, @@ -1219,25 +1220,16 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: w.write_str(" "); let name = v.name.unwrap(); match *v.kind { - clean::VariantItem(ref var) => match var { - // FIXME(#101337): Show discriminant - clean::Variant::CLike(..) => write!(w, "{}", name), - clean::Variant::Tuple(ref s) => { + // FIXME(#101337): Show discriminant + clean::VariantItem(ref var) => match var.kind { + clean::VariantKind::CLike => write!(w, "{}", name), + clean::VariantKind::Tuple(ref s) => { write!(w, "{}(", name); print_tuple_struct_fields(w, cx, s); w.write_str(")"); } - clean::Variant::Struct(ref s) => { - render_struct( - w, - v, - None, - s.ctor_kind, - &s.fields, - " ", - false, - cx, - ); + clean::VariantKind::Struct(ref s) => { + render_struct(w, v, None, None, &s.fields, " ", false, cx); } }, _ => unreachable!(), @@ -1285,25 +1277,28 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: " rightside", ); write!(w, "<h3 class=\"code-header\">{name}", name = variant.name.unwrap()); - if let clean::VariantItem(clean::Variant::Tuple(ref s)) = *variant.kind { + + let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() }; + + if let clean::VariantKind::Tuple(ref s) = variant_data.kind { w.write_str("("); print_tuple_struct_fields(w, cx, s); w.write_str(")"); } w.write_str("</h3></section>"); - use crate::clean::Variant; - - let heading_and_fields = match &*variant.kind { - clean::VariantItem(Variant::Struct(s)) => Some(("Fields", &s.fields)), - // Documentation on tuple variant fields is rare, so to reduce noise we only emit - // the section if at least one field is documented. - clean::VariantItem(Variant::Tuple(fields)) - if fields.iter().any(|f| f.doc_value().is_some()) => - { - Some(("Tuple Fields", fields)) + let heading_and_fields = match &variant_data.kind { + clean::VariantKind::Struct(s) => Some(("Fields", &s.fields)), + clean::VariantKind::Tuple(fields) => { + // Documentation on tuple variant fields is rare, so to reduce noise we only emit + // the section if at least one field is documented. + if fields.iter().any(|f| f.doc_value().is_some()) { + Some(("Tuple Fields", fields)) + } else { + None + } } - _ => None, + clean::VariantKind::CLike => None, }; if let Some((heading, fields)) = heading_and_fields { @@ -1362,17 +1357,17 @@ fn item_proc_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, m: &c let name = it.name.expect("proc-macros always have names"); match m.kind { MacroKind::Bang => { - wrap_item(w, "macro", |w| { + wrap_item(w, |w| { write!(w, "{}!() {{ /* proc-macro */ }}", name); }); } MacroKind::Attr => { - wrap_item(w, "attr", |w| { + wrap_item(w, |w| { write!(w, "#[{}]", name); }); } MacroKind::Derive => { - wrap_item(w, "derive", |w| { + wrap_item(w, |w| { write!(w, "#[derive({})]", name); if !m.helpers.is_empty() { w.push_str("\n{\n"); @@ -1406,7 +1401,7 @@ fn item_primitive(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) { wrap_into_item_decl(w, |w| { - wrap_item(w, "const", |w| { + wrap_item(w, |w| { let tcx = cx.tcx(); render_attributes_in_code(w, it); @@ -1456,7 +1451,7 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Struct) { wrap_into_item_decl(w, |w| { - wrap_item(w, "struct", |w| { + wrap_item(w, |w| { render_attributes_in_code(w, it); render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx); }); @@ -1509,7 +1504,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Static) { wrap_into_item_decl(w, |w| { - wrap_item(w, "static", |w| { + wrap_item(w, |w| { render_attributes_in_code(w, it); write!( w, @@ -1526,7 +1521,7 @@ fn item_static(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean fn item_foreign_type(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item) { wrap_into_item_decl(w, |w| { - wrap_item(w, "foreigntype", |w| { + wrap_item(w, |w| { w.write_str("extern {\n"); render_attributes_in_code(w, it); write!( @@ -1623,11 +1618,11 @@ where w.write_str("</div>") } -fn wrap_item<F>(w: &mut Buffer, item_name: &str, f: F) +fn wrap_item<F>(w: &mut Buffer, f: F) where F: FnOnce(&mut Buffer), { - w.write_fmt(format_args!("<pre class=\"rust {}\"><code>", item_name)); + w.write_str(r#"<pre class="rust"><code>"#); f(w); w.write_str("</code></pre>"); } @@ -1845,7 +1840,7 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) { if item.is_non_exhaustive() { write!( w, - "<details class=\"rustdoc-toggle non-exhaustive\">\ + "<details class=\"toggle non-exhaustive\">\ <summary class=\"hideme\"><span>{}</span></summary>\ <div class=\"docblock\">", { diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 8eb9c07f8..5b0caac09 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -3,7 +3,6 @@ use std::collections::BTreeMap; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::TyCtxt; -use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::Symbol; use serde::ser::{Serialize, SerializeStruct, Serializer}; @@ -24,18 +23,19 @@ pub(crate) fn build_index<'tcx>( tcx: TyCtxt<'tcx>, ) -> String { let mut itemid_to_pathid = FxHashMap::default(); + let mut primitives = FxHashMap::default(); let mut crate_paths = vec![]; // Attach all orphan items to the type's definition if the type // has since been learned. for &OrphanImplItem { parent, ref item, ref impl_generics } in &cache.orphan_impl_items { - if let Some(&(ref fqp, _)) = cache.paths.get(&parent) { + if let Some((fqp, _)) = cache.paths.get(&parent) { let desc = item .doc_value() .map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(cache))); cache.search_index.push(IndexItem { ty: item.type_(), - name: item.name.unwrap().to_string(), + name: item.name.unwrap(), path: join_with_double_colon(&fqp[..fqp.len() - 1]), desc, parent: Some(parent), @@ -58,8 +58,8 @@ pub(crate) fn build_index<'tcx>( // Sort search index items. This improves the compressibility of the search index. cache.search_index.sort_unstable_by(|k1, k2| { // `sort_unstable_by_key` produces lifetime errors - let k1 = (&k1.path, &k1.name, &k1.ty, &k1.parent); - let k2 = (&k2.path, &k2.name, &k2.ty, &k2.parent); + let k1 = (&k1.path, k1.name.as_str(), &k1.ty, &k1.parent); + let k2 = (&k2.path, k2.name.as_str(), &k2.ty, &k2.parent); std::cmp::Ord::cmp(&k1, &k2) }); @@ -78,16 +78,45 @@ pub(crate) fn build_index<'tcx>( // First, on function signatures let mut search_index = std::mem::replace(&mut cache.search_index, Vec::new()); for item in search_index.iter_mut() { + fn insert_into_map<F: std::hash::Hash + Eq>( + ty: &mut RenderType, + map: &mut FxHashMap<F, usize>, + itemid: F, + lastpathid: &mut usize, + crate_paths: &mut Vec<(ItemType, Symbol)>, + item_type: ItemType, + path: Symbol, + ) { + match map.entry(itemid) { + Entry::Occupied(entry) => ty.id = Some(RenderTypeId::Index(*entry.get())), + Entry::Vacant(entry) => { + let pathid = *lastpathid; + entry.insert(pathid); + *lastpathid += 1; + crate_paths.push((item_type, path)); + ty.id = Some(RenderTypeId::Index(pathid)); + } + } + } + fn convert_render_type( ty: &mut RenderType, cache: &mut Cache, itemid_to_pathid: &mut FxHashMap<ItemId, usize>, + primitives: &mut FxHashMap<Symbol, usize>, lastpathid: &mut usize, crate_paths: &mut Vec<(ItemType, Symbol)>, ) { if let Some(generics) = &mut ty.generics { for item in generics { - convert_render_type(item, cache, itemid_to_pathid, lastpathid, crate_paths); + convert_render_type( + item, + cache, + itemid_to_pathid, + primitives, + lastpathid, + crate_paths, + ); } } let Cache { ref paths, ref external_paths, .. } = *cache; @@ -95,33 +124,37 @@ pub(crate) fn build_index<'tcx>( assert!(ty.generics.is_some()); return; }; - let (itemid, path, item_type) = match id { + match id { RenderTypeId::DefId(defid) => { if let Some(&(ref fqp, item_type)) = paths.get(&defid).or_else(|| external_paths.get(&defid)) { - (ItemId::DefId(defid), *fqp.last().unwrap(), item_type) + insert_into_map( + ty, + itemid_to_pathid, + ItemId::DefId(defid), + lastpathid, + crate_paths, + item_type, + *fqp.last().unwrap(), + ); } else { ty.id = None; - return; } } - RenderTypeId::Primitive(primitive) => ( - ItemId::Primitive(primitive, LOCAL_CRATE), - primitive.as_sym(), - ItemType::Primitive, - ), - RenderTypeId::Index(_) => return, - }; - match itemid_to_pathid.entry(itemid) { - Entry::Occupied(entry) => ty.id = Some(RenderTypeId::Index(*entry.get())), - Entry::Vacant(entry) => { - let pathid = *lastpathid; - entry.insert(pathid); - *lastpathid += 1; - crate_paths.push((item_type, path)); - ty.id = Some(RenderTypeId::Index(pathid)); + RenderTypeId::Primitive(primitive) => { + let sym = primitive.as_sym(); + insert_into_map( + ty, + primitives, + sym, + lastpathid, + crate_paths, + ItemType::Primitive, + sym, + ); } + RenderTypeId::Index(_) => {} } } if let Some(search_type) = &mut item.search_type { @@ -130,6 +163,7 @@ pub(crate) fn build_index<'tcx>( item, cache, &mut itemid_to_pathid, + &mut primitives, &mut lastpathid, &mut crate_paths, ); @@ -139,6 +173,7 @@ pub(crate) fn build_index<'tcx>( item, cache, &mut itemid_to_pathid, + &mut primitives, &mut lastpathid, &mut crate_paths, ); @@ -205,7 +240,7 @@ pub(crate) fn build_index<'tcx>( )?; crate_data.serialize_field( "n", - &self.items.iter().map(|item| &item.name).collect::<Vec<_>>(), + &self.items.iter().map(|item| item.name.as_str()).collect::<Vec<_>>(), )?; crate_data.serialize_field( "q", @@ -264,7 +299,7 @@ pub(crate) fn build_index<'tcx>( )?; crate_data.serialize_field( "p", - &self.paths.iter().map(|(it, s)| (it, s.to_string())).collect::<Vec<_>>(), + &self.paths.iter().map(|(it, s)| (it, s.as_str())).collect::<Vec<_>>(), )?; if has_aliases { crate_data.serialize_field("a", &self.aliases)?; @@ -322,8 +357,7 @@ fn get_index_type_id(clean_type: &clean::Type) -> Option<RenderTypeId> { match *clean_type { clean::Type::Path { ref path, .. } => Some(RenderTypeId::DefId(path.def_id())), clean::DynTrait(ref bounds, _) => { - let path = &bounds[0].trait_; - Some(RenderTypeId::DefId(path.def_id())) + bounds.get(0).map(|b| RenderTypeId::DefId(b.trait_.def_id())) } clean::Primitive(p) => Some(RenderTypeId::Primitive(p)), clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => { @@ -539,7 +573,7 @@ fn get_fn_inputs_and_outputs<'tcx>( let decl = &func.decl; let combined_generics; - let (self_, generics) = if let Some(&(ref impl_self, ref impl_generics)) = impl_generics { + let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_generics { match (impl_generics.is_empty(), func.generics.is_empty()) { (true, _) => (Some(impl_self), &func.generics), (_, true) => (Some(impl_self), impl_generics), diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 94d8a9fec..bc8badad3 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -1,8 +1,9 @@ +use std::cell::RefCell; use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufReader}; use std::path::{Component, Path}; -use std::rc::Rc; +use std::rc::{Rc, Weak}; use itertools::Itertools; use rustc_data_structures::flock; @@ -184,23 +185,26 @@ pub(super) fn write_shared( use std::ffi::OsString; - #[derive(Debug)] + #[derive(Debug, Default)] struct Hierarchy { + parent: Weak<Self>, elem: OsString, - children: FxHashMap<OsString, Hierarchy>, - elems: FxHashSet<OsString>, + children: RefCell<FxHashMap<OsString, Rc<Self>>>, + elems: RefCell<FxHashSet<OsString>>, } impl Hierarchy { - fn new(elem: OsString) -> Hierarchy { - Hierarchy { elem, children: FxHashMap::default(), elems: FxHashSet::default() } + fn with_parent(elem: OsString, parent: &Rc<Self>) -> Self { + Self { elem, parent: Rc::downgrade(parent), ..Self::default() } } fn to_json_string(&self) -> String { - let mut subs: Vec<&Hierarchy> = self.children.values().collect(); + let borrow = self.children.borrow(); + let mut subs: Vec<_> = borrow.values().collect(); subs.sort_unstable_by(|a, b| a.elem.cmp(&b.elem)); let mut files = self .elems + .borrow() .iter() .map(|s| format!("\"{}\"", s.to_str().expect("invalid osstring conversion"))) .collect::<Vec<_>>(); @@ -220,36 +224,52 @@ pub(super) fn write_shared( files = files ) } - } - if cx.include_sources { - let mut hierarchy = Hierarchy::new(OsString::new()); - for source in cx - .shared - .local_sources - .iter() - .filter_map(|p| p.0.strip_prefix(&cx.shared.src_root).ok()) - { - let mut h = &mut hierarchy; - let mut elems = source + fn add_path(self: &Rc<Self>, path: &Path) { + let mut h = Rc::clone(&self); + let mut elems = path .components() .filter_map(|s| match s { Component::Normal(s) => Some(s.to_owned()), + Component::ParentDir => Some(OsString::from("..")), _ => None, }) .peekable(); loop { let cur_elem = elems.next().expect("empty file path"); + if cur_elem == ".." { + if let Some(parent) = h.parent.upgrade() { + h = parent; + } + continue; + } if elems.peek().is_none() { - h.elems.insert(cur_elem); + h.elems.borrow_mut().insert(cur_elem); break; } else { - let e = cur_elem.clone(); - h = h.children.entry(cur_elem.clone()).or_insert_with(|| Hierarchy::new(e)); + let entry = Rc::clone( + h.children + .borrow_mut() + .entry(cur_elem.clone()) + .or_insert_with(|| Rc::new(Self::with_parent(cur_elem, &h))), + ); + h = entry; } } } + } + if cx.include_sources { + let hierarchy = Rc::new(Hierarchy::default()); + for source in cx + .shared + .local_sources + .iter() + .filter_map(|p| p.0.strip_prefix(&cx.shared.src_root).ok()) + { + hierarchy.add_path(source); + } + let hierarchy = Rc::try_unwrap(hierarchy).unwrap(); let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix)); let make_sources = || { let (mut all_sources, _krates) = @@ -325,7 +345,7 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; }; let content = format!( - "<h1 class=\"fqn\">List of all crates</h1><ul class=\"all-items\">{}</ul>", + "<h1>List of all crates</h1><ul class=\"all-items\">{}</ul>", krates .iter() .map(|s| { |