1
+ use std:: fmt;
2
+
1
3
use hir:: { Field , HirDisplay , Layout , Semantics , Type } ;
2
4
use ide_db:: {
3
5
defs:: Definition ,
@@ -23,6 +25,36 @@ pub struct RecursiveMemoryLayout {
23
25
pub nodes : Vec < MemoryLayoutNode > ,
24
26
}
25
27
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
+
26
58
enum FieldOrTupleIdx {
27
59
Field ( Field ) ,
28
60
TupleIdx ( usize ) ,
@@ -191,22 +223,14 @@ mod tests {
191
223
use super :: * ;
192
224
193
225
use crate :: fixture;
226
+ use expect_test:: expect;
194
227
195
228
fn make_memory_layout ( ra_fixture : & str ) -> Option < RecursiveMemoryLayout > {
196
229
let ( analysis, position, _) = fixture:: annotations ( ra_fixture) ;
197
230
198
231
view_memory_layout ( & analysis. db , position)
199
232
}
200
233
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
-
210
234
#[ test]
211
235
fn view_memory_layout_none ( ) {
212
236
assert ! ( make_memory_layout( r#"$0"# ) . is_none( ) ) ;
@@ -215,123 +239,143 @@ mod tests {
215
239
216
240
#[ test]
217
241
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#"
220
248
fn main() {
221
249
let foo$0 = 109; // default i32
222
250
}
223
251
"# ,
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
+ ) ;
232
256
}
233
257
234
258
#[ test]
235
259
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#"
238
266
const BLAH$0: bool = 0;
239
267
"# ,
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
+ ) ;
248
272
}
249
273
250
274
#[ test]
251
275
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#"
254
282
static BLAH$0: bool = 0;
255
283
"# ,
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
+ ) ;
264
288
}
265
289
266
290
#[ test]
267
291
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#"
270
301
fn main() {
271
302
let x$0 = (101.0, 111u8, 119i64);
272
303
}
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
+ ) ;
281
309
}
282
310
283
311
#[ 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#"
287
324
#[repr(C)]
288
325
struct Blah$0 {
289
326
a: u32,
290
327
b: (i32, u8),
291
328
c: i8,
292
329
}
293
330
"# ,
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
+ }
313
336
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
+ ) ;
316
360
}
317
361
318
362
#[ test]
319
363
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)]
322
371
struct Oof {
323
- a$0: bool
372
+ a$0: bool,
324
373
}
325
374
"# ,
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
+ ) ;
335
379
}
336
380
337
381
#[ test]
@@ -345,29 +389,21 @@ struct X {
345
389
}
346
390
347
391
type Foo$0 = X;
348
- "#,
392
+ "# ,
349
393
)
350
394
. unwrap ( ) ;
395
+
351
396
let ml_b = make_memory_layout (
352
397
r#"
353
398
struct X$0 {
354
399
a: u32,
355
400
b: i8,
356
401
c: (f32, f32),
357
402
}
358
- "#,
403
+ "# ,
359
404
)
360
405
. unwrap ( ) ;
361
406
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( ) ) ;
372
408
}
373
409
}
0 commit comments