diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 74f330b7621..7371b44465b 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -11,6 +11,7 @@ use arrayvec::ArrayVec; use thin_vec::ThinVec; use rustc_ast as ast; +use rustc_ast_pretty::pprust; use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel}; use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -711,6 +712,78 @@ impl Item { }; Some(tcx.visibility(def_id)) } + + pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, keep_as_is: bool) -> Vec { + const ALLOWED_ATTRIBUTES: &[Symbol] = + &[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive]; + + use rustc_abi::IntegerType; + use rustc_middle::ty::ReprFlags; + + let mut attrs: Vec = self + .attrs + .other_attrs + .iter() + .filter_map(|attr| { + if keep_as_is { + Some(pprust::attribute_to_string(attr)) + } else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { + Some( + pprust::attribute_to_string(attr) + .replace("\\\n", "") + .replace('\n', "") + .replace(" ", " "), + ) + } else { + None + } + }) + .collect(); + if let Some(def_id) = self.item_id.as_def_id() && + !def_id.is_local() && + // This check is needed because `adt_def` will panic if not a compatible type otherwise... + matches!(self.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union) + { + let repr = tcx.adt_def(def_id).repr(); + let mut out = Vec::new(); + if repr.flags.contains(ReprFlags::IS_C) { + out.push("C"); + } + if repr.flags.contains(ReprFlags::IS_TRANSPARENT) { + out.push("transparent"); + } + if repr.flags.contains(ReprFlags::IS_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() { + return Vec::new(); + } + attrs.push(format!("#[repr({})]", out.join(", "))); + } + attrs + } } #[derive(Clone, Debug)] diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 55b249f8bbf..91ca048050e 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -48,7 +48,6 @@ use std::str; use std::string::ToString; use askama::Template; -use rustc_ast_pretty::pprust; use rustc_attr::{ConstStability, Deprecation, StabilityLevel}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -1021,76 +1020,6 @@ fn render_assoc_item( } } -const ALLOWED_ATTRIBUTES: &[Symbol] = - &[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive]; - -fn attributes(it: &clean::Item, tcx: TyCtxt<'_>) -> Vec { - use rustc_abi::IntegerType; - use rustc_middle::ty::ReprFlags; - - let mut attrs: Vec = it - .attrs - .other_attrs - .iter() - .filter_map(|attr| { - if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { - Some( - pprust::attribute_to_string(attr) - .replace("\\\n", "") - .replace('\n', "") - .replace(" ", " "), - ) - } else { - None - } - }) - .collect(); - if let Some(def_id) = it.item_id.as_def_id() && - !def_id.is_local() && - // This check is needed because `adt_def` will panic if not a compatible type otherwise... - matches!(it.type_(), ItemType::Struct | ItemType::Enum | ItemType::Union) - { - let repr = tcx.adt_def(def_id).repr(); - let mut out = Vec::new(); - if repr.flags.contains(ReprFlags::IS_C) { - out.push("C"); - } - if repr.flags.contains(ReprFlags::IS_TRANSPARENT) { - out.push("transparent"); - } - if repr.flags.contains(ReprFlags::IS_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() { - return Vec::new(); - } - attrs.push(format!("#[repr({})]", out.join(", "))); - } - attrs -} - // When an attribute is rendered inside a `
` tag, it is formatted using
 // a whitespace prefix and newline.
 fn render_attributes_in_pre<'a, 'b: 'a>(
@@ -1099,7 +1028,7 @@ fn render_attributes_in_pre<'a, 'b: 'a>(
     tcx: TyCtxt<'b>,
 ) -> impl fmt::Display + Captures<'a> + Captures<'b> {
     crate::html::format::display_fn(move |f| {
-        for a in attributes(it, tcx) {
+        for a in it.attributes(tcx, false) {
             writeln!(f, "{}{}", prefix, a)?;
         }
         Ok(())
@@ -1109,7 +1038,7 @@ fn render_attributes_in_pre<'a, 'b: 'a>(
 // When an attribute is rendered inside a  tag, it is formatted using
 // a div to produce a newline after it.
 fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item, tcx: TyCtxt<'_>) {
-    for a in attributes(it, tcx) {
+    for a in it.attributes(tcx, false) {
         write!(w, "
{}
", a); } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index edd046ab772..62aab46fa7e 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -41,12 +41,7 @@ impl JsonRenderer<'_> { }) .collect(); let docs = item.attrs.collapsed_doc_value(); - let attrs = item - .attrs - .other_attrs - .iter() - .map(rustc_ast_pretty::pprust::attribute_to_string) - .collect(); + let attrs = item.attributes(self.tcx, true); let span = item.span(self.tcx); let visibility = item.visibility(self.tcx); let clean::Item { name, item_id, .. } = item;