neo-decompiler 0.10.2

Neo N3 NEF decompiler: parse, disassemble, lift bytecode to high-level pseudocode and C# skeletons, with a CLI, JSON reports, and optional WebAssembly bindings.
Documentation
use super::*;
use crate::instruction::OpCode;

#[test]
fn decompilation_includes_slot_xrefs() {
    // Script:
    // INITSLOT 1 local, 0 args
    // PUSH1; STLOC0
    // LDLOC0; RET
    let script = [
        OpCode::Initslot.byte(),
        0x01,
        0x00,
        OpCode::Push1.byte(),
        OpCode::Stloc0.byte(),
        OpCode::Ldloc0.byte(),
        OpCode::Ret.byte(),
    ];
    let nef_bytes = build_nef(&script);
    let decompilation = Decompiler::new()
        .decompile_bytes_with_manifest(&nef_bytes, None, OutputFormat::Pseudocode)
        .expect("decompile succeeds");

    let method = &decompilation.xrefs.methods[0];
    assert_eq!(method.locals.len(), 1);
    assert!(method.locals[0].writes.contains(&4));
    assert!(method.locals[0].reads.contains(&5));
}

#[test]
fn decompilation_includes_argument_slot_xrefs() {
    // Script:
    // INITSLOT 0 locals, 2 args
    // LDARG0
    // PUSH1; STARG1
    // RET
    let script = [
        OpCode::Initslot.byte(),
        0x00,
        0x02,
        OpCode::Ldarg0.byte(),
        OpCode::Push1.byte(),
        OpCode::Starg1.byte(),
        OpCode::Ret.byte(),
    ];
    let nef_bytes = build_nef(&script);
    let decompilation = Decompiler::new()
        .decompile_bytes_with_manifest(&nef_bytes, None, OutputFormat::Pseudocode)
        .expect("decompile succeeds");

    let method = &decompilation.xrefs.methods[0];
    assert_eq!(method.arguments.len(), 2);
    assert!(method.arguments[0].reads.contains(&3));
    assert!(method.arguments[1].writes.contains(&5));
}

#[test]
fn decompilation_includes_indexed_slot_xrefs() {
    // Script:
    // INITSLOT 0 locals, 8 args
    // LDARG 7
    // PUSH1; STARG 7
    // RET
    let script = [
        OpCode::Initslot.byte(),
        0x00,
        0x08, // INITSLOT
        OpCode::Ldarg.byte(),
        0x07,                 // LDARG 7
        OpCode::Push1.byte(), // PUSH1
        OpCode::Starg.byte(),
        0x07,               // STARG 7
        OpCode::Ret.byte(), // RET
    ];
    let nef_bytes = build_nef(&script);
    let decompilation = Decompiler::new()
        .decompile_bytes_with_manifest(&nef_bytes, None, OutputFormat::Pseudocode)
        .expect("decompile succeeds");

    let method = &decompilation.xrefs.methods[0];
    assert!(method.arguments.len() >= 8);
    assert!(method.arguments[7].reads.contains(&3));
    assert!(method.arguments[7].writes.contains(&6));
}

#[test]
fn decompilation_includes_static_slot_xrefs() {
    // Script:
    // INITSSLOT 2
    // PUSH1; STSFLD0
    // LDSFLD0; RET
    let script = [
        OpCode::Initsslot.byte(),
        0x02,
        OpCode::Push1.byte(),
        OpCode::Stsfld0.byte(),
        OpCode::Ldsfld0.byte(),
        OpCode::Ret.byte(),
    ];
    let nef_bytes = build_nef(&script);
    let decompilation = Decompiler::new()
        .decompile_bytes_with_manifest(&nef_bytes, None, OutputFormat::Pseudocode)
        .expect("decompile succeeds");

    let method = &decompilation.xrefs.methods[0];
    assert_eq!(method.statics.len(), 2);
    assert!(method.statics[0].writes.contains(&3));
    assert!(method.statics[0].reads.contains(&4));
}

#[test]
fn decompilation_includes_indexed_static_slot_xrefs() {
    // Script:
    // INITSSLOT 8
    // PUSH1; STSFLD 7
    // LDSFLD 7; RET
    let script = [
        OpCode::Initsslot.byte(),
        0x08,                 // INITSSLOT 8
        OpCode::Push1.byte(), // PUSH1
        OpCode::Stsfld.byte(),
        0x07, // STSFLD 7
        OpCode::Ldsfld.byte(),
        0x07,               // LDSFLD 7
        OpCode::Ret.byte(), // RET
    ];
    let nef_bytes = build_nef(&script);
    let decompilation = Decompiler::new()
        .decompile_bytes_with_manifest(&nef_bytes, None, OutputFormat::Pseudocode)
        .expect("decompile succeeds");

    let method = &decompilation.xrefs.methods[0];
    assert!(method.statics.len() >= 8);
    assert!(method.statics[7].writes.contains(&3));
    assert!(method.statics[7].reads.contains(&5));
}