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

Allow using Self:: in doc #71289

Merged
merged 1 commit into from May 23, 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
54 changes: 50 additions & 4 deletions src/librustdoc/passes/collect_intra_doc_links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,43 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {

look_for_tests(&cx, &dox, &item, true);

// find item's parent to resolve `Self` in item's docs below
let parent_name = self.cx.as_local_hir_id(item.def_id).and_then(|item_hir| {
let parent_hir = self.cx.tcx.hir().get_parent_item(item_hir);
let item_parent = self.cx.tcx.hir().find(parent_hir);
match item_parent {
Some(hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Impl {
self_ty:
hir::Ty {
kind:
hir::TyKind::Path(hir::QPath::Resolved(
_,
hir::Path { segments, .. },
)),
..
},
..
},
..
})) => segments.first().and_then(|seg| Some(seg.ident.to_string())),
Some(hir::Node::Item(hir::Item {
ident, kind: hir::ItemKind::Enum(..), ..
}))
| Some(hir::Node::Item(hir::Item {
ident, kind: hir::ItemKind::Struct(..), ..
}))
| Some(hir::Node::Item(hir::Item {
ident, kind: hir::ItemKind::Union(..), ..
}))
| Some(hir::Node::Item(hir::Item {
ident, kind: hir::ItemKind::Trait(..), ..
})) => Some(ident.to_string()),
_ => None,
}
});

for (ori_link, link_range) in markdown_links(&dox) {
// Bail early for real links.
if ori_link.contains('/') {
Expand Down Expand Up @@ -467,7 +504,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
};
let (res, fragment) = {
let mut kind = None;
let path_str = if let Some(prefix) =
let mut path_str = if let Some(prefix) =
["struct@", "enum@", "type@", "trait@", "union@"]
.iter()
.find(|p| link.starts_with(**p))
Expand Down Expand Up @@ -521,6 +558,15 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
let base_node =
if item.is_mod() && item.attrs.inner_docs { None } else { parent_node };

let resolved_self;
// replace `Self` with suitable item's parent name
if path_str.starts_with("Self::") {
if let Some(ref name) = parent_name {
resolved_self = format!("{}::{}", name, &path_str[6..]);
path_str = &resolved_self;
}
}

match kind {
Some(ns @ ValueNS) => {
match self.resolve(
Expand All @@ -529,7 +575,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
&current_item,
base_node,
&extra_fragment,
None,
Some(&item),
) {
Ok(res) => res,
Err(ErrorKind::ResolutionFailure) => {
Expand All @@ -552,7 +598,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
&current_item,
base_node,
&extra_fragment,
None,
Some(&item),
) {
Ok(res) => res,
Err(ErrorKind::ResolutionFailure) => {
Expand All @@ -577,7 +623,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
&current_item,
base_node,
&extra_fragment,
None,
Some(&item),
) {
Err(ErrorKind::AnchorFailure(msg)) => {
anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
Expand Down
88 changes: 88 additions & 0 deletions src/test/rustdoc/intra-link-self.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![crate_name = "foo"]

// ignore-tidy-linelength

// @has foo/index.html '//a/@href' '../foo/struct.Foo.html#method.new'
// @has foo/struct.Foo.html '//a/@href' '../foo/struct.Foo.html#method.new'

Expand Down Expand Up @@ -27,3 +29,89 @@ impl Bar {
unimplemented!()
}
}

pub struct MyStruct {
// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#structfield.struct_field'

/// [`struct_field`]
///
/// [`struct_field`]: Self::struct_field
pub struct_field: u8,
}

pub enum MyEnum {
// @has foo/enum.MyEnum.html '//a/@href' '../foo/enum.MyEnum.html#EnumVariant.v'

/// [`EnumVariant`]
///
/// [`EnumVariant`]: Self::EnumVariant
EnumVariant,
}

pub union MyUnion {
// @has foo/union.MyUnion.html '//a/@href' '../foo/union.MyUnion.html#structfield.union_field'

/// [`union_field`]
///
/// [`union_field`]: Self::union_field
pub union_field: f32,
}

pub trait MyTrait {
// @has foo/trait.MyTrait.html '//a/@href' '../foo/trait.MyTrait.html#associatedtype.AssoType'

/// [`AssoType`]
///
/// [`AssoType`]: Self::AssoType
type AssoType;

// @has foo/trait.MyTrait.html '//a/@href' '../foo/trait.MyTrait.html#associatedconstant.ASSO_CONST'

/// [`ASSO_CONST`]
///
/// [`ASSO_CONST`]: Self::ASSO_CONST
const ASSO_CONST: i32 = 1;

// @has foo/trait.MyTrait.html '//a/@href' '../foo/trait.MyTrait.html#method.asso_fn'

/// [`asso_fn`]
///
/// [`asso_fn`]: Self::asso_fn
fn asso_fn() {}
}

impl MyStruct {
// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#method.for_impl'

/// [`for_impl`]
///
/// [`for_impl`]: Self::for_impl
pub fn for_impl() {
unimplemented!()
}
}

impl MyTrait for MyStruct {
// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#associatedtype.AssoType'

/// [`AssoType`]
///
/// [`AssoType`]: Self::AssoType
type AssoType = u32;

// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#associatedconstant.ASSO_CONST'

/// [`ASSO_CONST`]
///
/// [`ASSO_CONST`]: Self::ASSO_CONST
const ASSO_CONST: i32 = 10;

// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#method.asso_fn'

/// [`asso_fn`]
///
/// [`asso_fn`]: Self::asso_fn
fn asso_fn() {
unimplemented!()
}
}