diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 84cf8878af8..5134d916320 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -567,6 +567,7 @@ symbols! { doc_spotlight, doctest, document_private_items, + dotdot: "..", dotdot_in_tuple_patterns, dotdoteq_in_patterns, dreg, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index b91ba5523e0..a2e612955b3 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -9,7 +9,6 @@ use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::definitions::DefPathData; use rustc_hir::Mutability; use rustc_metadata::creader::{CStore, LoadedMacro}; use rustc_middle::ty::{self, TyCtxt}; @@ -164,12 +163,10 @@ crate fn load_attrs<'hir>(cx: &DocContext<'hir>, did: DefId) -> Attrs<'hir> { /// These names are used later on by HTML rendering to generate things like /// source links back to the original item. crate fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemType) { - let crate_name = cx.tcx.crate_name(did.krate).to_string(); + let crate_name = cx.tcx.crate_name(did.krate); - let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| { - // Filter out extern blocks - (elem.data != DefPathData::ForeignMod).then(|| elem.data.to_string()) - }); + let relative = + cx.tcx.def_path(did).data.into_iter().filter_map(|elem| elem.data.get_opt_name()); let fqn = if let ItemType::Macro = kind { // Check to see if it is a macro 2.0 or built-in macro if matches!( diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 6b9ccd37cfb..a8fef4a3178 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -4,13 +4,14 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX}; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::ty::TyCtxt; -use rustc_span::symbol::sym; +use rustc_span::{sym, Symbol}; use crate::clean::{self, types::ExternalLocation, ExternalCrate, ItemId, PrimitiveType}; use crate::core::DocContext; use crate::fold::DocFolder; use crate::formats::item_type::ItemType; use crate::formats::Impl; +use crate::html::format::join_with_double_colon; use crate::html::markdown::short_markdown_summary; use crate::html::render::search_index::get_function_type_for_search; use crate::html::render::IndexItem; @@ -39,11 +40,11 @@ crate struct Cache { /// URLs when a type is being linked to. External paths are not located in /// this map because the `External` type itself has all the information /// necessary. - crate paths: FxHashMap, ItemType)>, + crate paths: FxHashMap, ItemType)>, /// Similar to `paths`, but only holds external paths. This is only used for /// generating explicit hyperlinks to other crates. - crate external_paths: FxHashMap, ItemType)>, + crate external_paths: FxHashMap, ItemType)>, /// Maps local `DefId`s of exported types to fully qualified paths. /// Unlike 'paths', this mapping ignores any renames that occur @@ -55,7 +56,7 @@ crate struct Cache { /// to the path used if the corresponding type is inlined. By /// doing this, we can detect duplicate impls on a trait page, and only display /// the impl for the inlined type. - crate exact_paths: FxHashMap>, + crate exact_paths: FxHashMap>, /// This map contains information about all known traits of this crate. /// Implementations of a crate should inherit the documentation of the @@ -92,7 +93,7 @@ crate struct Cache { crate masked_crates: FxHashSet, // Private fields only used when initially crawling a crate to build a cache - stack: Vec, + stack: Vec, parent_stack: Vec, parent_is_trait_impl: bool, stripped_mod: bool, @@ -155,7 +156,7 @@ impl Cache { let dst = &render_options.output; let location = e.location(extern_url, extern_url_takes_precedence, dst, tcx); cx.cache.extern_locations.insert(e.crate_num, location); - cx.cache.external_paths.insert(e.def_id(), (vec![name.to_string()], ItemType::Module)); + cx.cache.external_paths.insert(e.def_id(), (vec![name], ItemType::Module)); } // FIXME: avoid this clone (requires implementing Default manually) @@ -164,10 +165,9 @@ impl Cache { let crate_name = tcx.crate_name(def_id.krate); // Recall that we only allow primitive modules to be at the root-level of the crate. // If that restriction is ever lifted, this will have to include the relative paths instead. - cx.cache.external_paths.insert( - def_id, - (vec![crate_name.to_string(), prim.as_sym().to_string()], ItemType::Primitive), - ); + cx.cache + .external_paths + .insert(def_id, (vec![crate_name, prim.as_sym()], ItemType::Primitive)); } krate = CacheBuilder { tcx, cache: &mut cx.cache }.fold_crate(krate); @@ -299,7 +299,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { self.cache.search_index.push(IndexItem { ty: item.type_(), name: s.to_string(), - path: path.join("::"), + path: join_with_double_colon(path), desc, parent, parent_idx: None, @@ -320,7 +320,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { // Keep track of the fully qualified path for this item. let pushed = match item.name { Some(n) if !n.is_empty() => { - self.cache.stack.push(n.to_string()); + self.cache.stack.push(n); true } _ => false, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 981eb9589e9..a4cdef9358b 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -19,6 +19,7 @@ use rustc_middle::ty; use rustc_middle::ty::DefIdTree; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::CRATE_DEF_INDEX; +use rustc_span::{sym, Symbol}; use rustc_target::spec::abi::Abi; use crate::clean::{ @@ -502,11 +503,45 @@ crate enum HrefError { NotInExternalCache, } +// This mostly works with sequences of symbols, but sometimes the first item +// comes from a string, and in that case we want to trim any trailing `/`. +// `syms` can be empty. +crate fn join_with_slash(first: Option<&str>, syms: &[Symbol]) -> String { + // 64 bytes covers 99.9%+ of cases. + let mut s = String::with_capacity(64); + if let Some(first) = first { + s.push_str(first.trim_end_matches('/')); + if !syms.is_empty() { + s.push('/'); + } + } + if !syms.is_empty() { + s.push_str(&syms[0].as_str()); + for sym in &syms[1..] { + s.push('/'); + s.push_str(&sym.as_str()); + } + } + s +} + +// Panics if `syms` is empty. +crate fn join_with_double_colon(syms: &[Symbol]) -> String { + // 64 bytes covers 99.9%+ of cases. + let mut s = String::with_capacity(64); + s.push_str(&syms[0].as_str()); + for sym in &syms[1..] { + s.push_str("::"); + s.push_str(&sym.as_str()); + } + s +} + crate fn href_with_root_path( did: DefId, cx: &Context<'_>, root_path: Option<&str>, -) -> Result<(String, ItemType, Vec), HrefError> { +) -> Result<(String, ItemType, Vec), HrefError> { let tcx = cx.tcx(); let def_kind = tcx.def_kind(did); let did = match def_kind { @@ -518,7 +553,7 @@ crate fn href_with_root_path( }; let cache = cx.cache(); let relative_to = &cx.current; - fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] { + fn to_module_fqp(shortty: ItemType, fqp: &[Symbol]) -> &[Symbol] { if shortty == ItemType::Module { fqp } else { &fqp[..fqp.len() - 1] } } @@ -533,9 +568,9 @@ crate fn href_with_root_path( let mut is_remote = false; let (fqp, shortty, mut url_parts) = match cache.paths.get(&did) { Some(&(ref fqp, shortty)) => (fqp, shortty, { - let module_fqp = to_module_fqp(shortty, fqp); + let module_fqp = to_module_fqp(shortty, fqp.as_slice()); debug!(?fqp, ?shortty, ?module_fqp); - href_relative_parts(module_fqp, relative_to) + href_relative_parts(module_fqp, relative_to).collect() }), None => { if let Some(&(ref fqp, shortty)) = cache.external_paths.get(&did) { @@ -548,10 +583,12 @@ crate fn href_with_root_path( is_remote = true; let s = s.trim_end_matches('/'); let mut builder = UrlPartsBuilder::singleton(s); - builder.extend(module_fqp.iter().map(String::as_str)); + builder.extend(module_fqp.iter().copied()); builder } - ExternalLocation::Local => href_relative_parts(module_fqp, relative_to), + ExternalLocation::Local => { + href_relative_parts(module_fqp, relative_to).collect() + } ExternalLocation::Unknown => return Err(HrefError::DocumentationNotBuilt), }, ) @@ -567,45 +604,50 @@ crate fn href_with_root_path( } } debug!(?url_parts); - let last = &fqp.last().unwrap()[..]; match shortty { ItemType::Module => { url_parts.push("index.html"); } _ => { - let filename = format!("{}.{}.html", shortty.as_str(), last); - url_parts.push(&filename); + let prefix = shortty.as_str(); + let last = fqp.last().unwrap(); + url_parts.push_fmt(format_args!("{}.{}.html", prefix, last)); } } Ok((url_parts.finish(), shortty, fqp.to_vec())) } -crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec), HrefError> { +crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec), HrefError> { href_with_root_path(did, cx, None) } /// Both paths should only be modules. /// This is because modules get their own directories; that is, `std::vec` and `std::vec::Vec` will /// both need `../iter/trait.Iterator.html` to get at the iterator trait. -crate fn href_relative_parts(fqp: &[String], relative_to_fqp: &[String]) -> UrlPartsBuilder { +crate fn href_relative_parts<'fqp>( + fqp: &'fqp [Symbol], + relative_to_fqp: &[Symbol], +) -> Box + 'fqp> { for (i, (f, r)) in fqp.iter().zip(relative_to_fqp.iter()).enumerate() { // e.g. linking to std::iter from std::vec (`dissimilar_part_count` will be 1) if f != r { let dissimilar_part_count = relative_to_fqp.len() - i; - let fqp_module = fqp[i..fqp.len()].iter().map(String::as_str); - return iter::repeat("..").take(dissimilar_part_count).chain(fqp_module).collect(); + let fqp_module = &fqp[i..fqp.len()]; + return box iter::repeat(sym::dotdot) + .take(dissimilar_part_count) + .chain(fqp_module.iter().copied()); } } // e.g. linking to std::sync::atomic from std::sync if relative_to_fqp.len() < fqp.len() { - fqp[relative_to_fqp.len()..fqp.len()].iter().map(String::as_str).collect() + box fqp[relative_to_fqp.len()..fqp.len()].iter().copied() // e.g. linking to std::sync from std::sync::atomic } else if fqp.len() < relative_to_fqp.len() { let dissimilar_part_count = relative_to_fqp.len() - fqp.len(); - iter::repeat("..").take(dissimilar_part_count).collect() + box iter::repeat(sym::dotdot).take(dissimilar_part_count) // linking to the same module } else { - UrlPartsBuilder::new() + box iter::empty() } } @@ -632,14 +674,14 @@ fn resolved_path<'cx>( if let Ok((_, _, fqp)) = href(did, cx) { format!( "{}::{}", - fqp[..fqp.len() - 1].join("::"), - anchor(did, fqp.last().unwrap(), cx) + join_with_double_colon(&fqp[..fqp.len() - 1]), + anchor(did, *fqp.last().unwrap(), cx) ) } else { last.name.to_string() } } else { - anchor(did, last.name.as_str(), cx).to_string() + anchor(did, last.name, cx).to_string() }; write!(w, "{}{}", path, last.args.print(cx))?; } @@ -668,30 +710,31 @@ fn primitive_link( needs_termination = true; } Some(&def_id) => { - let cname_sym; let loc = match m.extern_locations[&def_id.krate] { ExternalLocation::Remote(ref s) => { - cname_sym = ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()); - Some(vec![s.trim_end_matches('/'), cname_sym.as_str()]) + let cname_sym = ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()); + let builder: UrlPartsBuilder = + [s.as_str().trim_end_matches('/'), cname_sym.as_str()] + .into_iter() + .collect(); + Some(builder) } ExternalLocation::Local => { - cname_sym = ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()); - Some(if cx.current.first().map(|x| &x[..]) == Some(cname_sym.as_str()) { - iter::repeat("..").take(cx.current.len() - 1).collect() + let cname_sym = ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()); + Some(if cx.current.first() == Some(&cname_sym) { + iter::repeat(sym::dotdot).take(cx.current.len() - 1).collect() } else { - let cname = iter::once(cname_sym.as_str()); - iter::repeat("..").take(cx.current.len()).chain(cname).collect() + iter::repeat(sym::dotdot) + .take(cx.current.len()) + .chain(iter::once(cname_sym)) + .collect() }) } ExternalLocation::Unknown => None, }; - if let Some(loc) = loc { - write!( - f, - "", - loc.join("/"), - prim.as_sym() - )?; + if let Some(mut loc) = loc { + loc.push_fmt(format_args!("primitive.{}.html", prim.as_sym())); + write!(f, "", loc.finish())?; needs_termination = true; } } @@ -730,7 +773,7 @@ fn tybounds<'a, 'tcx: 'a>( crate fn anchor<'a, 'cx: 'a>( did: DefId, - text: &'a str, + text: Symbol, cx: &'cx Context<'_>, ) -> impl fmt::Display + 'a { let parts = href(did, cx); @@ -742,8 +785,8 @@ crate fn anchor<'a, 'cx: 'a>( short_ty, url, short_ty, - fqp.join("::"), - text + join_with_double_colon(&fqp), + &*text.as_str() ) } else { write!(f, "{}", text) @@ -960,7 +1003,7 @@ fn fmt_type<'cx>( url = url, shortty = ItemType::AssocType, name = name, - path = path.join("::") + path = join_with_double_colon(path), )?; } _ => write!(f, "{}", name)?, @@ -1270,7 +1313,7 @@ impl clean::Visibility { debug!("path={:?}", path); // modified from `resolved_path()` to work with `DefPathData` let last_name = path.data.last().unwrap().data.get_opt_name().unwrap(); - let anchor = anchor(vis_did, last_name.as_str(), cx).to_string(); + let anchor = anchor(vis_did, last_name, cx).to_string(); let mut s = "pub(in ".to_owned(); for seg in &path.data[..path.data.len() - 1] { diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 4f3455a9208..865e14f694d 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::source_map::FileName; -use rustc_span::symbol::sym; +use rustc_span::{sym, Symbol}; use super::print_item::{full_path, item_path, print_item}; use super::search_index::build_index; @@ -29,7 +29,7 @@ use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::formats::FormatRenderer; use crate::html::escape::Escape; -use crate::html::format::Buffer; +use crate::html::format::{join_with_double_colon, Buffer}; use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap}; use crate::html::{layout, sources}; use crate::scrape_examples::AllCallLocations; @@ -45,7 +45,7 @@ use crate::try_err; crate struct Context<'tcx> { /// Current hierarchy of components leading down to what's currently being /// rendered - pub(crate) current: Vec, + pub(crate) current: Vec, /// The current destination folder of where HTML artifacts should be placed. /// This changes as the context descends into the module hierarchy. crate dst: PathBuf, @@ -176,7 +176,7 @@ impl<'tcx> Context<'tcx> { title.push_str(" in "); } // No need to include the namespace for primitive types and keywords - title.push_str(&self.current.join("::")); + title.push_str(&join_with_double_colon(&self.current)); }; title.push_str(" - Rust"); let tyname = it.type_(); @@ -225,18 +225,18 @@ impl<'tcx> Context<'tcx> { if let Some(&(ref names, ty)) = self.cache().paths.get(&it.def_id.expect_def_id()) { let mut path = String::new(); for name in &names[..names.len() - 1] { - path.push_str(name); + path.push_str(&name.as_str()); path.push('/'); } - path.push_str(&item_path(ty, names.last().unwrap())); + path.push_str(&item_path(ty, &names.last().unwrap().as_str())); match self.shared.redirections { Some(ref redirections) => { let mut current_path = String::new(); for name in &self.current { - current_path.push_str(name); + current_path.push_str(&name.as_str()); current_path.push('/'); } - current_path.push_str(&item_path(ty, names.last().unwrap())); + current_path.push_str(&item_path(ty, &names.last().unwrap().as_str())); redirections.borrow_mut().insert(current_path, path); } None => return layout::redirect(&format!("{}{}", self.root_path(), path)), @@ -634,8 +634,8 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> { self.render_redirect_pages = item.is_stripped(); } let scx = &self.shared; - let item_name = item.name.as_ref().unwrap().to_string(); - self.dst.push(&item_name); + let item_name = item.name.unwrap(); + self.dst.push(&*item_name.as_str()); self.current.push(item_name); info!("Recursing into {}", self.dst.display()); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index dda74904931..8ba9a6dccac 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -69,8 +69,9 @@ use crate::formats::item_type::ItemType; use crate::formats::{AssocItemRender, Impl, RenderMode}; use crate::html::escape::Escape; use crate::html::format::{ - href, print_abi_with_space, print_constness_with_space, print_default_space, - print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace, + href, join_with_double_colon, print_abi_with_space, print_constness_with_space, + print_default_space, print_generic_bounds, print_where_clause, Buffer, HrefError, + PrintWithSpace, }; use crate::html::highlight; use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine}; @@ -2515,7 +2516,7 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec { let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern); if let Some(path) = fqp { - out.push(path.join("::")); + out.push(join_with_double_colon(&path)); } }; diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 5431bd8565b..6f7ba8aff5d 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -26,7 +26,8 @@ use crate::formats::item_type::ItemType; use crate::formats::{AssocItemRender, Impl, RenderMode}; use crate::html::escape::Escape; use crate::html::format::{ - print_abi_with_space, print_constness_with_space, print_where_clause, Buffer, PrintWithSpace, + join_with_double_colon, join_with_slash, print_abi_with_space, print_constness_with_space, + print_where_clause, Buffer, PrintWithSpace, }; use crate::html::highlight; use crate::html::layout::Page; @@ -40,9 +41,9 @@ const ITEM_TABLE_ROW_OPEN: &str = "
"; const ITEM_TABLE_ROW_CLOSE: &str = "
"; // A component in a `use` path, like `string` in std::string::ToString -struct PathComponent<'a> { +struct PathComponent { path: String, - name: &'a str, + name: Symbol, } #[derive(Template)] @@ -53,7 +54,7 @@ struct ItemVars<'a> { typ: &'a str, name: &'a str, item_type: &'a str, - path_components: Vec>, + path_components: Vec, stability_since_raw: &'a str, src_href: Option<&'a str>, } @@ -121,7 +122,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, .take(amt) .map(|(i, component)| PathComponent { path: "../".repeat(cur.len() - i - 1), - name: component, + name: *component, }) .collect() }; @@ -304,22 +305,18 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl w.write_str(ITEM_TABLE_ROW_OPEN); match *src { - Some(ref src) => write!( + Some(src) => write!( w, "
{}extern crate {} as {};", myitem.visibility.print_with_space(myitem.def_id, cx), - anchor(myitem.def_id.expect_def_id(), src.as_str(), cx), + anchor(myitem.def_id.expect_def_id(), src, cx), myitem.name.as_ref().unwrap(), ), None => write!( w, "
{}extern crate {};", myitem.visibility.print_with_space(myitem.def_id, cx), - anchor( - myitem.def_id.expect_def_id(), - myitem.name.as_ref().unwrap().as_str(), - cx - ), + anchor(myitem.def_id.expect_def_id(), *myitem.name.as_ref().unwrap(), cx), ), } w.write_str("
"); @@ -864,10 +861,10 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra ", root_path = vec![".."; cx.current.len()].join("/"), path = if it.def_id.is_local() { - cx.current.join("/") + join_with_slash(None, &cx.current) } else { let (ref path, _) = cache.external_paths[&it.def_id.expect_def_id()]; - path[..path.len() - 1].join("/") + join_with_slash(None, &path[..path.len() - 1]) }, ty = it.type_(), name = *it.name.as_ref().unwrap() @@ -1410,7 +1407,7 @@ crate fn compare_names(mut lhs: &str, mut rhs: &str) -> Ordering { } pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String { - let mut s = cx.current.join("::"); + let mut s = join_with_double_colon(&cx.current); s.push_str("::"); s.push_str(item.name.unwrap().as_str()); s diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 0fbe090f219..87138b9571c 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -10,6 +10,7 @@ use crate::clean; use crate::clean::types::{FnRetTy, Function, GenericBound, Generics, Type, WherePredicate}; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; +use crate::html::format::join_with_double_colon; use crate::html::markdown::short_markdown_summary; use crate::html::render::{IndexItem, IndexItemFunctionType, RenderType, TypeWithKind}; @@ -28,7 +29,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt< cache.search_index.push(IndexItem { ty: item.type_(), name: item.name.unwrap().to_string(), - path: fqp[..fqp.len() - 1].join("::"), + path: join_with_double_colon(&fqp[..fqp.len() - 1]), desc, parent: Some(did), parent_idx: None, @@ -102,7 +103,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt< struct CrateData<'a> { doc: String, items: Vec<&'a IndexItem>, - paths: Vec<(ItemType, String)>, + paths: Vec<(ItemType, Symbol)>, // The String is alias name and the vec is the list of the elements with this alias. // // To be noted: the `usize` elements are indexes to `items`. @@ -154,7 +155,10 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt< "f", &self.items.iter().map(|item| &item.search_type).collect::>(), )?; - crate_data.serialize_field("p", &self.paths)?; + crate_data.serialize_field( + "p", + &self.paths.iter().map(|(it, s)| (it, s.to_string())).collect::>(), + )?; if has_aliases { crate_data.serialize_field("a", &self.aliases)?; } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 2e763dbd8fe..e6900332a04 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -562,7 +562,7 @@ pub(super) fn write_shared( let mut mydst = dst.clone(); for part in &remote_path[..remote_path.len() - 1] { - mydst.push(part); + mydst.push(part.to_string()); } cx.shared.ensure_dir(&mydst)?; mydst.push(&format!("{}.{}.js", remote_item_type, remote_path[remote_path.len() - 1])); diff --git a/src/librustdoc/html/tests.rs b/src/librustdoc/html/tests.rs index dee9f5e5038..437d3995e29 100644 --- a/src/librustdoc/html/tests.rs +++ b/src/librustdoc/html/tests.rs @@ -1,44 +1,50 @@ use crate::html::format::href_relative_parts; +use rustc_span::{sym, Symbol}; -fn assert_relative_path(expected: &str, relative_to_fqp: &[&str], fqp: &[&str]) { - let relative_to_fqp: Vec = relative_to_fqp.iter().copied().map(String::from).collect(); - let fqp: Vec = fqp.iter().copied().map(String::from).collect(); - assert_eq!(expected, href_relative_parts(&fqp, &relative_to_fqp).finish()); +fn assert_relative_path(expected: &[Symbol], relative_to_fqp: &[Symbol], fqp: &[Symbol]) { + // No `create_default_session_globals_then` call is needed here because all + // the symbols used are static, and no `Symbol::intern` calls occur. + assert_eq!(expected, href_relative_parts(&fqp, &relative_to_fqp).collect::>()); } #[test] fn href_relative_parts_basic() { - let relative_to_fqp = &["std", "vec"]; - let fqp = &["std", "iter"]; - assert_relative_path("../iter", relative_to_fqp, fqp); + let relative_to_fqp = &[sym::std, sym::vec]; + let fqp = &[sym::std, sym::iter]; + assert_relative_path(&[sym::dotdot, sym::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); + let relative_to_fqp = &[sym::std, sym::vec]; + let fqp = &[sym::std]; + assert_relative_path(&[sym::dotdot], 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); + let relative_to_fqp = &[sym::std, sym::vec]; + let fqp = &[sym::core, sym::iter]; + assert_relative_path(&[sym::dotdot, sym::dotdot, sym::core, sym::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); + let relative_to_fqp = &[sym::std, sym::vec]; + let fqp = &[sym::std, sym::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); + let relative_to_fqp = &[sym::std]; + let fqp = &[sym::std, sym::vec]; + assert_relative_path(&[sym::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); + let fqp = &[sym::std]; + assert_relative_path(&[sym::std], relative_to_fqp, fqp); } diff --git a/src/librustdoc/html/url_parts_builder.rs b/src/librustdoc/html/url_parts_builder.rs index 918d5e6bd1b..5c1557078aa 100644 --- a/src/librustdoc/html/url_parts_builder.rs +++ b/src/librustdoc/html/url_parts_builder.rs @@ -1,3 +1,7 @@ +use std::fmt::{self, Write}; + +use rustc_span::Symbol; + /// A builder that allows efficiently and easily constructing the part of a URL /// after the domain: `nightly/core/str/struct.Bytes.html`. /// @@ -10,6 +14,7 @@ crate struct UrlPartsBuilder { impl UrlPartsBuilder { /// Create an empty buffer. + #[allow(dead_code)] crate fn new() -> Self { Self { buf: String::new() } } @@ -62,6 +67,13 @@ impl UrlPartsBuilder { self.buf.push_str(part); } + crate fn push_fmt(&mut self, args: fmt::Arguments<'_>) { + if !self.buf.is_empty() { + self.buf.push('/'); + } + self.buf.write_fmt(args).unwrap() + } + /// Push a component onto the front of the buffer. /// /// # Examples @@ -115,5 +127,26 @@ impl<'a> Extend<&'a str> for UrlPartsBuilder { } } +impl FromIterator for UrlPartsBuilder { + fn from_iter>(iter: T) -> Self { + // This code has to be duplicated from the `&str` impl because of + // `Symbol::as_str`'s lifetimes. + let iter = iter.into_iter(); + let mut builder = Self::with_capacity_bytes(AVG_PART_LENGTH * iter.size_hint().0); + iter.for_each(|part| builder.push(part.as_str())); + builder + } +} + +impl Extend for UrlPartsBuilder { + fn extend>(&mut self, iter: T) { + // This code has to be duplicated from the `&str` impl because of + // `Symbol::as_str`'s lifetimes. + let iter = iter.into_iter(); + self.buf.reserve(AVG_PART_LENGTH * iter.size_hint().0); + iter.for_each(|part| self.push(part.as_str())); + } +} + #[cfg(test)] mod tests; diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 88a5c0c5ca2..81fbfd9fdbd 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -120,7 +120,7 @@ impl<'tcx> JsonRenderer<'tcx> { }) .0 .last() - .map(Clone::clone), + .map(|s| s.to_string()), visibility: types::Visibility::Public, inner: types::ItemEnum::Trait(trait_item.clone().into_tcx(self.tcx)), span: None, @@ -230,7 +230,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { from_item_id(k.into()), types::ItemSummary { crate_id: k.krate.as_u32(), - path, + path: path.iter().map(|s| s.to_string()).collect(), kind: kind.into_tcx(self.tcx), }, ) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 6f1736afc3b..90cb5d586c2 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -5,7 +5,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::definitions::DefPathData; use rustc_hir::Node; use rustc_hir::CRATE_HIR_ID; use rustc_middle::middle::privacy::AccessLevel; @@ -43,12 +42,9 @@ impl Module<'_> { } // FIXME: Should this be replaced with tcx.def_path_str? -fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec { - let crate_name = tcx.crate_name(did.krate).to_string(); - let relative = tcx.def_path(did).data.into_iter().filter_map(|elem| { - // Filter out extern blocks - (elem.data != DefPathData::ForeignMod).then(|| elem.data.to_string()) - }); +fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec { + let crate_name = tcx.crate_name(did.krate); + let relative = tcx.def_path(did).data.into_iter().filter_map(|elem| elem.data.get_opt_name()); std::iter::once(crate_name).chain(relative).collect() } @@ -71,7 +67,7 @@ crate struct RustdocVisitor<'a, 'tcx> { inlining: bool, /// Are the current module and all of its parents public? inside_public_path: bool, - exact_paths: FxHashMap>, + exact_paths: FxHashMap>, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {