about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTymoteusz Jankowski <tymoteusz.jankowski@gmail.com>2020-05-19 13:54:22 +0200
committerTymoteusz Jankowski <tymoteusz.jankowski@gmail.com>2020-05-19 14:32:17 +0200
commitfc4c9a6c7f27dc4cc68d8b2afe77e88a29ff8a31 (patch)
tree2081d32b4a5e8f514ba43aafef5e88436297df4d
parent914adf04af1c1a984707f778da3d04590c03d144 (diff)
downloadrust-fc4c9a6c7f27dc4cc68d8b2afe77e88a29ff8a31.tar.gz
rust-fc4c9a6c7f27dc4cc68d8b2afe77e88a29ff8a31.zip
Make intra-link resolve links for both trait and impl items
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs61
-rw-r--r--src/test/rustdoc/issue-72340.rs19
2 files changed, 54 insertions, 26 deletions
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index a3ef350a048..05f3b598ecd 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -232,37 +232,46 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                     DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias,
                     did,
                 ) => {
-                    // We need item's parent to know if it's
-                    // trait impl or struct/enum/etc impl
-                    let item_parent = item_opt
+                    // Checks if item_name belongs to `impl SomeItem`
+                    let impl_item = cx
+                        .tcx
+                        .inherent_impls(did)
+                        .iter()
+                        .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order())
+                        .find(|item| item.ident.name == item_name);
+                    let trait_item = item_opt
                         .and_then(|item| self.cx.as_local_hir_id(item.def_id))
                         .and_then(|item_hir| {
+                            // Checks if item_name belongs to `impl SomeTrait for SomeItem`
                             let parent_hir = self.cx.tcx.hir().get_parent_item(item_hir);
-                            self.cx.tcx.hir().find(parent_hir)
+                            let item_parent = self.cx.tcx.hir().find(parent_hir);
+                            match item_parent {
+                                Some(hir::Node::Item(hir::Item {
+                                    kind: hir::ItemKind::Impl { of_trait: Some(_), self_ty, .. },
+                                    ..
+                                })) => cx
+                                    .tcx
+                                    .associated_item_def_ids(self_ty.hir_id.owner)
+                                    .iter()
+                                    .map(|child| {
+                                        let associated_item = cx.tcx.associated_item(*child);
+                                        associated_item
+                                    })
+                                    .find(|child| child.ident.name == item_name),
+                                _ => None,
+                            }
                         });
-                    let item = match item_parent {
-                        Some(hir::Node::Item(hir::Item {
-                            kind: hir::ItemKind::Impl { of_trait: Some(_), self_ty, .. },
-                            ..
-                        })) => {
-                            // trait impl
-                            cx.tcx
-                                .associated_item_def_ids(self_ty.hir_id.owner)
-                                .iter()
-                                .map(|child| {
-                                    let associated_item = cx.tcx.associated_item(*child);
-                                    associated_item
-                                })
-                                .find(|child| child.ident.name == item_name)
-                        }
-                        _ => {
-                            // struct/enum/etc. impl
-                            cx.tcx
-                                .inherent_impls(did)
-                                .iter()
-                                .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order())
-                                .find(|item| item.ident.name == item_name)
+                    let item = match (impl_item, trait_item) {
+                        (Some(from_impl), Some(_)) => {
+                            // Although it's ambiguous, return impl version for compat. sake.
+                            // To handle that properly resolve() would have to support
+                            // something like
+                            // [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
+                            Some(from_impl)
                         }
+                        (None, Some(from_trait)) => Some(from_trait),
+                        (Some(from_impl), None) => Some(from_impl),
+                        _ => None,
                     };
 
                     if let Some(item) = item {
diff --git a/src/test/rustdoc/issue-72340.rs b/src/test/rustdoc/issue-72340.rs
new file mode 100644
index 00000000000..6ed3bfbe3e5
--- /dev/null
+++ b/src/test/rustdoc/issue-72340.rs
@@ -0,0 +1,19 @@
+#![crate_name = "foo"]
+
+pub struct Body;
+
+impl Body {
+    pub fn empty() -> Self {
+        Body
+    }
+
+}
+
+impl Default for Body {
+    // @has foo/struct.Body.html '//a/@href' '../foo/struct.Body.html#method.empty'
+
+    /// Returns [`Body::empty()`](Body::empty).
+    fn default() -> Body {
+        Body::empty()
+    }
+}