about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2025-05-09 17:36:32 +0200
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2025-05-25 15:08:23 +0200
commit4194745687ead479898587b85f1388635b3422e2 (patch)
tree08dd688b51d857844998159097188dce37cdac76
parent560aec13ba62c1a8fd7b2f9fbeada61096809613 (diff)
downloadrust-4194745687ead479898587b85f1388635b3422e2.tar.gz
rust-4194745687ead479898587b85f1388635b3422e2.zip
Split `Item::attributes` method into three
-rw-r--r--src/librustdoc/clean/types.rs145
-rw-r--r--src/librustdoc/html/render/mod.rs4
-rw-r--r--src/librustdoc/json/conversions.rs2
3 files changed, 81 insertions, 70 deletions
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 98d57494dbe..1766627ce39 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -764,14 +764,11 @@ impl Item {
         Some(tcx.visibility(def_id))
     }
 
-    pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Vec<String> {
+    pub(crate) fn attributes_witout_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec<String> {
         const ALLOWED_ATTRIBUTES: &[Symbol] =
             &[sym::export_name, sym::link_section, sym::no_mangle, sym::non_exhaustive];
 
-        use rustc_abi::IntegerType;
-
-        let mut attrs: Vec<String> = self
-            .attrs
+        self.attrs
             .other_attrs
             .iter()
             .filter_map(|attr| {
@@ -799,74 +796,88 @@ impl Item {
                     None
                 }
             })
-            .collect();
+            .collect()
+    }
 
-        // Add #[repr(...)]
-        if let Some(def_id) = self.def_id()
-            && let ItemType::Struct | ItemType::Enum | ItemType::Union = self.type_()
-        {
-            let adt = tcx.adt_def(def_id);
-            let repr = adt.repr();
-            let mut out = Vec::new();
-            if repr.c() {
-                out.push("C");
-            }
-            if repr.transparent() {
-                // Render `repr(transparent)` iff the non-1-ZST field is public or at least one
-                // field is public in case all fields are 1-ZST fields.
-                let render_transparent = is_json
-                    || cache.document_private
-                    || adt
-                        .all_fields()
-                        .find(|field| {
-                            let ty =
-                                field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
-                            tcx.layout_of(
-                                ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty),
-                            )
-                            .is_ok_and(|layout| !layout.is_1zst())
-                        })
-                        .map_or_else(
-                            || adt.all_fields().any(|field| field.vis.is_public()),
-                            |field| field.vis.is_public(),
-                        );
+    pub(crate) fn attributes_and_repr(
+        &self,
+        tcx: TyCtxt<'_>,
+        cache: &Cache,
+        is_json: bool,
+    ) -> Vec<String> {
+        let mut attrs = self.attributes_witout_repr(tcx, is_json);
 
-                if render_transparent {
-                    out.push("transparent");
-                }
-            }
-            if repr.simd() {
-                out.push("simd");
-            }
-            let pack_s;
-            if let Some(pack) = repr.pack {
-                pack_s = format!("packed({})", pack.bytes());
-                out.push(&pack_s);
-            }
-            let align_s;
-            if let Some(align) = repr.align {
-                align_s = format!("align({})", align.bytes());
-                out.push(&align_s);
-            }
-            let int_s;
-            if let Some(int) = repr.int {
-                int_s = match int {
-                    IntegerType::Pointer(is_signed) => {
-                        format!("{}size", if is_signed { 'i' } else { 'u' })
-                    }
-                    IntegerType::Fixed(size, is_signed) => {
-                        format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
-                    }
-                };
-                out.push(&int_s);
-            }
-            if !out.is_empty() {
-                attrs.push(format!("#[repr({})]", out.join(", ")));
-            }
+        if let Some(repr_attr) = self.repr(tcx, cache) {
+            attrs.push(repr_attr);
         }
         attrs
     }
 
+    /// Returns a `#[repr(...)]` representation.
+    pub(crate) fn repr(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -> Option<String> {
+        use rustc_abi::IntegerType;
+
+        let def_id = self.def_id()?;
+        if !matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union) {
+            return None;
+        }
+        let adt = tcx.adt_def(def_id);
+        let repr = adt.repr();
+        let mut out = Vec::new();
+        if repr.c() {
+            out.push("C");
+        }
+        if repr.transparent() {
+            // Render `repr(transparent)` iff the non-1-ZST field is public or at least one
+            // field is public in case all fields are 1-ZST fields.
+            let render_transparent = is_json
+                || cache.document_private
+                || adt
+                    .all_fields()
+                    .find(|field| {
+                        let ty = field.ty(tcx, ty::GenericArgs::identity_for_item(tcx, field.did));
+                        tcx.layout_of(
+                            ty::TypingEnv::post_analysis(tcx, field.did).as_query_input(ty),
+                        )
+                        .is_ok_and(|layout| !layout.is_1zst())
+                    })
+                    .map_or_else(
+                        || adt.all_fields().any(|field| field.vis.is_public()),
+                        |field| field.vis.is_public(),
+                    );
+
+            if render_transparent {
+                out.push("transparent");
+            }
+        }
+        if repr.simd() {
+            out.push("simd");
+        }
+        let pack_s;
+        if let Some(pack) = repr.pack {
+            pack_s = format!("packed({})", pack.bytes());
+            out.push(&pack_s);
+        }
+        let align_s;
+        if let Some(align) = repr.align {
+            align_s = format!("align({})", align.bytes());
+            out.push(&align_s);
+        }
+        let int_s;
+        if let Some(int) = repr.int {
+            int_s = match int {
+                IntegerType::Pointer(is_signed) => {
+                    format!("{}size", if is_signed { 'i' } else { 'u' })
+                }
+                IntegerType::Fixed(size, is_signed) => {
+                    format!("{}{}", if is_signed { 'i' } else { 'u' }, size.size().bytes() * 8)
+                }
+            };
+            out.push(&int_s);
+        }
+        if !out.is_empty() { Some(format!("#[repr({})]", out.join(", "))) } else { None }
+    }
+
     pub fn is_doc_hidden(&self) -> bool {
         self.attrs.is_doc_hidden()
     }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 06cb9269cc8..6b4fd3cd834 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1194,7 +1194,7 @@ fn render_assoc_item(
 // a whitespace prefix and newline.
 fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display {
     fmt::from_fn(move |f| {
-        for a in it.attributes(cx.tcx(), cx.cache(), false) {
+        for a in it.attributes_and_repr(cx.tcx(), cx.cache(), false) {
             writeln!(f, "{prefix}{a}")?;
         }
         Ok(())
@@ -1204,7 +1204,7 @@ fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) ->
 // When an attribute is rendered inside a <code> tag, it is formatted using
 // a div to produce a newline after it.
 fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) {
-    for attr in it.attributes(cx.tcx(), cx.cache(), false) {
+    for attr in it.attributes_and_repr(cx.tcx(), cx.cache(), false) {
         write!(w, "<div class=\"code-attribute\">{attr}</div>").unwrap();
     }
 }
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 705f9b2202c..bfcb794b89a 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -40,7 +40,7 @@ impl JsonRenderer<'_> {
             })
             .collect();
         let docs = item.opt_doc_value();
-        let attrs = item.attributes(self.tcx, self.cache(), true);
+        let attrs = item.attributes_and_repr(self.tcx, self.cache(), true);
         let span = item.span(self.tcx);
         let visibility = item.visibility(self.tcx);
         let clean::ItemInner { name, item_id, .. } = *item.inner;