use crate::analysis::MagellanBridge;
use crate::cfg::{Cfg, Path as CfgPath};
use crate::storage::{Backend, MirageDb};
use anyhow::Result;
use std::path::Path;
#[derive(Debug, Clone)]
pub struct FunctionCfgResult {
pub name: String,
pub function_id: i64,
pub cfg: Cfg,
}
#[derive(Debug, Clone)]
pub struct CycleReport {
pub cycles: Vec<Vec<String>>,
}
#[derive(Debug, Clone)]
pub struct DeadSymbolInfo {
pub name: String,
pub kind: String,
pub file_path: String,
}
pub fn resolve_function(name: &str, file_filter: Option<&str>, db_path: &Path) -> Result<i64> {
let db = MirageDb::open(db_path)?;
db.resolve_function_name_with_file(name, file_filter)
}
pub fn get_function_cfg(
name: &str,
file_filter: Option<&str>,
db_path: &Path,
) -> Result<FunctionCfgResult> {
let db = MirageDb::open(db_path)?;
let function_id = db.resolve_function_name_with_file(name, file_filter)?;
let cfg = db.load_cfg(function_id)?;
Ok(FunctionCfgResult {
name: name.to_string(),
function_id,
cfg,
})
}
pub fn get_function_paths(
name: &str,
file_filter: Option<&str>,
db_path: &Path,
) -> Result<Option<Vec<CfgPath>>> {
let backend = Backend::detect_and_open(db_path)?;
let db = MirageDb::open(db_path)?;
let function_id = db.resolve_function_name_with_file(name, file_filter)?;
backend.get_cached_paths(function_id)
}
pub fn get_callees(name: &str, file_filter: Option<&str>, db_path: &Path) -> Result<Vec<i64>> {
let backend = Backend::detect_and_open(db_path)?;
let db = MirageDb::open(db_path)?;
let function_id = db.resolve_function_name_with_file(name, file_filter)?;
backend.get_callees(function_id)
}
pub fn detect_cycles(db_path: &Path) -> Result<CycleReport> {
let bridge = MagellanBridge::open(db_path.to_str().unwrap_or("."))?;
let result = bridge.detect_cycles()?;
let cycles = result
.cycles
.into_iter()
.map(|cycle| {
cycle
.members
.into_iter()
.filter_map(|info| info.fqn)
.collect()
})
.collect();
Ok(CycleReport { cycles })
}
pub fn find_dead_symbols(entry_symbol: &str, db_path: &Path) -> Result<Vec<DeadSymbolInfo>> {
let bridge = MagellanBridge::open(db_path.to_str().unwrap_or("."))?;
let dead = bridge.dead_symbols(entry_symbol)?;
Ok(dead
.into_iter()
.map(|d| DeadSymbolInfo {
name: d.symbol.fqn.clone().unwrap_or_default(),
kind: d.symbol.kind.clone(),
file_path: d.symbol.file_path.clone(),
})
.collect())
}
pub fn reachable_symbols(symbol_id: &str, db_path: &Path) -> Result<Vec<DeadSymbolInfo>> {
let bridge = MagellanBridge::open(db_path.to_str().unwrap_or("."))?;
let reachable = bridge.reachable_symbols(symbol_id)?;
Ok(reachable
.into_iter()
.map(|r| DeadSymbolInfo {
name: r.fqn.clone().unwrap_or_default(),
kind: r.kind.clone(),
file_path: r.file_path.clone(),
})
.collect())
}
pub fn database_status(db_path: &Path) -> Result<crate::storage::DatabaseStatus> {
let db = MirageDb::open(db_path)?;
db.status()
}