Skip to content

fix: Render size, align and offset hover values in hex #14904

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 26, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions crates/hir-ty/src/layout.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Compute the binary representation of a type
use base_db::CrateId;
use chalk_ir::{AdtId, TyKind};
use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
use hir_def::{
layout::{
Abi, FieldsShape, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, Scalar, Size,
@@ -83,7 +83,7 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
let dl = &*cx.current_data_layout();
let trait_env = Arc::new(TraitEnvironment::empty(krate));
let ty = normalize(db, trait_env, ty.clone());
Ok(match ty.kind(Interner) {
let layout = match ty.kind(Interner) {
TyKind::Adt(AdtId(def), subst) => db.layout_of_adt(*def, subst.clone(), krate)?,
TyKind::Scalar(s) => match s {
chalk_ir::Scalar::Bool => Layout::scalar(
@@ -104,12 +104,12 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
dl,
Primitive::Int(
match i {
chalk_ir::IntTy::Isize => dl.ptr_sized_integer(),
chalk_ir::IntTy::I8 => Integer::I8,
chalk_ir::IntTy::I16 => Integer::I16,
chalk_ir::IntTy::I32 => Integer::I32,
chalk_ir::IntTy::I64 => Integer::I64,
chalk_ir::IntTy::I128 => Integer::I128,
IntTy::Isize => dl.ptr_sized_integer(),
IntTy::I8 => Integer::I8,
IntTy::I16 => Integer::I16,
IntTy::I32 => Integer::I32,
IntTy::I64 => Integer::I64,
IntTy::I128 => Integer::I128,
},
true,
),
@@ -118,21 +118,21 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
dl,
Primitive::Int(
match i {
chalk_ir::UintTy::Usize => dl.ptr_sized_integer(),
chalk_ir::UintTy::U8 => Integer::I8,
chalk_ir::UintTy::U16 => Integer::I16,
chalk_ir::UintTy::U32 => Integer::I32,
chalk_ir::UintTy::U64 => Integer::I64,
chalk_ir::UintTy::U128 => Integer::I128,
UintTy::Usize => dl.ptr_sized_integer(),
UintTy::U8 => Integer::I8,
UintTy::U16 => Integer::I16,
UintTy::U32 => Integer::I32,
UintTy::U64 => Integer::I64,
UintTy::U128 => Integer::I128,
},
false,
),
),
chalk_ir::Scalar::Float(f) => scalar(
dl,
match f {
chalk_ir::FloatTy::F32 => Primitive::F32,
chalk_ir::FloatTy::F64 => Primitive::F64,
FloatTy::F32 => Primitive::F32,
FloatTy::F64 => Primitive::F64,
},
),
},
@@ -283,7 +283,8 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
| TyKind::Placeholder(_)
| TyKind::BoundVar(_)
| TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder),
})
};
Ok(layout)
}

fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result<Layout, LayoutError> {
44 changes: 28 additions & 16 deletions crates/hir/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1125,6 +1125,25 @@ impl Enum {
pub fn is_data_carrying(self, db: &dyn HirDatabase) -> bool {
self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit))
}

pub fn layout(self, db: &dyn HirDatabase) -> Result<(Layout, usize), LayoutError> {
let layout = Adt::from(self).layout(db)?;
let tag_size =
if let layout::Variants::Multiple { tag, tag_encoding, .. } = &layout.variants {
match tag_encoding {
TagEncoding::Direct => {
let target_data_layout = db
.target_data_layout(self.module(db).krate().id)
.ok_or(LayoutError::TargetLayoutNotAvailable)?;
tag.size(&*target_data_layout).bytes_usize()
}
TagEncoding::Niche { .. } => 0,
}
} else {
0
};
Ok((layout, tag_size))
}
}

impl HasVisibility for Enum {
@@ -1185,23 +1204,16 @@ impl Variant {
/// Return layout of the variant and tag size of the parent enum.
pub fn layout(&self, db: &dyn HirDatabase) -> Result<(Layout, usize), LayoutError> {
let parent_enum = self.parent_enum(db);
let parent_layout = Adt::from(parent_enum).layout(db)?;
if let layout::Variants::Multiple { variants, tag, tag_encoding, tag_field: _ } =
parent_layout.variants
{
let tag_size = match tag_encoding {
TagEncoding::Direct => {
let target_data_layout = db
.target_data_layout(parent_enum.module(db).krate().id)
.ok_or(LayoutError::TargetLayoutNotAvailable)?;
tag.size(&*target_data_layout).bytes_usize()
let (parent_layout, tag_size) = parent_enum.layout(db)?;
Ok((
match parent_layout.variants {
layout::Variants::Multiple { variants, .. } => {
variants[RustcEnumVariantIdx(self.id)].clone()
}
TagEncoding::Niche { .. } => 0,
};
Ok((variants[RustcEnumVariantIdx(self.id)].clone(), tag_size))
} else {
Ok((parent_layout, 0))
}
_ => parent_layout,
},
tag_size,
))
}
}

75 changes: 45 additions & 30 deletions crates/ide/src/hover/render.rs
Original file line number Diff line number Diff line change
@@ -401,11 +401,11 @@ pub(super) fn definition(
hir::VariantDef::Struct(s) => Adt::from(s)
.layout(db)
.ok()
.map(|layout| format!(", offset = {}", layout.fields.offset(id).bytes())),
.map(|layout| format!(", offset = {:#X}", layout.fields.offset(id).bytes())),
_ => None,
};
Some(format!(
"size = {}, align = {}{}",
"size = {:#X}, align = {:#X}{}",
layout.size.bytes(),
layout.align.abi.bytes(),
offset.as_deref().unwrap_or_default()
@@ -415,28 +415,38 @@ pub(super) fn definition(
Definition::Function(it) => label_and_docs(db, it),
Definition::Adt(it) => label_and_layout_info_and_docs(db, it, config, |&it| {
let layout = it.layout(db).ok()?;
Some(format!("size = {}, align = {}", layout.size.bytes(), layout.align.abi.bytes()))
Some(format!(
"size = {:#X}, align = {:#X}",
layout.size.bytes(),
layout.align.abi.bytes()
))
}),
Definition::Variant(it) => label_value_and_layout_info_and_docs(db, it, config, |&it| {
let layout = (|| {
Definition::Variant(it) => label_value_and_layout_info_and_docs(
db,
it,
config,
|&it| {
if !it.parent_enum(db).is_data_carrying(db) {
match it.eval(db) {
Ok(x) => {
Some(if x >= 10 { format!("{x} ({x:#X})") } else { format!("{x}") })
}
Err(_) => it.value(db).map(|x| format!("{x:?}")),
}
} else {
None
}
},
|it| {
let (layout, tag_size) = it.layout(db).ok()?;
let size = layout.size.bytes_usize() - tag_size;
if size == 0 {
// There is no value in showing layout info for fieldless variants
return None;
}
Some(format!("size = {}", layout.size.bytes()))
})();
let value = if !it.parent_enum(db).is_data_carrying(db) {
match it.eval(db) {
Ok(x) => Some(if x >= 10 { format!("{x} ({x:#X})") } else { format!("{x}") }),
Err(_) => it.value(db).map(|x| format!("{x:?}")),
}
} else {
None
};
(value, layout)
}),
Some(format!("size = {:#X}", layout.size.bytes()))
},
),
Definition::Const(it) => label_value_and_docs(db, it, |it| {
let body = it.render_eval(db);
match body {
@@ -463,7 +473,11 @@ pub(super) fn definition(
Definition::TraitAlias(it) => label_and_docs(db, it),
Definition::TypeAlias(it) => label_and_layout_info_and_docs(db, it, config, |&it| {
let layout = it.ty(db).layout(db).ok()?;
Some(format!("size = {}, align = {}", layout.size.bytes(), layout.align.abi.bytes()))
Some(format!(
"size = {:#X}, align = {:#X}",
layout.size.bytes(),
layout.align.abi.bytes()
))
}),
Definition::BuiltinType(it) => {
return famous_defs
@@ -634,41 +648,42 @@ fn label_and_layout_info_and_docs<D, E, V>(
db: &RootDatabase,
def: D,
config: &HoverConfig,
value_extractor: E,
layout_extractor: E,
) -> (String, Option<hir::Documentation>)
where
D: HasAttrs + HirDisplay,
E: Fn(&D) -> Option<V>,
V: Display,
{
let label = match value_extractor(&def) {
Some(value) if config.memory_layout => format!("{} // {value}", def.display(db)),
let label = match config.memory_layout.then(|| layout_extractor(&def)).flatten() {
Some(layout) => format!("{} // {layout}", def.display(db)),
_ => def.display(db).to_string(),
};
let docs = def.attrs(db).docs();
(label, docs)
}

fn label_value_and_layout_info_and_docs<D, E, V, L>(
fn label_value_and_layout_info_and_docs<D, E, E2, V, L>(
db: &RootDatabase,
def: D,
config: &HoverConfig,
value_extractor: E,
layout_extractor: E2,
) -> (String, Option<hir::Documentation>)
where
D: HasAttrs + HirDisplay,
E: Fn(&D) -> (Option<V>, Option<L>),
E: Fn(&D) -> Option<V>,
E2: Fn(&D) -> Option<L>,
V: Display,
L: Display,
{
let (value, layout) = value_extractor(&def);
let label = if let Some(value) = value {
format!("{} = {value}", def.display(db))
} else {
def.display(db).to_string()
let value = value_extractor(&def);
let label = match value {
Some(value) => format!("{} = {value}", def.display(db)),
None => def.display(db).to_string(),
};
let label = match layout {
Some(layout) if config.memory_layout => format!("{} // {layout}", label),
let label = match config.memory_layout.then(|| layout_extractor(&def)).flatten() {
Some(layout) => format!("{} // {layout}", label),
_ => label,
};
let docs = def.attrs(db).docs();
103 changes: 62 additions & 41 deletions crates/ide/src/hover/tests.rs
Original file line number Diff line number Diff line change
@@ -667,7 +667,7 @@ struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 }
```
```rust
field_a: u8 // size = 1, align = 1, offset = 4
field_a: u8 // size = 0x1, align = 0x1, offset = 0x4
```
"#]],
);
@@ -692,7 +692,7 @@ fn main() {
```
```rust
field_a: u32 // size = 4, align = 4, offset = 0
field_a: u32 // size = 0x4, align = 0x4, offset = 0x0
```
"#]],
);
@@ -714,7 +714,7 @@ fn main() {
```
```rust
field_a: u32 // size = 4, align = 4, offset = 0
field_a: u32 // size = 0x4, align = 0x4, offset = 0x0
```
"#]],
);
@@ -1521,16 +1521,16 @@ fn test_hover_function_pointer_show_identifiers() {
check(
r#"type foo$0 = fn(a: i32, b: i32) -> i32;"#,
expect![[r#"
*foo*
*foo*
```rust
test
```
```rust
test
```
```rust
type foo = fn(a: i32, b: i32) -> i32 // size = 8, align = 8
```
"#]],
```rust
type foo = fn(a: i32, b: i32) -> i32 // size = 0x8, align = 0x8
```
"#]],
);
}

@@ -1539,16 +1539,16 @@ fn test_hover_function_pointer_no_identifier() {
check(
r#"type foo$0 = fn(i32, _: i32) -> i32;"#,
expect![[r#"
*foo*
*foo*
```rust
test
```
```rust
test
```
```rust
type foo = fn(i32, i32) -> i32 // size = 8, align = 8
```
"#]],
```rust
type foo = fn(i32, i32) -> i32 // size = 0x8, align = 0x8
```
"#]],
);
}

@@ -1674,7 +1674,7 @@ fn foo() { let bar = Ba$0r; }
```
```rust
struct Bar // size = 0, align = 1
struct Bar // size = 0x0, align = 0x1
```
---
@@ -1710,7 +1710,7 @@ fn foo() { let bar = Ba$0r; }
```
```rust
struct Bar // size = 0, align = 1
struct Bar // size = 0x0, align = 0x1
```
---
@@ -1739,7 +1739,7 @@ fn foo() { let bar = Ba$0r; }
```
```rust
struct Bar // size = 0, align = 1
struct Bar // size = 0x0, align = 0x1
```
---
@@ -1767,7 +1767,7 @@ pub struct B$0ar
```
```rust
pub struct Bar // size = 0, align = 1
pub struct Bar // size = 0x0, align = 0x1
```
---
@@ -1794,7 +1794,7 @@ pub struct B$0ar
```
```rust
pub struct Bar // size = 0, align = 1
pub struct Bar // size = 0x0, align = 0x1
```
---
@@ -1883,7 +1883,28 @@ fn test_hover_layout_of_variant() {
```
```rust
Variant1(u8, u16) // size = 4
Variant1(u8, u16) // size = 0x4
```
"#]],
);
}

#[test]
fn test_hover_layout_of_enum() {
check(
r#"enum $0Foo {
Variant1(u8, u16),
Variant2(i32, u8, i64),
}"#,
expect![[r#"
*Foo*
```rust
test
```
```rust
enum Foo // size = 0x10, align = 0x8
```
"#]],
);
@@ -3192,7 +3213,7 @@ fn main() {
```
```rust
f: i32 // size = 4, align = 4, offset = 0
f: i32 // size = 0x4, align = 0x4, offset = 0x0
```
"#]],
);
@@ -3730,16 +3751,16 @@ struct Foo<const LEN: usize>;
type Fo$0o2 = Foo<2>;
"#,
expect![[r#"
*Foo2*
*Foo2*
```rust
test
```
```rust
test
```
```rust
type Foo2 = Foo<2> // size = 0, align = 1
```
"#]],
```rust
type Foo2 = Foo<2> // size = 0x0, align = 0x1
```
"#]],
);
}

@@ -4648,7 +4669,7 @@ pub fn gimme() -> theitem::TheItem {
```
```rust
pub struct TheItem // size = 0, align = 1
pub struct TheItem // size = 0x0, align = 0x1
```
---
@@ -4796,7 +4817,7 @@ mod string {
```
```rust
struct String // size = 0, align = 1
struct String // size = 0x0, align = 0x1
```
---
@@ -5465,7 +5486,7 @@ foo_macro!(
```
```rust
pub struct Foo // size = 0, align = 1
pub struct Foo // size = 0x0, align = 0x1
```
---
@@ -5490,7 +5511,7 @@ pub struct Foo(i32);
```
```rust
pub struct Foo // size = 4, align = 4
pub struct Foo // size = 0x4, align = 0x4
```
---
@@ -5589,7 +5610,7 @@ enum Enum {
```
```rust
RecordV { field: u32 } // size = 4
RecordV { field: u32 } // size = 0x4
```
"#]],
);
@@ -5611,7 +5632,7 @@ enum Enum {
```
```rust
field: u32 // size = 4, align = 4
field: u32 // size = 0x4, align = 0x4
```
"#]],
);
@@ -6113,7 +6134,7 @@ fn test() {
```
```rust
f: u32 // size = 4, align = 4, offset = 0
f: u32 // size = 0x4, align = 0x4, offset = 0x0
```
"#]],
);
12 changes: 6 additions & 6 deletions crates/ide/src/inlay_hints/chaining.rs
Original file line number Diff line number Diff line change
@@ -474,7 +474,7 @@ fn main() {
file_id: FileId(
1,
),
range: 9164..9172,
range: 9165..9173,
},
),
tooltip: "",
@@ -487,7 +487,7 @@ fn main() {
file_id: FileId(
1,
),
range: 9196..9200,
range: 9197..9201,
},
),
tooltip: "",
@@ -511,7 +511,7 @@ fn main() {
file_id: FileId(
1,
),
range: 9164..9172,
range: 9165..9173,
},
),
tooltip: "",
@@ -524,7 +524,7 @@ fn main() {
file_id: FileId(
1,
),
range: 9196..9200,
range: 9197..9201,
},
),
tooltip: "",
@@ -548,7 +548,7 @@ fn main() {
file_id: FileId(
1,
),
range: 9164..9172,
range: 9165..9173,
},
),
tooltip: "",
@@ -561,7 +561,7 @@ fn main() {
file_id: FileId(
1,
),
range: 9196..9200,
range: 9197..9201,
},
),
tooltip: "",
6 changes: 6 additions & 0 deletions crates/test-utils/src/minicore.rs
Original file line number Diff line number Diff line change
@@ -38,6 +38,7 @@
//! option: panic
//! ord: eq, option
//! panic: fmt
//! phantom_data:
//! pin:
//! range:
//! result:
@@ -119,6 +120,11 @@ pub mod marker {
#[lang = "tuple_trait"]
pub trait Tuple {}
// endregion:fn

// region:phantom_data
#[lang = "phantom_data"]
pub struct PhantomData<T: ?Sized>;
// endregion:phantom_data
}

// region:default