Skip to content

Commit 6933a67

Browse files
committed
Handle structured stable attribute 'since' version in rustdoc
1 parent 7b0e315 commit 6933a67

File tree

6 files changed

+49
-29
lines changed

6 files changed

+49
-29
lines changed

compiler/rustc_attr/src/builtin.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_session::parse::{feature_err, ParseSess};
1313
use rustc_session::Session;
1414
use rustc_span::hygiene::Transparency;
1515
use rustc_span::{symbol::sym, symbol::Symbol, Span};
16+
use std::fmt::{self, Display};
1617
use std::num::NonZeroU32;
1718

1819
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
@@ -590,6 +591,12 @@ fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> {
590591
Some(Version { major, minor, patch })
591592
}
592593

594+
impl Display for Version {
595+
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
596+
write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
597+
}
598+
}
599+
593600
/// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
594601
/// evaluate individual items.
595602
pub fn eval_condition(

src/librustdoc/clean/types.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use thin_vec::ThinVec;
1212

1313
use rustc_ast as ast;
1414
use rustc_ast_pretty::pprust;
15-
use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel};
15+
use rustc_attr::{ConstStability, Deprecation, Since, Stability, StabilityLevel};
1616
use rustc_const_eval::const_eval::is_unstable_const_fn;
1717
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1818
use rustc_hir as hir;
@@ -585,14 +585,14 @@ impl Item {
585585
})
586586
}
587587

588-
pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
588+
pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option<Since> {
589589
match self.stability(tcx)?.level {
590590
StabilityLevel::Stable { since, .. } => Some(since),
591591
StabilityLevel::Unstable { .. } => None,
592592
}
593593
}
594594

595-
pub(crate) fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<Symbol> {
595+
pub(crate) fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option<Since> {
596596
match self.const_stability(tcx)?.level {
597597
StabilityLevel::Stable { since, .. } => Some(since),
598598
StabilityLevel::Unstable { .. } => None,

src/librustdoc/html/render/mod.rs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ use std::str;
4848
use std::string::ToString;
4949

5050
use askama::Template;
51-
use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
51+
use rustc_attr::{rust_version_symbol, ConstStability, Deprecation, Since, StabilityLevel};
5252
use rustc_data_structures::captures::Captures;
5353
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
5454
use rustc_hir::def_id::{DefId, DefIdSet};
@@ -911,13 +911,17 @@ fn assoc_method(
911911
/// consequence of the above rules.
912912
fn render_stability_since_raw_with_extra(
913913
w: &mut Buffer,
914-
ver: Option<Symbol>,
914+
ver: Option<Since>,
915915
const_stability: Option<ConstStability>,
916-
containing_ver: Option<Symbol>,
917-
containing_const_ver: Option<Symbol>,
916+
containing_ver: Option<Since>,
917+
containing_const_ver: Option<Since>,
918918
extra_class: &str,
919919
) -> bool {
920-
let stable_version = ver.filter(|inner| !inner.is_empty() && Some(*inner) != containing_ver);
920+
let stable_version = if ver != containing_ver && let Some(ver) = &ver {
921+
since_to_string(ver)
922+
} else {
923+
None
924+
};
921925

922926
let mut title = String::new();
923927
let mut stability = String::new();
@@ -931,7 +935,8 @@ fn render_stability_since_raw_with_extra(
931935
Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. })
932936
if Some(since) != containing_const_ver =>
933937
{
934-
Some((format!("const since {since}"), format!("const: {since}")))
938+
since_to_string(&since)
939+
.map(|since| (format!("const since {since}"), format!("const: {since}")))
935940
}
936941
Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => {
937942
let unstable = if let Some(n) = issue {
@@ -971,13 +976,21 @@ fn render_stability_since_raw_with_extra(
971976
!stability.is_empty()
972977
}
973978

979+
fn since_to_string(since: &Since) -> Option<String> {
980+
match since {
981+
Since::Version(since) => Some(since.to_string()),
982+
Since::Current => Some(rust_version_symbol().to_string()),
983+
Since::Err => None,
984+
}
985+
}
986+
974987
#[inline]
975988
fn render_stability_since_raw(
976989
w: &mut Buffer,
977-
ver: Option<Symbol>,
990+
ver: Option<Since>,
978991
const_stability: Option<ConstStability>,
979-
containing_ver: Option<Symbol>,
980-
containing_const_ver: Option<Symbol>,
992+
containing_ver: Option<Since>,
993+
containing_const_ver: Option<Since>,
981994
) -> bool {
982995
render_stability_since_raw_with_extra(
983996
w,

tests/rustdoc/html-no-source.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@
1111
// @files 'src/foo' '[]'
1212

1313
// @has foo/fn.foo.html
14-
// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · '
15-
// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
14+
// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
15+
// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
1616
#[stable(feature = "bar", since = "1.0")]
1717
pub fn foo() {}
1818

1919
// @has foo/struct.Bar.html
20-
// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · '
21-
// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
20+
// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
21+
// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
2222
#[stable(feature = "bar", since = "1.0")]
2323
pub struct Bar;
2424

2525
impl Bar {
26-
// @has - '//*[@id="method.bar"]/*[@class="since rightside"]' '2.0'
27-
// @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0 ·'
26+
// @has - '//*[@id="method.bar"]/*[@class="since rightside"]' '2.0.0'
27+
// @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0.0 ·'
2828
#[stable(feature = "foobar", since = "2.0")]
2929
pub fn bar() {}
3030
}

tests/rustdoc/source-version-separator.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,23 @@
33
#![feature(staged_api)]
44

55
// @has foo/trait.Bar.html
6-
// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
6+
// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
77
#[stable(feature = "bar", since = "1.0")]
88
pub trait Bar {
9-
// @has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0 · source'
9+
// @has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0.0 · source'
1010
#[stable(feature = "foobar", since = "3.0")]
1111
fn foo();
1212
}
1313

14-
// @has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0 · source'
14+
// @has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0.0 · source'
1515

1616
// @has foo/struct.Foo.html
17-
// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
17+
// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
1818
#[stable(feature = "baz", since = "1.0")]
1919
pub struct Foo;
2020

2121
impl Foo {
22-
// @has - '//*[@id="method.foofoo"]/*[@class="rightside"]' '3.0 · source'
22+
// @has - '//*[@id="method.foofoo"]/*[@class="rightside"]' '3.0.0 · source'
2323
#[stable(feature = "foobar", since = "3.0")]
2424
pub fn foofoo() {}
2525
}

tests/rustdoc/version-separator-without-source.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,20 @@
44
#![crate_name = "foo"]
55

66
// @has foo/fn.foo.html
7-
// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · '
8-
// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
7+
// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
8+
// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
99
#[stable(feature = "bar", since = "1.0")]
1010
pub fn foo() {}
1111

1212
// @has foo/struct.Bar.html
13-
// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · '
14-
// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
13+
// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
14+
// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
1515
#[stable(feature = "bar", since = "1.0")]
1616
pub struct Bar;
1717

1818
impl Bar {
19-
// @has - '//*[@id="method.bar"]/*[@class="since rightside"]' '2.0'
20-
// @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0 ·'
19+
// @has - '//*[@id="method.bar"]/*[@class="since rightside"]' '2.0.0'
20+
// @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0.0 ·'
2121
#[stable(feature = "foobar", since = "2.0")]
2222
pub fn bar() {}
2323
}

0 commit comments

Comments
 (0)