Rustdoc-Json: Add enum discriminant
This commit is contained in:
parent
b88e510cc8
commit
b76a012be1
13 changed files with 209 additions and 21 deletions
|
@ -1786,7 +1786,13 @@ pub(crate) fn clean_visibility(vis: ty::Visibility) -> Visibility {
|
|||
|
||||
pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item {
|
||||
let kind = match variant.ctor_kind {
|
||||
CtorKind::Const => Variant::CLike,
|
||||
CtorKind::Const => Variant::CLike(match variant.discr {
|
||||
ty::VariantDiscr::Explicit(def_id) => Some(Discriminant {
|
||||
expr: None,
|
||||
value: print_evaluated_const(cx.tcx, def_id, false).unwrap(),
|
||||
}),
|
||||
ty::VariantDiscr::Relative(_) => None,
|
||||
}),
|
||||
CtorKind::Fn => Variant::Tuple(
|
||||
variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
|
||||
),
|
||||
|
@ -1803,6 +1809,7 @@ pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocCont
|
|||
|
||||
fn clean_variant_data<'tcx>(
|
||||
variant: &hir::VariantData<'tcx>,
|
||||
disr_expr: &Option<hir::AnonConst>,
|
||||
cx: &mut DocContext<'tcx>,
|
||||
) -> Variant {
|
||||
match variant {
|
||||
|
@ -1813,7 +1820,17 @@ fn clean_variant_data<'tcx>(
|
|||
hir::VariantData::Tuple(..) => {
|
||||
Variant::Tuple(variant.fields().iter().map(|x| clean_field(x, cx)).collect())
|
||||
}
|
||||
hir::VariantData::Unit(..) => Variant::CLike,
|
||||
hir::VariantData::Unit(..) => Variant::CLike(disr_expr.map(|disr| {
|
||||
Discriminant {
|
||||
expr: Some(print_const_expr(cx.tcx, disr.body)),
|
||||
value: print_evaluated_const(
|
||||
cx.tcx,
|
||||
cx.tcx.hir().local_def_id(disr.hir_id).to_def_id(),
|
||||
false,
|
||||
)
|
||||
.unwrap(),
|
||||
}
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1967,7 +1984,7 @@ fn clean_maybe_renamed_item<'tcx>(
|
|||
}
|
||||
|
||||
fn clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
|
||||
let kind = VariantItem(clean_variant_data(&variant.data, cx));
|
||||
let kind = VariantItem(clean_variant_data(&variant.data, &variant.disr_expr, cx));
|
||||
let what_rustc_thinks =
|
||||
Item::from_hir_id_and_parts(variant.id, Some(variant.ident.name), kind, cx);
|
||||
// don't show `pub` for variants, which are always public
|
||||
|
|
|
@ -2098,7 +2098,7 @@ impl Enum {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum Variant {
|
||||
CLike,
|
||||
CLike(Option<Discriminant>),
|
||||
Tuple(Vec<Item>),
|
||||
Struct(VariantStruct),
|
||||
}
|
||||
|
@ -2107,11 +2107,19 @@ impl Variant {
|
|||
pub(crate) fn has_stripped_entries(&self) -> Option<bool> {
|
||||
match *self {
|
||||
Self::Struct(ref struct_) => Some(struct_.has_stripped_entries()),
|
||||
Self::CLike | Self::Tuple(_) => None,
|
||||
Self::CLike(..) | Self::Tuple(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct Discriminant {
|
||||
// In the case of cross crate re-exports, we don't have the nessesary information
|
||||
// to reconstruct the expression of the discriminant, only the value.
|
||||
pub(crate) expr: Option<String>,
|
||||
pub(crate) value: String,
|
||||
}
|
||||
|
||||
/// Small wrapper around [`rustc_span::Span`] that adds helper methods
|
||||
/// and enforces calling [`rustc_span::Span::source_callsite()`].
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -2338,7 +2346,7 @@ impl ConstantKind {
|
|||
match *self {
|
||||
ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None,
|
||||
ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => {
|
||||
print_evaluated_const(tcx, def_id)
|
||||
print_evaluated_const(tcx, def_id, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -261,7 +261,11 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_evaluated_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<String> {
|
||||
pub(crate) fn print_evaluated_const(
|
||||
tcx: TyCtxt<'_>,
|
||||
def_id: DefId,
|
||||
underscores_and_type: bool,
|
||||
) -> Option<String> {
|
||||
tcx.const_eval_poly(def_id).ok().and_then(|val| {
|
||||
let ty = tcx.type_of(def_id);
|
||||
match (val, ty.kind()) {
|
||||
|
@ -269,7 +273,7 @@ pub(crate) fn print_evaluated_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<St
|
|||
(ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
|
||||
(ConstValue::Scalar(_), _) => {
|
||||
let const_ = mir::ConstantKind::from_value(val, ty);
|
||||
Some(print_const_with_custom_print_scalar(tcx, const_))
|
||||
Some(print_const_with_custom_print_scalar(tcx, const_, underscores_and_type))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
@ -302,23 +306,35 @@ fn format_integer_with_underscore_sep(num: &str) -> String {
|
|||
.collect()
|
||||
}
|
||||
|
||||
fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: mir::ConstantKind<'_>) -> String {
|
||||
fn print_const_with_custom_print_scalar(
|
||||
tcx: TyCtxt<'_>,
|
||||
ct: mir::ConstantKind<'_>,
|
||||
underscores_and_type: bool,
|
||||
) -> String {
|
||||
// Use a slightly different format for integer types which always shows the actual value.
|
||||
// For all other types, fallback to the original `pretty_print_const`.
|
||||
match (ct, ct.ty().kind()) {
|
||||
(mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Uint(ui)) => {
|
||||
format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
|
||||
if underscores_and_type {
|
||||
format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
|
||||
} else {
|
||||
int.to_string()
|
||||
}
|
||||
}
|
||||
(mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Int(i)) => {
|
||||
let ty = tcx.lift(ct.ty()).unwrap();
|
||||
let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
|
||||
let data = int.assert_bits(size);
|
||||
let sign_extended_data = size.sign_extend(data) as i128;
|
||||
format!(
|
||||
"{}{}",
|
||||
format_integer_with_underscore_sep(&sign_extended_data.to_string()),
|
||||
i.name_str()
|
||||
)
|
||||
if underscores_and_type {
|
||||
format!(
|
||||
"{}{}",
|
||||
format_integer_with_underscore_sep(&sign_extended_data.to_string()),
|
||||
i.name_str()
|
||||
)
|
||||
} else {
|
||||
sign_extended_data.to_string()
|
||||
}
|
||||
}
|
||||
_ => ct.to_string(),
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ pub(crate) trait DocFolder: Sized {
|
|||
let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
|
||||
VariantItem(Variant::Tuple(fields))
|
||||
}
|
||||
Variant::CLike => VariantItem(Variant::CLike),
|
||||
Variant::CLike(disr) => VariantItem(Variant::CLike(disr)),
|
||||
},
|
||||
ExternCrateItem { src: _ }
|
||||
| ImportItem(_)
|
||||
|
|
|
@ -1203,7 +1203,8 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
|
|||
let name = v.name.unwrap();
|
||||
match *v.kind {
|
||||
clean::VariantItem(ref var) => match var {
|
||||
clean::Variant::CLike => write!(w, "{}", name),
|
||||
// FIXME(#101337): Show discriminant
|
||||
clean::Variant::CLike(..) => write!(w, "{}", name),
|
||||
clean::Variant::Tuple(ref s) => {
|
||||
write!(w, "{}(", name);
|
||||
print_tuple_struct_fields(w, cx, s);
|
||||
|
|
|
@ -662,7 +662,7 @@ impl FromWithTcx<clean::Variant> for Variant {
|
|||
fn from_tcx(variant: clean::Variant, tcx: TyCtxt<'_>) -> Self {
|
||||
use clean::Variant::*;
|
||||
match variant {
|
||||
CLike => Variant::Plain,
|
||||
CLike(disr) => Variant::Plain(disr.map(convert_discriminant)),
|
||||
Tuple(fields) => Variant::Tuple(
|
||||
fields
|
||||
.into_iter()
|
||||
|
@ -678,6 +678,16 @@ impl FromWithTcx<clean::Variant> for Variant {
|
|||
}
|
||||
}
|
||||
|
||||
fn convert_discriminant(disr: clean::Discriminant) -> Discriminant {
|
||||
Discriminant {
|
||||
// expr is only none if going throught the inlineing path, which gets
|
||||
// `rustc_middle` types, not `rustc_hir`, but because JSON never inlines
|
||||
// the expr is always some.
|
||||
expr: disr.expr.unwrap(),
|
||||
value: disr.value,
|
||||
}
|
||||
}
|
||||
|
||||
impl FromWithTcx<clean::Import> for Import {
|
||||
fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self {
|
||||
use clean::ImportKind::*;
|
||||
|
|
|
@ -20,7 +20,7 @@ pub(crate) trait DocVisitor: Sized {
|
|||
VariantItem(i) => match i {
|
||||
Variant::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
|
||||
Variant::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
|
||||
Variant::CLike => {}
|
||||
Variant::CLike(_) => {}
|
||||
},
|
||||
ExternCrateItem { src: _ }
|
||||
| ImportItem(_)
|
||||
|
|
|
@ -9,7 +9,7 @@ use std::path::PathBuf;
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// rustdoc format-version.
|
||||
pub const FORMAT_VERSION: u32 = 18;
|
||||
pub const FORMAT_VERSION: u32 = 19;
|
||||
|
||||
/// 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
|
||||
|
@ -308,11 +308,28 @@ pub struct Enum {
|
|||
#[serde(rename_all = "snake_case")]
|
||||
#[serde(tag = "variant_kind", content = "variant_inner")]
|
||||
pub enum Variant {
|
||||
Plain,
|
||||
Plain(Option<Discriminant>),
|
||||
Tuple(Vec<Type>),
|
||||
Struct(Vec<Id>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct Discriminant {
|
||||
/// The expression that produced the discriminant.
|
||||
///
|
||||
/// Unlike `value`, this preserves the original formatting (eg suffixes,
|
||||
/// hexadecimal, and underscores), making it unsuitable to be machine
|
||||
/// interpreted.
|
||||
///
|
||||
/// In some cases, when the value is to complex, this may be `"{ _ }"`.
|
||||
/// When this occurs is unstable, and may change without notice.
|
||||
pub expr: String,
|
||||
/// The numerical value of the discriminant. Stored as a string due to
|
||||
/// JSON's poor support for large integers, and the fact that it would need
|
||||
/// to store from [`i128::MIN`] to [`u128::MAX`].
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum StructType {
|
||||
|
|
12
src/test/rustdoc-json/enums/discriminant/basic.rs
Normal file
12
src/test/rustdoc-json/enums/discriminant/basic.rs
Normal file
|
@ -0,0 +1,12 @@
|
|||
#[repr(i8)]
|
||||
pub enum Ordering {
|
||||
// @is "$.index[*][?(@.name=='Less')].inner.variant_inner.expr" '"-1"'
|
||||
// @is "$.index[*][?(@.name=='Less')].inner.variant_inner.value" '"-1"'
|
||||
Less = -1,
|
||||
// @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.expr" '"0"'
|
||||
// @is "$.index[*][?(@.name=='Equal')].inner.variant_inner.value" '"0"'
|
||||
Equal = 0,
|
||||
// @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.expr" '"1"'
|
||||
// @is "$.index[*][?(@.name=='Greater')].inner.variant_inner.value" '"1"'
|
||||
Greater = 1,
|
||||
}
|
39
src/test/rustdoc-json/enums/discriminant/expr.rs
Normal file
39
src/test/rustdoc-json/enums/discriminant/expr.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
pub enum Foo {
|
||||
// @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.value" '"0"'
|
||||
// @is "$.index[*][?(@.name=='Addition')].inner.variant_inner.expr" '"{ _ }"'
|
||||
Addition = 0 + 0,
|
||||
// @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.value" '"1"'
|
||||
// @is "$.index[*][?(@.name=='Bin')].inner.variant_inner.expr" '"0b1"'
|
||||
Bin = 0b1,
|
||||
// @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.value" '"2"'
|
||||
// @is "$.index[*][?(@.name=='Oct')].inner.variant_inner.expr" '"0o2"'
|
||||
Oct = 0o2,
|
||||
// @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.value" '"3"'
|
||||
// @is "$.index[*][?(@.name=='PubConst')].inner.variant_inner.expr" '"THREE"'
|
||||
PubConst = THREE,
|
||||
// @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.value" '"4"'
|
||||
// @is "$.index[*][?(@.name=='Hex')].inner.variant_inner.expr" '"0x4"'
|
||||
Hex = 0x4,
|
||||
// @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.value" '"5"'
|
||||
// @is "$.index[*][?(@.name=='Cast')].inner.variant_inner.expr" '"{ _ }"'
|
||||
Cast = 5 as isize,
|
||||
// @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.value" '"6"'
|
||||
// @is "$.index[*][?(@.name=='PubCall')].inner.variant_inner.expr" '"{ _ }"'
|
||||
PubCall = six(),
|
||||
// @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.value" '"7"'
|
||||
// @is "$.index[*][?(@.name=='PrivCall')].inner.variant_inner.expr" '"{ _ }"'
|
||||
PrivCall = seven(),
|
||||
// @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.value" '"8"'
|
||||
// @is "$.index[*][?(@.name=='PrivConst')].inner.variant_inner.expr" '"EIGHT"'
|
||||
PrivConst = EIGHT,
|
||||
}
|
||||
|
||||
pub const THREE: isize = 3;
|
||||
const EIGHT: isize = 8;
|
||||
|
||||
pub const fn six() -> isize {
|
||||
6
|
||||
}
|
||||
const fn seven() -> isize {
|
||||
7
|
||||
}
|
43
src/test/rustdoc-json/enums/discriminant/limits.rs
Normal file
43
src/test/rustdoc-json/enums/discriminant/limits.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
// ignore-tidy-linelength
|
||||
#![feature(repr128)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
#[repr(u64)]
|
||||
pub enum U64 {
|
||||
// @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.value" '"0"'
|
||||
// @is "$.index[*][?(@.name=='U64Min')].inner.variant_inner.expr" '"u64::MIN"'
|
||||
U64Min = u64::MIN,
|
||||
// @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.value" '"18446744073709551615"'
|
||||
// @is "$.index[*][?(@.name=='U64Max')].inner.variant_inner.expr" '"u64::MAX"'
|
||||
U64Max = u64::MAX,
|
||||
}
|
||||
|
||||
#[repr(i64)]
|
||||
pub enum I64 {
|
||||
// @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.value" '"-9223372036854775808"'
|
||||
// @is "$.index[*][?(@.name=='I64Min')].inner.variant_inner.expr" '"i64::MIN"'
|
||||
I64Min = i64::MIN,
|
||||
// @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.value" '"9223372036854775807"'
|
||||
// @is "$.index[*][?(@.name=='I64Max')].inner.variant_inner.expr" '"i64::MAX"'
|
||||
I64Max = i64::MAX,
|
||||
}
|
||||
|
||||
#[repr(u128)]
|
||||
pub enum U128 {
|
||||
// @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.value" '"0"'
|
||||
// @is "$.index[*][?(@.name=='U128Min')].inner.variant_inner.expr" '"u128::MIN"'
|
||||
U128Min = u128::MIN,
|
||||
// @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.value" '"340282366920938463463374607431768211455"'
|
||||
// @is "$.index[*][?(@.name=='U128Max')].inner.variant_inner.expr" '"u128::MAX"'
|
||||
U128Max = u128::MAX,
|
||||
}
|
||||
|
||||
#[repr(i128)]
|
||||
pub enum I128 {
|
||||
// @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.value" '"-170141183460469231731687303715884105728"'
|
||||
// @is "$.index[*][?(@.name=='I128Min')].inner.variant_inner.expr" '"i128::MIN"'
|
||||
I128Min = i128::MIN,
|
||||
// @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.value" '"170141183460469231731687303715884105727"'
|
||||
// @is "$.index[*][?(@.name=='I128Max')].inner.variant_inner.expr" '"i128::MAX"'
|
||||
I128Max = i128::MAX,
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#[repr(u32)]
|
||||
pub enum Foo {
|
||||
// @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.value" '"0"'
|
||||
// @is "$.index[*][?(@.name=='Basic')].inner.variant_inner.expr" '"0"'
|
||||
Basic = 0,
|
||||
// @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.value" '"10"'
|
||||
// @is "$.index[*][?(@.name=='Suffix')].inner.variant_inner.expr" '"10u32"'
|
||||
Suffix = 10u32,
|
||||
// @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.value" '"100"'
|
||||
// @is "$.index[*][?(@.name=='Underscore')].inner.variant_inner.expr" '"1_0_0"'
|
||||
Underscore = 1_0_0,
|
||||
// @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.value" '"1000"'
|
||||
// @is "$.index[*][?(@.name=='SuffixUnderscore')].inner.variant_inner.expr" '"1_0_0_0u32"'
|
||||
SuffixUnderscore = 1_0_0_0u32,
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
pub enum Foo {
|
||||
// @is "$.index[*][?(@.name=='Has')].inner.variant_inner" '{"expr":"0", "value":"0"}'
|
||||
Has = 0,
|
||||
// @is "$.index[*][?(@.name=='Doesnt')].inner.variant_inner" null
|
||||
Doesnt,
|
||||
// @is "$.index[*][?(@.name=='AlsoDoesnt')].inner.variant_inner" null
|
||||
AlsoDoesnt,
|
||||
// @is "$.index[*][?(@.name=='AlsoHas')].inner.variant_inner" '{"expr":"44", "value":"44"}'
|
||||
AlsoHas = 44,
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue