Rustdoc-Json: Correcty handle intra-doc-links to items without HTML page

Closes #101531
This commit is contained in:
Nixon Enraght-Moony 2022-09-10 00:04:10 +01:00
parent 98f3001eec
commit 2c17099671
5 changed files with 63 additions and 7 deletions

View File

@ -510,7 +510,7 @@ pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
.get(&self.item_id)
.map_or(&[][..], |v| v.as_slice())
.iter()
.filter_map(|ItemLink { link: s, link_text, did, ref fragment }| {
.filter_map(|ItemLink { link: s, link_text, page_id: did, ref fragment }| {
debug!(?did);
if let Ok((mut href, ..)) = href(*did, cx) {
debug!(?href);
@ -1134,7 +1134,10 @@ pub(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: DefId,
/// The `DefId` of the Item whose **HTML Page** contains the item being
/// linked to. This will be different to `item_id` on item's that don't
/// have their own page, such as struct fields and enum variants.
pub(crate) page_id: DefId,
/// The url fragment to append to the link
pub(crate) fragment: Option<UrlFragment>,
}

View File

@ -19,6 +19,7 @@
use crate::clean::{self, ItemId};
use crate::formats::item_type::ItemType;
use crate::json::JsonRenderer;
use crate::passes::collect_intra_doc_links::UrlFragment;
impl JsonRenderer<'_> {
pub(super) fn convert_item(&self, item: clean::Item) -> Option<Item> {
@ -29,8 +30,14 @@ pub(super) fn convert_item(&self, item: clean::Item) -> Option<Item> {
.get(&item.item_id)
.into_iter()
.flatten()
.map(|clean::ItemLink { link, did, .. }| {
(link.clone(), from_item_id((*did).into(), self.tcx))
.map(|clean::ItemLink { link, page_id, fragment, .. }| {
let id = match fragment {
Some(UrlFragment::Item(frag_id)) => *frag_id,
// FIXME: Pass the `UserWritten` segment to JSON consumer.
Some(UrlFragment::UserWritten(_)) | None => *page_id,
};
(link.clone(), from_item_id(id.into(), self.tcx))
})
.collect();
let docs = item.attrs.collapsed_doc_value();

View File

@ -223,6 +223,9 @@ enum MalformedGenerics {
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub(crate) enum UrlFragment {
Item(DefId),
/// A part of a page that isn't a rust item.
///
/// Eg: `[Vector Examples](std::vec::Vec#examples)`
UserWritten(String),
}
@ -1127,7 +1130,7 @@ fn resolve_link(
Some(ItemLink {
link: ori_link.link.clone(),
link_text: link_text.clone(),
did: res.def_id(self.cx.tcx),
page_id: res.def_id(self.cx.tcx),
fragment,
})
}
@ -1146,11 +1149,12 @@ fn resolve_link(
item,
&diag_info,
)?;
let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
let page_id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
Some(ItemLink {
link: ori_link.link.clone(),
link_text: link_text.clone(),
did: id,
page_id,
fragment,
})
}

View File

@ -0,0 +1,34 @@
// Regression test for <https://github.com/rust-lang/rust/issues/101531>,
// where links where to the item who's HTML page had the item linked to.
//! [`Struct::struct_field`]
//! [`Enum::Variant`]
//! [`Trait::AssocType`]
//! [`Trait::ASSOC_CONST`]
//! [`Trait::method`]
// @set struct_field = "$.index[*][?(@.name=='struct_field')].id"
// @set Variant = "$.index[*][?(@.name=='Variant')].id"
// @set AssocType = "$.index[*][?(@.name=='AssocType')].id"
// @set ASSOC_CONST = "$.index[*][?(@.name=='ASSOC_CONST')].id"
// @set method = "$.index[*][?(@.name=='method')].id"
// @is "$.index[*][?(@.name=='non_page')].links['`Struct::struct_field`']" $struct_field
// @is "$.index[*][?(@.name=='non_page')].links['`Enum::Variant`']" $Variant
// @is "$.index[*][?(@.name=='non_page')].links['`Trait::AssocType`']" $AssocType
// @is "$.index[*][?(@.name=='non_page')].links['`Trait::ASSOC_CONST`']" $ASSOC_CONST
// @is "$.index[*][?(@.name=='non_page')].links['`Trait::method`']" $method
pub struct Struct {
pub struct_field: i32,
}
pub enum Enum {
Variant(),
}
pub trait Trait {
const ASSOC_CONST: i32;
type AssocType;
fn method();
}

View File

@ -0,0 +1,8 @@
//! For motivation, see [the reasons](foo#reasons)
/// # Reasons
/// To test rustdoc json
pub fn foo() {}
// @set foo = "$.index[*][?(@.name=='foo')].id"
// @is "$.index[*][?(@.name=='user_written')].links['foo#reasons']" $foo