From 1c8de173238a02abeb5642c25c3cef1eea52ac18 Mon Sep 17 00:00:00 2001 From: Nixon Enraght-Moony Date: Wed, 7 Sep 2022 09:37:22 +0100 Subject: [PATCH] Rustdoc-Json: More accurate struct type. Closes #101489 --- src/etc/check_missing_items.py | 8 ++-- src/librustdoc/json/conversions.rs | 36 +++++----------- src/rustdoc-json-types/lib.rs | 42 +++++++++++++------ src/rustdoc-json-types/tests.rs | 4 +- src/test/rustdoc-json/nested.rs | 2 +- .../rustdoc-json/structs/plain_all_pub.rs | 11 +++++ .../rustdoc-json/structs/plain_doc_hidden.rs | 11 +++++ src/test/rustdoc-json/structs/plain_empty.rs | 9 ++-- .../rustdoc-json/structs/plain_pub_priv.rs | 9 ++++ src/test/rustdoc-json/structs/tuple.rs | 7 ++-- src/test/rustdoc-json/structs/tuple_empty.rs | 2 + .../rustdoc-json/structs/tuple_pub_priv.rs | 13 ++++++ src/test/rustdoc-json/structs/unit.rs | 7 ++-- .../rustdoc-json/structs/with_generics.rs | 16 +++---- .../rustdoc-json/structs/with_primitives.rs | 12 +++--- 15 files changed, 118 insertions(+), 71 deletions(-) create mode 100644 src/test/rustdoc-json/structs/plain_all_pub.rs create mode 100644 src/test/rustdoc-json/structs/plain_doc_hidden.rs create mode 100644 src/test/rustdoc-json/structs/plain_pub_priv.rs create mode 100644 src/test/rustdoc-json/structs/tuple_empty.rs create mode 100644 src/test/rustdoc-json/structs/tuple_pub_priv.rs diff --git a/src/etc/check_missing_items.py b/src/etc/check_missing_items.py index 27fb018aecadd..991c881bae10d 100644 --- a/src/etc/check_missing_items.py +++ b/src/etc/check_missing_items.py @@ -132,9 +132,11 @@ def check_type(ty): work_list |= set(item["inner"]["items"]) - visited elif item["kind"] == "struct": check_generics(item["inner"]["generics"]) - work_list |= ( - set(item["inner"]["fields"]) | set(item["inner"]["impls"]) - ) - visited + work_list |= set(item["inner"]["impls"]) - visited + if "tuple" in item["inner"]["kind"]: + work_list |= set(filter(None, item["inner"]["kind"]["tuple"])) - visited + elif "plain" in item["inner"]["kind"]: + work_list |= set(item["inner"]["kind"]["plain"]["fields"]) - visited elif item["kind"] == "struct_field": check_type(item["inner"]) elif item["kind"] == "enum": diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index c2d3543942db1..1177d482ac06d 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -304,11 +304,19 @@ impl FromWithTcx for Struct { fn from_tcx(struct_: clean::Struct, tcx: TyCtxt<'_>) -> Self { let fields_stripped = struct_.has_stripped_entries(); let clean::Struct { struct_type, generics, fields } = struct_; + + let kind = match struct_type { + CtorKind::Fn => StructKind::Tuple(ids_keeping_stripped(fields, tcx)), + CtorKind::Const => { + assert!(fields.is_empty()); + StructKind::Unit + } + CtorKind::Fictive => StructKind::Plain { fields: ids(fields, tcx), fields_stripped }, + }; + Struct { - struct_type: from_ctor_kind(struct_type), + kind, generics: generics.into_tcx(tcx), - fields_stripped, - fields: ids(fields, tcx), impls: Vec::new(), // Added in JsonRenderer::item } } @@ -327,14 +335,6 @@ impl FromWithTcx for Union { } } -pub(crate) fn from_ctor_kind(struct_type: CtorKind) -> StructType { - match struct_type { - CtorKind::Fictive => StructType::Plain, - CtorKind::Fn => StructType::Tuple, - CtorKind::Const => StructType::Unit, - } -} - pub(crate) fn from_fn_header(header: &rustc_hir::FnHeader) -> Header { Header { async_: header.is_async(), @@ -644,20 +644,6 @@ impl FromWithTcx for Enum { } } -impl FromWithTcx for Struct { - fn from_tcx(struct_: clean::VariantStruct, tcx: TyCtxt<'_>) -> Self { - let fields_stripped = struct_.has_stripped_entries(); - let clean::VariantStruct { struct_type, fields } = struct_; - Struct { - struct_type: from_ctor_kind(struct_type), - generics: Generics { params: vec![], where_predicates: vec![] }, - fields_stripped, - fields: ids(fields, tcx), - impls: Vec::new(), - } - } -} - impl FromWithTcx for Variant { fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self { use clean::Variant::*; diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index eea62f3af5ab4..13bafa506e4a6 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; use serde::{Deserialize, Serialize}; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 20; +pub const FORMAT_VERSION: u32 = 21; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow @@ -289,13 +289,39 @@ pub struct Union { #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Struct { - pub struct_type: StructType, + pub kind: StructKind, pub generics: Generics, - pub fields_stripped: bool, - pub fields: Vec, pub impls: Vec, } +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum StructKind { + /// A struct with no fields and no parentheses. + /// + /// ```rust + /// pub struct Unit; + /// ``` + Unit, + /// A struct with unnamed fields. + /// + /// ```rust + /// pub struct TupleStruct(i32); + /// pub struct EmptyTupleStruct(); + /// ``` + /// + /// All [`Id`]'s will point to [`ItemEnum::StructField`]. Private and + /// `#[doc(hidden)]` fields will be given as `None` + Tuple(Vec>), + /// A struct with nammed fields. + /// + /// ```rust + /// pub struct PlainStruct { x: i32 } + /// pub struct EmptyPlainStruct {} + /// ``` + Plain { fields: Vec, fields_stripped: bool }, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Enum { pub generics: Generics, @@ -357,14 +383,6 @@ pub struct Discriminant { pub value: String, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -#[serde(rename_all = "snake_case")] -pub enum StructType { - Plain, - Tuple, - Unit, -} - #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Header { #[serde(rename = "const")] diff --git a/src/rustdoc-json-types/tests.rs b/src/rustdoc-json-types/tests.rs index e7f6447ed8753..399ff54b29497 100644 --- a/src/rustdoc-json-types/tests.rs +++ b/src/rustdoc-json-types/tests.rs @@ -3,10 +3,8 @@ use super::*; #[test] fn test_struct_info_roundtrip() { let s = ItemEnum::Struct(Struct { - struct_type: StructType::Plain, generics: Generics { params: vec![], where_predicates: vec![] }, - fields_stripped: false, - fields: vec![], + kind: StructKind::Plain { fields: vec![], fields_stripped: false }, impls: vec![], }); diff --git a/src/test/rustdoc-json/nested.rs b/src/test/rustdoc-json/nested.rs index 73ec9392ce94b..ee2d2efa960e8 100644 --- a/src/test/rustdoc-json/nested.rs +++ b/src/test/rustdoc-json/nested.rs @@ -17,7 +17,7 @@ pub mod l1 { pub mod l3 { // @is "$.index[*][?(@.name=='L4')].kind" \"struct\" - // @is "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\" + // @is "$.index[*][?(@.name=='L4')].inner.kind" \"unit\" // @set l4_id = "$.index[*][?(@.name=='L4')].id" // @ismany "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id pub struct L4; diff --git a/src/test/rustdoc-json/structs/plain_all_pub.rs b/src/test/rustdoc-json/structs/plain_all_pub.rs new file mode 100644 index 0000000000000..b86ab93c264d5 --- /dev/null +++ b/src/test/rustdoc-json/structs/plain_all_pub.rs @@ -0,0 +1,11 @@ +pub struct Demo { + pub x: i32, + pub y: i32, +} + +// @set x = "$.index[*][?(@.name=='x')].id" +// @set y = "$.index[*][?(@.name=='y')].id" +// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x +// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[1]" $y +// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 2 +// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" false diff --git a/src/test/rustdoc-json/structs/plain_doc_hidden.rs b/src/test/rustdoc-json/structs/plain_doc_hidden.rs new file mode 100644 index 0000000000000..7800b55a481ac --- /dev/null +++ b/src/test/rustdoc-json/structs/plain_doc_hidden.rs @@ -0,0 +1,11 @@ +pub struct Demo { + pub x: i32, + #[doc(hidden)] + pub y: i32, +} + +// @set x = "$.index[*][?(@.name=='x')].id" +// @!has "$.index[*][?(@.name=='y')].id" +// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x +// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 1 +// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" true diff --git a/src/test/rustdoc-json/structs/plain_empty.rs b/src/test/rustdoc-json/structs/plain_empty.rs index 2ad9e86096c36..1d01b8bc14a81 100644 --- a/src/test/rustdoc-json/structs/plain_empty.rs +++ b/src/test/rustdoc-json/structs/plain_empty.rs @@ -1,6 +1,5 @@ -// @has "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\" -// @has "$.index[*][?(@.name=='PlainEmpty')].kind" \"struct\" -// @has "$.index[*][?(@.name=='PlainEmpty')].inner.struct_type" \"plain\" -// @has "$.index[*][?(@.name=='PlainEmpty')].inner.fields_stripped" false -// @has "$.index[*][?(@.name=='PlainEmpty')].inner.fields" [] +// @is "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\" +// @is "$.index[*][?(@.name=='PlainEmpty')].kind" \"struct\" +// @is "$.index[*][?(@.name=='PlainEmpty')].inner.kind.plain.fields_stripped" false +// @is "$.index[*][?(@.name=='PlainEmpty')].inner.kind.plain.fields" [] pub struct PlainEmpty {} diff --git a/src/test/rustdoc-json/structs/plain_pub_priv.rs b/src/test/rustdoc-json/structs/plain_pub_priv.rs new file mode 100644 index 0000000000000..9b771224d9741 --- /dev/null +++ b/src/test/rustdoc-json/structs/plain_pub_priv.rs @@ -0,0 +1,9 @@ +pub struct Demo { + pub x: i32, + y: i32, +} + +// @set x = "$.index[*][?(@.name=='x')].id" +// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x +// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 1 +// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" true diff --git a/src/test/rustdoc-json/structs/tuple.rs b/src/test/rustdoc-json/structs/tuple.rs index 91fac359422e9..6bdb753ee0136 100644 --- a/src/test/rustdoc-json/structs/tuple.rs +++ b/src/test/rustdoc-json/structs/tuple.rs @@ -1,5 +1,4 @@ -// @has "$.index[*][?(@.name=='Tuple')].visibility" \"public\" -// @has "$.index[*][?(@.name=='Tuple')].kind" \"struct\" -// @has "$.index[*][?(@.name=='Tuple')].inner.struct_type" \"tuple\" -// @has "$.index[*][?(@.name=='Tuple')].inner.fields_stripped" true +// @is "$.index[*][?(@.name=='Tuple')].visibility" \"public\" +// @is "$.index[*][?(@.name=='Tuple')].kind" \"struct\" +// @is "$.index[*][?(@.name=='Tuple')].inner.kind.tuple" '[null, null]' pub struct Tuple(u32, String); diff --git a/src/test/rustdoc-json/structs/tuple_empty.rs b/src/test/rustdoc-json/structs/tuple_empty.rs new file mode 100644 index 0000000000000..0ad6a89547fc3 --- /dev/null +++ b/src/test/rustdoc-json/structs/tuple_empty.rs @@ -0,0 +1,2 @@ +// @is "$.index[*][?(@.name=='TupleUnit')].inner.kind.tuple" [] +pub struct TupleUnit(); diff --git a/src/test/rustdoc-json/structs/tuple_pub_priv.rs b/src/test/rustdoc-json/structs/tuple_pub_priv.rs new file mode 100644 index 0000000000000..9d5a1d1c8be7f --- /dev/null +++ b/src/test/rustdoc-json/structs/tuple_pub_priv.rs @@ -0,0 +1,13 @@ +pub struct Demo( + i32, + /// field + pub i32, + #[doc(hidden)] i32, +); + +// @set field = "$.index[*][?(@.docs=='field')].id" + +// @is "$.index[*][?(@.name=='Demo')].inner.kind.tuple[0]" null +// @is "$.index[*][?(@.name=='Demo')].inner.kind.tuple[1]" $field +// @is "$.index[*][?(@.name=='Demo')].inner.kind.tuple[2]" null +// @count "$.index[*][?(@.name=='Demo')].inner.kind.tuple[*]" 3 diff --git a/src/test/rustdoc-json/structs/unit.rs b/src/test/rustdoc-json/structs/unit.rs index 85a515b5e78ac..265709717212f 100644 --- a/src/test/rustdoc-json/structs/unit.rs +++ b/src/test/rustdoc-json/structs/unit.rs @@ -1,5 +1,4 @@ -// @has "$.index[*][?(@.name=='Unit')].visibility" \"public\" -// @has "$.index[*][?(@.name=='Unit')].kind" \"struct\" -// @has "$.index[*][?(@.name=='Unit')].inner.struct_type" \"unit\" -// @has "$.index[*][?(@.name=='Unit')].inner.fields" [] +// @is "$.index[*][?(@.name=='Unit')].visibility" \"public\" +// @is "$.index[*][?(@.name=='Unit')].kind" \"struct\" +// @is "$.index[*][?(@.name=='Unit')].inner.kind" \"unit\" pub struct Unit; diff --git a/src/test/rustdoc-json/structs/with_generics.rs b/src/test/rustdoc-json/structs/with_generics.rs index b0ad1883f8a2f..00474800a0e54 100644 --- a/src/test/rustdoc-json/structs/with_generics.rs +++ b/src/test/rustdoc-json/structs/with_generics.rs @@ -1,13 +1,13 @@ use std::collections::HashMap; -// @has "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\" -// @has "$.index[*][?(@.name=='WithGenerics')].kind" \"struct\" -// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].name" \"T\" -// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].kind.type" -// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].name" \"U\" -// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].kind.type" -// @has "$.index[*][?(@.name=='WithGenerics')].inner.struct_type" \"plain\" -// @has "$.index[*][?(@.name=='WithGenerics')].inner.fields_stripped" true +// @is "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\" +// @is "$.index[*][?(@.name=='WithGenerics')].kind" \"struct\" +// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].name" \"T\" +// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].kind.type.bounds" [] +// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].name" \"U\" +// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].kind.type.bounds" [] +// @is "$.index[*][?(@.name=='WithGenerics')].inner.kind.plain.fields_stripped" true +// @is "$.index[*][?(@.name=='WithGenerics')].inner.kind.plain.fields" [] pub struct WithGenerics { stuff: Vec, things: HashMap, diff --git a/src/test/rustdoc-json/structs/with_primitives.rs b/src/test/rustdoc-json/structs/with_primitives.rs index b74050dde7869..9c5a37f3957c0 100644 --- a/src/test/rustdoc-json/structs/with_primitives.rs +++ b/src/test/rustdoc-json/structs/with_primitives.rs @@ -1,9 +1,9 @@ -// @has "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\" -// @has "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\" -// @has "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\" -// @has "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" [] -// @has "$.index[*][?(@.name=='WithPrimitives')].inner.struct_type" \"plain\" -// @has "$.index[*][?(@.name=='WithPrimitives')].inner.fields_stripped" true +// @is "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\" +// @is "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\" +// @is "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\" +// @is "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" [] +// @is "$.index[*][?(@.name=='WithPrimitives')].inner.kind.plain.fields_stripped" true +// @is "$.index[*][?(@.name=='WithPrimitives')].inner.kind.plain.fields" [] pub struct WithPrimitives<'a> { num: u32, s: &'a str,