diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 84faa98384cc4..dbca330898c2a 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -75,6 +75,7 @@ impl JsonRenderer<'_> { name: name.map(|sym| sym.to_string()), span: span.and_then(|span| span.into_json(self)), visibility: visibility.into_json(self), + stability: item.stability(self.tcx).into_json(self), docs, attrs, deprecation: deprecation.into_json(self), @@ -203,6 +204,18 @@ impl FromClean for Deprecation { } } +impl FromClean for Stability { + fn from_clean(stab: &hir::Stability, _renderer: &JsonRenderer<'_>) -> Self { + Stability { + feature: stab.feature.to_string(), + level: match stab.level { + hir::StabilityLevel::Unstable { .. } => StabilityLevel::Unstable, + hir::StabilityLevel::Stable { .. } => StabilityLevel::Stable, + }, + } + } +} + impl FromClean for Option> { fn from_clean(generic_args: &clean::GenericArgs, renderer: &JsonRenderer<'_>) -> Self { use clean::GenericArgs::*; @@ -922,6 +935,8 @@ fn maybe_from_hir_attr(attr: &hir::Attribute, item_id: ItemId, tcx: TyCtxt<'_>) vec![match kind { AK::Deprecated { .. } => return Vec::new(), // Handled separately into Item::deprecation. + AK::Stability { .. } => return Vec::new(), // Handled separately into Item::stability + AK::DocComment { .. } => unreachable!("doc comments stripped out earlier"), AK::MacroExport { .. } => Attribute::MacroExport, diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index e33d2d44cffd3..6437344edc0d1 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -361,6 +361,6 @@ mod size_asserts { // tidy-alphabetical-end // These contains a `PathBuf`, which is different sizes on different OSes. - static_assert_size!(Item, 528 + size_of::()); + static_assert_size!(Item, 560 + size_of::()); static_assert_size!(ExternalCrate, 48 + size_of::()); } diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 37dd226b73ce8..59aaba46f99cc 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -114,8 +114,8 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc // will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line // are deliberately not in a doc comment, because they need not be in public docs.) // -// Latest feature: Add `ExternCrate::path`. -pub const FORMAT_VERSION: u32 = 57; +// Latest feature: Add `Item::stability`. +pub const FORMAT_VERSION: u32 = 58; /// The root of the emitted JSON blob. /// @@ -294,10 +294,30 @@ pub struct Item { pub attrs: Vec, /// Information about the item’s deprecation, if present. pub deprecation: Option, + + pub stability: Option, + /// The type-specific fields describing this item. pub inner: ItemEnum, } +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] +pub struct Stability { + pub feature: String, + pub level: StabilityLevel, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] +#[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] +#[serde(rename_all = "snake_case")] +pub enum StabilityLevel { + Stable, + Unstable, +} + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(feature = "rkyv_0_8", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))] #[cfg_attr(feature = "rkyv_0_8", rkyv(derive(Debug)))] diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs index 74bf5b0595ad3..cd64bdb94ffbe 100644 --- a/src/tools/jsondoclint/src/validator/tests.rs +++ b/src/tools/jsondoclint/src/validator/tests.rs @@ -33,6 +33,7 @@ fn errors_on_missing_links() { links: FxHashMap::from_iter([("Not Found".to_owned(), Id(1))]), attrs: vec![], deprecation: None, + stability: None, inner: ItemEnum::Module(Module { is_crate: true, items: vec![], @@ -81,6 +82,7 @@ fn errors_on_local_in_paths_and_not_index() { links: FxHashMap::from_iter([("prim@i32".to_owned(), Id(2))]), attrs: Vec::new(), deprecation: None, + stability: None, inner: ItemEnum::Module(Module { is_crate: true, items: vec![Id(1)], @@ -100,6 +102,7 @@ fn errors_on_local_in_paths_and_not_index() { links: FxHashMap::default(), attrs: Vec::new(), deprecation: None, + stability: None, inner: ItemEnum::Primitive(Primitive { name: "i32".to_owned(), impls: vec![] }), }, ), @@ -153,6 +156,7 @@ fn errors_on_missing_path() { links: FxHashMap::default(), attrs: Vec::new(), deprecation: None, + stability: None, inner: ItemEnum::Module(Module { is_crate: true, items: vec![Id(1), Id(2)], @@ -172,6 +176,7 @@ fn errors_on_missing_path() { links: FxHashMap::default(), attrs: Vec::new(), deprecation: None, + stability: None, inner: ItemEnum::Struct(Struct { kind: StructKind::Unit, generics: generics.clone(), @@ -191,6 +196,7 @@ fn errors_on_missing_path() { links: FxHashMap::default(), attrs: Vec::new(), deprecation: None, + stability: None, inner: ItemEnum::Function(Function { sig: FunctionSignature { inputs: vec![], @@ -253,6 +259,7 @@ fn checks_local_crate_id_is_correct() { links: FxHashMap::default(), attrs: Vec::new(), deprecation: None, + stability: None, inner: ItemEnum::Module(Module { is_crate: true, items: vec![], diff --git a/tests/rustdoc-json/attrs/stability/stable.rs b/tests/rustdoc-json/attrs/stability/stable.rs new file mode 100644 index 0000000000000..a3f7afc39cb80 --- /dev/null +++ b/tests/rustdoc-json/attrs/stability/stable.rs @@ -0,0 +1,7 @@ +#![feature(staged_api)] + +//@ is "$.index[?(@.name=='foo')].stability.level" '"stable"' +//@ is "$.index[?(@.name=='foo')].stability.feature" '"eeeee"' +//@ is "$.index[?(@.name=='foo')].attrs" [] +#[stable(since = "2.71.8", feature = "eeeee")] +pub fn foo() {} diff --git a/tests/rustdoc-json/attrs/stability/unmarked.rs b/tests/rustdoc-json/attrs/stability/unmarked.rs new file mode 100644 index 0000000000000..6aa8f5ba37cd9 --- /dev/null +++ b/tests/rustdoc-json/attrs/stability/unmarked.rs @@ -0,0 +1,3 @@ +//@ is "$.index[?(@.name=='foo')].stability" null +//@ is "$.index[?(@.name=='foo')].attrs" [] +pub fn foo() {} diff --git a/tests/rustdoc-json/attrs/stability/unstable.rs b/tests/rustdoc-json/attrs/stability/unstable.rs new file mode 100644 index 0000000000000..df73f127e0c47 --- /dev/null +++ b/tests/rustdoc-json/attrs/stability/unstable.rs @@ -0,0 +1,7 @@ +#![feature(staged_api)] + +//@ is "$.index[?(@.name=='foo')].stability.level" '"unstable"' +//@ is "$.index[?(@.name=='foo')].stability.feature" '"delights"' +//@ is "$.index[?(@.name=='foo')].attrs" [] +#[unstable(feature = "delights", issue = "26")] +pub fn foo() {}