neo-decompiler 0.10.1

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::{BTreeMap, BTreeSet};

use crate::decompiler::cfg::BlockId;

use super::super::form::{SsaExpr, SsaForm, SsaStmt, UseSite};
use super::super::variable::SsaVariable;
use super::Subst;

/// Variables still referenced after substitution is applied.
pub(super) fn collect_used(ssa: &SsaForm, _subst: &Subst) -> BTreeSet<SsaVariable> {
    let mut used = BTreeSet::new();
    for (_bid, block) in ssa.blocks.iter() {
        for phi in &block.phi_nodes {
            for var in phi.operands.values() {
                used.insert(var.clone());
            }
        }
        for stmt in &block.stmts {
            if let SsaStmt::Assign { value, .. } = stmt {
                used.extend(collect_expr_vars(value));
            }
        }
    }
    used
}

/// Recompute the `definitions` and `uses` indexes from the current blocks.
pub(super) fn rebuild_indexes(ssa: &mut SsaForm) {
    let mut definitions: BTreeMap<SsaVariable, BlockId> = BTreeMap::new();
    let mut uses: BTreeMap<SsaVariable, BTreeSet<UseSite>> = BTreeMap::new();
    for (bid, block) in ssa.blocks.iter() {
        for phi in &block.phi_nodes {
            definitions.insert(phi.target.clone(), *bid);
            for var in phi.operands.values() {
                uses.entry(var.clone())
                    .or_default()
                    .insert(UseSite::new(*bid, 0));
            }
        }
        for (i, stmt) in block.stmts.iter().enumerate() {
            if let SsaStmt::Assign { target, value } = stmt {
                definitions.insert(target.clone(), *bid);
                for var in collect_expr_vars(value) {
                    uses.entry(var).or_default().insert(UseSite::new(*bid, i));
                }
            }
        }
    }
    ssa.definitions = definitions;
    ssa.uses = uses;
}

fn collect_expr_vars(expr: &SsaExpr) -> Vec<SsaVariable> {
    let mut out = Vec::new();
    collect_expr_vars_into(expr, &mut out);
    out
}

fn collect_expr_vars_into(expr: &SsaExpr, out: &mut Vec<SsaVariable>) {
    match expr {
        SsaExpr::Variable(var) => out.push(var.clone()),
        SsaExpr::Binary { left, right, .. } => {
            collect_expr_vars_into(left, out);
            collect_expr_vars_into(right, out);
        }
        SsaExpr::Unary { operand, .. } => collect_expr_vars_into(operand, out),
        SsaExpr::Call { args, .. } => {
            for arg in args {
                collect_expr_vars_into(arg, out);
            }
        }
        SsaExpr::Index { base, index } => {
            collect_expr_vars_into(base, out);
            collect_expr_vars_into(index, out);
        }
        SsaExpr::Member { base, .. } => collect_expr_vars_into(base, out),
        SsaExpr::Cast { expr, .. } => collect_expr_vars_into(expr, out),
        SsaExpr::Array(elements) => {
            for element in elements {
                collect_expr_vars_into(element, out);
            }
        }
        SsaExpr::Map(pairs) => {
            for (key, value) in pairs {
                collect_expr_vars_into(key, out);
                collect_expr_vars_into(value, out);
            }
        }
        SsaExpr::Ternary {
            condition,
            then_expr,
            else_expr,
        } => {
            collect_expr_vars_into(condition, out);
            collect_expr_vars_into(then_expr, out);
            collect_expr_vars_into(else_expr, out);
        }
        SsaExpr::Literal(_) => {}
    }
}