Skip to content

Commit 1c8de17

Browse files
committed
Rustdoc-Json: More accurate struct type.
Closes #101489
1 parent 78a891d commit 1c8de17

15 files changed

+118
-71
lines changed

src/etc/check_missing_items.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,11 @@ def check_type(ty):
132132
work_list |= set(item["inner"]["items"]) - visited
133133
elif item["kind"] == "struct":
134134
check_generics(item["inner"]["generics"])
135-
work_list |= (
136-
set(item["inner"]["fields"]) | set(item["inner"]["impls"])
137-
) - visited
135+
work_list |= set(item["inner"]["impls"]) - visited
136+
if "tuple" in item["inner"]["kind"]:
137+
work_list |= set(filter(None, item["inner"]["kind"]["tuple"])) - visited
138+
elif "plain" in item["inner"]["kind"]:
139+
work_list |= set(item["inner"]["kind"]["plain"]["fields"]) - visited
138140
elif item["kind"] == "struct_field":
139141
check_type(item["inner"])
140142
elif item["kind"] == "enum":

src/librustdoc/json/conversions.rs

+11-25
Original file line numberDiff line numberDiff line change
@@ -304,11 +304,19 @@ impl FromWithTcx<clean::Struct> for Struct {
304304
fn from_tcx(struct_: clean::Struct, tcx: TyCtxt<'_>) -> Self {
305305
let fields_stripped = struct_.has_stripped_entries();
306306
let clean::Struct { struct_type, generics, fields } = struct_;
307+
308+
let kind = match struct_type {
309+
CtorKind::Fn => StructKind::Tuple(ids_keeping_stripped(fields, tcx)),
310+
CtorKind::Const => {
311+
assert!(fields.is_empty());
312+
StructKind::Unit
313+
}
314+
CtorKind::Fictive => StructKind::Plain { fields: ids(fields, tcx), fields_stripped },
315+
};
316+
307317
Struct {
308-
struct_type: from_ctor_kind(struct_type),
318+
kind,
309319
generics: generics.into_tcx(tcx),
310-
fields_stripped,
311-
fields: ids(fields, tcx),
312320
impls: Vec::new(), // Added in JsonRenderer::item
313321
}
314322
}
@@ -327,14 +335,6 @@ impl FromWithTcx<clean::Union> for Union {
327335
}
328336
}
329337

