From a576dfd0c63508b7424dc1b59ad7f6b154341730 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 25 Sep 2023 14:51:32 +0200 Subject: [PATCH 1/9] Show enum variant value if it is a C-like variant --- src/librustdoc/clean/types.rs | 7 ++--- src/librustdoc/clean/utils.rs | 40 +++++++++++++++++------- src/librustdoc/html/render/print_item.rs | 16 ++++++++-- src/librustdoc/json/conversions.rs | 2 +- 4 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index b665f68416785..fc7072972bcc4 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2091,9 +2091,8 @@ impl Discriminant { pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> Option { self.expr.map(|body| rendered_const(tcx, body)) } - /// Will always be a machine readable number, without underscores or suffixes. - pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> String { - print_evaluated_const(tcx, self.value, false).unwrap() + pub(crate) fn value(&self, tcx: TyCtxt<'_>, with_underscores: bool) -> String { + print_evaluated_const(tcx, self.value, with_underscores, false).unwrap() } } @@ -2348,7 +2347,7 @@ impl ConstantKind { match *self { ConstantKind::TyConst { .. } | ConstantKind::Anonymous { .. } => None, ConstantKind::Extern { def_id } | ConstantKind::Local { def_id, .. } => { - print_evaluated_const(tcx, def_id, true) + print_evaluated_const(tcx, def_id, true, true) } } } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 8388f722a7f1a..3be4f065ccdd6 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -275,7 +275,8 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { pub(crate) fn print_evaluated_const( tcx: TyCtxt<'_>, def_id: DefId, - underscores_and_type: bool, + with_underscores: bool, + with_type: bool, ) -> Option { tcx.const_eval_poly(def_id).ok().and_then(|val| { let ty = tcx.type_of(def_id).instantiate_identity(); @@ -284,7 +285,7 @@ pub(crate) fn print_evaluated_const( (mir::ConstValue::Scalar(_), &ty::Adt(_, _)) => None, (mir::ConstValue::Scalar(_), _) => { let const_ = mir::Const::from_value(val, ty); - Some(print_const_with_custom_print_scalar(tcx, const_, underscores_and_type)) + Some(print_const_with_custom_print_scalar(tcx, const_, with_underscores, with_type)) } _ => None, } @@ -320,14 +321,25 @@ fn format_integer_with_underscore_sep(num: &str) -> String { fn print_const_with_custom_print_scalar<'tcx>( tcx: TyCtxt<'tcx>, ct: mir::Const<'tcx>, - underscores_and_type: bool, + with_underscores: bool, + with_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::Const::Val(mir::ConstValue::Scalar(int), _), ty::Uint(ui)) => { - if underscores_and_type { - format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str()) + if with_underscores { + if with_type { + format!( + "{}{}", + format_integer_with_underscore_sep(&int.to_string()), + ui.name_str() + ) + } else { + format_integer_with_underscore_sep(&int.to_string()) + } + } else if with_type { + format!("{}{}", int.to_string(), ui.name_str()) } else { int.to_string() } @@ -337,12 +349,18 @@ fn print_const_with_custom_print_scalar<'tcx>( 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; - if underscores_and_type { - format!( - "{}{}", - format_integer_with_underscore_sep(&sign_extended_data.to_string()), - i.name_str() - ) + if with_underscores { + if with_type { + format!( + "{}{}", + format_integer_with_underscore_sep(&sign_extended_data.to_string()), + i.name_str() + ) + } else { + format_integer_with_underscore_sep(&sign_extended_data.to_string()) + } + } else if with_type { + format!("{}{}", sign_extended_data.to_string(), i.name_str()) } else { sign_extended_data.to_string() } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index c6751c9585ee9..747235adbe5b5 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1467,9 +1467,15 @@ fn render_enum_fields<'a>( match *v.kind { // FIXME(#101337): Show discriminant clean::VariantItem(ref var) => match var.kind { - clean::VariantKind::CLike => w.write_str(name.as_str()), + clean::VariantKind::CLike => { + if let Some(ref value) = var.discriminant { + write!(w, "{} = {}", name.as_str(), value.value(cx.tcx(), true)); + } else { + w.write_str(name.as_str()); + } + } clean::VariantKind::Tuple(ref s) => { - write!(w, "{name}({})", print_tuple_struct_fields(cx, s),); + write!(w, "{name}({})", print_tuple_struct_fields(cx, s)); } clean::VariantKind::Struct(ref s) => { render_struct(w, v, None, None, &s.fields, TAB, false, cx); @@ -1523,6 +1529,12 @@ fn item_variants<'a>( " rightside", ); write!(w, "

{name}", name = variant.name.unwrap()); + if let clean::VariantItem(ref var) = *variant.kind && + let clean::VariantKind::CLike = var.kind && + let Some(ref value) = var.discriminant + { + write!(w, " = {}", value.value(cx.tcx(), true)); + } let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() }; diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 0886501596056..fabaec9899e38 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -745,7 +745,7 @@ impl FromWithTcx for Discriminant { // `rustc_middle` types, not `rustc_hir`, but because JSON never inlines // the expr is always some. expr: disr.expr(tcx).unwrap(), - value: disr.value(tcx), + value: disr.value(tcx, false), } } } From 4a64c796ee4d243566beff014016e12c165ef534 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 25 Sep 2023 14:59:41 +0200 Subject: [PATCH 2/9] Add test for enum variant value display --- tests/rustdoc/enum-variant-value.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/rustdoc/enum-variant-value.rs diff --git a/tests/rustdoc/enum-variant-value.rs b/tests/rustdoc/enum-variant-value.rs new file mode 100644 index 0000000000000..09956b8c866dd --- /dev/null +++ b/tests/rustdoc/enum-variant-value.rs @@ -0,0 +1,15 @@ +// This test ensures that the variant value is displayed with underscores but without +// a type name at the end. + +#![crate_name = "foo"] + +// @has 'foo/enum.B.html' +// @has - '//*[@class="rust item-decl"]/code' 'A = 12,' +// @has - '//*[@class="rust item-decl"]/code' 'C = 1_245,' +// @matches - '//*[@id="variant.A"]/h3' '^A = 12$' +// @matches - '//*[@id="variant.C"]/h3' '^C = 1_245$' +pub enum B { + A = 12, + B, + C = 1245, +} From 91114d6616f58996b6009bcb23196e8dc253e8bf Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 6 Oct 2023 23:55:30 +0200 Subject: [PATCH 3/9] Show values of C-like variants even if not defined by the user --- src/librustdoc/html/render/print_item.rs | 112 ++++++++++++++++++----- 1 file changed, 90 insertions(+), 22 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 747235adbe5b5..e7c66fedc11f9 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1257,13 +1257,13 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c w, cx, Some(&t.generics), - variants_iter(), + &variants, variants_count, has_stripped_entries, *is_non_exhaustive, ) }); - item_variants(w, cx, it, variants_iter()); + item_variants(w, cx, it, &variants); } clean::TypeAliasInnerType::Union { fields } => { wrap_item(w, |w| { @@ -1416,11 +1416,12 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: it.name.unwrap(), e.generics.print(cx), ); + render_enum_fields( w, cx, Some(&e.generics), - e.variants(), + &e.variants, count_variants, e.has_stripped_entries(), it.is_non_exhaustive(), @@ -1430,22 +1431,80 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: write!(w, "{}", document(cx, it, None, HeadingOffset::H2)); if count_variants != 0 { - item_variants(w, cx, it, e.variants()); + item_variants(w, cx, it, &e.variants); } let def_id = it.item_id.expect_def_id(); write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)); write!(w, "{}", document_type_layout(cx, def_id)); } -fn render_enum_fields<'a>( +fn get_parent_enum_def_id( + cx: &mut Context<'_>, + variant_def_id: rustc_hir::def_id::LocalDefId, +) -> DefId { + use rustc_hir::{ItemKind, Node}; + let variant_hir_id = cx.tcx().hir().local_def_id_to_hir_id(variant_def_id); + + for (_, node) in cx.tcx().hir().parent_iter(variant_hir_id) { + if let Node::Item(item) = node && matches!(item.kind, ItemKind::Enum(..)) { + return item.owner_id.to_def_id(); + } + } + panic!("No parent enum found for variant {variant_def_id:?}"); +} + +fn is_c_like_enum( + variants: &rustc_index::IndexVec, +) -> bool { + !variants.iter().any(|variant| { + matches!( + *variant.kind, + clean::VariantItem(clean::Variant { + kind: clean::VariantKind::Tuple(_) | clean::VariantKind::Struct(_), + .. + }) + ) + }) +} + +fn display_c_like_variant( + w: &mut Buffer, + cx: &mut Context<'_>, + item: &clean::Item, + variant: &clean::Variant, + index: rustc_target::abi::VariantIdx, + is_c_like_enum: bool, +) { + let name = item.name.unwrap(); + if let Some(ref value) = variant.discriminant { + write!(w, "{} = {}", name.as_str(), value.value(cx.tcx(), true)); + } else if is_c_like_enum && + let Some(variant_def_id) = item.item_id.as_def_id() && + let Some(variant_def_id) = variant_def_id.as_local() + { + let enum_def_id = get_parent_enum_def_id(cx, variant_def_id); + let adt_def = cx.tcx().adt_def(enum_def_id); + let discr = adt_def.discriminant_for_variant(cx.tcx(), index); + if discr.ty.is_signed() { + write!(w, "{} = {}", name.as_str(), discr.val as i128); + } else { + write!(w, "{} = {}", name.as_str(), discr.val); + } + } else { + w.write_str(name.as_str()); + } +} + +fn render_enum_fields( mut w: &mut Buffer, cx: &mut Context<'_>, g: Option<&clean::Generics>, - variants: impl Iterator, + variants: &rustc_index::IndexVec, count_variants: usize, has_stripped_entries: bool, is_non_exhaustive: bool, ) { + let is_c_like_enum = is_c_like_enum(variants); if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) { // If there wasn't a `where` clause, we add a whitespace. w.write_str(" "); @@ -1461,21 +1520,18 @@ fn render_enum_fields<'a>( toggle_open(&mut w, format_args!("{count_variants} variants")); } const TAB: &str = " "; - for v in variants { + for (index, v) in variants.iter_enumerated() { + if v.is_stripped() { + continue; + } w.write_str(TAB); - let name = v.name.unwrap(); match *v.kind { - // FIXME(#101337): Show discriminant clean::VariantItem(ref var) => match var.kind { clean::VariantKind::CLike => { - if let Some(ref value) = var.discriminant { - write!(w, "{} = {}", name.as_str(), value.value(cx.tcx(), true)); - } else { - w.write_str(name.as_str()); - } + display_c_like_variant(w, cx, v, var, index, is_c_like_enum) } clean::VariantKind::Tuple(ref s) => { - write!(w, "{name}({})", print_tuple_struct_fields(cx, s)); + write!(w, "{}({})", v.name.unwrap(), print_tuple_struct_fields(cx, s)); } clean::VariantKind::Struct(ref s) => { render_struct(w, v, None, None, &s.fields, TAB, false, cx); @@ -1496,11 +1552,11 @@ fn render_enum_fields<'a>( } } -fn item_variants<'a>( +fn item_variants( w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, - variants: impl Iterator, + variants: &rustc_index::IndexVec, ) { let tcx = cx.tcx(); write!( @@ -1513,7 +1569,11 @@ fn item_variants<'a>( document_non_exhaustive_header(it), document_non_exhaustive(it) ); - for variant in variants { + let is_c_like_enum = is_c_like_enum(variants); + for (index, variant) in variants.iter_enumerated() { + if variant.is_stripped() { + continue; + } let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap())); write!( w, @@ -1528,12 +1588,20 @@ fn item_variants<'a>( it.const_stable_since(tcx), " rightside", ); - write!(w, "

{name}", name = variant.name.unwrap()); + w.write_str("

"); if let clean::VariantItem(ref var) = *variant.kind && - let clean::VariantKind::CLike = var.kind && - let Some(ref value) = var.discriminant + let clean::VariantKind::CLike = var.kind { - write!(w, " = {}", value.value(cx.tcx(), true)); + display_c_like_variant( + w, + cx, + variant, + var, + index, + is_c_like_enum, + ); + } else { + w.write_str(variant.name.unwrap().as_str()); } let clean::VariantItem(variant_data) = &*variant.kind else { unreachable!() }; From 9e15f363be1f62cf81d4efb55d95a542663fe6da Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 7 Oct 2023 00:14:57 +0200 Subject: [PATCH 4/9] Only display enum variants integer values if one of them has a value set --- src/librustdoc/html/render/print_item.rs | 45 ++++++++++++++---------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index e7c66fedc11f9..b3a8f678b437f 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1453,18 +1453,22 @@ fn get_parent_enum_def_id( panic!("No parent enum found for variant {variant_def_id:?}"); } -fn is_c_like_enum( +/// It'll return true if all variants are C-like variants and if at least one of them has a value +/// set. +fn should_show_c_like_variants_value( variants: &rustc_index::IndexVec, ) -> bool { - !variants.iter().any(|variant| { - matches!( - *variant.kind, - clean::VariantItem(clean::Variant { - kind: clean::VariantKind::Tuple(_) | clean::VariantKind::Struct(_), - .. - }) - ) - }) + let mut has_variants_with_value = false; + for variant in variants { + if let clean::VariantItem(ref var) = *variant.kind && + matches!(var.kind, clean::VariantKind::CLike) + { + has_variants_with_value |= var.discriminant.is_some(); + } else { + return false; + } + } + has_variants_with_value } fn display_c_like_variant( @@ -1473,12 +1477,12 @@ fn display_c_like_variant( item: &clean::Item, variant: &clean::Variant, index: rustc_target::abi::VariantIdx, - is_c_like_enum: bool, + should_show_c_like_variants_value: bool, ) { let name = item.name.unwrap(); if let Some(ref value) = variant.discriminant { write!(w, "{} = {}", name.as_str(), value.value(cx.tcx(), true)); - } else if is_c_like_enum && + } else if should_show_c_like_variants_value && let Some(variant_def_id) = item.item_id.as_def_id() && let Some(variant_def_id) = variant_def_id.as_local() { @@ -1504,7 +1508,7 @@ fn render_enum_fields( has_stripped_entries: bool, is_non_exhaustive: bool, ) { - let is_c_like_enum = is_c_like_enum(variants); + let should_show_c_like_variants_value = should_show_c_like_variants_value(variants); if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) { // If there wasn't a `where` clause, we add a whitespace. w.write_str(" "); @@ -1527,9 +1531,14 @@ fn render_enum_fields( w.write_str(TAB); match *v.kind { clean::VariantItem(ref var) => match var.kind { - clean::VariantKind::CLike => { - display_c_like_variant(w, cx, v, var, index, is_c_like_enum) - } + clean::VariantKind::CLike => display_c_like_variant( + w, + cx, + v, + var, + index, + should_show_c_like_variants_value, + ), clean::VariantKind::Tuple(ref s) => { write!(w, "{}({})", v.name.unwrap(), print_tuple_struct_fields(cx, s)); } @@ -1569,7 +1578,7 @@ fn item_variants( document_non_exhaustive_header(it), document_non_exhaustive(it) ); - let is_c_like_enum = is_c_like_enum(variants); + let should_show_c_like_variants_value = should_show_c_like_variants_value(variants); for (index, variant) in variants.iter_enumerated() { if variant.is_stripped() { continue; @@ -1598,7 +1607,7 @@ fn item_variants( variant, var, index, - is_c_like_enum, + should_show_c_like_variants_value, ); } else { w.write_str(variant.name.unwrap().as_str()); From 1994d0b4a42b9b2d6e0c821f57d37a184f4df44a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 7 Oct 2023 00:25:34 +0200 Subject: [PATCH 5/9] Update enum-variant-value test --- tests/rustdoc/enum-variant-value.rs | 51 +++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/tests/rustdoc/enum-variant-value.rs b/tests/rustdoc/enum-variant-value.rs index 09956b8c866dd..7fd8a72f6135b 100644 --- a/tests/rustdoc/enum-variant-value.rs +++ b/tests/rustdoc/enum-variant-value.rs @@ -3,13 +3,60 @@ #![crate_name = "foo"] -// @has 'foo/enum.B.html' +// In this case, since all variants are C-like variants and at least one of them +// has its value set, we display values for all of them. + +// @has 'foo/enum.A.html' // @has - '//*[@class="rust item-decl"]/code' 'A = 12,' +// @has - '//*[@class="rust item-decl"]/code' 'B = 13,' // @has - '//*[@class="rust item-decl"]/code' 'C = 1_245,' // @matches - '//*[@id="variant.A"]/h3' '^A = 12$' +// @matches - '//*[@id="variant.B"]/h3' '^B = 13$' // @matches - '//*[@id="variant.C"]/h3' '^C = 1_245$' -pub enum B { +pub enum A { A = 12, B, C = 1245, } + +// In this case, all variants are C-like variants but none of them has its value set. +// Therefore we don't display values. + +// @has 'foo/enum.B.html' +// @has - '//*[@class="rust item-decl"]/code' 'A,' +// @has - '//*[@class="rust item-decl"]/code' 'B,' +// @matches - '//*[@id="variant.A"]/h3' '^A$' +// @matches - '//*[@id="variant.B"]/h3' '^B$' +pub enum B { + A, + B, +} + +// In this case, not all variants are C-like variants so we don't display values. + +// @has 'foo/enum.C.html' +// @has - '//*[@class="rust item-decl"]/code' 'A = 12,' +// @has - '//*[@class="rust item-decl"]/code' 'B,' +// @has - '//*[@class="rust item-decl"]/code' 'C(u32),' +// @matches - '//*[@id="variant.A"]/h3' '^A = 12$' +// @matches - '//*[@id="variant.B"]/h3' '^B$' +// @has - '//*[@id="variant.C"]/h3' 'C(u32)' +#[repr(u32)] +pub enum C { + A = 12, + B, + C(u32), +} + +// In this case, not all variants are C-like variants and no C-like variant has its +// value set, so we don't display values. + +// @has 'foo/enum.D.html' +// @has - '//*[@class="rust item-decl"]/code' 'A,' +// @has - '//*[@class="rust item-decl"]/code' 'C(u32),' +// @matches - '//*[@id="variant.A"]/h3' '^A$' +// @has - '//*[@id="variant.C"]/h3' 'C(u32)' +pub enum D { + A, + C(u32), +} From de70a77be235f839dede3c06fdb70c5528f540e6 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 7 Oct 2023 14:37:30 +0200 Subject: [PATCH 6/9] Correctly handle cross-crate C-like variants --- src/librustdoc/html/render/print_item.rs | 27 ++++++------------------ 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index b3a8f678b437f..2da5e8ef17a04 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1261,6 +1261,7 @@ fn item_type_alias(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &c variants_count, has_stripped_entries, *is_non_exhaustive, + it.def_id().unwrap(), ) }); item_variants(w, cx, it, &variants); @@ -1425,6 +1426,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: count_variants, e.has_stripped_entries(), it.is_non_exhaustive(), + it.def_id().unwrap(), ); }); @@ -1438,21 +1440,6 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: write!(w, "{}", document_type_layout(cx, def_id)); } -fn get_parent_enum_def_id( - cx: &mut Context<'_>, - variant_def_id: rustc_hir::def_id::LocalDefId, -) -> DefId { - use rustc_hir::{ItemKind, Node}; - let variant_hir_id = cx.tcx().hir().local_def_id_to_hir_id(variant_def_id); - - for (_, node) in cx.tcx().hir().parent_iter(variant_hir_id) { - if let Node::Item(item) = node && matches!(item.kind, ItemKind::Enum(..)) { - return item.owner_id.to_def_id(); - } - } - panic!("No parent enum found for variant {variant_def_id:?}"); -} - /// It'll return true if all variants are C-like variants and if at least one of them has a value /// set. fn should_show_c_like_variants_value( @@ -1478,15 +1465,12 @@ fn display_c_like_variant( variant: &clean::Variant, index: rustc_target::abi::VariantIdx, should_show_c_like_variants_value: bool, + enum_def_id: DefId, ) { let name = item.name.unwrap(); if let Some(ref value) = variant.discriminant { write!(w, "{} = {}", name.as_str(), value.value(cx.tcx(), true)); - } else if should_show_c_like_variants_value && - let Some(variant_def_id) = item.item_id.as_def_id() && - let Some(variant_def_id) = variant_def_id.as_local() - { - let enum_def_id = get_parent_enum_def_id(cx, variant_def_id); + } else if should_show_c_like_variants_value { let adt_def = cx.tcx().adt_def(enum_def_id); let discr = adt_def.discriminant_for_variant(cx.tcx(), index); if discr.ty.is_signed() { @@ -1507,6 +1491,7 @@ fn render_enum_fields( count_variants: usize, has_stripped_entries: bool, is_non_exhaustive: bool, + enum_def_id: DefId, ) { let should_show_c_like_variants_value = should_show_c_like_variants_value(variants); if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) { @@ -1538,6 +1523,7 @@ fn render_enum_fields( var, index, should_show_c_like_variants_value, + enum_def_id, ), clean::VariantKind::Tuple(ref s) => { write!(w, "{}({})", v.name.unwrap(), print_tuple_struct_fields(cx, s)); @@ -1608,6 +1594,7 @@ fn item_variants( var, index, should_show_c_like_variants_value, + it.def_id().unwrap(), ); } else { w.write_str(variant.name.unwrap().as_str()); From b0badc17cdc8d2f75061d2e4674a8adcfa8983d5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 7 Oct 2023 14:37:47 +0200 Subject: [PATCH 7/9] Add cross-crate C-like variant test --- tests/rustdoc/auxiliary/enum-variant.rs | 24 +++++++++++++++++ tests/rustdoc/enum-variant-value.rs | 36 +++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 tests/rustdoc/auxiliary/enum-variant.rs diff --git a/tests/rustdoc/auxiliary/enum-variant.rs b/tests/rustdoc/auxiliary/enum-variant.rs new file mode 100644 index 0000000000000..90c71b863290d --- /dev/null +++ b/tests/rustdoc/auxiliary/enum-variant.rs @@ -0,0 +1,24 @@ +#![crate_name = "bar"] + +pub enum E { + A = 12, + B, + C = 1245, +} + +pub enum F { + A, + B, +} + +#[repr(u32)] +pub enum G { + A = 12, + B, + C(u32), +} + +pub enum H { + A, + C(u32), +} diff --git a/tests/rustdoc/enum-variant-value.rs b/tests/rustdoc/enum-variant-value.rs index 7fd8a72f6135b..f08907cf94fa4 100644 --- a/tests/rustdoc/enum-variant-value.rs +++ b/tests/rustdoc/enum-variant-value.rs @@ -1,8 +1,12 @@ // This test ensures that the variant value is displayed with underscores but without // a type name at the end. +// aux-build:enum-variant.rs + #![crate_name = "foo"] +extern crate bar; + // In this case, since all variants are C-like variants and at least one of them // has its value set, we display values for all of them. @@ -60,3 +64,35 @@ pub enum D { A, C(u32), } + +// @has 'foo/enum.E.html' +// @has - '//*[@class="rust item-decl"]/code' 'A = 12,' +// @has - '//*[@class="rust item-decl"]/code' 'B = 13,' +// @has - '//*[@class="rust item-decl"]/code' 'C = 1_245,' +// @matches - '//*[@id="variant.A"]/h3' '^A = 12$' +// @matches - '//*[@id="variant.B"]/h3' '^B = 13$' +// @matches - '//*[@id="variant.C"]/h3' '^C = 1_245$' +pub use bar::E; + +// @has 'foo/enum.F.html' +// @has - '//*[@class="rust item-decl"]/code' 'A,' +// @has - '//*[@class="rust item-decl"]/code' 'B,' +// @matches - '//*[@id="variant.A"]/h3' '^A$' +// @matches - '//*[@id="variant.B"]/h3' '^B$' +pub use bar::F; + +// @has 'foo/enum.G.html' +// @has - '//*[@class="rust item-decl"]/code' 'A = 12,' +// @has - '//*[@class="rust item-decl"]/code' 'B,' +// @has - '//*[@class="rust item-decl"]/code' 'C(u32),' +// @matches - '//*[@id="variant.A"]/h3' '^A = 12$' +// @matches - '//*[@id="variant.B"]/h3' '^B$' +// @has - '//*[@id="variant.C"]/h3' 'C(u32)' +pub use bar::G; + +// @has 'foo/enum.H.html' +// @has - '//*[@class="rust item-decl"]/code' 'A,' +// @has - '//*[@class="rust item-decl"]/code' 'C(u32),' +// @matches - '//*[@id="variant.A"]/h3' '^A$' +// @has - '//*[@id="variant.C"]/h3' 'C(u32)' +pub use bar::H; From 4b6fc8b70fd355614bad31d4268993dc7ef17431 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 9 Oct 2023 14:26:52 +0200 Subject: [PATCH 8/9] Improve code --- src/librustdoc/clean/utils.rs | 36 ++++++++---------------- src/librustdoc/html/render/print_item.rs | 24 ++++++++-------- 2 files changed, 24 insertions(+), 36 deletions(-) diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 3be4f065ccdd6..01078504b713a 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -328,42 +328,30 @@ fn print_const_with_custom_print_scalar<'tcx>( // For all other types, fallback to the original `pretty_print_const`. match (ct, ct.ty().kind()) { (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Uint(ui)) => { - if with_underscores { - if with_type { - format!( - "{}{}", - format_integer_with_underscore_sep(&int.to_string()), - ui.name_str() - ) - } else { - format_integer_with_underscore_sep(&int.to_string()) - } - } else if with_type { - format!("{}{}", int.to_string(), ui.name_str()) + let mut output = if with_underscores { + format_integer_with_underscore_sep(&int.to_string()) } else { int.to_string() + }; + if with_type { + output += ui.name_str(); } + output } (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Int(i)) => { let ty = ct.ty(); 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; - if with_underscores { - if with_type { - format!( - "{}{}", - format_integer_with_underscore_sep(&sign_extended_data.to_string()), - i.name_str() - ) - } else { - format_integer_with_underscore_sep(&sign_extended_data.to_string()) - } - } else if with_type { - format!("{}{}", sign_extended_data.to_string(), i.name_str()) + let mut output = if with_underscores { + format_integer_with_underscore_sep(&sign_extended_data.to_string()) } else { sign_extended_data.to_string() + }; + if with_type { + output += i.name_str(); } + output } _ => ct.to_string(), } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 2da5e8ef17a04..467493cb0b30d 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -5,10 +5,12 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; +use rustc_index::IndexVec; use rustc_middle::middle::stability; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; +use rustc_target::abi::VariantIdx; use std::cell::{RefCell, RefMut}; use std::cmp::Ordering; use std::fmt; @@ -1442,9 +1444,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: /// It'll return true if all variants are C-like variants and if at least one of them has a value /// set. -fn should_show_c_like_variants_value( - variants: &rustc_index::IndexVec, -) -> bool { +fn should_show_enum_discriminant(variants: &IndexVec) -> bool { let mut has_variants_with_value = false; for variant in variants { if let clean::VariantItem(ref var) = *variant.kind && @@ -1463,14 +1463,14 @@ fn display_c_like_variant( cx: &mut Context<'_>, item: &clean::Item, variant: &clean::Variant, - index: rustc_target::abi::VariantIdx, - should_show_c_like_variants_value: bool, + index: VariantIdx, + should_show_enum_discriminant: bool, enum_def_id: DefId, ) { let name = item.name.unwrap(); if let Some(ref value) = variant.discriminant { write!(w, "{} = {}", name.as_str(), value.value(cx.tcx(), true)); - } else if should_show_c_like_variants_value { + } else if should_show_enum_discriminant { let adt_def = cx.tcx().adt_def(enum_def_id); let discr = adt_def.discriminant_for_variant(cx.tcx(), index); if discr.ty.is_signed() { @@ -1487,13 +1487,13 @@ fn render_enum_fields( mut w: &mut Buffer, cx: &mut Context<'_>, g: Option<&clean::Generics>, - variants: &rustc_index::IndexVec, + variants: &IndexVec, count_variants: usize, has_stripped_entries: bool, is_non_exhaustive: bool, enum_def_id: DefId, ) { - let should_show_c_like_variants_value = should_show_c_like_variants_value(variants); + let should_show_enum_discriminant = should_show_enum_discriminant(variants); if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) { // If there wasn't a `where` clause, we add a whitespace. w.write_str(" "); @@ -1522,7 +1522,7 @@ fn render_enum_fields( v, var, index, - should_show_c_like_variants_value, + should_show_enum_discriminant, enum_def_id, ), clean::VariantKind::Tuple(ref s) => { @@ -1551,7 +1551,7 @@ fn item_variants( w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, - variants: &rustc_index::IndexVec, + variants: &IndexVec, ) { let tcx = cx.tcx(); write!( @@ -1564,7 +1564,7 @@ fn item_variants( document_non_exhaustive_header(it), document_non_exhaustive(it) ); - let should_show_c_like_variants_value = should_show_c_like_variants_value(variants); + let should_show_enum_discriminant = should_show_enum_discriminant(variants); for (index, variant) in variants.iter_enumerated() { if variant.is_stripped() { continue; @@ -1593,7 +1593,7 @@ fn item_variants( variant, var, index, - should_show_c_like_variants_value, + should_show_enum_discriminant, it.def_id().unwrap(), ); } else { From 1210aac1c00d9d3435ba801e0dee2d4ac502a738 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 9 Oct 2023 14:33:04 +0200 Subject: [PATCH 9/9] Add more complex test cases for enum discriminant display --- tests/rustdoc/enum-variant-value.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/rustdoc/enum-variant-value.rs b/tests/rustdoc/enum-variant-value.rs index f08907cf94fa4..c306736bfe919 100644 --- a/tests/rustdoc/enum-variant-value.rs +++ b/tests/rustdoc/enum-variant-value.rs @@ -96,3 +96,22 @@ pub use bar::G; // @matches - '//*[@id="variant.A"]/h3' '^A$' // @has - '//*[@id="variant.C"]/h3' 'C(u32)' pub use bar::H; + +// Testing more complex cases. +pub const X: isize = 2; +// @has 'foo/enum.I.html' +// @has - '//*[@class="rust item-decl"]/code' 'A = 2,' +// @has - '//*[@class="rust item-decl"]/code' 'B = 4,' +// @has - '//*[@class="rust item-decl"]/code' 'C = 9,' +// @has - '//*[@class="rust item-decl"]/code' 'D = -1,' +// @matches - '//*[@id="variant.A"]/h3' '^A = 2$' +// @matches - '//*[@id="variant.B"]/h3' '^B = 4$' +// @matches - '//*[@id="variant.C"]/h3' '^C = 9$' +// @matches - '//*[@id="variant.D"]/h3' '^D = -1$' +#[repr(isize)] +pub enum I { + A = X, + B = X * 2, + C = Self::B as isize + X + 3, + D = -1, +}