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 std::collections::HashSet;
use std::fmt::Write;

use crate::instruction::OpCode;
use crate::manifest::ContractManifest;

use super::super::super::super::helpers::{next_inferred_method_offset, offset_as_usize};
use super::super::body;
use super::util::{format_inferred_parameters, instruction_slice};
use super::MethodsContext;

pub(super) fn write_inferred_methods(
    output: &mut String,
    context: &MethodsContext<'_>,
    manifest: Option<&ContractManifest>,
    warnings: &mut Vec<String>,
) {
    let entry_offset = context.instructions.first().map(|ins| ins.offset);
    let manifest_offsets: HashSet<usize> = manifest
        .map(|manifest| {
            manifest
                .abi
                .methods
                .iter()
                .filter_map(|method| offset_as_usize(method.offset))
                .collect()
        })
        .unwrap_or_default();

    for start in context.inferred_method_starts {
        if Some(*start) == entry_offset || manifest_offsets.contains(start) {
            continue;
        }

        let end = next_inferred_method_offset(context.inferred_method_starts, *start)
            .or_else(|| context.instructions.last().map(|ins| ins.offset + 1))
            .unwrap_or(*start);
        let slice = instruction_slice(context.instructions, *start, Some(end));
        if slice.is_empty() || slice.iter().all(|ins| ins.opcode == OpCode::Nop) {
            continue;
        }

        let arg_count = context
            .body_context
            .method_arg_counts_by_offset
            .get(start)
            .copied()
            .unwrap_or(0);
        let params = format_inferred_parameters(
            arg_count,
            *start,
            context,
            context.body_context.typed_declarations,
            "dynamic",
        );

        writeln!(
            output,
            "        private static dynamic sub_0x{start:04X}({params})"
        )
        .unwrap();
        writeln!(output, "        {{").unwrap();
        let labels = (0..arg_count)
            .map(|index| format!("arg{index}"))
            .collect::<Vec<_>>();
        body::write_lifted_body(
            output,
            &slice,
            (!labels.is_empty()).then_some(labels.as_slice()),
            warnings,
            &context.body_context,
            false,
        );
        writeln!(output, "        }}").unwrap();
        writeln!(output).unwrap();
    }
}