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();
}
}