Render size, align and offset hover values in hex

This commit is contained in:
Lukas Wirth 2023-05-26 16:41:45 +02:00
parent eee6872647
commit be9cc0baae
6 changed files with 165 additions and 110 deletions

View File

@ -1,7 +1,7 @@
//! Compute the binary representation of a type //! Compute the binary representation of a type
use base_db::CrateId; use base_db::CrateId;
use chalk_ir::{AdtId, TyKind}; use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
use hir_def::{ use hir_def::{
layout::{ layout::{
Abi, FieldsShape, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, Scalar, Size, 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 dl = &*cx.current_data_layout();
let trait_env = Arc::new(TraitEnvironment::empty(krate)); let trait_env = Arc::new(TraitEnvironment::empty(krate));
let ty = normalize(db, trait_env, ty.clone()); 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::Adt(AdtId(def), subst) => db.layout_of_adt(*def, subst.clone(), krate)?,
TyKind::Scalar(s) => match s { TyKind::Scalar(s) => match s {
chalk_ir::Scalar::Bool => Layout::scalar( 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, dl,
Primitive::Int( Primitive::Int(
match i { match i {
chalk_ir::IntTy::Isize => dl.ptr_sized_integer(), IntTy::Isize => dl.ptr_sized_integer(),
chalk_ir::IntTy::I8 => Integer::I8, IntTy::I8 => Integer::I8,
chalk_ir::IntTy::I16 => Integer::I16, IntTy::I16 => Integer::I16,
chalk_ir::IntTy::I32 => Integer::I32, IntTy::I32 => Integer::I32,
chalk_ir::IntTy::I64 => Integer::I64, IntTy::I64 => Integer::I64,
chalk_ir::IntTy::I128 => Integer::I128, IntTy::I128 => Integer::I128,
}, },
true, true,
), ),
@ -118,12 +118,12 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
dl, dl,
Primitive::Int( Primitive::Int(
match i { match i {
chalk_ir::UintTy::Usize => dl.ptr_sized_integer(), UintTy::Usize => dl.ptr_sized_integer(),
chalk_ir::UintTy::U8 => Integer::I8, UintTy::U8 => Integer::I8,
chalk_ir::UintTy::U16 => Integer::I16, UintTy::U16 => Integer::I16,
chalk_ir::UintTy::U32 => Integer::I32, UintTy::U32 => Integer::I32,
chalk_ir::UintTy::U64 => Integer::I64, UintTy::U64 => Integer::I64,
chalk_ir::UintTy::U128 => Integer::I128, UintTy::U128 => Integer::I128,
}, },
false, false,
), ),
@ -131,8 +131,8 @@ pub fn layout_of_ty(db: &dyn HirDatabase, ty: &Ty, krate: CrateId) -> Result<Lay
chalk_ir::Scalar::Float(f) => scalar( chalk_ir::Scalar::Float(f) => scalar(
dl, dl,
match f { match f {
chalk_ir::FloatTy::F32 => Primitive::F32, FloatTy::F32 => Primitive::F32,
chalk_ir::FloatTy::F64 => Primitive::F64, 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::Placeholder(_)
| TyKind::BoundVar(_) | TyKind::BoundVar(_)
| TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder), | TyKind::InferenceVar(_, _) => return Err(LayoutError::HasPlaceholder),
}) };
Ok(layout)
} }
fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result<Layout, LayoutError> { fn layout_of_unit(cx: &LayoutCx<'_>, dl: &TargetDataLayout) -> Result<Layout, LayoutError> {

View File

@ -1125,6 +1125,25 @@ impl Enum {
pub fn is_data_carrying(self, db: &dyn HirDatabase) -> bool { pub fn is_data_carrying(self, db: &dyn HirDatabase) -> bool {
self.variants(db).iter().any(|v| !matches!(v.kind(db), StructKind::Unit)) 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 { impl HasVisibility for Enum {
@ -1185,23 +1204,16 @@ impl Variant {
/// Return layout of the variant and tag size of the parent enum. /// Return layout of the variant and tag size of the parent enum.
pub fn layout(&self, db: &dyn HirDatabase) -> Result<(Layout, usize), LayoutError> { pub fn layout(&self, db: &dyn HirDatabase) -> Result<(Layout, usize), LayoutError> {
let parent_enum = self.parent_enum(db); let parent_enum = self.parent_enum(db);
let parent_layout = Adt::from(parent_enum).layout(db)?; let (parent_layout, tag_size) = parent_enum.layout(db)?;
if let layout::Variants::Multiple { variants, tag, tag_encoding, tag_field: _ } = Ok((
parent_layout.variants match parent_layout.variants {
{ layout::Variants::Multiple { variants, .. } => {
let tag_size = match tag_encoding { variants[RustcEnumVariantIdx(self.id)].clone()
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()
} }
TagEncoding::Niche { .. } => 0, _ => parent_layout,
}; },
Ok((variants[RustcEnumVariantIdx(self.id)].clone(), tag_size)) tag_size,
} else { ))
Ok((parent_layout, 0))
}
} }
} }

View File

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

View File

@ -667,7 +667,7 @@ struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 }
``` ```
```rust ```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 ```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 ```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( check(
r#"type foo$0 = fn(a: i32, b: i32) -> i32;"#, r#"type foo$0 = fn(a: i32, b: i32) -> i32;"#,
expect![[r#" expect![[r#"
*foo* *foo*
```rust ```rust
test test
``` ```
```rust ```rust
type foo = fn(a: i32, b: i32) -> i32 // size = 8, align = 8 type foo = fn(a: i32, b: i32) -> i32 // size = 0x8, align = 0x8
``` ```
"#]], "#]],
); );
} }
@ -1539,16 +1539,16 @@ fn test_hover_function_pointer_no_identifier() {
check( check(
r#"type foo$0 = fn(i32, _: i32) -> i32;"#, r#"type foo$0 = fn(i32, _: i32) -> i32;"#,
expect![[r#" expect![[r#"
*foo* *foo*
```rust ```rust
test test
``` ```
```rust ```rust
type foo = fn(i32, i32) -> i32 // size = 8, align = 8 type foo = fn(i32, i32) -> i32 // size = 0x8, align = 0x8
``` ```
"#]], "#]],
); );
} }
@ -1674,7 +1674,7 @@ fn foo() { let bar = Ba$0r; }
``` ```
```rust ```rust
struct Bar // size = 0, align = 1 struct Bar // size = 0x0, align = 0x1
``` ```
--- ---
@ -1710,7 +1710,7 @@ fn foo() { let bar = Ba$0r; }
``` ```
```rust ```rust
struct Bar // size = 0, align = 1 struct Bar // size = 0x0, align = 0x1
``` ```
--- ---
@ -1739,7 +1739,7 @@ fn foo() { let bar = Ba$0r; }
``` ```
```rust ```rust
struct Bar // size = 0, align = 1 struct Bar // size = 0x0, align = 0x1
``` ```
--- ---
@ -1767,7 +1767,7 @@ pub struct B$0ar
``` ```
```rust ```rust
pub struct Bar // size = 0, align = 1 pub struct Bar // size = 0x0, align = 0x1
``` ```
--- ---
@ -1794,7 +1794,7 @@ pub struct B$0ar
``` ```
```rust ```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 ```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 ```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>; type Fo$0o2 = Foo<2>;
"#, "#,
expect![[r#" expect![[r#"
*Foo2* *Foo2*
```rust ```rust
test test
``` ```
```rust ```rust
type Foo2 = Foo<2> // size = 0, align = 1 type Foo2 = Foo<2> // size = 0x0, align = 0x1
``` ```
"#]], "#]],
); );
} }
@ -4648,7 +4669,7 @@ pub fn gimme() -> theitem::TheItem {
``` ```
```rust ```rust
pub struct TheItem // size = 0, align = 1 pub struct TheItem // size = 0x0, align = 0x1
``` ```
--- ---
@ -4796,7 +4817,7 @@ mod string {
``` ```
```rust ```rust
struct String // size = 0, align = 1 struct String // size = 0x0, align = 0x1
``` ```
--- ---
@ -5465,7 +5486,7 @@ foo_macro!(
``` ```
```rust ```rust
pub struct Foo // size = 0, align = 1 pub struct Foo // size = 0x0, align = 0x1
``` ```
--- ---
@ -5490,7 +5511,7 @@ pub struct Foo(i32);
``` ```
```rust ```rust
pub struct Foo // size = 4, align = 4 pub struct Foo // size = 0x4, align = 0x4
``` ```
--- ---
@ -5589,7 +5610,7 @@ enum Enum {
``` ```
```rust ```rust
RecordV { field: u32 } // size = 4 RecordV { field: u32 } // size = 0x4
``` ```
"#]], "#]],
); );
@ -5611,7 +5632,7 @@ enum Enum {
``` ```
```rust ```rust
field: u32 // size = 4, align = 4 field: u32 // size = 0x4, align = 0x4
``` ```
"#]], "#]],
); );
@ -6113,7 +6134,7 @@ fn test() {
``` ```
```rust ```rust
f: u32 // size = 4, align = 4, offset = 0 f: u32 // size = 0x4, align = 0x4, offset = 0x0
``` ```
"#]], "#]],
); );

View File

@ -474,7 +474,7 @@ fn main() {
file_id: FileId( file_id: FileId(
1, 1,
), ),
range: 9164..9172, range: 9165..9173,
}, },
), ),
tooltip: "", tooltip: "",
@ -487,7 +487,7 @@ fn main() {
file_id: FileId( file_id: FileId(
1, 1,
), ),
range: 9196..9200, range: 9197..9201,
}, },
), ),
tooltip: "", tooltip: "",
@ -511,7 +511,7 @@ fn main() {
file_id: FileId( file_id: FileId(
1, 1,
), ),
range: 9164..9172, range: 9165..9173,
}, },
), ),
tooltip: "", tooltip: "",
@ -524,7 +524,7 @@ fn main() {
file_id: FileId( file_id: FileId(
1, 1,
), ),
range: 9196..9200, range: 9197..9201,
}, },
), ),
tooltip: "", tooltip: "",
@ -548,7 +548,7 @@ fn main() {
file_id: FileId( file_id: FileId(
1, 1,
), ),
range: 9164..9172, range: 9165..9173,
}, },
), ),
tooltip: "", tooltip: "",
@ -561,7 +561,7 @@ fn main() {
file_id: FileId( file_id: FileId(
1, 1,
), ),
range: 9196..9200, range: 9197..9201,
}, },
), ),
tooltip: "", tooltip: "",

View File

@ -38,6 +38,7 @@
//! option: panic //! option: panic
//! ord: eq, option //! ord: eq, option
//! panic: fmt //! panic: fmt
//! phantom_data:
//! pin: //! pin:
//! range: //! range:
//! result: //! result:
@ -119,6 +120,11 @@ pub mod marker {
#[lang = "tuple_trait"] #[lang = "tuple_trait"]
pub trait Tuple {} pub trait Tuple {}
// endregion:fn // endregion:fn
// region:phantom_data
#[lang = "phantom_data"]
pub struct PhantomData<T: ?Sized>;
// endregion:phantom_data
} }
// region:default // region:default