Skip to content

Commit 3e33ef4

Browse files
committed
Correct anchor for links to associated trait items
1 parent dc1f683 commit 3e33ef4

File tree

5 files changed

+143
-81
lines changed

5 files changed

+143
-81
lines changed

src/librustdoc/clean/inline.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use rustc::middle::const_eval;
2626

2727
use core::DocContext;
2828
use doctree;
29-
use clean::{self, Attributes};
29+
use clean::{self, Attributes, GetDefId};
3030

3131
use super::{Clean, ToSource};
3232

@@ -414,15 +414,22 @@ pub fn build_impl(cx: &DocContext,
414414
clean::RegionBound(..) => unreachable!(),
415415
}
416416
});
417-
if let Some(clean::ResolvedPath { did, .. }) = trait_ {
418-
if Some(did) == cx.deref_trait_did.get() {
419-
super::build_deref_target_impls(cx, &trait_items, ret);
420-
}
417+
if trait_.def_id() == cx.deref_trait_did.get() {
418+
super::build_deref_target_impls(cx, &trait_items, ret);
421419
}
420+
421+
let provided = trait_.def_id().map(|did| {
422+
cx.tcx().provided_trait_methods(did)
423+
.into_iter()
424+
.map(|meth| meth.name.to_string())
425+
.collect()
426+
}).unwrap_or(HashSet::new());
427+
422428
ret.push(clean::Item {
423429
inner: clean::ImplItem(clean::Impl {
424430
unsafety: hir::Unsafety::Normal, // FIXME: this should be decoded
425431
derived: clean::detect_derived(&attrs),
432+
provided_trait_methods: provided,
426433
trait_: trait_,
427434
for_: ty.ty.clean(cx),
428435
generics: (&ty.generics, &predicates, subst::TypeSpace).clean(cx),

src/librustdoc/clean/mod.rs

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ use rustc::middle::stability;
4444

4545
use rustc_front::hir;
4646

47-
use std::collections::HashMap;
47+
use std::collections::{HashMap, HashSet};
4848
use std::path::PathBuf;
4949
use std::rc::Rc;
5050
use std::u32;
@@ -559,15 +559,9 @@ impl TyParamBound {
559559
fn is_sized_bound(&self, cx: &DocContext) -> bool {
560560
use rustc_front::hir::TraitBoundModifier as TBM;
561561
if let Some(tcx) = cx.tcx_opt() {
562-
let sized_did = match tcx.lang_items.sized_trait() {
563-
Some(did) => did,
564-
None => return false
565-
};
566-
if let TyParamBound::TraitBound(PolyTrait {
567-
trait_: Type::ResolvedPath { did, .. }, ..
568-
}, TBM::None) = *self {
569-
if did == sized_did {
570-
return true
562+
if let TyParamBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
563+
if trait_.def_id() == tcx.lang_items.sized_trait() {
564+
return true;
571565
}
572566
}
573567
}
@@ -724,15 +718,18 @@ impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
724718
}
725719
}
726720

727-
TraitBound(PolyTrait {
728-
trait_: ResolvedPath {
729-
path: path,
730-
typarams: None,
731-
did: self.def_id,
732-
is_generic: false,
721+
TraitBound(
722+
PolyTrait {
723+
trait_: ResolvedPath {
724+
path: path,
725+
typarams: None,
726+
did: self.def_id,
727+
is_generic: false,
728+
},
729+
lifetimes: late_bounds,
733730
},
734-
lifetimes: late_bounds
735-
}, hir::TraitBoundModifier::None)
731+
hir::TraitBoundModifier::None
732+
)
736733
}
737734
}
738735

@@ -932,7 +929,6 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>,
932929
&'a ty::GenericPredicates<'tcx>,
933930
subst::ParamSpace) {
934931
fn clean(&self, cx: &DocContext) -> Generics {
935-
use std::collections::HashSet;
936932
use self::WherePredicate as WP;
937933

938934
let (gens, preds, space) = *self;
@@ -1486,6 +1482,16 @@ pub enum TypeKind {
14861482
TypeTypedef,
14871483
}
14881484

1485+
pub trait GetDefId {
1486+
fn def_id(&self) -> Option<DefId>;
1487+
}
1488+
1489+
impl<T: GetDefId> GetDefId for Option<T> {
1490+
fn def_id(&self) -> Option<DefId> {
1491+
self.as_ref().and_then(|d| d.def_id())
1492+
}
1493+
}
1494+
14891495
impl Type {
14901496
pub fn primitive_type(&self) -> Option<PrimitiveType> {
14911497
match *self {
@@ -1499,7 +1505,9 @@ impl Type {
14991505
_ => None,
15001506
}
15011507
}
1508+
}
15021509

1510+
impl GetDefId for Type {
15031511
fn def_id(&self) -> Option<DefId> {
15041512
match *self {
15051513
ResolvedPath { did, .. } => Some(did),
@@ -2208,6 +2216,7 @@ impl Clean<ImplPolarity> for hir::ImplPolarity {
22082216
pub struct Impl {
22092217
pub unsafety: hir::Unsafety,
22102218
pub generics: Generics,
2219+
pub provided_trait_methods: HashSet<String>,
22112220
pub trait_: Option<Type>,
22122221
pub for_: Type,
22132222
pub items: Vec<Item>,
@@ -2227,12 +2236,19 @@ impl Clean<Vec<Item>> for doctree::Impl {
22272236

22282237
// If this impl block is an implementation of the Deref trait, then we
22292238
// need to try inlining the target's inherent impl blocks as well.
2230-
if let Some(ResolvedPath { did, .. }) = trait_ {
2231-
if Some(did) == cx.deref_trait_did.get() {
2232-
build_deref_target_impls(cx, &items, &mut ret);
2233-
}
2239+
if trait_.def_id() == cx.deref_trait_did.get() {
2240+
build_deref_target_impls(cx, &items, &mut ret);
22342241
}
22352242

2243+
let provided = trait_.def_id().and_then(|did| {
2244+
cx.tcx_opt().map(|tcx| {
2245+
tcx.provided_trait_methods(did)
2246+
.into_iter()
2247+
.map(|meth| meth.name.to_string())
2248+
.collect()
2249+
})
2250+
}).unwrap_or(HashSet::new());
2251+
22362252
ret.push(Item {
22372253
name: None,
22382254
attrs: self.attrs.clean(cx),
@@ -2244,6 +2260,7 @@ impl Clean<Vec<Item>> for doctree::Impl {
22442260
inner: ImplItem(Impl {
22452261
unsafety: self.unsafety,
22462262
generics: self.generics.clean(cx),
2263+
provided_trait_methods: provided,
22472264
trait_: trait_,
22482265
for_: self.for_.clean(cx),
22492266
items: items,

src/librustdoc/html/render.rs

Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ use rustc::middle::stability;
6262
use rustc::session::config::get_unstable_features_setting;
6363
use rustc_front::hir;
6464

65-
use clean::{self, SelfTy, Attributes};
65+
use clean::{self, SelfTy, Attributes, GetDefId};
6666
use doctree;
6767
use fold::DocFolder;
6868
use html::escape::Escape;
@@ -144,9 +144,7 @@ pub struct Impl {
144144

145145
impl Impl {
146146
fn trait_did(&self) -> Option<DefId> {
147-
self.impl_.trait_.as_ref().and_then(|tr| {
148-
if let clean::ResolvedPath { did, .. } = *tr {Some(did)} else {None}
149-
})
147+
self.impl_.trait_.def_id()
150148
}
151149
}
152150

@@ -967,7 +965,7 @@ impl DocFolder for Cache {
967965

968966
// Collect all the implementors of traits.
969967
if let clean::ImplItem(ref i) = item.inner {
970-
if let Some(clean::ResolvedPath{ did, .. }) = i.trait_ {
968+
if let Some(did) = i.trait_.def_id() {
971969
self.implementors.entry(did).or_insert(vec![]).push(Implementor {
972970
def_id: item.def_id,
973971
stability: item.stability.clone(),
@@ -2066,10 +2064,11 @@ fn render_stability_since(w: &mut fmt::Formatter,
20662064
render_stability_since_raw(w, item.stable_since(), containing_item.stable_since())
20672065
}
20682066

2069-
fn render_assoc_item(w: &mut fmt::Formatter, meth: &clean::Item,
2067+
fn render_assoc_item(w: &mut fmt::Formatter,
2068+
item: &clean::Item,
20702069
link: AssocItemLink) -> fmt::Result {
20712070
fn method(w: &mut fmt::Formatter,
2072-
it: &clean::Item,
2071+
meth: &clean::Item,
20732072
unsafety: hir::Unsafety,
20742073
constness: hir::Constness,
20752074
abi: abi::Abi,
@@ -2080,12 +2079,20 @@ fn render_assoc_item(w: &mut fmt::Formatter, meth: &clean::Item,
20802079
-> fmt::Result {
20812080
use syntax::abi::Abi;
20822081

2083-
let name = it.name.as_ref().unwrap();
2084-
let anchor = format!("#{}.{}", shortty(it), name);
2082+
let name = meth.name.as_ref().unwrap();
2083+
let anchor = format!("#{}.{}", shortty(meth), name);
20852084
let href = match link {
20862085
AssocItemLink::Anchor => anchor,
2087-
AssocItemLink::GotoSource(did) => {
2088-
href(did).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
2086+
AssocItemLink::GotoSource(did, provided_methods) => {
2087+
// We're creating a link from an impl-item to the corresponding
2088+
// trait-item and need to map the anchored type accordingly.
2089+
let ty = if provided_methods.contains(name) {
2090+
ItemType::Method
2091+
} else {
2092+
ItemType::TyMethod
2093+
};
2094+
2095+
href(did).map(|p| format!("{}#{}.{}", p.0, ty, name)).unwrap_or(anchor)
20892096
}
20902097
};
20912098
let vis_constness = match get_unstable_features_setting() {
@@ -2106,21 +2113,21 @@ fn render_assoc_item(w: &mut fmt::Formatter, meth: &clean::Item,
21062113
decl = Method(selfty, d),
21072114
where_clause = WhereClause(g))
21082115
}
2109-
match meth.inner {
2116+
match item.inner {
21102117
clean::TyMethodItem(ref m) => {
2111-
method(w, meth, m.unsafety, hir::Constness::NotConst,
2118+
method(w, item, m.unsafety, hir::Constness::NotConst,
21122119
m.abi, &m.generics, &m.self_, &m.decl, link)
21132120
}
21142121
clean::MethodItem(ref m) => {
2115-
method(w, meth, m.unsafety, m.constness,
2122+
method(w, item, m.unsafety, m.constness,
21162123
m.abi, &m.generics, &m.self_, &m.decl,
21172124
link)
21182125
}
21192126
clean::AssociatedConstItem(ref ty, ref default) => {
2120-
assoc_const(w, meth, ty, default.as_ref())
2127+
assoc_const(w, item, ty, default.as_ref())
21212128
}
21222129
clean::AssociatedTypeItem(ref bounds, ref default) => {
2123-
assoc_type(w, meth, bounds, default)
2130+
assoc_type(w, item, bounds, default)
21242131
}
21252132
_ => panic!("render_assoc_item called on non-associated-item")
21262133
}
@@ -2338,9 +2345,9 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
23382345
}
23392346

23402347
#[derive(Copy, Clone)]
2341-
enum AssocItemLink {
2348+
enum AssocItemLink<'a> {
23422349
Anchor,
2343-
GotoSource(DefId),
2350+
GotoSource(DefId, &'a HashSet<String>),
23442351
}
23452352

23462353
enum AssocItemRender<'a> {
@@ -2383,12 +2390,7 @@ fn render_assoc_items(w: &mut fmt::Formatter,
23832390
}
23842391
if !traits.is_empty() {
23852392
let deref_impl = traits.iter().find(|t| {
2386-
match *t.impl_.trait_.as_ref().unwrap() {
2387-
clean::ResolvedPath { did, .. } => {
2388-
Some(did) == c.deref_trait_did
2389-
}
2390-
_ => false
2391-
}
2393+
t.impl_.trait_.def_id() == c.deref_trait_did
23922394
});
23932395
if let Some(impl_) = deref_impl {
23942396
render_deref_methods(w, cx, impl_, containing_item)?;
@@ -2400,17 +2402,17 @@ fn render_assoc_items(w: &mut fmt::Formatter,
24002402
});
24012403
for i in &manual {
24022404
let did = i.trait_did().unwrap();
2403-
render_impl(w, cx, i, AssocItemLink::GotoSource(did), true,
2404-
containing_item.stable_since())?;
2405+
let assoc_link = AssocItemLink::GotoSource(did, &i.impl_.provided_trait_methods);
2406+
render_impl(w, cx, i, assoc_link, true, containing_item.stable_since())?;
24052407
}
24062408
if !derived.is_empty() {
24072409
write!(w, "<h3 id='derived_implementations'>\
24082410
Derived Implementations \
24092411
</h3>")?;
24102412
for i in &derived {
24112413
let did = i.trait_did().unwrap();
2412-
render_impl(w, cx, i, AssocItemLink::GotoSource(did), true,
2413-
containing_item.stable_since())?;
2414+
let assoc_link = AssocItemLink::GotoSource(did, &i.impl_.provided_trait_methods);
2415+
render_impl(w, cx, i, assoc_link, true, containing_item.stable_since())?;
24142416
}
24152417
}
24162418
}
@@ -2427,17 +2429,16 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl,
24272429
}
24282430
}).next().expect("Expected associated type binding");
24292431
let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target };
2430-
match *target {
2431-
clean::ResolvedPath { did, .. } => render_assoc_items(w, cx, container_item, did, what),
2432-
_ => {
2433-
if let Some(prim) = target.primitive_type() {
2434-
if let Some(c) = cache().primitive_locations.get(&prim) {
2435-
let did = DefId { krate: *c, index: prim.to_def_index() };
2436-
render_assoc_items(w, cx, container_item, did, what)?;
2437-
}
2432+
if let Some(did) = target.def_id() {
2433+
render_assoc_items(w, cx, container_item, did, what)
2434+
} else {
2435+
if let Some(prim) = target.primitive_type() {
2436+
if let Some(c) = cache().primitive_locations.get(&prim) {
2437+
let did = DefId { krate: *c, index: prim.to_def_index() };
2438+
render_assoc_items(w, cx, container_item, did, what)?;
24382439
}
2439-
Ok(())
24402440
}
2441+
Ok(())
24412442
}
24422443
}
24432444

@@ -2521,18 +2522,19 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
25212522

25222523
fn render_default_items(w: &mut fmt::Formatter,
25232524
cx: &Context,
2524-
did: DefId,
25252525
t: &clean::Trait,
2526-
i: &clean::Impl,
2527-
render_static: bool,
2528-
outer_version: Option<&str>) -> fmt::Result {
2526+
i: &clean::Impl,
2527+
render_static: bool,
2528+
outer_version: Option<&str>) -> fmt::Result {
25292529
for trait_item in &t.items {
25302530
let n = trait_item.name.clone();
2531-
if i.items.iter().find(|m| { m.name == n }).is_some() {
2531+
if i.items.iter().find(|m| m.name == n).is_some() {
25322532
continue;
25332533
}
2534+
let did = i.trait_.as_ref().unwrap().def_id().unwrap();
2535+
let assoc_link = AssocItemLink::GotoSource(did, &i.provided_trait_methods);
25342536

2535-
doctraititem(w, cx, trait_item, AssocItemLink::GotoSource(did), render_static,
2537+
doctraititem(w, cx, trait_item, assoc_link, render_static,
25362538
outer_version)?;
25372539
}
25382540
Ok(())
@@ -2542,9 +2544,9 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
25422544
// default methods which weren't overridden in the implementation block.
25432545
// FIXME: this also needs to be done for associated types, whenever defaults
25442546
// for them work.
2545-
if let Some(clean::ResolvedPath { did, .. }) = i.impl_.trait_ {
2547+
if let Some(did) = i.trait_did() {
25462548
if let Some(t) = cache().traits.get(&did) {
2547-
render_default_items(w, cx, did, t, &i.impl_, render_header, outer_version)?;
2549+
render_default_items(w, cx, t, &i.impl_, render_header, outer_version)?;
25482550
}
25492551
}
25502552
write!(w, "</div>")?;

0 commit comments

Comments
 (0)