use std::collections::HashSet;
use crate::disassembler::DisassemblyOutput;
use crate::error::Result;
use crate::manifest::ContractManifest;
use super::super::cfg::CfgBuilder;
use super::super::decompilation::Decompilation;
use super::super::output_format::{OutputFormat, RenderOptions};
use super::super::{analysis, csharp, high_level, pseudocode};
use super::Decompiler;
impl Decompiler {
pub(super) fn disassemble_bytes_inner(&self, bytes: &[u8]) -> Result<DisassemblyOutput> {
let nef = self.parser.parse(bytes)?;
self.disassembler.disassemble_with_warnings(&nef.script)
}
pub(super) fn decompile_bytes_with_manifest_inner(
&self,
bytes: &[u8],
manifest: Option<ContractManifest>,
output_format: OutputFormat,
) -> Result<Decompilation> {
let parse_output = self.parser.parse_with_warnings(bytes)?;
let nef = parse_output.nef;
let disassembly = self.disassembler.disassemble_with_warnings(&nef.script)?;
let instructions = disassembly.instructions;
let mut warnings = UniqueWarnings::default();
warnings.extend(
parse_output
.warnings
.into_iter()
.map(|warning| warning.to_string()),
);
warnings.extend(
disassembly
.warnings
.into_iter()
.map(|warning| warning.to_string()),
);
let cfg = CfgBuilder::new(&instructions).build();
let call_graph =
analysis::call_graph::build_call_graph(&nef, &instructions, manifest.as_ref());
let xrefs = analysis::xrefs::build_xrefs(&instructions, manifest.as_ref());
let types = analysis::types::infer_types_with_method_tokens(
&instructions,
manifest.as_ref(),
&nef.method_tokens,
);
let render_opts = RenderOptions {
inline_single_use_temps: self.inline_single_use_temps,
emit_trace_comments: self.emit_trace_comments,
typed_declarations: self.typed_declarations,
};
let pseudocode = output_format
.wants_pseudocode()
.then(|| pseudocode::render(&instructions));
let high_level = output_format.wants_high_level().then(|| {
let render = high_level::render_high_level(
&nef,
&instructions,
manifest.as_ref(),
&call_graph,
&types,
&render_opts,
);
warnings.extend(render.warnings);
render.text
});
let csharp = output_format.wants_csharp().then(|| {
let render = csharp::render_csharp(
&nef,
&instructions,
manifest.as_ref(),
&call_graph,
&types,
&render_opts,
);
warnings.extend(render.warnings);
render.source
});
Ok(Decompilation {
nef,
manifest,
warnings: warnings.into_vec(),
instructions,
cfg,
call_graph,
xrefs,
types,
pseudocode,
high_level,
csharp,
ssa: None,
})
}
}
#[derive(Default)]
struct UniqueWarnings {
values: Vec<String>,
seen: HashSet<String>,
}
impl UniqueWarnings {
fn extend(&mut self, warnings: impl IntoIterator<Item = String>) {
for warning in warnings {
if self.seen.insert(warning.clone()) {
self.values.push(warning);
}
}
}
fn into_vec(self) -> Vec<String> {
self.values
}
}