Skip to content

Commit b76a012

Browse files
committed
Rustdoc-Json: Add enum discriminant
1 parent b88e510 commit b76a012

File tree

13 files changed

+209
-21
lines changed

13 files changed

+209
-21
lines changed

src/librustdoc/clean/mod.rs

+20-3
Original file line numberDiff line numberDiff line change
@@ -1786,7 +1786,13 @@ pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility {
17861786

17871787
pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item {
17881788
let kind = match variant.ctor_kind {
1789-
CtorKind::Const => Variant::CLike,
1789+
CtorKind::Const => Variant::CLike(match variant.discr {
1790+
ty::VariantDiscr::Explicit(def_id) => Some(Discriminant {
1791+
expr: None,
1792+
value: print_evaluated_const(cx.tcx, def_id, false).unwrap(),
1793+
}),
1794+
ty::VariantDiscr::Relative(_) => None,
1795+
}),
17901796
CtorKind::Fn => Variant::Tuple(
17911797
variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
17921798
),
@@ -1803,6 +1809,7 @@ pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocCont
18031809

18041810
fn clean_variant_data<'tcx>(
18051811
variant: &hir::VariantData<'tcx>,
1812+
disr_expr: &Option<hir::AnonConst>,
18061813
cx: &mut DocContext<'tcx>,
18071814
) -> Variant {
18081815
match variant {
@@ -1813,7 +1820,17 @@ fn clean_variant_data<'tcx>(
18131820
hir::VariantData::Tuple(..) => {
18141821
Variant::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
18151822
}
1816-
hir::VariantData::Unit(..) => Variant::CLike,
1823+
hir::VariantData::Unit(..) => Variant::CLike(disr_expr.map(|disr| {
1824+
Discriminant {
1825+
expr: Some(print_const_expr(cx.tcx, disr.body)),
1826+
value: print_evaluated_const(
1827+
cx.tcx,
1828+
cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
1829+
false,
1830+
)
1831+
.unwrap(),
1832+
}
1833+
})),
18171834
}
18181835
}
18191836

@@ -1967,7 +1984,7 @@ fn clean_maybe_renamed_item<'tcx>(
19671984
}
19681985

19691986
fn clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
1970-
let kind = VariantItem(clean_variant_data(&variant.data, cx));
1987+
let kind = VariantItem(clean_variant_data(&variant.data, &variant.disr_expr, cx));
19711988
let what_rustc_thinks =
19721989
Item::from_hir_id_and_parts(variant.id, Some(variant.ident.name), kind, cx);
19731990
// don't show `pub` for variants, which are always public

src/librustdoc/clean/types.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -2098,7 +2098,7 @@ impl Enum {
20982098

20992099
#[derive(Clone, Debug)]
21002100
pub(crate) enum Variant {
2101-
CLike,
2101+
CLike(Option<Discriminant>),
21022102
Tuple(Vec<Item>),
21032103
Struct(VariantStruct),
21042104
}
@@ -2107,11 +2107,19 @@ impl Variant {
21072107
pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
21082108
match *self {
21092109
Self::Struct(ref struct_) => Some(struct_.has_stripped_entries()),
2110-
Self::CLike | Self::Tuple(_) => None,
2110+
Self::CLike(..) | Self::Tuple(_) => None,
21112111
}
21122112
}
21132113
}
21142114

2115+
#[derive(Clone, Debug)]
2116+
pub(crate) struct Discriminant {
2117+
// In the case of cross crate re-exports, we don't have the nessesary information
2118+
// to reconstruct the expression of the discriminant, only the value.
2119+
pub(crate) expr: Option<String>,
2120+
pub(crate) value: String,
2121+
}
2122+
21152123
/// Small wrapper around [`rustc_span::Span`] that adds helper methods
21162124
/// and enforces calling [`rustc_span::Span::source_callsite()`].
21172125
#[derive(Copy, Clone, Debug)]
@@ -2338,7 +2346,7 @@ impl ConstantKind {
23382346
match *self {
23392347
ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None,
23402348
ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
2341-
print_evaluated_const(tcx, def_id)
2349+
print_evaluated_const(tcx, def_id, true)
23422350
}
23432351
}
23442352
}

src/librustdoc/clean/utils.rs

+25-9
Original file line numberDiff line numberDiff line change
@@ -261,15 +261,19 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
261261
}
262262
}
263263

