Compute data layout of types

This commit is contained in:
hkalbasi 2022-10-23 11:42:05 +03:30
parent 957b4bb216
commit 86b5b609f1
16 changed files with 2822 additions and 157 deletions

View file

@ -2,7 +2,10 @@
use std::fmt::Display;
use either::Either;
use hir::{AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay, Semantics, TypeInfo};
use hir::{
db::HirDatabase, Adt, AsAssocItem, AttributeTemplate, HasAttrs, HasSource, HirDisplay,
Semantics, TypeInfo,
};
use ide_db::{
base_db::SourceDatabase,
defs::Definition,
@ -388,10 +391,30 @@ pub(super) fn definition(
let mod_path = definition_mod_path(db, &def);
let (label, docs) = match def {
Definition::Macro(it) => label_and_docs(db, it),
Definition::Field(it) => label_and_docs(db, it),
Definition::Field(it) => label_and_layout_info_and_docs(db, it, |&it| {
let var_def = it.parent_def(db);
let id = it.index();
let layout = it.layout(db).ok()?;
let offset = match var_def {
hir::VariantDef::Struct(s) => {
let layout = Adt::from(s).layout(db).ok()?;
layout.fields.offset(id, &db.current_target_data_layout())
}
_ => return None,
};
Some(format!(
"size = {}, align = {}, offset = {}",
layout.size.bytes(),
layout.align.abi.bytes(),
offset.bytes()
))
}),
Definition::Module(it) => label_and_docs(db, it),
Definition::Function(it) => label_and_docs(db, it),
Definition::Adt(it) => label_and_docs(db, it),
Definition::Adt(it) => label_and_layout_info_and_docs(db, it, |&it| {
let layout = it.layout(db).ok()?;
Some(format!("size = {}, align = {}", layout.size.bytes(), layout.align.abi.bytes()))
}),
Definition::Variant(it) => label_value_and_docs(db, it, |&it| {
if !it.parent_enum(db).is_data_carrying(db) {
match it.eval(db) {
@ -489,6 +512,25 @@ where
(label, docs)
}
fn label_and_layout_info_and_docs<D, E, V>(
db: &RootDatabase,
def: D,
value_extractor: E,
) -> (String, Option<hir::Documentation>)
where
D: HasAttrs + HirDisplay,
E: Fn(&D) -> Option<V>,
V: Display,
{
let label = if let Some(value) = value_extractor(&def) {
format!("{} // {}", def.display(db), value)
} else {
def.display(db).to_string()
};
let docs = def.attrs(db).docs();
(label, docs)
}
fn label_value_and_docs<D, E, V>(
db: &RootDatabase,
def: D,

View file

@ -522,6 +522,27 @@ fn main() { }
);
}
#[test]
fn hover_field_offset() {
// Hovering over the field when instantiating
check(
r#"
struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 }
"#,
expect![[r#"
*field_a*
```rust
test::Foo
```
```rust
field_a: u8 // size = 1, align = 1, offset = 6
```
"#]],
);
}
#[test]
fn hover_shows_struct_field_info() {
// Hovering over the field when instantiating
@ -534,16 +555,16 @@ fn main() {
}
"#,
expect![[r#"
*field_a*
*field_a*
```rust
test::Foo
```
```rust
test::Foo
```
```rust
field_a: u32
```
"#]],
```rust
field_a: u32 // size = 4, align = 4, offset = 0
```
"#]],
);
// Hovering over the field in the definition
@ -556,16 +577,16 @@ fn main() {
}
"#,
expect![[r#"
*field_a*
*field_a*
```rust
test::Foo
```
```rust
test::Foo
```
```rust
field_a: u32
```
"#]],
```rust
field_a: u32 // size = 4, align = 4, offset = 0
```
"#]],
);
}
@ -1508,30 +1529,30 @@ struct Bar;
fn foo() { let bar = Ba$0r; }
"#,
expect![[r##"
*Bar*
expect![[r#"
*Bar*
```rust
test
```
```rust
test
```
```rust
struct Bar
```
```rust
struct Bar // size = 0, align = 1
```
---
---
This is an example
multiline doc
This is an example
multiline doc
# Example
# Example
```
let five = 5;
```
let five = 5;
assert_eq!(6, my_crate::add_one(5));
```
"##]],
assert_eq!(6, my_crate::add_one(5));
```
"#]],
);
}
@ -1545,20 +1566,20 @@ struct Bar;
fn foo() { let bar = Ba$0r; }
"#,
expect![[r#"
*Bar*
*Bar*
```rust
test
```
```rust
test
```
```rust
struct Bar
```
```rust
struct Bar // size = 0, align = 1
```
---
---
bar docs
"#]],
bar docs
"#]],
);
}
@ -1574,22 +1595,22 @@ struct Bar;
fn foo() { let bar = Ba$0r; }
"#,
expect![[r#"
*Bar*
*Bar*
```rust
test
```
```rust
test
```
```rust
struct Bar
```
```rust
struct Bar // size = 0, align = 1
```
---
---
bar docs 0
bar docs 1
bar docs 2
"#]],
bar docs 0
bar docs 1
bar docs 2
"#]],
);
}
@ -1602,20 +1623,20 @@ pub struct Foo;
pub struct B$0ar
"#,
expect![[r#"
*Bar*
*Bar*
```rust
test
```
```rust
test
```
```rust
pub struct Bar
```
```rust
pub struct Bar // size = 0, align = 1
```
---
---
[external](https://www.google.com)
"#]],
[external](https://www.google.com)
"#]],
);
}
@ -1629,20 +1650,20 @@ pub struct Foo;
pub struct B$0ar
"#,
expect![[r#"
*Bar*
*Bar*
```rust
test
```
```rust
test
```
```rust
pub struct Bar
```
```rust
pub struct Bar // size = 0, align = 1
```
---
---
[baz](Baz)
"#]],
[baz](Baz)
"#]],
);
}
@ -2960,7 +2981,7 @@ fn main() {
```
```rust
f: i32
f: i32 // size = 4, align = 4, offset = 0
```
"#]],
);
@ -4203,20 +4224,20 @@ pub fn gimme() -> theitem::TheItem {
}
"#,
expect![[r#"
*[`TheItem`]*
*[`TheItem`]*
```rust
test::theitem
```
```rust
test::theitem
```
```rust
pub struct TheItem
```
```rust
pub struct TheItem // size = 0, align = 1
```
---
---
This is the item. Cool!
"#]],
This is the item. Cool!
"#]],
);
}
@ -4351,20 +4372,20 @@ mod string {
}
"#,
expect![[r#"
*String*
*String*
```rust
main
```
```rust
main
```
```rust
struct String
```
```rust
struct String // size = 0, align = 1
```
---
---
Custom `String` type.
"#]],
Custom `String` type.
"#]],
)
}
@ -5025,7 +5046,7 @@ foo_macro!(
```
```rust
pub struct Foo
pub struct Foo // size = 0, align = 1
```
---
@ -5040,7 +5061,7 @@ fn hover_intra_in_attr() {
check(
r#"
#[doc = "Doc comment for [`Foo$0`]"]
pub struct Foo;
pub struct Foo(i32);
"#,
expect![[r#"
*[`Foo`]*
@ -5050,7 +5071,7 @@ pub struct Foo;
```
```rust
pub struct Foo
pub struct Foo // size = 4, align = 4
```
---