Skip to content

Commit 75acee2

Browse files
committed
Rustdoc - display since version for stable items
Fixes #27607
1 parent 32b2ef7 commit 75acee2

File tree

3 files changed

+94
-27
lines changed

3 files changed

+94
-27
lines changed

src/librustdoc/clean/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,14 @@ impl Item {
339339
_ => String::new(),
340340
}
341341
}
342+
343+
pub fn stable_since(&self) -> Option<&str> {
344+
if let Some(ref s) = self.stability {
345+
return Some(&s.since[..]);
346+
}
347+
348+
None
349+
}
342350
}
343351

344352
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]

src/librustdoc/html/render.rs

+71-27
Original file line numberDiff line numberDiff line change
@@ -1913,6 +1913,7 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
19131913
generics = f.generics,
19141914
where_clause = WhereClause(&f.generics),
19151915
decl = f.decl));
1916+
try!(render_stability_since_raw(w, it.stable_since(), None));
19161917
document(w, cx, it)
19171918
}
19181919

@@ -1992,15 +1993,17 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
19921993
// Trait documentation
19931994
try!(document(w, cx, it));
19941995

1995-
fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item)
1996+
fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item, t: &clean::Item)
19961997
-> fmt::Result {
19971998
let name = m.name.as_ref().unwrap();
19981999
let id = derive_id(format!("{}.{}", shortty(m), name));
19992000
try!(write!(w, "<h3 id='{id}' class='method stab {stab}'><code>",
20002001
id = id,
20012002
stab = m.stability_class()));
20022003
try!(render_assoc_item(w, m, AssocItemLink::Anchor));
2003-
try!(write!(w, "</code></h3>"));
2004+
try!(write!(w, "</code>"));
2005+
try!(render_stability_since(w, m, t));
2006+
try!(write!(w, "</h3>"));
20042007
try!(document(w, cx, m));
20052008
Ok(())
20062009
}
@@ -2011,7 +2014,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
20112014
<div class='methods'>
20122015
"));
20132016
for t in &types {
2014-
try!(trait_item(w, cx, *t));
2017+
try!(trait_item(w, cx, *t, it));
20152018
}
20162019
try!(write!(w, "</div>"));
20172020
}
@@ -2022,7 +2025,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
20222025
<div class='methods'>
20232026
"));
20242027
for t in &consts {
2025-
try!(trait_item(w, cx, *t));
2028+
try!(trait_item(w, cx, *t, it));
20262029
}
20272030
try!(write!(w, "</div>"));
20282031
}
@@ -2034,7 +2037,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
20342037
<div class='methods'>
20352038
"));
20362039
for m in &required {
2037-
try!(trait_item(w, cx, *m));
2040+
try!(trait_item(w, cx, *m, it));
20382041
}
20392042
try!(write!(w, "</div>"));
20402043
}
@@ -2044,13 +2047,13 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
20442047
<div class='methods'>
20452048
"));
20462049
for m in &provided {
2047-
try!(trait_item(w, cx, *m));
2050+
try!(trait_item(w, cx, *m, it));
20482051
}
20492052
try!(write!(w, "</div>"));
20502053
}
20512054

20522055
// If there are methods directly on this trait object, render them here.
2053-
try!(render_assoc_items(w, cx, it.def_id, AssocItemRender::All));
2056+
try!(render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All));
20542057

20552058
let cache = cache();
20562059
try!(write!(w, "
@@ -2106,6 +2109,29 @@ fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
21062109
Ok(())
21072110
}
21082111

2112+
fn render_stability_since_raw<'a>(w: &mut fmt::Formatter,
2113+
ver: Option<&'a str>,
2114+
containing_ver: Option<&'a str>) -> fmt::Result {
2115+
if containing_ver != ver {
2116+
match ver {
2117+
Some(v) =>
2118+
if v.len() > 0 {
2119+
try!(write!(w, "<span class=\"since\">{}</span>",
2120+
v))
2121+
},
2122+
None => {}
2123+
}
2124+
}
2125+
2126+
Ok(())
2127+
}
2128+
2129+
fn render_stability_since(w: &mut fmt::Formatter,
2130+
item: &clean::Item,
2131+
containing_item: &clean::Item) -> fmt::Result {
2132+
render_stability_since_raw(w, item.stable_since(), containing_item.stable_since())
2133+
}
2134+
21092135
fn render_assoc_item(w: &mut fmt::Formatter, meth: &clean::Item,
21102136
link: AssocItemLink) -> fmt::Result {
21112137
fn method(w: &mut fmt::Formatter,
@@ -2178,6 +2204,7 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
21782204
"",
21792205
true));
21802206
try!(write!(w, "</pre>"));
2207+
try!(render_stability_since_raw(w, it.stable_since(), None));
21812208

21822209
try!(document(w, cx, it));
21832210
let mut fields = s.fields.iter().filter(|f| {
@@ -2202,7 +2229,7 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
22022229
try!(write!(w, "</table>"));
22032230
}
22042231
}
2205-
render_assoc_items(w, cx, it.def_id, AssocItemRender::All)
2232+
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
22062233
}
22072234

22082235
fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
@@ -2257,10 +2284,11 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
22572284
try!(write!(w, "}}"));
22582285
}
22592286
try!(write!(w, "</pre>"));
2287+
try!(render_stability_since_raw(w, it.stable_since(), None));
22602288

22612289
try!(document(w, cx, it));
22622290
if !e.variants.is_empty() {
2263-
try!(write!(w, "<h2 class='variants'>Variants</h2>\n<table>"));
2291+
try!(write!(w, "<h2 class='variants'>Variants</h2>\n<table class='variants_table'>"));
22642292
for variant in &e.variants {
22652293
try!(write!(w, "<tr><td id='variant.{name}'><code>{name}</code></td><td>",
22662294
name = variant.name.as_ref().unwrap()));
@@ -2296,12 +2324,14 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
22962324
}
22972325
_ => ()
22982326
}
2327+
try!(write!(w, "</td><td>"));
2328+
try!(render_stability_since(w, variant, it));
22992329
try!(write!(w, "</td></tr>"));
23002330
}
23012331
try!(write!(w, "</table>"));
23022332

23032333
}
2304-
try!(render_assoc_items(w, cx, it.def_id, AssocItemRender::All));
2334+
try!(render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All));
23052335
Ok(())
23062336
}
23072337

@@ -2397,6 +2427,7 @@ enum AssocItemRender<'a> {
23972427

23982428
fn render_assoc_items(w: &mut fmt::Formatter,
23992429
cx: &Context,
2430+
containing_item: &clean::Item,
24002431
it: DefId,
24012432
what: AssocItemRender) -> fmt::Result {
24022433
let c = cache();
@@ -2420,7 +2451,8 @@ fn render_assoc_items(w: &mut fmt::Formatter,
24202451
}
24212452
};
24222453
for i in &non_trait {
2423-
try!(render_impl(w, cx, i, AssocItemLink::Anchor, render_header));
2454+
try!(render_impl(w, cx, i, AssocItemLink::Anchor, render_header,
2455+
containing_item.stable_since()));
24242456
}
24252457
}
24262458
if let AssocItemRender::DerefFor { .. } = what {
@@ -2436,7 +2468,7 @@ fn render_assoc_items(w: &mut fmt::Formatter,
24362468
}
24372469
});
24382470
if let Some(impl_) = deref_impl {
2439-
try!(render_deref_methods(w, cx, impl_));
2471+
try!(render_deref_methods(w, cx, impl_, containing_item));
24402472
}
24412473
try!(write!(w, "<h2 id='implementations'>Trait \
24422474
Implementations</h2>"));
@@ -2445,22 +2477,25 @@ fn render_assoc_items(w: &mut fmt::Formatter,
24452477
});
24462478
for i in &manual {
24472479
let did = i.trait_did().unwrap();
2448-
try!(render_impl(w, cx, i, AssocItemLink::GotoSource(did), true));
2480+
try!(render_impl(w, cx, i, AssocItemLink::GotoSource(did), true,
2481+
containing_item.stable_since()));
24492482
}
24502483
if !derived.is_empty() {
24512484
try!(write!(w, "<h3 id='derived_implementations'>\
24522485
Derived Implementations \
24532486
</h3>"));
24542487
for i in &derived {
24552488
let did = i.trait_did().unwrap();
2456-
try!(render_impl(w, cx, i, AssocItemLink::GotoSource(did), true));
2489+
try!(render_impl(w, cx, i, AssocItemLink::GotoSource(did), true,
2490+
containing_item.stable_since()));
24572491
}
24582492
}
24592493
}
24602494
Ok(())
24612495
}
24622496

2463-
fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl) -> fmt::Result {
2497+
fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl,
2498+
container_item: &clean::Item) -> fmt::Result {
24642499
let deref_type = impl_.impl_.trait_.as_ref().unwrap();
24652500
let target = impl_.impl_.items.iter().filter_map(|item| {
24662501
match item.inner {
@@ -2470,12 +2505,12 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl) -> f
24702505
}).next().expect("Expected associated type binding");
24712506
let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target };
24722507
match *target {
2473-
clean::ResolvedPath { did, .. } => render_assoc_items(w, cx, did, what),
2508+
clean::ResolvedPath { did, .. } => render_assoc_items(w, cx, container_item, did, what),
24742509
_ => {
24752510
if let Some(prim) = target.primitive_type() {
24762511
if let Some(c) = cache().primitive_locations.get(&prim) {
24772512
let did = DefId { krate: *c, index: prim.to_def_index() };
2478-
try!(render_assoc_items(w, cx, did, what));
2513+
try!(render_assoc_items(w, cx, container_item, did, what));
24792514
}
24802515
}
24812516
Ok(())
@@ -2487,24 +2522,30 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl) -> f
24872522
// otherwise. If render_header is false, we will avoid rendering static
24882523
// methods, since they are not accessible for the type implementing `Deref`
24892524
fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLink,
2490-
render_header: bool) -> fmt::Result {
2525+
render_header: bool, outer_version: Option<&str>) -> fmt::Result {
24912526
if render_header {
2492-
try!(write!(w, "<h3 class='impl'><code>{}</code></h3>", i.impl_));
2527+
try!(write!(w, "<h3 class='impl'><code>{}</code>", i.impl_));
2528+
let since = i.stability.as_ref().map(|s| &s.since[..]);
2529+
try!(render_stability_since_raw(w, since, outer_version));
2530+
try!(write!(w, "</h3>"));
24932531
if let Some(ref dox) = i.dox {
24942532
try!(write!(w, "<div class='docblock'>{}</div>", Markdown(dox)));
24952533
}
24962534
}
24972535

24982536
fn doctraititem(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
2499-
link: AssocItemLink, render_static: bool) -> fmt::Result {
2537+
link: AssocItemLink, render_static: bool,
2538+
outer_version: Option<&str>) -> fmt::Result {
25002539
let name = item.name.as_ref().unwrap();
25012540
match item.inner {
25022541
clean::MethodItem(..) | clean::TyMethodItem(..) => {
25032542
// Only render when the method is not static or we allow static methods
25042543
if !is_static_method(item) || render_static {
25052544
let id = derive_id(format!("method.{}", name));
2506-
try!(write!(w, "<h4 id='{}' class='{}'><code>", id, shortty(item)));
2507-
try!(render_assoc_item(w, item, link));
2545+
try!(write!(w, "<h4 id='{}' class='{}'>", id, shortty(item)));
2546+
try!(render_stability_since_raw(w, item.stable_since(), outer_version));
2547+
try!(write!(w, "<code>"));
2548+
try!(render_assoc_item(w, item, link));
25082549
try!(write!(w, "</code></h4>\n"));
25092550
}
25102551
}
@@ -2556,23 +2597,25 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
25562597

25572598
try!(write!(w, "<div class='impl-items'>"));
25582599
for trait_item in &i.impl_.items {
2559-
try!(doctraititem(w, cx, trait_item, link, render_header));
2600+
try!(doctraititem(w, cx, trait_item, link, render_header, outer_version));
25602601
}
25612602

25622603
fn render_default_items(w: &mut fmt::Formatter,
25632604
cx: &Context,
25642605
did: DefId,
25652606
t: &clean::Trait,
25662607
i: &clean::Impl,
2567-
render_static: bool) -> fmt::Result {
2608+
render_static: bool,
2609+
outer_version: Option<&str>) -> fmt::Result {
25682610
for trait_item in &t.items {
25692611
let n = trait_item.name.clone();
25702612
match i.items.iter().find(|m| { m.name == n }) {
25712613
Some(..) => continue,
25722614
None => {}
25732615
}
25742616

2575-
try!(doctraititem(w, cx, trait_item, AssocItemLink::GotoSource(did), render_static));
2617+
try!(doctraititem(w, cx, trait_item, AssocItemLink::GotoSource(did), render_static,
2618+
outer_version));
25762619
}
25772620
Ok(())
25782621
}
@@ -2583,7 +2626,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
25832626
// for them work.
25842627
if let Some(clean::ResolvedPath { did, .. }) = i.impl_.trait_ {
25852628
if let Some(t) = cache().traits.get(&did) {
2586-
try!(render_default_items(w, cx, did, t, &i.impl_, render_header));
2629+
try!(render_default_items(w, cx, did, t, &i.impl_, render_header, outer_version));
25872630

25882631
}
25892632
}
@@ -2675,14 +2718,15 @@ fn item_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
26752718
try!(w.write_str(&highlight::highlight(&t.source,
26762719
Some("macro"),
26772720
None)));
2721+
try!(render_stability_since_raw(w, it.stable_since(), None));
26782722
document(w, cx, it)
26792723
}
26802724

26812725
fn item_primitive(w: &mut fmt::Formatter, cx: &Context,
26822726
it: &clean::Item,
26832727
_p: &clean::PrimitiveType) -> fmt::Result {
26842728
try!(document(w, cx, it));
2685-
render_assoc_items(w, cx, it.def_id, AssocItemRender::All)
2729+
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
26862730
}
26872731

26882732
fn get_basic_keywords() -> &'static str {

src/librustdoc/html/static/rustdoc.css

+15
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,21 @@ em.stab p {
498498
opacity: 0.65;
499499
}
500500

501+
span.since {
502+
float: right;
503+
font-weight: normal;
504+
font-size: initial;
505+
color: grey;
506+
}
507+
508+
.variants_table {
509+
width: 100%;
510+
}
511+
512+
.variants_table tbody tr td:first-child {
513+
width: 1%; /* make the variant name as small as possible */
514+
}
515+
501516
td.summary-column {
502517
width: 100%;
503518
}

0 commit comments

Comments
 (0)