crate fn keywords(&self, tcx: TyCtxt<'_>) -> ThinVec<(DefId, Symbol)> {
let root = self.def_id();
- let as_keyword = |res: Res| {
+ 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;
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))
+ as_keyword(path.res.expect_non_local())
+ .map(|(_, prim)| (id.def_id.to_def_id(), prim))
}
_ => None,
}
// 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| {
+ 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;
hir::ItemKind::Use(ref path, hir::UseKind::Single)
if item.vis.node.is_pub() =>
{
- as_primitive(path.res).map(|(_, prim)| {
+ as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
// Pretend the primitive is local.
(id.def_id.to_def_id(), prim)
})
def_id,
name,
kind,
- Box::new(ast_attrs.clean(cx)),
+ box ast_attrs.clean(cx),
cx,
ast_attrs.cfg(cx.sess()),
)
Item {
def_id: def_id.into(),
- kind: Box::new(kind),
+ kind: box kind,
name,
attrs,
visibility: cx.tcx.visibility(def_id).clean(cx),
.map_or(&[][..], |v| v.as_slice())
.iter()
.filter_map(|ItemLink { link: s, link_text, did, ref fragment }| {
- match did {
- Some(did) => {
- if let Ok((mut href, ..)) = href(did.clone(), cx) {
- if let Some(ref fragment) = *fragment {
- href.push('#');
- href.push_str(fragment);
- }
- Some(RenderedLink {
- original_text: s.clone(),
- new_text: link_text.clone(),
- href,
- })
- } else {
- None
- }
- }
- // FIXME(83083): using fragments as a side-channel for
- // primitive names is very unfortunate
- None => {
- let relative_to = &cx.current;
- if let Some(ref fragment) = *fragment {
- let url = match cx.cache().extern_locations.get(&self.def_id.krate()) {
- Some(&ExternalLocation::Local) => {
- if relative_to[0] == "std" {
- let depth = relative_to.len() - 1;
- "../".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::Unknown) | None => {
- format!("{}/std/", crate::DOC_RUST_LANG_ORG_CHANNEL)
- }
- };
- // This is a primitive so the url is done "by hand".
- let tail = fragment.find('#').unwrap_or_else(|| fragment.len());
- Some(RenderedLink {
- original_text: s.clone(),
- new_text: link_text.clone(),
- href: format!(
- "{}primitive.{}.html{}",
- url,
- &fragment[..tail],
- &fragment[tail..]
- ),
- })
- } else {
- panic!("This isn't a primitive?!");
- }
+ debug!(?did);
+ if let Ok((mut href, ..)) = href(*did, cx) {
+ debug!(?href);
+ if let Some(ref fragment) = *fragment {
+ href.push('#');
+ href.push_str(fragment);
}
+ Some(RenderedLink {
+ original_text: s.clone(),
+ new_text: link_text.clone(),
+ href,
+ })
+ } else {
+ None
}
})
.collect()
.get(&self.def_id)
.map_or(&[][..], |v| v.as_slice())
.iter()
- .filter_map(|ItemLink { link: s, link_text, did, fragment }| {
- // FIXME(83083): using fragments as a side-channel for
- // primitive names is very unfortunate
- if did.is_some() || fragment.is_some() {
- Some(RenderedLink {
- original_text: s.clone(),
- new_text: link_text.clone(),
- href: String::new(),
- })
- } else {
- None
- }
+ .map(|ItemLink { link: s, link_text, .. }| RenderedLink {
+ original_text: s.clone(),
+ new_text: link_text.clone(),
+ href: String::new(),
})
.collect()
}
}
}
-/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
-/// as well as doc comments.
-#[derive(Clone, Debug, Default)]
-crate struct Attributes {
- crate doc_strings: Vec<DocFragment>,
- crate other_attrs: Vec<ast::Attribute>,
-}
-
-#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
/// A link that has not yet been rendered.
///
/// This link will be turned into a rendered link by [`Item::links`].
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
crate struct ItemLink {
/// The original link written in the markdown
pub(crate) link: String,
/// This may not be the same as `link` if there was a disambiguator
/// in an intra-doc link (e.g. \[`fn@f`\])
pub(crate) link_text: String,
- pub(crate) did: Option<DefId>,
+ pub(crate) did: DefId,
/// The url fragment to append to the link
pub(crate) fragment: Option<String>,
}
pub(crate) href: String,
}
+/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
+/// as well as doc comments.
+#[derive(Clone, Debug, Default)]
+crate struct Attributes {
+ crate doc_strings: Vec<DocFragment>,
+ crate other_attrs: Vec<ast::Attribute>,
+}
+
impl Attributes {
crate fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
self.other_attrs.lists(name)
crate fn maybe_sized(cx: &mut DocContext<'_>) -> GenericBound {
let did = cx.tcx.require_lang_item(LangItem::Sized, None);
let empty = cx.tcx.intern_substs(&[]);
- let path = external_path(cx, cx.tcx.item_name(did), Some(did), false, vec![], empty);
+ let path = external_path(cx, did, false, vec![], empty);
inline::record_extern_fqn(cx, did, ItemType::Trait);
GenericBound::TraitBound(
PolyTrait {
ImplTrait(Vec<GenericBound>),
}
-#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
-/// N.B. this has to be different from `hir::PrimTy` because it also includes types that aren't
-/// paths, like `Unit`.
-crate enum PrimitiveType {
- Isize,
- I8,
- I16,
- I32,
- I64,
- I128,
- Usize,
- U8,
- U16,
- U32,
- U64,
- U128,
- F32,
- F64,
- Char,
- Bool,
- Str,
- Slice,
- Array,
- Tuple,
- Unit,
- RawPointer,
- Reference,
- Fn,
- Never,
-}
-
crate trait GetDefId {
/// Use this method to get the [`DefId`] of a [`clean`] AST node.
/// This will return [`None`] when called on a primitive [`clean::Type`].
};
Some((&self_, trait_did, *name))
}
-}
-impl Type {
fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
let t: PrimitiveType = match *self {
ResolvedPath { did, .. } => return Some(did),
}
}
+/// N.B. this has to be different from `hir::PrimTy` because it also includes types that aren't
+/// paths, like `Unit`.
+#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
+crate enum PrimitiveType {
+ Isize,
+ I8,
+ I16,
+ I32,
+ I64,
+ I128,
+ Usize,
+ U8,
+ U16,
+ U32,
+ U64,
+ U128,
+ F32,
+ F64,
+ Char,
+ Bool,
+ Str,
+ Slice,
+ Array,
+ Tuple,
+ Unit,
+ RawPointer,
+ Reference,
+ Fn,
+ Never,
+}
+
impl PrimitiveType {
crate fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
use ast::{FloatTy, IntTy, UintTy};
Never => sym::never,
}
}
+
+ /// Returns the DefId of the module with `doc(primitive)` for this primitive type.
+ /// Panics if there is no such module.
+ ///
+ /// This gives precedence to primitives defined in the current crate, and deprioritizes primitives defined in `core`,
+ /// but otherwise, if multiple crates define the same primitive, there is no guarantee of which will be picked.
+ /// In particular, if a crate depends on both `std` and another crate that also defines `doc(primitive)`, then
+ /// it's entirely random whether `std` or the other crate is picked. (no_std crates are usually fine unless multiple dependencies define a primitive.)
+ crate fn primitive_locations(tcx: TyCtxt<'_>) -> &FxHashMap<PrimitiveType, DefId> {
+ static PRIMITIVE_LOCATIONS: OnceCell<FxHashMap<PrimitiveType, DefId>> = OnceCell::new();
+ PRIMITIVE_LOCATIONS.get_or_init(|| {
+ let mut primitive_locations = FxHashMap::default();
+ // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate.
+ // This is a degenerate case that I don't plan to support.
+ for &crate_num in tcx.crates(()) {
+ let e = ExternalCrate { crate_num };
+ let crate_name = e.name(tcx);
+ debug!(?crate_num, ?crate_name);
+ for &(def_id, prim) in &e.primitives(tcx) {
+ // HACK: try to link to std instead where possible
+ if crate_name == sym::core && primitive_locations.contains_key(&prim) {
+ continue;
+ }
+ primitive_locations.insert(prim, def_id);
+ }
+ }
+ let local_primitives = ExternalCrate { crate_num: LOCAL_CRATE }.primitives(tcx);
+ for (def_id, prim) in local_primitives {
+ primitive_locations.insert(prim, def_id);
+ }
+ primitive_locations
+ })
+ }
}
impl From<ast::IntTy> for PrimitiveType {