about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNixon Enraght-Moony <nixon.emoony@gmail.com>2022-09-10 00:04:10 +0100
committerNixon Enraght-Moony <nixon.emoony@gmail.com>2022-09-10 00:40:30 +0100
commit2c17099671fb869a6836f08495d17d473c8cde18 (patch)
treec5e4f395de884eda6770f84ef7caa6bb023dc44c
parent98f3001eecbe4cbd091c10ffab45b4c164bb507b (diff)
downloadrust-2c17099671fb869a6836f08495d17d473c8cde18.tar.gz
rust-2c17099671fb869a6836f08495d17d473c8cde18.zip
Rustdoc-Json: Correcty handle intra-doc-links to items without HTML page
Closes #101531
-rw-r--r--src/librustdoc/clean/types.rs7
-rw-r--r--src/librustdoc/json/conversions.rs11
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs10
-rw-r--r--src/test/rustdoc-json/intra-doc-links/non_page.rs34
-rw-r--r--src/test/rustdoc-json/intra-doc-links/user_written.rs8
5 files changed, 63 insertions, 7 deletions
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 2077cf71b2e..f973fd0889e 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -510,7 +510,7 @@ impl Item {
             .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>,
 }
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 1177d482ac0..49a31f5f1da 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -19,6 +19,7 @@ use crate::clean::utils::print_const_expr;
 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 @@ impl JsonRenderer<'_> {
             .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();
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index cfd6ce402c2..677c980f63c 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -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 @@ impl LinkCollector<'_, '_> {
                 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 @@ impl LinkCollector<'_, '_> {
                     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,
                 })
             }
diff --git a/src/test/rustdoc-json/intra-doc-links/non_page.rs b/src/test/rustdoc-json/intra-doc-links/non_page.rs
new file mode 100644
index 00000000000..73c5334bb5c
--- /dev/null
+++ b/src/test/rustdoc-json/intra-doc-links/non_page.rs
@@ -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();
+}
diff --git a/src/test/rustdoc-json/intra-doc-links/user_written.rs b/src/test/rustdoc-json/intra-doc-links/user_written.rs
new file mode 100644
index 00000000000..6871dfea44a
--- /dev/null
+++ b/src/test/rustdoc-json/intra-doc-links/user_written.rs
@@ -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