330-
pub(crate) fn from_ctor_kind(struct_type: CtorKind) -> StructType {
331-
match struct_type {
332-
CtorKind::Fictive => StructType::Plain,
333-
CtorKind::Fn => StructType::Tuple,
334-
CtorKind::Const => StructType::Unit,
335-
}
336-
}
337-
338338
pub(crate) fn from_fn_header(header: &rustc_hir::FnHeader) -> Header {
339339
Header {
340340
async_: header.is_async(),
@@ -644,20 +644,6 @@ impl FromWithTcx<clean::Enum> for Enum {
644644
}
645645
}
646646

647-
impl FromWithTcx<clean::VariantStruct> for Struct {
648-
fn from_tcx(struct_: clean::VariantStruct, tcx: TyCtxt<'_>) -> Self {
649-
let fields_stripped = struct_.has_stripped_entries();
650-
let clean::VariantStruct { struct_type, fields } = struct_;
651-
Struct {
652-
struct_type: from_ctor_kind(struct_type),
653-
generics: Generics { params: vec![], where_predicates: vec![] },
654-
fields_stripped,
655-
fields: ids(fields, tcx),
656-
impls: Vec::new(),
657-
}
658-
}
659-
}
660-
661647
impl FromWithTcx<clean::Variant> for Variant {
662648
fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
663649
use clean::Variant::*;

src/rustdoc-json-types/lib.rs

+30-12
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::path::PathBuf;
99
use serde::{Deserialize, Serialize};
1010

1111
/// rustdoc format-version.
12-
pub const FORMAT_VERSION: u32 = 20;
12+
pub const FORMAT_VERSION: u32 = 21;
1313

1414
/// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
1515
/// about the language items in the local crate, as well as info about external items to allow
@@ -289,13 +289,39 @@ pub struct Union {
289289

290290
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
291291
pub struct Struct {
292-
pub struct_type: StructType,
292+
pub kind: StructKind,
293293
pub generics: Generics,
294-
pub fields_stripped: bool,
295-
pub fields: Vec<Id>,
296294
pub impls: Vec<Id>,
297295
}
298296

297+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
298+
#[serde(rename_all = "snake_case")]
299+
pub enum StructKind {
300+
/// A struct with no fields and no parentheses.
301+
///
302+
/// ```rust
303+
/// pub struct Unit;
304+
/// ```
305+
Unit,
306+
/// A struct with unnamed fields.
307+
///
308+
/// ```rust
309+
/// pub struct TupleStruct(i32);
310+
/// pub struct EmptyTupleStruct();
311+
/// ```
312+
///
313+
/// All [`Id`]'s will point to [`ItemEnum::StructField`]. Private and
314+
/// `#[doc(hidden)]` fields will be given as `None`
315+
Tuple(Vec<Option<Id>>),
316+
/// A struct with nammed fields.
317+
///
318+
/// ```rust
319+
/// pub struct PlainStruct { x: i32 }
320+
/// pub struct EmptyPlainStruct {}
321+
/// ```
322+
Plain { fields: Vec<Id>, fields_stripped: bool },
323+
}
324+
299325
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
300326
pub struct Enum {
301327
pub generics: Generics,
@@ -357,14 +383,6 @@ pub struct Discriminant {
357383
pub value: String,
358384
}
359385

360-
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
361-
#[serde(rename_all = "snake_case")]
362-
pub enum StructType {
363-
Plain,
364-
Tuple,
365-
Unit,
366-
}
367-
368386
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
369387
pub struct Header {
370388
#[serde(rename = "const")]

src/rustdoc-json-types/tests.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,8 @@ use super::*;
33
#[test]
44
fn test_struct_info_roundtrip() {
55
let s = ItemEnum::Struct(Struct {
6-
struct_type: StructType::Plain,
76
generics: Generics { params: vec![], where_predicates: vec![] },
8-
fields_stripped: false,
9-
fields: vec![],
7+
kind: StructKind::Plain { fields: vec![], fields_stripped: false },
108
impls: vec![],
119
});
1210

src/test/rustdoc-json/nested.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub mod l1 {
1717
pub mod l3 {
1818

1919
// @is "$.index[*][?(@.name=='L4')].kind" \"struct\"
20-
// @is "$.index[*][?(@.name=='L4')].inner.struct_type" \"unit\"
20+
// @is "$.index[*][?(@.name=='L4')].inner.kind" \"unit\"
2121
// @set l4_id = "$.index[*][?(@.name=='L4')].id"
2222
// @ismany "$.index[*][?(@.name=='l3')].inner.items[*]" $l4_id
2323
pub struct L4;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
pub struct Demo {
2+
pub x: i32,
3+
pub y: i32,
4+
}
5+
6+
// @set x = "$.index[*][?(@.name=='x')].id"
7+
// @set y = "$.index[*][?(@.name=='y')].id"
8+
// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x
9+
// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[1]" $y
10+
// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 2
11+
// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
pub struct Demo {
2+
pub x: i32,
3+
#[doc(hidden)]
4+
pub y: i32,
5+
}
6+
7+
// @set x = "$.index[*][?(@.name=='x')].id"
8+
// @!has "$.index[*][?(@.name=='y')].id"
9+
// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x
10+
// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 1
11+
// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" true
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
// @has "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\"
2-
// @has "$.index[*][?(@.name=='PlainEmpty')].kind" \"struct\"
3-
// @has "$.index[*][?(@.name=='PlainEmpty')].inner.struct_type" \"plain\"
4-
// @has "$.index[*][?(@.name=='PlainEmpty')].inner.fields_stripped" false
5-
// @has "$.index[*][?(@.name=='PlainEmpty')].inner.fields" []
1+
// @is "$.index[*][?(@.name=='PlainEmpty')].visibility" \"public\"
2+
// @is "$.index[*][?(@.name=='PlainEmpty')].kind" \"struct\"
3+
// @is "$.index[*][?(@.name=='PlainEmpty')].inner.kind.plain.fields_stripped" false
4+
// @is "$.index[*][?(@.name=='PlainEmpty')].inner.kind.plain.fields" []
65
pub struct PlainEmpty {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
pub struct Demo {
2+
pub x: i32,
3+
y: i32,
4+
}
5+
6+
// @set x = "$.index[*][?(@.name=='x')].id"
7+
// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[0]" $x
8+
// @count "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields[*]" 1
9+
// @is "$.index[*][?(@.name=='Demo')].inner.kind.plain.fields_stripped" true
+3-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// @has "$.index[*][?(@.name=='Tuple')].visibility" \"public\"
2-
// @has "$.index[*][?(@.name=='Tuple')].kind" \"struct\"
3-
// @has "$.index[*][?(@.name=='Tuple')].inner.struct_type" \"tuple\"
4-
// @has "$.index[*][?(@.name=='Tuple')].inner.fields_stripped" true
1+
// @is "$.index[*][?(@.name=='Tuple')].visibility" \"public\"
2+
// @is "$.index[*][?(@.name=='Tuple')].kind" \"struct\"
3+
// @is "$.index[*][?(@.name=='Tuple')].inner.kind.tuple" '[null, null]'
54
pub struct Tuple(u32, String);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// @is "$.index[*][?(@.name=='TupleUnit')].inner.kind.tuple" []
2+
pub struct TupleUnit();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pub struct Demo(
2+
i32,
3+
/// field
4+
pub i32,
5+
#[doc(hidden)] i32,
6+
);
7+
8+
// @set field = "$.index[*][?(@.docs=='field')].id"
9+
10+
// @is "$.index[*][?(@.name=='Demo')].inner.kind.tuple[0]" null
11+
// @is "$.index[*][?(@.name=='Demo')].inner.kind.tuple[1]" $field
12+
// @is "$.index[*][?(@.name=='Demo')].inner.kind.tuple[2]" null
13+
// @count "$.index[*][?(@.name=='Demo')].inner.kind.tuple[*]" 3

src/test/rustdoc-json/structs/unit.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
// @has "$.index[*][?(@.name=='Unit')].visibility" \"public\"
2-
// @has "$.index[*][?(@.name=='Unit')].kind" \"struct\"
3-
// @has "$.index[*][?(@.name=='Unit')].inner.struct_type" \"unit\"
4-
// @has "$.index[*][?(@.name=='Unit')].inner.fields" []
1+
// @is "$.index[*][?(@.name=='Unit')].visibility" \"public\"
2+
// @is "$.index[*][?(@.name=='Unit')].kind" \"struct\"
3+
// @is "$.index[*][?(@.name=='Unit')].inner.kind" \"unit\"
54
pub struct Unit;

src/test/rustdoc-json/structs/with_generics.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use std::collections::HashMap;
22

3-
// @has "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\"
4-
// @has "$.index[*][?(@.name=='WithGenerics')].kind" \"struct\"
5-
// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].name" \"T\"
6-
// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].kind.type"
7-
// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].name" \"U\"
8-
// @has "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].kind.type"
9-
// @has "$.index[*][?(@.name=='WithGenerics')].inner.struct_type" \"plain\"
10-
// @has "$.index[*][?(@.name=='WithGenerics')].inner.fields_stripped" true
3+
// @is "$.index[*][?(@.name=='WithGenerics')].visibility" \"public\"
4+
// @is "$.index[*][?(@.name=='WithGenerics')].kind" \"struct\"
5+
// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].name" \"T\"
6+
// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[0].kind.type.bounds" []
7+
// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].name" \"U\"
8+
// @is "$.index[*][?(@.name=='WithGenerics')].inner.generics.params[1].kind.type.bounds" []
9+
// @is "$.index[*][?(@.name=='WithGenerics')].inner.kind.plain.fields_stripped" true
10+
// @is "$.index[*][?(@.name=='WithGenerics')].inner.kind.plain.fields" []
1111
pub struct WithGenerics<T, U> {
1212
stuff: Vec<T>,
1313
things: HashMap<U, U>,

src/test/rustdoc-json/structs/with_primitives.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
// @has "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\"
2-
// @has "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\"
3-
// @has "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\"
4-
// @has "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" []
5-
// @has "$.index[*][?(@.name=='WithPrimitives')].inner.struct_type" \"plain\"
6-
// @has "$.index[*][?(@.name=='WithPrimitives')].inner.fields_stripped" true
1+
// @is "$.index[*][?(@.name=='WithPrimitives')].visibility" \"public\"
2+
// @is "$.index[*][?(@.name=='WithPrimitives')].kind" \"struct\"
3+
// @is "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].name" \"\'a\"
4+
// @is "$.index[*][?(@.name=='WithPrimitives')].inner.generics.params[0].kind.lifetime.outlives" []
5+
// @is "$.index[*][?(@.name=='WithPrimitives')].inner.kind.plain.fields_stripped" true
6+
// @is "$.index[*][?(@.name=='WithPrimitives')].inner.kind.plain.fields" []
77
pub struct WithPrimitives<'a> {
88
num: u32,
99
s: &'a str,

0 commit comments

Comments
 (0)