diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7d33cf210139c..72046645e3a97 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -84,123 +84,8 @@ impl, U> Clean> for Option { impl Clean for CrateNum { fn clean(&self, cx: &mut DocContext<'_>) -> ExternalCrate { - let tcx = cx.tcx; let root = DefId { krate: *self, index: CRATE_DEF_INDEX }; - let krate_span = tcx.def_span(root); - let krate_src = cx.sess().source_map().span_to_filename(krate_span); - - // Collect all inner modules which are tagged as implementations of - // primitives. - // - // Note that this loop only searches the top-level items of the crate, - // and this is intentional. If we were to search the entire crate for an - // item tagged with `#[doc(primitive)]` then we would also have to - // search the entirety of external modules for items tagged - // `#[doc(primitive)]`, which is a pretty inefficient process (decoding - // all that metadata unconditionally). - // - // In order to keep the metadata load under control, the - // `#[doc(primitive)]` feature is explicitly designed to only allow the - // primitive tags to show up as the top level items in a crate. - // - // Also note that this does not attempt to deal with modules tagged - // duplicately for the same primitive. This is handled later on when - // rendering by delegating everything to a hash map. - let mut as_primitive = |res: Res| { - if let Res::Def(DefKind::Mod, def_id) = res { - let attrs = cx.tcx.get_attrs(def_id).clean(cx); - let mut prim = None; - for attr in attrs.lists(sym::doc) { - if let Some(v) = attr.value_str() { - if attr.has_name(sym::primitive) { - prim = PrimitiveType::from_symbol(v); - if prim.is_some() { - break; - } - // FIXME: should warn on unknown primitives? - } - } - } - return prim.map(|p| (def_id, p)); - } - None - }; - let primitives = if root.is_local() { - tcx.hir() - .krate() - .item - .item_ids - .iter() - .filter_map(|&id| { - let item = tcx.hir().item(id); - match item.kind { - hir::ItemKind::Mod(_) => { - as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id())) - } - hir::ItemKind::Use(ref path, hir::UseKind::Single) - if item.vis.node.is_pub() => - { - as_primitive(path.res).map(|(_, prim)| { - // Pretend the primitive is local. - (id.def_id.to_def_id(), prim) - }) - } - _ => None, - } - }) - .collect() - } else { - tcx.item_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect() - }; - - let mut as_keyword = |res: Res| { - if let Res::Def(DefKind::Mod, def_id) = res { - let attrs = tcx.get_attrs(def_id).clean(cx); - let mut keyword = None; - for attr in attrs.lists(sym::doc) { - if attr.has_name(sym::keyword) { - if let Some(v) = attr.value_str() { - keyword = Some(v); - break; - } - } - } - return keyword.map(|p| (def_id, p)); - } - None - }; - let keywords = if root.is_local() { - tcx.hir() - .krate() - .item - .item_ids - .iter() - .filter_map(|&id| { - let item = tcx.hir().item(id); - match item.kind { - hir::ItemKind::Mod(_) => { - as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id())) - } - hir::ItemKind::Use(ref path, hir::UseKind::Single) - if item.vis.node.is_pub() => - { - as_keyword(path.res).map(|(_, prim)| (id.def_id.to_def_id(), prim)) - } - _ => None, - } - }) - .collect() - } else { - tcx.item_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect() - }; - - ExternalCrate { - name: tcx.crate_name(*self), - src: krate_src, - attrs: tcx.get_attrs(root).clean(cx), - primitives, - keywords, - } + ExternalCrate { crate_num: *self, attrs: cx.tcx.get_attrs(root).clean(cx) } } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 2b25c6a26bcc4..9f686d19e3c91 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -17,8 +17,8 @@ use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIndex}; +use rustc_hir::def::{CtorKind, DefKind, Res}; +use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use rustc_hir::lang_items::LangItem; use rustc_hir::{BodyId, Mutability}; use rustc_index::vec::IndexVec; @@ -72,11 +72,138 @@ crate struct TraitWithExtraInfo { #[derive(Clone, Debug)] crate struct ExternalCrate { - crate name: Symbol, - crate src: FileName, + crate crate_num: CrateNum, crate attrs: Attributes, - crate primitives: ThinVec<(DefId, PrimitiveType)>, - crate keywords: ThinVec<(DefId, Symbol)>, +} + +impl ExternalCrate { + #[inline] + fn def_id(&self) -> DefId { + DefId { krate: self.crate_num, index: CRATE_DEF_INDEX } + } + + crate fn src(&self, tcx: TyCtxt<'_>) -> FileName { + let krate_span = tcx.def_span(self.def_id()); + tcx.sess.source_map().span_to_filename(krate_span) + } + + crate fn name(&self, tcx: TyCtxt<'_>) -> Symbol { + tcx.crate_name(self.crate_num) + } + + crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> { + let root = self.def_id(); + + let as_keyword = |res: Res| { + if let Res::Def(DefKind::Mod, def_id) = res { + let attrs = tcx.get_attrs(def_id); + let mut keyword = None; + for attr in attrs.lists(sym::doc) { + if attr.has_name(sym::keyword) { + if let Some(v) = attr.value_str() { + keyword = Some(v); + break; + } + } + } + return keyword.map(|p| (def_id, p)); + } + None + }; + if root.is_local() { + tcx.hir() + .krate() + .item + .item_ids + .iter() + .filter_map(|&id| { + let item = tcx.hir().item(id); + match item.kind { + hir::ItemKind::Mod(_) => { + as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id())) + } + hir::ItemKind::Use(ref path, hir::UseKind::Single) + if item.vis.node.is_pub() => + { + as_keyword(path.res).map(|(_, prim)| (id.def_id.to_def_id(), prim)) + } + _ => None, + } + }) + .collect() + } else { + tcx.item_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect() + } + } + + crate fn primitives(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, PrimitiveType)> { + let root = self.def_id(); + + // Collect all inner modules which are tagged as implementations of + // primitives. + // + // Note that this loop only searches the top-level items of the crate, + // and this is intentional. If we were to search the entire crate for an + // item tagged with `#[doc(primitive)]` then we would also have to + // search the entirety of external modules for items tagged + // `#[doc(primitive)]`, which is a pretty inefficient process (decoding + // all that metadata unconditionally). + // + // In order to keep the metadata load under control, the + // `#[doc(primitive)]` feature is explicitly designed to only allow the + // primitive tags to show up as the top level items in a crate. + // + // Also note that this does not attempt to deal with modules tagged + // duplicately for the same primitive. This is handled later on when + // rendering by delegating everything to a hash map. + let as_primitive = |res: Res| { + if let Res::Def(DefKind::Mod, def_id) = res { + let attrs = tcx.get_attrs(def_id); + let mut prim = None; + for attr in attrs.lists(sym::doc) { + if let Some(v) = attr.value_str() { + if attr.has_name(sym::primitive) { + prim = PrimitiveType::from_symbol(v); + if prim.is_some() { + break; + } + // FIXME: should warn on unknown primitives? + } + } + } + return prim.map(|p| (def_id, p)); + } + None + }; + + if root.is_local() { + tcx.hir() + .krate() + .item + .item_ids + .iter() + .filter_map(|&id| { + let item = tcx.hir().item(id); + match item.kind { + hir::ItemKind::Mod(_) => { + as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id())) + } + hir::ItemKind::Use(ref path, hir::UseKind::Single) + if item.vis.node.is_pub() => + { + as_primitive(path.res).map(|(_, prim)| { + // Pretend the primitive is local. + (id.def_id.to_def_id(), prim) + }) + } + _ => None, + } + }) + .collect() + } else { + tcx.item_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect() + } + } } /// Anything with a source location and set of attributes and, optionally, a diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index c2a971d637513..55a0cb42a2081 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -1,9 +1,9 @@ use crate::clean::auto_trait::AutoTraitFinder; use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::{ - inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, - ItemKind, Lifetime, MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, - TypeBinding, TypeKind, + inline, Clean, Crate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, + MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Type, TypeBinding, + TypeKind, }; use crate::core::DocContext; @@ -54,7 +54,11 @@ crate fn krate(cx: &mut DocContext<'_>) -> Crate { _ => unreachable!(), } - let ExternalCrate { name, src, primitives, keywords, .. } = LOCAL_CRATE.clean(cx); + let local_crate = LOCAL_CRATE.clean(cx); + let src = local_crate.src(cx.tcx); + let name = local_crate.name(cx.tcx); + let primitives = local_crate.primitives(cx.tcx); + let keywords = local_crate.keywords(cx.tcx); { let m = match *module.kind { ItemKind::ModuleItem(ref mut m) => m, diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index b2b895cc6726e..9a61f963a3ec3 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -155,19 +155,20 @@ impl Cache { // Cache where all our extern crates are located // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code for &(n, ref e) in &krate.externs { - let src_root = match e.src { + let src_root = match e.src(tcx) { FileName::Real(ref p) => match p.local_path().parent() { Some(p) => p.to_path_buf(), None => PathBuf::new(), }, _ => PathBuf::new(), }; - let extern_url = extern_html_root_urls.get(&*e.name.as_str()).map(|u| &**u); + let name = e.name(tcx); + let extern_url = extern_html_root_urls.get(&*name.as_str()).map(|u| &**u); self.extern_locations - .insert(n, (e.name, src_root, extern_location(e, extern_url, &dst))); + .insert(n, (name, src_root, extern_location(e, extern_url, &dst, tcx))); let did = DefId { krate: n, index: CRATE_DEF_INDEX }; - self.external_paths.insert(did, (vec![e.name.to_string()], ItemType::Module)); + self.external_paths.insert(did, (vec![name.to_string()], ItemType::Module)); } // Cache where all known primitives have their documentation located. @@ -175,7 +176,7 @@ impl Cache { // Favor linking to as local extern as possible, so iterate all crates in // reverse topological order. for &(_, ref e) in krate.externs.iter().rev() { - for &(def_id, prim) in &e.primitives { + for &(def_id, prim) in &e.primitives(tcx) { self.primitive_locations.insert(prim, def_id); } } diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index 2265905dcbaf4..b8544a0f439a7 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -31,10 +31,11 @@ crate fn extern_location( e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Path, + tcx: TyCtxt<'_>, ) -> ExternalLocation { use ExternalLocation::*; // See if there's documentation generated into the local directory - let local_location = dst.join(&*e.name.as_str()); + let local_location = dst.join(&*e.name(tcx).as_str()); if local_location.is_dir() { return Local; }