Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make intra-link resolve links for both trait and impl items #72347

Merged
merged 1 commit into from May 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 35 additions & 26 deletions src/librustdoc/passes/collect_intra_doc_links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
19 changes: 19 additions & 0 deletions src/test/rustdoc/issue-72340.rs
Original file line number Diff line number Diff line change
@@ -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()
}
}