Skip to content

Commit 6257d2f

Browse files
authored
Rollup merge of #140863 - GuillaumeGomez:cleanup-tyalias-render, r=lolbinarycat
[rustdoc] Unify type aliases rendering with other ADT Fixes #140739. Better reviewed one commit at a time. Just one thing I'm wondering: should we also render non-`repr` attributes? If so, I wonder if we shouldn't simply change `clean::TypeAlias` to contain the other ADT directly (`Struct`, `Enum` and `Union`) and remove the `TypeAlias::generics` field. Can be done in a follow-up too. cc ``@camelid`` r? ``@notriddle``
2 parents 761e546 + ec97b0f commit 6257d2f

File tree

8 files changed

+376
-214
lines changed

8 files changed

+376
-214
lines changed

src/librustdoc/clean/types.rs

Lines changed: 100 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,9 @@ impl Item {
610610
UnionItem(ref union_) => Some(union_.has_stripped_entries()),
611611
EnumItem(ref enum_) => Some(enum_.has_stripped_entries()),
612612
VariantItem(ref v) => v.has_stripped_entries(),
613+
TypeAliasItem(ref type_alias) => {
614+
type_alias.inner_type.as_ref().and_then(|t| t.has_stripped_entries())
615+
}
613616
_ => None,
614617
}
615618
}
@@ -761,14 +764,11 @@ impl Item {
761764
Some(tcx.visibility(def_id))
762765
}
763766

764-
pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec<String> {
767+
pub(crate) fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec<String> {
765768
const ALLOWED_ATTRIBUTES: &[Symbol] =
766769
&[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];
767770

768-
use rustc_abi::IntegerType;
769-
770-
let mut attrs: Vec<String> = self
771-
.attrs
771+
self.attrs
772772
.other_attrs
773773
.iter()
774774
.filter_map(|attr| {
@@ -796,74 +796,28 @@ impl Item {
796796
None
797797
}
798798
})
799-
.collect();
799+
.collect()
800+
}
800801

801-
// Add #[repr(...)]
802-
if let Some(def_id) = self.def_id()
803-
&& let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_()
804-
{
805-
let adt = tcx.adt_def(def_id);
806-
let repr = adt.repr();
807-
let mut out = Vec::new();
808-
if repr.c() {
809-
out.push("C");
810-
}
811-
if repr.transparent() {
812-
// Render `repr(transparent)` iff the non-1-ZST field is public or at least one
813-
// field is public in case all fields are 1-ZST fields.
814-
let render_transparent = is_json
815-
|| cache.document_private
816-
|| adt
817-
.all_fields()
818-
.find(|field| {
819-
let ty =
820-
field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
821-
tcx.layout_of(
822-
ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty),
823-
)
824-
.is_ok_and(|layout| !layout.is_1zst())
825-
})
826-
.map_or_else(
827-
|| adt.all_fields().any(|field| field.vis.is_public()),
828-
|field| field.vis.is_public(),
829-
);
802+
pub(crate) fn attributes_and_repr(
803+
&self,
804+
tcx: TyCtxt<'_>,
805+
cache: &Cache,
806+
is_json: bool,
807+
) -> Vec<String> {
808+
let mut attrs = self.attributes_without_repr(tcx, is_json);
830809

831-
if render_transparent {
832-
out.push("transparent");
833-
}
834-
}
835-
if repr.simd() {
836-
out.push("simd");
837-
}
838-
let pack_s;
839-
if let Some(pack) = repr.pack {
840-
pack_s = format!("packed({})", pack.bytes());
841-
out.push(&pack_s);
842-
}
843-
let align_s;
844-
if let Some(align) = repr.align {
845-
align_s = format!("align({})", align.bytes());
846-
out.push(&align_s);
847-
}
848-
let int_s;
849-
if let Some(int) = repr.int {
850-
int_s = match int {
851-
IntegerType::Pointer(is_signed) => {
852-
format!("{}size", if is_signed { 'i' } else { 'u' })
853-
}
854-
IntegerType::Fixed(size, is_signed) => {
855-
format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
856-
}
857-
};
858-
out.push(&int_s);
859-
}
860-
if !out.is_empty() {
861-
attrs.push(format!("#[repr({})]", out.join(", ")));
862-
}
810+
if let Some(repr_attr) = self.repr(tcx, cache, is_json) {
811+
attrs.push(repr_attr);
863812
}
864813
attrs
865814
}
866815

816+
/// Returns a stringified `#[repr(...)]` attribute.
817+
pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Option<String> {
818+
repr_attributes(tcx, cache, self.def_id()?, self.type_(), is_json)
819+
}
820+
867821
pub fn is_doc_hidden(&self) -> bool {
868822
self.attrs.is_doc_hidden()
869823
}
@@ -873,6 +827,73 @@ impl Item {
873827
}
874828
}
875829

