Rollup merge of #101521 - aDotInTheVoid:rdj-structkind, r=GuillaumeGomez

Rustdoc-Json: More accurate struct type.

Closes #101489

r? `@GuillaumeGomez`
This commit is contained in:
Matthias Krüger 2022-09-07 21:48:19 +02:00 committed by GitHub
commit 8d21e97d64
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 118 additions and 71 deletions

View File

@ -132,9 +132,11 @@ while work_list:
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":

View File

@ -304,11 +304,19 @@ impl FromWithTcx<clean::Struct> 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<clean::Union> 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<clean::Enum> for Enum {
}
}
impl FromWithTcx<clean::VariantStruct> 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<clean::Variant> for Variant {
fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
use clean::Variant::*;

View File

@ -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<Id>,
pub impls: Vec<Id>,
}
#[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<Option<Id>>),
/// A struct with nammed fields.
///
/// ```rust
/// pub struct PlainStruct { x: i32 }
/// pub struct EmptyPlainStruct {}
/// ```
Plain { fields: Vec<Id>, 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")]

View File

@ -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![],
});

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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 {}

View File

@ -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

View File

@ -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);

View File

@ -0,0 +1,2 @@
// @is "$.index[*][?(@.name=='TupleUnit')].inner.kind.tuple" []
pub struct TupleUnit();

View File

@ -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

View File

@ -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;

View File

@ -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<T, U> {
stuff: Vec<T>,
things: HashMap<U, U>,

View File

@ -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,