Skip to content

Commit 641bca0

Browse files
committed
rustdoc: Link "Trait Implementations" to sources
All methods listed in "Trait Implementations" now hyperlink to the source trait instead of themselves, allowing easy browsing of the documentation of a trait method. Closes #17476
1 parent fcc89ea commit 641bca0

File tree

4 files changed

+143
-105
lines changed

4 files changed

+143
-105
lines changed

src/librustdoc/html/format.rs

Lines changed: 41 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -281,48 +281,46 @@ impl fmt::Display for clean::Path {
281281
}
282282
}
283283

284+
pub fn href(did: ast::DefId) -> Option<(String, ItemType, Vec<String>)> {
285+
let cache = cache();
286+
let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone());
287+
let &(ref fqp, shortty) = match cache.paths.get(&did) {
288+
Some(p) => p,
289+
None => return None,
290+
};
291+
let mut url = if ast_util::is_local(did) || cache.inlined.contains(&did) {
292+
repeat("../").take(loc.len()).collect::<String>()
293+
} else {
294+
match cache.extern_locations[&did.krate] {
295+
render::Remote(ref s) => s.to_string(),
296+
render::Local => repeat("../").take(loc.len()).collect::<String>(),
297+
render::Unknown => return None,
298+
}
299+
};
300+
for component in &fqp[..fqp.len() - 1] {
301+
url.push_str(component);
302+
url.push_str("/");
303+
}
304+
match shortty {
305+
ItemType::Module => {
306+
url.push_str(fqp.last().unwrap());
307+
url.push_str("/index.html");
308+
}
309+
_ => {
310+
url.push_str(shortty.to_static_str());
311+
url.push_str(".");
312+
url.push_str(fqp.last().unwrap());
313+
url.push_str(".html");
314+
}
315+
}
316+
Some((url, shortty, fqp.to_vec()))
317+
}
318+
284319
/// Used when rendering a `ResolvedPath` structure. This invokes the `path`
285320
/// rendering function with the necessary arguments for linking to a local path.
286-
fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, p: &clean::Path,
321+
fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, path: &clean::Path,
287322
print_all: bool) -> fmt::Result {
288-
path(w, p, print_all,
289-
|cache, loc| {
290-
if ast_util::is_local(did) || cache.inlined.contains(&did) {
291-
Some(repeat("../").take(loc.len()).collect::<String>())
292-
} else {
293-
match cache.extern_locations[&did.krate] {
294-
render::Remote(ref s) => Some(s.to_string()),
295-
render::Local => {
296-
Some(repeat("../").take(loc.len()).collect::<String>())
297-
}
298-
render::Unknown => None,
299-
}
300-
}
301-
},
302-
|cache| {
303-
match cache.paths.get(&did) {
304-
None => None,
305-
Some(&(ref fqp, shortty)) => Some((fqp.clone(), shortty))
306-
}
307-
})
308-
}
309-
310-
fn path<F, G>(w: &mut fmt::Formatter,
311-
path: &clean::Path,
312-
print_all: bool,
313-
root: F,
314-
info: G)
315-
-> fmt::Result where
316-
F: FnOnce(&render::Cache, &[String]) -> Option<String>,
317-
G: FnOnce(&render::Cache) -> Option<(Vec<String>, ItemType)>,
318-
{
319-
// The generics will get written to both the title and link
320323
let last = path.segments.last().unwrap();
321-
let generics = format!("{}", last.params);
322-
323-
let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone());
324-
let cache = cache();
325-
let abs_root = root(&*cache, &loc);
326324
let rel_root = match &*path.segments[0].name {
327325
"self" => Some("./".to_string()),
328326
_ => None,
@@ -334,8 +332,7 @@ fn path<F, G>(w: &mut fmt::Formatter,
334332
Some(root) => {
335333
let mut root = String::from_str(&root);
336334
for seg in &path.segments[..amt] {
337-
if "super" == seg.name ||
338-
"self" == seg.name {
335+
if "super" == seg.name || "self" == seg.name {
339336
try!(write!(w, "{}::", seg.name));
340337
} else {
341338
root.push_str(&seg.name);
@@ -355,37 +352,14 @@ fn path<F, G>(w: &mut fmt::Formatter,
355352
}
356353
}
357354

358-
match info(&*cache) {
359-
// This is a documented path, link to it!
360-
Some((ref fqp, shortty)) if abs_root.is_some() => {
361-
let mut url = String::from_str(&abs_root.unwrap());
362-
let to_link = &fqp[..fqp.len() - 1];
363-
for component in to_link {
364-
url.push_str(component);
365-
url.push_str("/");
366-
}
367-
match shortty {
368-
ItemType::Module => {
369-
url.push_str(fqp.last().unwrap());
370-
url.push_str("/index.html");
371-
}
372-
_ => {
373-
url.push_str(shortty.to_static_str());
374-
url.push_str(".");
375-
url.push_str(fqp.last().unwrap());
376-
url.push_str(".html");
377-
}
378-
}
379-
355+
match href(did) {
356+
Some((url, shortty, fqp)) => {
380357
try!(write!(w, "<a class='{}' href='{}' title='{}'>{}</a>",
381358
shortty, url, fqp.connect("::"), last.name));
382359
}
383-
384-
_ => {
385-
try!(write!(w, "{}", last.name));
386-
}
360+
_ => try!(write!(w, "{}", last.name)),
387361
}
388-
try!(write!(w, "{}", generics));
362+
try!(write!(w, "{}", last.params));
389363
Ok(())
390364
}
391365

src/librustdoc/html/render.rs

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ use clean;
6262
use doctree;
6363
use fold::DocFolder;
6464
use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace, Stability};
65-
use html::format::{ConciseStability, TyParamBounds, WhereClause};
65+
use html::format::{ConciseStability, TyParamBounds, WhereClause, href};
6666
use html::highlight;
6767
use html::item_type::ItemType;
6868
use html::layout;
@@ -137,6 +137,14 @@ pub struct Impl {
137137
pub stability: Option<clean::Stability>,
138138
}
139139

140+
impl Impl {
141+
fn trait_did(&self) -> Option<ast::DefId> {
142+
self.impl_.trait_.as_ref().and_then(|tr| {
143+
if let clean::ResolvedPath { did, .. } = *tr {Some(did)} else {None}
144+
})
145+
}
146+
}
147+
140148
/// This cache is used to store information about the `clean::Crate` being
141149
/// rendered in order to provide more useful documentation. This contains
142150
/// information like all implementors of a trait, all traits a type implements,
@@ -277,7 +285,9 @@ impl fmt::Display for IndexItemFunctionType {
277285
return write!(f, "null")
278286
}
279287

280-
let inputs: Vec<String> = self.inputs.iter().map(|ref t| format!("{}", t)).collect();
288+
let inputs: Vec<String> = self.inputs.iter().map(|ref t| {
289+
format!("{}", t)
290+
}).collect();
281291
try!(write!(f, "{{\"inputs\":[{}],\"output\":", inputs.connect(",")));
282292

283293
match self.output {
@@ -1780,23 +1790,23 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
17801790
try!(write!(w, "{{\n"));
17811791
for t in &types {
17821792
try!(write!(w, " "));
1783-
try!(render_method(w, t));
1793+
try!(render_method(w, t, MethodLink::Anchor));
17841794
try!(write!(w, ";\n"));
17851795
}
17861796
if types.len() > 0 && required.len() > 0 {
17871797
try!(w.write_str("\n"));
17881798
}
17891799
for m in &required {
17901800
try!(write!(w, " "));
1791-
try!(render_method(w, m));
1801+
try!(render_method(w, m, MethodLink::Anchor));
17921802
try!(write!(w, ";\n"));
17931803
}
17941804
if required.len() > 0 && provided.len() > 0 {
17951805
try!(w.write_str("\n"));
17961806
}
17971807
for m in &provided {
17981808
try!(write!(w, " "));
1799-
try!(render_method(w, m));
1809+
try!(render_method(w, m, MethodLink::Anchor));
18001810
try!(write!(w, " {{ ... }}\n"));
18011811
}
18021812
try!(write!(w, "}}"));
@@ -1812,7 +1822,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
18121822
shortty(m),
18131823
*m.name.as_ref().unwrap(),
18141824
ConciseStability(&m.stability)));
1815-
try!(render_method(w, m));
1825+
try!(render_method(w, m, MethodLink::Anchor));
18161826
try!(write!(w, "</code></h3>"));
18171827
try!(document(w, m));
18181828
Ok(())
@@ -1896,14 +1906,23 @@ fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
18961906
Ok(())
18971907
}
18981908

1899-
fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result {
1909+
fn render_method(w: &mut fmt::Formatter, meth: &clean::Item,
1910+
link: MethodLink) -> fmt::Result {
19001911
fn method(w: &mut fmt::Formatter, it: &clean::Item,
19011912
unsafety: ast::Unsafety, abi: abi::Abi,
19021913
g: &clean::Generics, selfty: &clean::SelfTy,
1903-
d: &clean::FnDecl) -> fmt::Result {
1914+
d: &clean::FnDecl, link: MethodLink) -> fmt::Result {
19041915
use syntax::abi::Abi;
19051916

1906-
write!(w, "{}{}fn <a href='#{ty}.{name}' class='fnname'>{name}</a>\
1917+
let name = it.name.as_ref().unwrap();
1918+
let anchor = format!("#{}.{}", shortty(it), name);
1919+
let href = match link {
1920+
MethodLink::Anchor => anchor,
1921+
MethodLink::GotoSource(did) => {
1922+
href(did).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
1923+
}
1924+
};
1925+
write!(w, "{}{}fn <a href='{href}' class='fnname'>{name}</a>\
19071926
{generics}{decl}{where_clause}",
19081927
match unsafety {
19091928
ast::Unsafety::Unsafe => "unsafe ",
@@ -1913,18 +1932,20 @@ fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result {
19131932
Abi::Rust => String::new(),
19141933
a => format!("extern {} ", a.to_string())
19151934
},
1916-
ty = shortty(it),
1917-
name = it.name.as_ref().unwrap(),
1935+
href = href,
1936+
name = name,
19181937
generics = *g,
19191938
decl = Method(selfty, d),
19201939
where_clause = WhereClause(g))
19211940
}
19221941
match meth.inner {
19231942
clean::TyMethodItem(ref m) => {
1924-
method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl)
1943+
method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl,
1944+
link)
19251945
}
19261946
clean::MethodItem(ref m) => {
1927-
method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl)
1947+
method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl,
1948+
link)
19281949
}
19291950
clean::AssociatedTypeItem(ref bounds, ref default) => {
19301951
assoc_type(w, meth, bounds, default)
@@ -2151,6 +2172,12 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
21512172
Ok(())
21522173
}
21532174

2175+
#[derive(Copy, Clone)]
2176+
enum MethodLink {
2177+
Anchor,
2178+
GotoSource(ast::DefId),
2179+
}
2180+
21542181
fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
21552182
match cache().impls.get(&it.def_id) {
21562183
Some(v) => {
@@ -2159,7 +2186,7 @@ fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
21592186
if non_trait.len() > 0 {
21602187
try!(write!(w, "<h2 id='methods'>Methods</h2>"));
21612188
for i in &non_trait {
2162-
try!(render_impl(w, i));
2189+
try!(render_impl(w, i, MethodLink::Anchor));
21632190
}
21642191
}
21652192
if traits.len() > 0 {
@@ -2168,13 +2195,16 @@ fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
21682195
let (derived, manual): (Vec<_>, _) = traits.into_iter()
21692196
.partition(|i| i.impl_.derived);
21702197
for i in &manual {
2171-
try!(render_impl(w, i));
2198+
let did = i.trait_did().unwrap();
2199+
try!(render_impl(w, i, MethodLink::GotoSource(did)));
21722200
}
21732201
if derived.len() > 0 {
2174-
try!(write!(w, "<h3 id='derived_implementations'>Derived Implementations \
2175-
</h3>"));
2202+
try!(write!(w, "<h3 id='derived_implementations'>\
2203+
Derived Implementations \
2204+
</h3>"));
21762205
for i in &derived {
2177-
try!(render_impl(w, i));
2206+
let did = i.trait_did().unwrap();
2207+
try!(render_impl(w, i, MethodLink::GotoSource(did)));
21782208
}
21792209
}
21802210
}
@@ -2184,36 +2214,32 @@ fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
21842214
Ok(())
21852215
}
21862216

2187-
fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
2217+
fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink)
2218+
-> fmt::Result {
21882219
try!(write!(w, "<h3 class='impl'>{}<code>impl{} ",
21892220
ConciseStability(&i.stability),
21902221
i.impl_.generics));
2191-
match i.impl_.polarity {
2192-
Some(clean::ImplPolarity::Negative) => try!(write!(w, "!")),
2193-
_ => {}
2222+
if let Some(clean::ImplPolarity::Negative) = i.impl_.polarity {
2223+
try!(write!(w, "!"));
21942224
}
2195-
match i.impl_.trait_ {
2196-
Some(ref ty) => try!(write!(w, "{} for ", *ty)),
2197-
None => {}
2225+
if let Some(ref ty) = i.impl_.trait_ {
2226+
try!(write!(w, "{} for ", *ty));
21982227
}
2199-
try!(write!(w, "{}{}</code></h3>", i.impl_.for_, WhereClause(&i.impl_.generics)));
2200-
match i.dox {
2201-
Some(ref dox) => {
2202-
try!(write!(w, "<div class='docblock'>{}</div>",
2203-
Markdown(dox)));
2204-
}
2205-
None => {}
2228+
try!(write!(w, "{}{}</code></h3>", i.impl_.for_,
2229+
WhereClause(&i.impl_.generics)));
2230+
if let Some(ref dox) = i.dox {
2231+
try!(write!(w, "<div class='docblock'>{}</div>", Markdown(dox)));
22062232
}
22072233

2208-
fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item, dox: bool)
2209-
-> fmt::Result {
2234+
fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item,
2235+
dox: bool, link: MethodLink) -> fmt::Result {
22102236
match item.inner {
22112237
clean::MethodItem(..) | clean::TyMethodItem(..) => {
22122238
try!(write!(w, "<h4 id='method.{}' class='{}'>{}<code>",
22132239
*item.name.as_ref().unwrap(),
22142240
shortty(item),
22152241
ConciseStability(&item.stability)));
2216-
try!(render_method(w, item));
2242+
try!(render_method(w, item, link));
22172243
try!(write!(w, "</code></h4>\n"));
22182244
}
22192245
clean::TypedefItem(ref tydef) => {
@@ -2247,10 +2273,11 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
22472273

22482274
try!(write!(w, "<div class='impl-items'>"));
22492275
for trait_item in i.impl_.items.iter() {
2250-
try!(doctraititem(w, trait_item, true));
2276+
try!(doctraititem(w, trait_item, true, link));
22512277
}
22522278

22532279
fn render_default_methods(w: &mut fmt::Formatter,
2280+
did: ast::DefId,
22542281
t: &clean::Trait,
22552282
i: &clean::Impl) -> fmt::Result {
22562283
for trait_item in &t.items {
@@ -2260,7 +2287,8 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
22602287
None => {}
22612288
}
22622289

2263-
try!(doctraititem(w, trait_item, false));
2290+
try!(doctraititem(w, trait_item, false,
2291+
MethodLink::GotoSource(did)));
22642292
}
22652293
Ok(())
22662294
}
@@ -2271,7 +2299,7 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl) -> fmt::Result {
22712299
// for them work.
22722300
if let Some(clean::ResolvedPath { did, .. }) = i.impl_.trait_ {
22732301
if let Some(t) = cache().traits.get(&did) {
2274-
try!(render_default_methods(w, t, &i.impl_));
2302+
try!(render_default_methods(w, did, t, &i.impl_));
22752303
}
22762304
}
22772305
try!(write!(w, "</div>"));

0 commit comments

Comments
 (0)