///|
/// Independent format; Top never truncates this result.
pub fn render_function_callers_json(report : FunctionCallersReport) -> String {
let root : Map[String, Json] = Map([])
root.set("format", Json::string("moonsize-function-callers"))
root.set("schema_version", int_json(1))
root.set("file_size", int_json(report.file_size))
root.set("sha256", Json::string(report.sha256))
root.set("target", path_node_json(report.target))
root.set("caller_count", int_json(report.caller_count))
root.set("source_count", int_json(report.source_count))
root.set("graph_complete", Json::boolean(report.graph_complete))
root.set("diagnostics", diagnostic_records_json(report.diagnostics))
root.set("modeling_scope", Json::string(report.modeling_scope))
root.set(
"callers",
Json::array(
report.callers.map(fn(group) {
let row : Map[String, Json] = Map([])
row.set("caller", path_node_json(group.caller))
row.set(
"sources",
Json::array(
group.sources.map(fn(source) {
let item : Map[String, Json] = Map([])
item.set("caller", int_json(source.caller))
item.set("callee", int_json(source.callee))
item.set("kind", Json::string(path_edge_kind(source.kind)))
item.set("candidate", Json::boolean(source.kind is Indirect))
item.set("opcode", Json::string(source.opcode.name()))
item.set("file_offset", int_json(source.offset))
item.set("type_index", optional_index_json(source.type_index))
item.set("table_index", optional_index_json(source.table_index))
Json::object(item)
}),
),
)
Json::object(row)
}),
),
)
Json::object(root).stringify(indent=2) + "\n"
}
///|
pub fn render_function_callers(
report : FunctionCallersReport,
top : Int,
) -> String {
let out = StringBuilder()
let shown = top.max(0).min(report.callers.length())
out.write_string(
"FUNCTION INCOMING REFERENCES\n\nTarget: #" +
report.target.index.to_string() +
" " +
Json::string(report.target.name).stringify() +
"\n",
)
out.write_string(
"Identity: " +
(if report.target.imported {
"imported; no local body (encoded size is not measured)\n"
} else {
"local; encoded bytes " +
report.target.encoded_size.unwrap_or(0).to_string() +
"\n"
}),
)
out.write_string(
"Input: " +
report.file_size.to_string() +
" bytes; SHA-256 " +
report.sha256 +
"\n",
)
out.write_string(
"Unique callers: " +
report.caller_count.to_string() +
"; source instructions: " +
report.source_count.to_string() +
"\n",
)
out.write_string(
"Showing " +
shown.to_string() +
" of " +
report.caller_count.to_string() +
" caller groups\n",
)
for i in 0.. "direct"
Reference => "reference taken"
Indirect => "indirect candidate"
}
out.write_string(
source.caller.to_string() +
" " +
kind +
" " +
source.opcode.name() +
" " +
source.offset.to_string() +
" " +
(match source.type_index {
Some(n) => n.to_string()
None => "-"
}) +
" " +
(match source.table_index {
Some(n) => n.to_string()
None => "-"
}) +
"\n",
)
}
}
if report.callers.is_empty() {
out.write_string(
"\nNo incoming instruction references recorded in the current model.\nThis does not prove the function is unused or removable.\n",
)
}
if !report.graph_warning.is_empty() {
out.write_string("\n" + report.graph_warning + "\n")
}
out.write_string("\n" + report.modeling_scope + "\n")
out.to_string()
}