830+
pub(crate) fn repr_attributes(
831+
tcx: TyCtxt<'_>,
832+
cache: &Cache,
833+
def_id: DefId,
834+
item_type: ItemType,
835+
is_json: bool,
836+
) -> Option<String> {
837+
use rustc_abi::IntegerType;
838+
839+
if !matches!(item_type, ItemType::Struct | ItemType::Enum | ItemType::Union) {
840+
return None;
841+
}
842+
let adt = tcx.adt_def(def_id);
843+
let repr = adt.repr();
844+
let mut out = Vec::new();
845+
if repr.c() {
846+
out.push("C");
847+
}
848+
if repr.transparent() {
849+
// Render `repr(transparent)` iff the non-1-ZST field is public or at least one
850+
// field is public in case all fields are 1-ZST fields.
851+
let render_transparent = cache.document_private
852+
|| is_json
853+
|| adt
854+
.all_fields()
855+
.find(|field| {
856+
let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
857+
tcx.layout_of(ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty))
858+
.is_ok_and(|layout| !layout.is_1zst())
859+
})
860+
.map_or_else(
861+
|| adt.all_fields().any(|field| field.vis.is_public()),
862+
|field| field.vis.is_public(),
863+
);
864+
865+
if render_transparent {
866+
out.push("transparent");
867+
}
868+
}
869+
if repr.simd() {
870+
out.push("simd");
871+
}
872+
let pack_s;
873+
if let Some(pack) = repr.pack {
874+
pack_s = format!("packed({})", pack.bytes());
875+
out.push(&pack_s);
876+
}
877+
let align_s;
878+
if let Some(align) = repr.align {
879+
align_s = format!("align({})", align.bytes());
880+
out.push(&align_s);
881+
}
882+
let int_s;
883+
if let Some(int) = repr.int {
884+
int_s = match int {
885+
IntegerType::Pointer(is_signed) => {
886+
format!("{}size", if is_signed { 'i' } else { 'u' })
887+
}
888+
IntegerType::Fixed(size, is_signed) => {
889+
format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
890+
}
891+
};
892+
out.push(&int_s);
893+
}
894+
if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
895+
}
896+
876897
#[derive(Clone, Debug)]
877898
pub(crate) enum ItemKind {
878899
ExternCrateItem {
@@ -2107,7 +2128,7 @@ impl Enum {
21072128
self.variants.iter().any(|f| f.is_stripped())
21082129
}
21092130

2110-
pub(crate) fn variants(&self) -> impl Iterator<Item = &Item> {
2131+
pub(crate) fn non_stripped_variants(&self) -> impl Iterator<Item = &Item> {
21112132
self.variants.iter().filter(|v| !v.is_stripped())
21122133
}
21132134
}
@@ -2345,6 +2366,17 @@ pub(crate) enum TypeAliasInnerType {
23452366
Struct { ctor_kind: Option<CtorKind>, fields: Vec<Item> },
23462367
}
23472368

2369+
impl TypeAliasInnerType {
2370+
fn has_stripped_entries(&self) -> Option<bool> {
2371+
Some(match self {
2372+
Self::Enum { variants, .. } => variants.iter().any(|v| v.is_stripped()),
2373+
Self::Union { fields } | Self::Struct { fields, .. } => {
2374+
fields.iter().any(|f| f.is_stripped())
2375+
}
2376+
})
2377+
}
2378+
}
2379+
23482380
#[derive(Clone, Debug)]
23492381
pub(crate) struct TypeAlias {
23502382
pub(crate) type_: Type,

src/librustdoc/html/render/mod.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,18 +1194,36 @@ fn render_assoc_item(
11941194
// a whitespace prefix and newline.
11951195
fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display {
11961196
fmt::from_fn(move |f| {
1197-
for a in it.attributes(cx.tcx(), cx.cache(), false) {
1197+
for a in it.attributes_and_repr(cx.tcx(), cx.cache(), false) {
11981198
writeln!(f, "{prefix}{a}")?;
11991199
}
12001200
Ok(())
12011201
})
12021202
}
12031203

1204+
struct CodeAttribute(String);
1205+
1206+
fn render_code_attribute(code_attr: CodeAttribute, w: &mut impl fmt::Write) {
1207+
write!(w, "<div class=\"code-attribute\">{}</div>", code_attr.0).unwrap();
1208+
}
1209+
12041210
// When an attribute is rendered inside a <code> tag, it is formatted using
12051211
// a div to produce a newline after it.
12061212
fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) {
1207-
for attr in it.attributes(cx.tcx(), cx.cache(), false) {
1208-
write!(w, "<div class=\"code-attribute\">{attr}</div>").unwrap();
1213+
for attr in it.attributes_and_repr(cx.tcx(), cx.cache(), false) {
1214+
render_code_attribute(CodeAttribute(attr), w);
1215+
}
1216+
}
1217+
1218+
/// used for type aliases to only render their `repr` attribute.
1219+
fn render_repr_attributes_in_code(
1220+
w: &mut impl fmt::Write,
1221+
cx: &Context<'_>,
1222+
def_id: DefId,
1223+
item_type: ItemType,
1224+
) {
1225+
if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type, false) {
1226+
render_code_attribute(CodeAttribute(repr), w);
12091227
}
12101228
}
12111229

0 commit comments

Comments
 (0)