1+ use std:: fmt;
2+
13use hir:: { Field , HirDisplay , Layout , Semantics , Type } ;
24use ide_db:: {
35 defs:: Definition ,
@@ -23,6 +25,36 @@ pub struct RecursiveMemoryLayout {
2325 pub nodes : Vec < MemoryLayoutNode > ,
2426}
2527
28+ // NOTE: this is currently strictly for testing and so isn't super useful as a visualization tool, however it could be adapted to become one?
29+ impl fmt:: Display for RecursiveMemoryLayout {
30+ fn fmt ( & self , fmt : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
31+ fn process (
32+ fmt : & mut fmt:: Formatter < ' _ > ,
33+ nodes : & Vec < MemoryLayoutNode > ,
34+ idx : usize ,
35+ depth : usize ,
36+ ) -> fmt:: Result {
37+ let mut out = "\t " . repeat ( depth) ;
38+ let node = & nodes[ idx] ;
39+ out += & format ! (
40+ "{}: {} (size: {}, align: {}, field offset: {})\n " ,
41+ node. item_name, node. typename, node. size, node. alignment, node. offset
42+ ) ;
43+ write ! ( fmt, "{}" , out) ?;
44+ if node. children_start != -1 {
45+ for j in nodes[ idx] . children_start
46+ ..( nodes[ idx] . children_start + nodes[ idx] . children_len as i64 )
47+ {
48+ process ( fmt, nodes, j as usize , depth + 1 ) ?;
49+ }
50+ }
51+ Ok ( ( ) )
52+ }
53+
54+ process ( fmt, & self . nodes , 0 , 0 )
55+ }
56+ }
57+
2658enum FieldOrTupleIdx {
2759 Field ( Field ) ,
2860 TupleIdx ( usize ) ,
@@ -191,22 +223,14 @@ mod tests {
191223 use super :: * ;
192224
193225 use crate :: fixture;
226+ use expect_test:: expect;
194227
195228 fn make_memory_layout ( ra_fixture : & str ) -> Option < RecursiveMemoryLayout > {
196229 let ( analysis, position, _) = fixture:: annotations ( ra_fixture) ;
197230
198231 view_memory_layout ( & analysis. db , position)
199232 }
200233
201- fn check_item_info < T > ( node : & MemoryLayoutNode , item_name : & str , check_typename : bool ) {
202- assert_eq ! ( node. item_name, item_name) ;
203- assert_eq ! ( node. size, core:: mem:: size_of:: <T >( ) as u64 ) ;
204- assert_eq ! ( node. alignment, core:: mem:: align_of:: <T >( ) as u64 ) ;
205- if check_typename {
206- assert_eq ! ( node. typename, std:: any:: type_name:: <T >( ) ) ;
207- }
208- }
209-
210234 #[ test]
211235 fn view_memory_layout_none ( ) {
212236 assert ! ( make_memory_layout( r#"$0"# ) . is_none( ) ) ;
@@ -215,123 +239,143 @@ mod tests {
215239
216240 #[ test]
217241 fn view_memory_layout_primitive ( ) {
218- let ml = make_memory_layout (
219- r#"
242+ expect ! [ [ r#"
243+ foo: i32 (size: 4, align: 4, field offset: 0)
244+ "# ] ]
245+ . assert_eq (
246+ & make_memory_layout (
247+ r#"
220248fn main() {
221249 let foo$0 = 109; // default i32
222250}
223251"# ,
224- )
225- . unwrap ( ) ;
226-
227- assert_eq ! ( ml. nodes. len( ) , 1 ) ;
228- assert_eq ! ( ml. nodes[ 0 ] . parent_idx, -1 ) ;
229- assert_eq ! ( ml. nodes[ 0 ] . children_start, -1 ) ;
230- check_item_info :: < i32 > ( & ml. nodes [ 0 ] , "foo" , true ) ;
231- assert_eq ! ( ml. nodes[ 0 ] . offset, 0 ) ;
252+ )
253+ . unwrap ( )
254+ . to_string ( ) ,
255+ ) ;
232256 }
233257
234258 #[ test]
235259 fn view_memory_layout_constant ( ) {
236- let ml = make_memory_layout (
237- r#"
260+ expect ! [ [ r#"
261+ BLAH: bool (size: 1, align: 1, field offset: 0)
262+ "# ] ]
263+ . assert_eq (
264+ & make_memory_layout (
265+ r#"
238266const BLAH$0: bool = 0;
239267"# ,
240- )
241- . unwrap ( ) ;
242-
243- assert_eq ! ( ml. nodes. len( ) , 1 ) ;
244- assert_eq ! ( ml. nodes[ 0 ] . parent_idx, -1 ) ;
245- assert_eq ! ( ml. nodes[ 0 ] . children_start, -1 ) ;
246- check_item_info :: < bool > ( & ml. nodes [ 0 ] , "BLAH" , true ) ;
247- assert_eq ! ( ml. nodes[ 0 ] . offset, 0 ) ;
268+ )
269+ . unwrap ( )
270+ . to_string ( ) ,
271+ ) ;
248272 }
249273
250274 #[ test]
251275 fn view_memory_layout_static ( ) {
252- let ml = make_memory_layout (
253- r#"
276+ expect ! [ [ r#"
277+ BLAH: bool (size: 1, align: 1, field offset: 0)
278+ "# ] ]
279+ . assert_eq (
280+ & make_memory_layout (
281+ r#"
254282static BLAH$0: bool = 0;
255283"# ,
256- )
257- . unwrap ( ) ;
258-
259- assert_eq ! ( ml. nodes. len( ) , 1 ) ;
260- assert_eq ! ( ml. nodes[ 0 ] . parent_idx, -1 ) ;
261- assert_eq ! ( ml. nodes[ 0 ] . children_start, -1 ) ;
262- check_item_info :: < bool > ( & ml. nodes [ 0 ] , "BLAH" , true ) ;
263- assert_eq ! ( ml. nodes[ 0 ] . offset, 0 ) ;
284+ )
285+ . unwrap ( )
286+ . to_string ( ) ,
287+ ) ;
264288 }
265289
266290 #[ test]
267291 fn view_memory_layout_tuple ( ) {
268- let ml = make_memory_layout (
269- r#"
292+ expect ! [ [ r#"
293+ x: (f64, u8, i64) (size: 24, align: 8, field offset: 0)
294+ .0: f64 (size: 8, align: 8, field offset: 0)
295+ .1: u8 (size: 1, align: 1, field offset: 8)
296+ .2: i64 (size: 8, align: 8, field offset: 16)
297+ "# ] ]
298+ . assert_eq (
299+ & make_memory_layout (
300+ r#"
270301fn main() {
271302 let x$0 = (101.0, 111u8, 119i64);
272303}
273- "# ,
274- )
275- . unwrap ( ) ;
276-
277- assert_eq ! ( ml. nodes. len( ) , 4 ) ;
278- assert_eq ! ( ml. nodes[ 0 ] . children_start, 1 ) ;
279- assert_eq ! ( ml. nodes[ 0 ] . children_len, 3 ) ;
280- check_item_info :: < ( f64 , u8 , i64 ) > ( & ml. nodes [ 0 ] , "x" , true ) ;
304+ "# ,
305+ )
306+ . unwrap ( )
307+ . to_string ( ) ,
308+ ) ;
281309 }
282310
283311 #[ test]
284- fn view_memory_layout_struct ( ) {
285- let ml = make_memory_layout (
286- r#"
312+ fn view_memory_layout_c_struct ( ) {
313+ expect ! [ [ r#"
314+ [ROOT]: Blah (size: 16, align: 4, field offset: 0)
315+ a: u32 (size: 4, align: 4, field offset: 0)
316+ b: (i32, u8) (size: 8, align: 4, field offset: 4)
317+ .0: i32 (size: 4, align: 4, field offset: 0)
318+ .1: u8 (size: 1, align: 1, field offset: 4)
319+ c: i8 (size: 1, align: 1, field offset: 12)
320+ "# ] ]
321+ . assert_eq (
322+ & make_memory_layout (
323+ r#"
287324#[repr(C)]
288325struct Blah$0 {
289326 a: u32,
290327 b: (i32, u8),
291328 c: i8,
292329}
293330"# ,
294- )
295- . unwrap ( ) ;
296-
297- #[ repr( C ) ] // repr C makes this testable, rustc doesn't enforce a layout otherwise ;-;
298- struct Blah {
299- a : u32 ,
300- b : ( i32 , u8 ) ,
301- c : i8 ,
302- }
303-
304- assert_eq ! ( ml. nodes. len( ) , 6 ) ;
305- check_item_info :: < Blah > ( & ml. nodes [ 0 ] , "[ROOT]" , false ) ;
306- assert_eq ! ( ml. nodes[ 0 ] . offset, 0 ) ;
307-
308- check_item_info :: < u32 > ( & ml. nodes [ 1 ] , "a" , true ) ;
309- assert_eq ! ( ml. nodes[ 1 ] . offset, 0 ) ;
310-
311- check_item_info :: < ( i32 , u8 ) > ( & ml. nodes [ 2 ] , "b" , true ) ;
312- assert_eq ! ( ml. nodes[ 2 ] . offset, 4 ) ;
331+ )
332+ . unwrap ( )
333+ . to_string ( ) ,
334+ ) ;
335+ }
313336
314- check_item_info :: < i8 > ( & ml. nodes [ 3 ] , "c" , true ) ;
315- assert_eq ! ( ml. nodes[ 3 ] . offset, 12 ) ;
337+ #[ test]
338+ fn view_memory_layout_struct ( ) {
339+ expect ! [ [ r#"
340+ [ROOT]: Blah (size: 16, align: 4, field offset: 0)
341+ b: (i32, u8) (size: 8, align: 4, field offset: 0)
342+ .0: i32 (size: 4, align: 4, field offset: 0)
343+ .1: u8 (size: 1, align: 1, field offset: 4)
344+ a: u32 (size: 4, align: 4, field offset: 8)
345+ c: i8 (size: 1, align: 1, field offset: 12)
346+ "# ] ]
347+ . assert_eq (
348+ & make_memory_layout (
349+ r#"
350+ struct Blah$0 {
351+ a: u32,
352+ b: (i32, u8),
353+ c: i8,
354+ }
355+ "# ,
356+ )
357+ . unwrap ( )
358+ . to_string ( ) ,
359+ ) ;
316360 }
317361
318362 #[ test]
319363 fn view_memory_layout_member ( ) {
320- let ml = make_memory_layout (
321- r#"
364+ expect ! [ [ r#"
365+ a: bool (size: 1, align: 1, field offset: 0)
366+ "# ] ]
367+ . assert_eq (
368+ & make_memory_layout (
369+ r#"
370+ #[repr(C)]
322371struct Oof {
323- a$0: bool
372+ a$0: bool,
324373}
325374"# ,
326- )
327- . unwrap ( ) ;
328-
329- assert_eq ! ( ml. nodes. len( ) , 1 ) ;
330- assert_eq ! ( ml. nodes[ 0 ] . parent_idx, -1 ) ;
331- assert_eq ! ( ml. nodes[ 0 ] . children_start, -1 ) ;
332- check_item_info :: < bool > ( & ml. nodes [ 0 ] , "a" , true ) ;
333- // NOTE: this should not give the memory layout relative to the parent structure, but the type referred to by the member variable alone.
334- assert_eq ! ( ml. nodes[ 0 ] . offset, 0 ) ;
375+ )
376+ . unwrap ( )
377+ . to_string ( ) ,
378+ ) ;
335379 }
336380
337381 #[ test]
@@ -345,29 +389,21 @@ struct X {
345389}
346390
347391type Foo$0 = X;
348- "#,
392+ "# ,
349393 )
350394 . unwrap ( ) ;
395+
351396 let ml_b = make_memory_layout (
352397 r#"
353398struct X$0 {
354399 a: u32,
355400 b: i8,
356401 c: (f32, f32),
357402}
358- "#,
403+ "# ,
359404 )
360405 . unwrap ( ) ;
361406
362- ml_a. nodes . iter ( ) . zip ( ml_b. nodes . iter ( ) ) . for_each ( |( a, b) | {
363- assert_eq ! ( a. item_name, b. item_name) ;
364- assert_eq ! ( a. typename, b. typename) ;
365- assert_eq ! ( a. size, b. size) ;
366- assert_eq ! ( a. alignment, b. alignment) ;
367- assert_eq ! ( a. offset, b. offset) ;
368- assert_eq ! ( a. parent_idx, b. parent_idx) ;
369- assert_eq ! ( a. children_start, b. children_start) ;
370- assert_eq ! ( a. children_len, b. children_len) ;
371- } )
407+ assert_eq ! ( ml_a. to_string( ) , ml_b. to_string( ) ) ;
372408 }
373409}
0 commit comments