Skip to content

Commit c44372d

Browse files
authored
Merge pull request #19876 from ShoyuVanilla/layout-padding
feat: Render padding information when hovering on structs
2 parents a420ef2 + e806957 commit c44372d

File tree

7 files changed

+272
-23
lines changed

7 files changed

+272
-23
lines changed

crates/hir/src/lib.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5972,6 +5972,59 @@ impl Layout {
59725972
}
59735973
}
59745974

5975+
pub fn tail_padding(&self, field_size: &mut impl FnMut(usize) -> Option<u64>) -> Option<u64> {
5976+
match self.0.fields {
5977+
layout::FieldsShape::Primitive => None,
5978+
layout::FieldsShape::Union(_) => None,
5979+
layout::FieldsShape::Array { stride, count } => count.checked_sub(1).and_then(|tail| {
5980+
let tail_field_size = field_size(tail as usize)?;
5981+
let offset = stride.bytes() * tail;
5982+
self.0.size.bytes().checked_sub(offset)?.checked_sub(tail_field_size)
5983+
}),
5984+
layout::FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
5985+
let tail = memory_index.last_index()?;
5986+
let tail_field_size = field_size(tail.0.into_raw().into_u32() as usize)?;
5987+
let offset = offsets.get(tail)?.bytes();
5988+
self.0.size.bytes().checked_sub(offset)?.checked_sub(tail_field_size)
5989+
}
5990+
}
5991+
}
5992+
5993+
pub fn largest_padding(
5994+
&self,
5995+
field_size: &mut impl FnMut(usize) -> Option<u64>,
5996+
) -> Option<u64> {
5997+
match self.0.fields {
5998+
layout::FieldsShape::Primitive => None,
5999+
layout::FieldsShape::Union(_) => None,
6000+
layout::FieldsShape::Array { stride: _, count: 0 } => None,
6001+
layout::FieldsShape::Array { stride, .. } => {
6002+
let size = field_size(0)?;
6003+
stride.bytes().checked_sub(size)
6004+
}
6005+
layout::FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
6006+
let mut reverse_index = vec![None; memory_index.len()];
6007+
for (src, (mem, offset)) in memory_index.iter().zip(offsets.iter()).enumerate() {
6008+
reverse_index[*mem as usize] = Some((src, offset.bytes()));
6009+
}
6010+
if reverse_index.iter().any(|it| it.is_none()) {
6011+
stdx::never!();
6012+
return None;
6013+
}
6014+
reverse_index
6015+
.into_iter()
6016+
.flatten()
6017+
.chain(std::iter::once((0, self.0.size.bytes())))
6018+
.tuple_windows()
6019+
.filter_map(|((i, start), (_, end))| {
6020+
let size = field_size(i)?;
6021+
end.checked_sub(start)?.checked_sub(size)
6022+
})
6023+
.max()
6024+
}
6025+
}
6026+
}
6027+
59756028
pub fn enum_tag_size(&self) -> Option<usize> {
59766029
let tag_size =
59776030
if let layout::Variants::Multiple { tag, tag_encoding, .. } = &self.0.variants {

crates/ide/src/hover.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ pub struct MemoryLayoutHoverConfig {
5858
pub size: Option<MemoryLayoutHoverRenderKind>,
5959
pub offset: Option<MemoryLayoutHoverRenderKind>,
6060
pub alignment: Option<MemoryLayoutHoverRenderKind>,
61+
pub padding: Option<MemoryLayoutHoverRenderKind>,
6162
pub niches: bool,
6263
}
6364

crates/ide/src/hover/render.rs

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -630,27 +630,57 @@ pub(super) fn definition(
630630
}
631631
},
632632
|_| None,
633+
|_| None,
634+
),
635+
Definition::Adt(it @ Adt::Struct(strukt)) => render_memory_layout(
636+
config.memory_layout,
637+
|| it.layout(db),
638+
|_| None,
639+
|layout| {
640+
let mut field_size =
641+
|i: usize| Some(strukt.fields(db).get(i)?.layout(db).ok()?.size());
642+
if strukt.repr(db).is_some_and(|it| it.inhibit_struct_field_reordering()) {
643+
Some(("tail padding", layout.tail_padding(&mut field_size)?))
644+
} else {
645+
Some(("largest padding", layout.largest_padding(&mut field_size)?))
646+
}
647+
},
648+
|_| None,
649+
),
650+
Definition::Adt(it) => render_memory_layout(
651+
config.memory_layout,
652+
|| it.layout(db),
653+
|_| None,
654+
|_| None,
655+
|_| None,
633656
),
634-
Definition::Adt(it) => {
635-
render_memory_layout(config.memory_layout, || it.layout(db), |_| None, |_| None)
636-
}
637657
Definition::Variant(it) => render_memory_layout(
638658
config.memory_layout,
639659
|| it.layout(db),
640660
|_| None,
661+
|_| None,
641662
|layout| layout.enum_tag_size(),
642663
),
643-
Definition::TypeAlias(it) => {
644-
render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None)
645-
}
646-
Definition::Local(it) => {
647-
render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None)
648-
}
664+
Definition::TypeAlias(it) => render_memory_layout(
665+
config.memory_layout,
666+
|| it.ty(db).layout(db),
667+
|_| None,
668+
|_| None,
669+
|_| None,
670+
),
671+
Definition::Local(it) => render_memory_layout(
672+
config.memory_layout,
673+
|| it.ty(db).layout(db),
674+
|_| None,
675+
|_| None,
676+
|_| None,
677+
),
649678
Definition::SelfType(it) => render_memory_layout(
650679
config.memory_layout,
651680
|| it.self_ty(db).layout(db),
652681
|_| None,
653682
|_| None,
683+
|_| None,
654684
),
655685
_ => None,
656686
};
@@ -1055,9 +1085,13 @@ fn closure_ty(
10551085
if let Some(trait_) = c.fn_trait(sema.db).get_id(sema.db, original.krate(sema.db).into()) {
10561086
push_new_def(hir::Trait::from(trait_).into())
10571087
}
1058-
if let Some(layout) =
1059-
render_memory_layout(config.memory_layout, || original.layout(sema.db), |_| None, |_| None)
1060-
{
1088+
if let Some(layout) = render_memory_layout(
1089+
config.memory_layout,
1090+
|| original.layout(sema.db),
1091+
|_| None,
1092+
|_| None,
1093+
|_| None,
1094+
) {
10611095
format_to!(markup, "\n___\n{layout}");
10621096
}
10631097
format_to!(markup, "{adjusted}\n\n## Captures\n{}", captures_rendered,);
@@ -1142,6 +1176,7 @@ fn render_memory_layout(
11421176
config: Option<MemoryLayoutHoverConfig>,
11431177
layout: impl FnOnce() -> Result<Layout, LayoutError>,
11441178
offset: impl FnOnce(&Layout) -> Option<u64>,
1179+
padding: impl FnOnce(&Layout) -> Option<(&str, u64)>,
11451180
tag: impl FnOnce(&Layout) -> Option<usize>,
11461181
) -> Option<String> {
11471182
let config = config?;
@@ -1199,6 +1234,23 @@ fn render_memory_layout(
11991234
}
12001235
}
12011236

1237+
if let Some(render) = config.padding {
1238+
if let Some((padding_name, padding)) = padding(&layout) {
1239+
format_to!(label, "{padding_name} = ");
1240+
match render {
1241+
MemoryLayoutHoverRenderKind::Decimal => format_to!(label, "{padding}"),
1242+
MemoryLayoutHoverRenderKind::Hexadecimal => format_to!(label, "{padding:#X}"),
1243+
MemoryLayoutHoverRenderKind::Both if padding >= 10 => {
1244+
format_to!(label, "{padding} ({padding:#X})")
1245+
}
1246+
MemoryLayoutHoverRenderKind::Both => {
1247+
format_to!(label, "{padding}")
1248+
}
1249+
}
1250+
format_to!(label, ", ");
1251+
}
1252+
}
1253+
12021254
if config.niches {
12031255
if let Some(niches) = layout.niches() {
12041256
if niches > 1024 {

0 commit comments

Comments
 (0)