use crate::{Args, CrateData};
use binfarce::demangle::{self, SymbolName};
pub const UNKNOWN: &str = "[Unknown]";
pub fn from_sym(d: &CrateData, args: &Args, sym: &SymbolName) -> (String, bool) {
let (mut name, is_exact) = from_sym_impl(d, sym);
if !args.split_std {
if d.std_crates.contains(&name) {
name = "std".to_string();
}
}
(name, is_exact)
}
fn from_sym_impl(d: &CrateData, sym: &SymbolName) -> (String, bool) {
if let Some(name) = d.deps_symbols.get(&sym.complete) {
return (name.to_string(), true);
}
match sym.kind {
demangle::Kind::Legacy => parse_sym(d, &sym.complete),
demangle::Kind::V0 => match sym.crate_name {
Some(ref name) => (name.to_string(), true),
None => parse_sym_v0(d, &sym.trimmed),
},
demangle::Kind::Unknown => (UNKNOWN.to_string(), true),
}
}
fn parse_sym(d: &CrateData, sym: &str) -> (String, bool) {
let mut is_exact = true;
let name = if sym.contains(" as ") {
let parts: Vec<_> = sym.split(" as ").collect();
let crate_name1 = parse_crate_from_sym(parts[0]);
let crate_name2 = parse_crate_from_sym(parts[1]);
if crate_name1.is_empty() {
crate_name2
} else {
if crate_name1 == crate_name2 {
crate_name1
} else {
if let Some(names) = d.deps_symbols.get_vec(sym) {
if names.contains(&crate_name1) {
crate_name1
} else if names.contains(&crate_name2) {
crate_name2
} else {
is_exact = false;
crate_name1
}
} else {
is_exact = false;
crate_name1
}
}
}
} else {
parse_crate_from_sym(sym)
};
(name, is_exact)
}
fn parse_crate_from_sym(sym: &str) -> String {
if !sym.contains("::") {
return String::new();
}
let mut crate_name = if let Some(s) = sym.split("::").next() {
s.to_string()
} else {
sym.to_string()
};
if crate_name.starts_with('<') {
while crate_name.starts_with('<') {
crate_name.remove(0);
}
while crate_name.starts_with('&') {
crate_name.remove(0);
}
crate_name = crate_name.split_whitespace().last().unwrap().to_owned();
}
crate_name
}
fn parse_sym_v0(d: &CrateData, sym: &str) -> (String, bool) {
let name = parse_crate_from_sym(sym);
if d.std_crates.contains(&name) || d.dep_crates.contains(&name) {
(name, false)
} else {
(UNKNOWN.to_string(), true)
}
}