Fix broken handling of primitive items
- Fix broken handling of primitive associated items - Remove fragment hack Fixes 83083 - more logging - Update CrateNum hacks The CrateNum has no relation to where in the dependency tree the crate is, only when it's loaded. Explicitly special-case core instead of assuming it will be the first DefId. - Update and add tests - Cache calculation of primitive locations This could possibly be avoided by passing a Cache into collect_intra_doc_links; but that's a much larger change, and doesn't seem valuable other than for this.
This commit is contained in:
parent
f78acaee03
commit
cb7e527692
16 changed files with 144 additions and 165 deletions
|
|
@ -461,60 +461,20 @@ impl Item {
|
|||
.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, 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()
|
||||
|
|
@ -531,18 +491,10 @@ impl Item {
|
|||
.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()
|
||||
}
|
||||
|
|
@ -963,7 +915,7 @@ crate struct Attributes {
|
|||
crate other_attrs: Vec<ast::Attribute>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
/// A link that has not yet been rendered.
|
||||
///
|
||||
/// This link will be turned into a rendered link by [`Item::links`].
|
||||
|
|
@ -975,7 +927,7 @@ crate struct ItemLink {
|
|||
/// 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>,
|
||||
}
|
||||
|
|
@ -1802,6 +1754,39 @@ impl PrimitiveType {
|
|||
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.get(&prim).is_some() {
|
||||
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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue