Skip to content

Commit 5f34316

Browse files
committed
simplify deprecation and stability rendering
1 parent f4b07e0 commit 5f34316

File tree

5 files changed

+141
-129
lines changed

5 files changed

+141
-129
lines changed

src/librustdoc/clean/mod.rs

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ impl Item {
478478
classes.push("unstable");
479479
}
480480

481-
if !s.deprecated_since.is_empty() {
481+
if s.deprecation.is_some() {
482482
classes.push("deprecated");
483483
}
484484

@@ -503,6 +503,15 @@ impl Item {
503503
pub fn type_(&self) -> ItemType {
504504
ItemType::from(self)
505505
}
506+
507+
/// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes.
508+
///
509+
/// If the item is not deprecated, returns `None`.
510+
pub fn deprecation(&self) -> Option<&Deprecation> {
511+
self.deprecation
512+
.as_ref()
513+
.or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref()))
514+
}
506515
}
507516

508517
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
@@ -3838,40 +3847,37 @@ impl Clean<Item> for doctree::ProcMacro {
38383847
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
38393848
pub struct Stability {
38403849
pub level: stability::StabilityLevel,
3841-
pub feature: String,
3850+
pub feature: Option<String>,
38423851
pub since: String,
3843-
pub deprecated_since: String,
3844-
pub deprecated_reason: String,
3845-
pub unstable_reason: String,
3846-
pub issue: Option<u32>
3852+
pub deprecation: Option<Deprecation>,
3853+
pub unstable_reason: Option<String>,
3854+
pub issue: Option<u32>,
38473855
}
38483856

38493857
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
38503858
pub struct Deprecation {
3851-
pub since: String,
3852-
pub note: String,
3859+
pub since: Option<String>,
3860+
pub note: Option<String>,
38533861
}
38543862

38553863
impl Clean<Stability> for attr::Stability {
38563864
fn clean(&self, _: &DocContext) -> Stability {
38573865
Stability {
38583866
level: stability::StabilityLevel::from_attr_level(&self.level),
3859-
feature: self.feature.to_string(),
3867+
feature: Some(self.feature.to_string()).filter(|f| !f.is_empty()),
38603868
since: match self.level {
38613869
attr::Stable {ref since} => since.to_string(),
38623870
_ => String::new(),
38633871
},
3864-
deprecated_since: match self.rustc_depr {
3865-
Some(attr::RustcDeprecation {ref since, ..}) => since.to_string(),
3866-
_=> String::new(),
3867-
},
3868-
deprecated_reason: match self.rustc_depr {
3869-
Some(ref depr) => depr.reason.to_string(),
3870-
_ => String::new(),
3871-
},
3872+
deprecation: self.rustc_depr.as_ref().map(|d| {
3873+
Deprecation {
3874+
note: Some(d.reason.to_string()).filter(|r| !r.is_empty()),
3875+
since: Some(d.since.to_string()).filter(|d| !d.is_empty()),
3876+
}
3877+
}),
38723878
unstable_reason: match self.level {
3873-
attr::Unstable { reason: Some(ref reason), .. } => reason.to_string(),
3874-
_ => String::new(),
3879+
attr::Unstable { reason: Some(ref reason), .. } => Some(reason.to_string()),
3880+
_ => None,
38753881
},
38763882
issue: match self.level {
38773883
attr::Unstable {issue, ..} => Some(issue),
@@ -3890,8 +3896,8 @@ impl<'a> Clean<Stability> for &'a attr::Stability {
38903896
impl Clean<Deprecation> for attr::Deprecation {
38913897
fn clean(&self, _: &DocContext) -> Deprecation {
38923898
Deprecation {
3893-
since: self.since.as_ref().map_or(String::new(), |s| s.to_string()),
3894-
note: self.note.as_ref().map_or(String::new(), |s| s.to_string()),
3899+
since: self.since.map(|s| s.to_string()).filter(|s| !s.is_empty()),
3900+
note: self.note.map(|n| n.to_string()).filter(|n| !n.is_empty()),
38953901
}
38963902
}
38973903
}

src/librustdoc/html/render.rs

Lines changed: 84 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ use rustc::hir;
6565
use rustc::util::nodemap::{FxHashMap, FxHashSet};
6666
use rustc_data_structures::flock;
6767

68-
use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability};
68+
use clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, Mutability};
6969
use config::RenderOptions;
7070
use doctree;
7171
use fold::DocFolder;
@@ -2449,7 +2449,7 @@ fn document_full(w: &mut fmt::Formatter, item: &clean::Item,
24492449

24502450
fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
24512451
is_hidden: bool) -> fmt::Result {
2452-
let stabilities = short_stability(item, cx, true);
2452+
let stabilities = short_stability(item, cx);
24532453
if !stabilities.is_empty() {
24542454
write!(w, "<div class='stability{}'>", if is_hidden { " hidden" } else { "" })?;
24552455
for stability in stabilities {
@@ -2642,18 +2642,6 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
26422642
_ => {
26432643
if myitem.name.is_none() { continue }
26442644

2645-
let stabilities = short_stability(myitem, cx, false);
2646-
2647-
let stab_docs = if !stabilities.is_empty() {
2648-
stabilities.iter()
2649-
.map(|s| format!("[{}]", s))
2650-
.collect::<Vec<_>>()
2651-
.as_slice()
2652-
.join(" ")
2653-
} else {
2654-
String::new()
2655-
};
2656-
26572645
let unsafety_flag = match myitem.inner {
26582646
clean::FunctionItem(ref func) | clean::ForeignFunctionItem(ref func)
26592647
if func.header.unsafety == hir::Unsafety::Unsafe => {
@@ -2674,11 +2662,11 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
26742662
<tr class='{stab}{add}module-item'>\
26752663
<td><a class=\"{class}\" href=\"{href}\" \
26762664
title='{title}'>{name}</a>{unsafety_flag}</td>\
2677-
<td class='docblock-short'>{stab_docs}{docs}\
2665+
<td class='docblock-short'>{stab_tags}{docs}\
26782666
</td>\
26792667
</tr>",
26802668
name = *myitem.name.as_ref().unwrap(),
2681-
stab_docs = stab_docs,
2669+
stab_tags = stability_tags(myitem),
26822670
docs = MarkdownSummaryLine(doc_value, &myitem.links()),
26832671
class = myitem.type_(),
26842672
add = add,
@@ -2705,101 +2693,99 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
27052693
Ok(())
27062694
}
27072695

2708-
fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<String> {
2696+
/// Render the stability and deprecation tags that are displayed in the item's summary at the
2697+
/// module level.
2698+
fn stability_tags(item: &clean::Item) -> String {
2699+
let mut tags = String::new();
2700+
2701+
// The trailing space after each tag is to space it properly against the rest of the docs.
2702+
if item.deprecation().is_some() {
2703+
tags.push_str("[<div class='stab deprecated'>Deprecated</div>] ");
2704+
}
2705+
2706+
if item
2707+
.stability
2708+
.as_ref()
2709+
.filter(|s| s.level == stability::Unstable)
2710+
.is_some()
2711+
{
2712+
tags.push_str("[<div class='stab unstable'>Experimental</div>] ");
2713+
}
2714+
2715+
if let Some(ref cfg) = item.attrs.cfg {
2716+
tags.push_str(&format!(
2717+
"[<div class='stab portability'>{}</div>] ",
2718+
cfg.render_short_html()
2719+
));
2720+
}
2721+
2722+
tags
2723+
}
2724+
2725+
/// Render the stability and/or deprecation warning that is displayed at the top of the item's
2726+
/// documentation.
2727+
fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
27092728
let mut stability = vec![];
27102729
let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
27112730

2712-
if let Some(stab) = item.stability.as_ref() {
2713-
let deprecated_reason = if show_reason && !stab.deprecated_reason.is_empty() {
2714-
format!(": {}", stab.deprecated_reason)
2731+
if let Some(Deprecation { since, note }) = &item.deprecation() {
2732+
let mut message = if let Some(since) = since {
2733+
if stability::deprecation_in_effect(since) {
2734+
format!("Deprecated since {}", Escape(since))
2735+
} else {
2736+
format!("Deprecating in {}", Escape(since))
2737+
}
27152738
} else {
2716-
String::new()
2739+
String::from("Deprecated")
27172740
};
2718-
if !stab.deprecated_since.is_empty() {
2719-
let since = if show_reason {
2720-
format!(" since {}", Escape(&stab.deprecated_since))
2721-
} else {
2722-
String::new()
2723-
};
2741+
2742+
if let Some(note) = note {
27242743
let mut ids = cx.id_map.borrow_mut();
2725-
let html = MarkdownHtml(&deprecated_reason, RefCell::new(&mut ids), error_codes);
2726-
let text = if stability::deprecation_in_effect(&stab.deprecated_since) {
2727-
format!("Deprecated{}{}", since, html)
2728-
} else {
2729-
format!("Deprecating in {}{}", Escape(&stab.deprecated_since), html)
2730-
};
2731-
stability.push(format!("<div class='stab deprecated'>{}</div>", text))
2732-
};
2744+
let html = MarkdownHtml(&note, RefCell::new(&mut ids), error_codes);
2745+
message.push_str(&format!(": {}", html));
2746+
}
2747+
stability.push(format!("<div class='stab deprecated'>{}</div>", message));
2748+
}
27332749

2734-
if stab.level == stability::Unstable {
2735-
if show_reason {
2736-
let unstable_extra = match (!stab.feature.is_empty(),
2737-
&cx.shared.issue_tracker_base_url,
2738-
stab.issue) {
2739-
(true, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
2740-
format!(" (<code>{} </code><a href=\"{}{}\">#{}</a>)",
2741-
Escape(&stab.feature), tracker_url, issue_no, issue_no),
2742-
(false, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
2743-
format!(" (<a href=\"{}{}\">#{}</a>)", Escape(&tracker_url), issue_no,
2744-
issue_no),
2745-
(true, ..) =>
2746-
format!(" (<code>{}</code>)", Escape(&stab.feature)),
2747-
_ => String::new(),
2748-
};
2749-
if stab.unstable_reason.is_empty() {
2750-
stability.push(format!("<div class='stab unstable'>\
2751-
<span class=microscope>🔬</span> \
2752-
This is a nightly-only experimental API. {}\
2753-
</div>",
2754-
unstable_extra));
2755-
} else {
2756-
let mut ids = cx.id_map.borrow_mut();
2757-
let text = format!("<summary><span class=microscope>🔬</span> \
2758-
This is a nightly-only experimental API. {}\
2759-
</summary>{}",
2760-
unstable_extra,
2761-
MarkdownHtml(
2762-
&stab.unstable_reason,
2763-
RefCell::new(&mut ids),
2764-
error_codes));
2765-
stability.push(format!("<div class='stab unstable'><details>{}</details></div>",
2766-
text));
2767-
}
2768-
} else {
2769-
stability.push("<div class='stab unstable'>Experimental</div>".to_string())
2750+
if let Some(stab) = item
2751+
.stability
2752+
.as_ref()
2753+
.filter(|stab| stab.level == stability::Unstable)
2754+
{
2755+
let mut message = String::from(
2756+
"<span class=microscope>🔬</span> This is a nightly-only experimental API.",
2757+
);
2758+
2759+
if let Some(feature) = stab.feature.as_ref() {
2760+
let mut feature = format!("<code>{}</code>", Escape(&feature));
2761+
if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, stab.issue) {
2762+
feature.push_str(&format!(
2763+
"&nbsp;<a href=\"{url}{issue}\">#{issue}</a>",
2764+
url = url,
2765+
issue = issue
2766+
));
27702767
}
2771-
};
2772-
} else if let Some(depr) = item.deprecation.as_ref() {
2773-
let note = if show_reason && !depr.note.is_empty() {
2774-
format!(": {}", depr.note)
2775-
} else {
2776-
String::new()
2777-
};
2778-
let since = if show_reason && !depr.since.is_empty() {
2779-
format!(" since {}", Escape(&depr.since))
2780-
} else {
2781-
String::new()
2782-
};
27832768

2784-
let mut ids = cx.id_map.borrow_mut();
2785-
let text = if stability::deprecation_in_effect(&depr.since) {
2786-
format!("Deprecated{}{}",
2787-
since,
2788-
MarkdownHtml(&note, RefCell::new(&mut ids), error_codes))
2789-
} else {
2790-
format!("Deprecating in {}{}",
2791-
Escape(&depr.since),
2792-
MarkdownHtml(&note, RefCell::new(&mut ids), error_codes))
2793-
};
2794-
stability.push(format!("<div class='stab deprecated'>{}</div>", text))
2769+
message.push_str(&format!(" ({})", feature));
2770+
}
2771+
2772+
if let Some(unstable_reason) = &stab.unstable_reason {
2773+
let mut ids = cx.id_map.borrow_mut();
2774+
message = format!(
2775+
"<details><summary>{}</summary>{}</details>",
2776+
message,
2777+
MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes)
2778+
);
2779+
}
2780+
2781+
stability.push(format!("<div class='stab unstable'>{}</div>", message))
27952782
}
27962783

27972784
if let Some(ref cfg) = item.attrs.cfg {
2798-
stability.push(format!("<div class='stab portability'>{}</div>", if show_reason {
2785+
stability.push(format!(
2786+
"<div class='stab portability'>{}</div>",
27992787
cfg.render_long_html()
2800-
} else {
2801-
cfg.render_short_html()
2802-
}));
2788+
));
28032789
}
28042790

28052791
stability

src/test/rustdoc/deprecated.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,29 @@
1010

1111
#![feature(deprecated)]
1212

13+
// @matches deprecated/index.html '//*[@class="docblock-short"]' \
14+
// '^\[Deprecated\] Deprecated docs'
1315
// @has deprecated/struct.S.html '//*[@class="stab deprecated"]' \
1416
// 'Deprecated since 1.0.0: text'
17+
/// Deprecated docs
1518
#[deprecated(since = "1.0.0", note = "text")]
1619
pub struct S;
20+
21+
// @matches deprecated/index.html '//*[@class="docblock-short"]' '^Docs'
22+
/// Docs
23+
pub struct T;
24+
25+
// @matches deprecated/struct.U.html '//*[@class="stab deprecated"]' \
26+
// 'Deprecated since 1.0.0$'
27+
#[deprecated(since = "1.0.0")]
28+
pub struct U;
29+
30+
// @matches deprecated/struct.V.html '//*[@class="stab deprecated"]' \
31+
// 'Deprecated: text$'
32+
#[deprecated(note = "text")]
33+
pub struct V;
34+
35+
// @matches deprecated/struct.W.html '//*[@class="stab deprecated"]' \
36+
// 'Deprecated$'
37+
#[deprecated]
38+
pub struct W;

src/test/rustdoc/issue-27759.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,11 @@
1414
#![unstable(feature="test", issue="27759")]
1515

1616
// @has issue_27759/unstable/index.html
17-
// @has - '<code>test </code>'
18-
// @has - '<a href="http://issue_url/27759">#27759</a>'
17+
// @has - '<code>test</code>&nbsp;<a href="http://issue_url/27759">#27759</a>'
1918
#[unstable(feature="test", issue="27759")]
2019
pub mod unstable {
2120
// @has issue_27759/unstable/fn.issue.html
22-
// @has - '<code>test_function </code>'
23-
// @has - '<a href="http://issue_url/1234567890">#1234567890</a>'
24-
#[unstable(feature="test_function", issue="1234567890")]
21+
// @has - '<code>test_function</code>&nbsp;<a href="http://issue_url/12345">#12345</a>'
22+
#[unstable(feature="test_function", issue="12345")]
2523
pub fn issue() {}
2624
}

src/test/rustdoc/issue-32374.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@
1313

1414
#![unstable(feature="test", issue = "32374")]
1515

16-
// @has issue_32374/index.html '//*[@class="docblock-short"]' \
17-
// '[Deprecated] [Experimental]'
16+
// @matches issue_32374/index.html '//*[@class="docblock-short"]' \
17+
// '^\[Deprecated\] \[Experimental\] Docs'
1818

1919
// @has issue_32374/struct.T.html '//*[@class="stab deprecated"]' \
2020
// 'Deprecated since 1.0.0: text'
21-
// @has - '<code>test </code>'
22-
// @has - '<a href="http://issue_url/32374">#32374</a>'
21+
// @has - '<code>test</code>&nbsp;<a href="http://issue_url/32374">#32374</a>'
2322
// @matches issue_32374/struct.T.html '//*[@class="stab unstable"]' \
24-
// '🔬 This is a nightly-only experimental API. \(test #32374\)$'
23+
// '🔬 This is a nightly-only experimental API. \(test #32374\)$'
24+
/// Docs
2525
#[rustc_deprecated(since = "1.0.0", reason = "text")]
2626
#[unstable(feature = "test", issue = "32374")]
2727
pub struct T;

0 commit comments

Comments
 (0)