264-
pub(crate) fn print_evaluated_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<String> {
264+
pub(crate) fn print_evaluated_const(
265+
tcx: TyCtxt<'_>,
266+
def_id: DefId,
267+
underscores_and_type: bool,
268+
) -> Option<String> {
265269
tcx.const_eval_poly(def_id).ok().and_then(|val| {
266270
let ty = tcx.type_of(def_id);
267271
match (val, ty.kind()) {
268272
(_, &ty::Ref(..)) => None,
269273
(ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
270274
(ConstValue::Scalar(_), _) => {
271275
let const_ = mir::ConstantKind::from_value(val, ty);
272-
Some(print_const_with_custom_print_scalar(tcx, const_))
276+
Some(print_const_with_custom_print_scalar(tcx, const_, underscores_and_type))
273277
}
274278
_ => None,
275279
}
@@ -302,23 +306,35 @@ fn format_integer_with_underscore_sep(num: &str) -> String {
302306
.collect()
303307
}
304308

305-
fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: mir::ConstantKind<'_>) -> String {
309+
fn print_const_with_custom_print_scalar(
310+
tcx: TyCtxt<'_>,
311+
ct: mir::ConstantKind<'_>,
312+
underscores_and_type: bool,
313+
) -> String {
306314
// Use a slightly different format for integer types which always shows the actual value.
307315
// For all other types, fallback to the original `pretty_print_const`.
308316
match (ct, ct.ty().kind()) {
309317
(mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Uint(ui)) => {
310-
format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
318+
if underscores_and_type {
319+
format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
320+
} else {
321+
int.to_string()
322+
}
311323
}
312324
(mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Int(i)) => {
313325
let ty = tcx.lift(ct.ty()).unwrap();
314326
let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
315327
let data = int.assert_bits(size);
316328
let sign_extended_data = size.sign_extend(data) as i128;
317-
format!(
318-
"{}{}",
319-
format_integer_with_underscore_sep(&sign_extended_data.to_string()),
320-
i.name_str()
321-
)
329+
if underscores_and_type {
330+
format!(
331+
"{}{}",
332+
format_integer_with_underscore_sep(&sign_extended_data.to_string()),
333+
i.name_str()
334+
)
335+
} else {
336+
sign_extended_data.to_string()
337+
}
322338
}
323339
_ => ct.to_string(),
324340
}

src/librustdoc/fold.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ pub(crate) trait DocFolder: Sized {
4646
let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
4747
VariantItem(Variant::Tuple(fields))
4848
}
49-
Variant::CLike => VariantItem(Variant::CLike),
49+
Variant::CLike(disr) => VariantItem(Variant::CLike(disr)),
5050
},
5151
ExternCrateItem { src: _ }
5252
| ImportItem(_)

src/librustdoc/html/render/print_item.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1203,7 +1203,8 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
12031203
let name = v.name.unwrap();
12041204
match *v.kind {
12051205
clean::VariantItem(ref var) => match var {
1206-
clean::Variant::CLike => write!(w, "{}", name),
1206+
// FIXME(#101337): Show discriminant
1207+
clean::Variant::CLike(..) => write!(w, "{}", name),
12071208
clean::Variant::Tuple(ref s) => {
12081209
write!(w, "{}(", name);
12091210
print_tuple_struct_fields(w, cx, s);

src/librustdoc/json/conversions.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ impl FromWithTcx<clean::Variant> for Variant {
662662
fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
663663
use clean::Variant::*;
664664
match variant {
665-
CLike => Variant::Plain,
665+
CLike(disr) => Variant::Plain(disr.map(convert_discriminant)),
666666
Tuple(fields) => Variant::Tuple(
667667
fields
668668
.into_iter()
@@ -678,6 +678,16 @@ impl FromWithTcx<clean::Variant> for Variant {
678678
}
679679
}
680680

681+
fn convert_discriminant(disr: clean::Discriminant) -> Discriminant {
682+
Discriminant {
683+
// expr is only none if going throught the inlineing path, which gets
684+
// `rustc_middle` types, not `rustc_hir`, but because JSON never inlines
685+
// the expr is always some.
686+
expr: disr.expr.unwrap(),
687+
value: disr.value,
688+
}
689+
}
690+
681691
impl FromWithTcx<clean::Import> for Import {
682692
fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self {
683693
use clean::ImportKind::*;

src/librustdoc/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub(crate) trait DocVisitor: Sized {
2020
VariantItem(i) => match i {
2121
Variant::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
2222
Variant::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
23-
Variant::CLike => {}
23+
Variant::CLike(_) => {}
2424
},
2525
ExternCrateItem { src: _ }
2626
| ImportItem(_)

src/rustdoc-json-types/lib.rs

+19-2
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 = 18;
12+
pub const FORMAT_VERSION: u32 = 19;
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
@@ -308,11 +308,28 @@ pub struct Enum {
308308
#[serde(rename_all = "snake_case")]
309309
#[serde(tag = "variant_kind", content = "variant_inner")]
310310
pub enum Variant {
311-
Plain,
311+
Plain(Option<Discriminant>),
312312
Tuple(Vec<Type>),
313313
Struct(Vec<Id>),
314314
}
315315

316+
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
317+
pub struct Discriminant {
318+
/// The expression that produced the discriminant.
319+
///
320+
/// Unlike `value`, this preserves the original formatting (eg suffixes,
321+
/// hexadecimal, and underscores), making it unsuitable to be machine
322+
/// interpreted.
323+
///
324+
/// In some cases, when the value is to complex, this may be `"{ _ }"`.
325+
/// When this occurs is unstable, and may change without notice.
326+
pub expr: String,
327+
/// The numerical value of the discriminant. Stored as a string due to
328+
/// JSON's poor support for large integers, and the fact that it would need
329+
/// to store from [`i128::MIN`] to [`u128::MAX`].
330+
pub value: String,
331+
}
332+
316333
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
317334
#[serde(rename_all = "snake_case")]
318335
pub enum StructType {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#[repr(i8)]
2+
pub enum Ordering {
3+
// @is "$.index[*][?(@.name=='Less')].inner.variant_inner.expr" '"-1"'
4+
// @is "$.index[*][?(@.name=='Less')].inner.variant_inner.value" '"-1"'
5+
Less = -1,
6+
// @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.expr" '"0"'
7+
// @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.value" '"0"'
8+
Equal = 0,
9+
// @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.expr" '"1"'
10+
// @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.value" '"1"'
11+
Greater = 1,
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
pub enum Foo {
2+
// @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.value" '"0"'
3+
// @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.expr" '"{ _ }"'
4+
Addition = 0 + 0,
5+
// @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.value" '"1"'
6+
// @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.expr" '"0b1"'
7+
Bin = 0b1,
8+
// @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.value" '"2"'
9+
// @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.expr" '"0o2"'
10+
Oct = 0o2,
11+
// @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.value" '"3"'
12+
// @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.expr" '"THREE"'
13+
PubConst = THREE,
14+
// @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.value" '"4"'
15+
// @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.expr" '"0x4"'
16+
Hex = 0x4,
17+
// @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.value" '"5"'
18+
// @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.expr" '"{ _ }"'
19+
Cast = 5 as isize,
20+
// @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.value" '"6"'
21+
// @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.expr" '"{ _ }"'
22+
PubCall = six(),
23+
// @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.value" '"7"'
24+
// @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.expr" '"{ _ }"'
25+
PrivCall = seven(),
26+
// @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.value" '"8"'
27+
// @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.expr" '"EIGHT"'
28+
PrivConst = EIGHT,
29+
}
30+
31+
pub const THREE: isize = 3;
32+
const EIGHT: isize = 8;
33+
34+
pub const fn six() -> isize {
35+
6
36+
}
37+
const fn seven() -> isize {
38+
7
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// ignore-tidy-linelength
2+
#![feature(repr128)]
3+
#![allow(incomplete_features)]
4+
5+
#[repr(u64)]
6+
pub enum U64 {
7+
// @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.value" '"0"'
8+
// @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.expr" '"u64::MIN"'
9+
U64Min = u64::MIN,
10+
// @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.value" '"18446744073709551615"'
11+
// @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.expr" '"u64::MAX"'
12+
U64Max = u64::MAX,
13+
}
14+
15+
#[repr(i64)]
16+
pub enum I64 {
17+
// @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.value" '"-9223372036854775808"'
18+
// @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.expr" '"i64::MIN"'
19+
I64Min = i64::MIN,
20+
// @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.value" '"9223372036854775807"'
21+
// @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.expr" '"i64::MAX"'
22+
I64Max = i64::MAX,
23+
}
24+
25+
#[repr(u128)]
26+
pub enum U128 {
27+
// @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.value" '"0"'
28+
// @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.expr" '"u128::MIN"'
29+
U128Min = u128::MIN,
30+
// @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.value" '"340282366920938463463374607431768211455"'
31+
// @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.expr" '"u128::MAX"'
32+
U128Max = u128::MAX,
33+
}
34+
35+
#[repr(i128)]
36+
pub enum I128 {
37+
// @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.value" '"-170141183460469231731687303715884105728"'
38+
// @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.expr" '"i128::MIN"'
39+
I128Min = i128::MIN,
40+
// @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.value" '"170141183460469231731687303715884105727"'
41+
// @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.expr" '"i128::MAX"'
42+
I128Max = i128::MAX,
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#[repr(u32)]
2+
pub enum Foo {
3+
// @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.value" '"0"'
4+
// @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.expr" '"0"'
5+
Basic = 0,
6+
// @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.value" '"10"'
7+
// @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.expr" '"10u32"'
8+
Suffix = 10u32,
9+
// @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.value" '"100"'
10+
// @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.expr" '"1_0_0"'
11+
Underscore = 1_0_0,
12+
// @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.value" '"1000"'
13+
// @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.expr" '"1_0_0_0u32"'
14+
SuffixUnderscore = 1_0_0_0u32,
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
pub enum Foo {
2+
// @is "$.index[*][?(@.name=='Has')].inner.variant_inner" '{"expr":"0", "value":"0"}'
3+
Has = 0,
4+
// @is "$.index[*][?(@.name=='Doesnt')].inner.variant_inner" null
5+
Doesnt,
6+
// @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.variant_inner" null
7+
AlsoDoesnt,
8+
// @is "$.index[*][?(@.name=='AlsoHas')].inner.variant_inner" '{"expr":"44", "value":"44"}'
9+
AlsoHas = 44,
10+
}

0 commit comments

Comments
 (0)