diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b7edf73f7ceda..77521db835be6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -20,7 +20,7 @@ pub use self::Visibility::{Public, Inherited}; use rustc_target::spec::abi::Abi; use syntax; -use syntax::ast::{self, AttrStyle, NodeId, Ident}; +use syntax::ast::{self, AttrStyle, Name, NodeId, Ident}; use syntax::attr; use syntax::codemap::{dummy_spanned, Spanned}; use syntax::feature_gate::UnstableFeatures; @@ -39,6 +39,7 @@ use rustc::hir::{self, GenericArg, HirVec}; use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::hir::def_id::DefIndexAddressSpace; +use rustc::hir::map::Node; use rustc::ty::subst::Substs; use rustc::ty::{self, TyCtxt, Region, RegionVid, Ty, AdtKind}; use rustc::middle::stability; @@ -584,10 +585,23 @@ impl Clean for doctree::Module { .next() .map_or(true, |a| a.style == AttrStyle::Inner) { // inner doc comment, use the module's own scope for resolution + if self.id != NodeId::new(0) { + *cx.current_item_name.borrow_mut() = Some(cx.tcx.hir.name(self.id)); + } else { + *cx.current_item_name.borrow_mut() = None; + } cx.mod_ids.borrow_mut().push(self.id); self.attrs.clean(cx) } else { // outer doc comment, use its parent's scope + match cx.mod_ids.borrow().last() { + Some(parent) if *parent != NodeId::new(0) => { + *cx.current_item_name.borrow_mut() = Some(cx.tcx.hir.name(*parent)); + } + _ => { + *cx.current_item_name.borrow_mut() = None; + } + } let attrs = self.attrs.clean(cx); cx.mod_ids.borrow_mut().push(self.id); attrs @@ -1165,11 +1179,17 @@ fn resolve(cx: &DocContext, path_str: &str, is_val: bool) -> Result<(Def, Option }; let mut path = if let Some(second) = split.next() { - second + second.to_owned() } else { return Err(()) }; + if path == "self" || path == "Self" { + if let Some(name) = *cx.current_item_name.borrow() { + path = name.to_string(); + } + } + let ty = cx.resolver.borrow_mut() .with_scope(*id, |resolver| { @@ -2143,6 +2163,8 @@ impl Clean for doctree::Function { let (generics, decl) = enter_impl_trait(cx, || { (self.generics.clean(cx), (&self.decl, self.body).clean(cx)) }); + + *cx.current_item_name.borrow_mut() = Some(self.name); Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -2321,6 +2343,7 @@ pub struct Trait { impl Clean for doctree::Trait { fn clean(&self, cx: &DocContext) -> Item { + *cx.current_item_name.borrow_mut() = Some(self.name); let attrs = self.attrs.clean(cx); let is_spotlight = attrs.has_doc_flag("spotlight"); Item { @@ -2392,6 +2415,7 @@ impl Clean for hir::TraitItem { AssociatedTypeItem(bounds.clean(cx), default.clean(cx)) } }; + *cx.current_item_name.borrow_mut() = Some(self.ident.name); Item { name: Some(self.ident.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -2424,6 +2448,7 @@ impl Clean for hir::ImplItem { generics: Generics::default(), }, true), }; + *cx.current_item_name.borrow_mut() = Some(self.ident.name); Item { name: Some(self.ident.name.clean(cx)), source: self.span.clean(cx), @@ -3217,6 +3242,7 @@ impl<'tcx> Clean for Ty<'tcx> { impl Clean for hir::StructField { fn clean(&self, cx: &DocContext) -> Item { + *cx.current_item_name.borrow_mut() = Some(self.ident.name); Item { name: Some(self.ident.name).clean(cx), attrs: self.attrs.clean(cx), @@ -3295,6 +3321,7 @@ impl Clean> for doctree::Struct { let name = self.name.clean(cx); let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone()); + *cx.current_item_name.borrow_mut() = Some(self.name); ret.push(Item { name: Some(name), attrs: self.attrs.clean(cx), @@ -3320,6 +3347,7 @@ impl Clean> for doctree::Union { let name = self.name.clean(cx); let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone()); + *cx.current_item_name.borrow_mut() = Some(self.name); ret.push(Item { name: Some(name), attrs: self.attrs.clean(cx), @@ -3372,6 +3400,7 @@ impl Clean> for doctree::Enum { let name = self.name.clean(cx); let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone()); + *cx.current_item_name.borrow_mut() = Some(self.name); ret.push(Item { name: Some(name), attrs: self.attrs.clean(cx), @@ -3398,6 +3427,7 @@ pub struct Variant { impl Clean for doctree::Variant { fn clean(&self, cx: &DocContext) -> Item { + *cx.current_item_name.borrow_mut() = Some(self.name); Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -3693,6 +3723,7 @@ pub struct Typedef { impl Clean for doctree::Typedef { fn clean(&self, cx: &DocContext) -> Item { + *cx.current_item_name.borrow_mut() = Some(self.name); Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -3768,6 +3799,7 @@ pub struct Static { impl Clean for doctree::Static { fn clean(&self, cx: &DocContext) -> Item { debug!("cleaning static {}: {:?}", self.name.clean(cx), self); + *cx.current_item_name.borrow_mut() = Some(self.name); Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -3793,6 +3825,7 @@ pub struct Constant { impl Clean for doctree::Constant { fn clean(&self, cx: &DocContext) -> Item { + *cx.current_item_name.borrow_mut() = Some(self.name); Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -3862,6 +3895,23 @@ pub fn get_auto_traits_with_def_id(cx: &DocContext, id: DefId) -> Vec { finder.get_with_def_id(id) } +fn get_name_if_possible(cx: &DocContext, node: NodeId) -> Option { + match cx.tcx.hir.get(node) { + Node::NodeItem(_) | + Node::NodeForeignItem(_) | + Node::NodeImplItem(_) | + Node::NodeTraitItem(_) | + Node::NodeVariant(_) | + Node::NodeField(_) | + Node::NodeLifetime(_) | + Node::NodeGenericParam(_) | + Node::NodeBinding(&hir::Pat { node: hir::PatKind::Binding(_,_,_,_), .. }) | + Node::NodeStructCtor(_) => {} + _ => return None, + } + Some(cx.tcx.hir.name(node)) +} + impl Clean> for doctree::Impl { fn clean(&self, cx: &DocContext) -> Vec { let mut ret = Vec::new(); @@ -3881,6 +3931,7 @@ impl Clean> for doctree::Impl { .collect() }).unwrap_or(FxHashSet()); + *cx.current_item_name.borrow_mut() = get_name_if_possible(cx, self.for_.id); ret.push(Item { name: None, attrs: self.attrs.clean(cx), @@ -3967,6 +4018,7 @@ fn build_deref_target_impls(cx: &DocContext, impl Clean for doctree::ExternCrate { fn clean(&self, cx: &DocContext) -> Item { + *cx.current_item_name.borrow_mut() = Some(self.name); Item { name: None, attrs: self.attrs.clean(cx), @@ -4013,6 +4065,8 @@ impl Clean> for doctree::Import { } Import::Simple(name.clean(cx), resolve_use_source(cx, path)) }; + + *cx.current_item_name.borrow_mut() = Some(self.name); vec![Item { name: None, attrs: self.attrs.clean(cx), @@ -4081,6 +4135,8 @@ impl Clean for hir::ForeignItem { ForeignTypeItem } }; + + *cx.current_item_name.borrow_mut() = Some(self.name); Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), @@ -4256,6 +4312,7 @@ pub struct Macro { impl Clean for doctree::Macro { fn clean(&self, cx: &DocContext) -> Item { let name = self.name.clean(cx); + *cx.current_item_name.borrow_mut() = None; Item { name: Some(name.clone()), attrs: self.attrs.clean(cx), diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 0a56c639220b4..375a9c981a10c 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -25,7 +25,7 @@ use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::CStore; use rustc_target::spec::TargetTriple; -use syntax::ast::NodeId; +use syntax::ast::{Name, NodeId}; use syntax::codemap; use syntax::edition::Edition; use syntax::feature_gate::UnstableFeatures; @@ -82,7 +82,8 @@ pub struct DocContext<'a, 'tcx: 'a, 'rcx: 'a> { pub fake_def_ids: RefCell>, pub all_fake_def_ids: RefCell>, /// Maps (type_id, trait_id) -> auto trait impl - pub generated_synthetics: RefCell> + pub generated_synthetics: RefCell>, + pub current_item_name: RefCell>, } impl<'a, 'tcx, 'rcx> DocContext<'a, 'tcx, 'rcx> { @@ -383,6 +384,7 @@ pub fn run_core(search_paths: SearchPaths, fake_def_ids: RefCell::new(FxHashMap()), all_fake_def_ids: RefCell::new(FxHashSet()), generated_synthetics: RefCell::new(FxHashSet()), + current_item_name: RefCell::new(None), }; debug!("crate: {:?}", tcx.hir.krate()); diff --git a/src/test/rustdoc/intra-link-self.rs b/src/test/rustdoc/intra-link-self.rs new file mode 100644 index 0000000000000..21317f2af42be --- /dev/null +++ b/src/test/rustdoc/intra-link-self.rs @@ -0,0 +1,39 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_name = "foo"] + +// @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' + +/// Use [`new`] to create a new instance. +/// +/// [`new`]: Self::new +pub struct Foo; + +impl Foo { + pub fn new() -> Self { + unimplemented!() + } +} + +// @has foo/index.html '//a/@href' '../foo/struct.Bar.html#method.new2' +// @has foo/struct.Bar.html '//a/@href' '../foo/struct.Bar.html#method.new2' + +/// Use [`new2`] to create a new instance. +/// +/// [`new2`]: Self::new2 +pub struct Bar; + +impl Bar { + pub fn new2() -> Self { + unimplemented!() + } +}