pub mod debug;
pub mod default;
pub mod graph;
use std::{
collections::{HashMap, HashSet},
fmt::{self, Debug, Display},
fs::File,
io::Write,
process::Command,
};
use crate::{analysis::Analysis, utils::source::get_fn_name_byid};
use rustc_hir::{def::DefKind, def_id::DefId};
use rustc_index::IndexVec;
use rustc_middle::{
mir::{Body, Local},
ty::TyCtxt,
};
use rustc_span::Span;
pub type Arg2Ret = IndexVec<Local, bool>;
pub type Arg2RetMap = HashMap<DefId, IndexVec<Local, bool>>;
#[derive(Clone)]
pub struct DataFlowGraph {
pub nodes: GraphNodes,
pub edges: GraphEdges,
pub param_ret_deps: Arg2Ret,
}
pub type DataFlowGraphMap = HashMap<DefId, DataFlowGraph>;
pub struct Arg2RetWrapper(pub Arg2Ret);
pub struct Arg2RetMapWrapper(pub Arg2RetMap);
pub struct DataFlowGraphWrapper(pub DataFlowGraph);
pub struct DataFlowGraphMapWrapper(pub HashMap<DefId, DataFlowGraph>);
pub type EdgeIdx = usize;
pub type GraphNodes = IndexVec<Local, GraphNode>;
pub type GraphEdges = IndexVec<EdgeIdx, GraphEdge>;
#[derive(Clone, Debug)]
pub struct GraphEdge {
pub src: Local,
pub dst: Local,
pub op: EdgeOp,
pub seq: usize,
}
#[derive(Clone, Debug)]
pub struct GraphNode {
pub ops: Vec<NodeOp>,
pub span: Span, pub seq: usize, pub out_edges: Vec<EdgeIdx>,
pub in_edges: Vec<EdgeIdx>,
}
pub trait DataFlowAnalysis: Analysis {
fn get_fn_dataflow(&self, def_id: DefId) -> Option<DataFlowGraph>;
fn get_all_dataflow(&self) -> DataFlowGraphMap;
fn has_flow_between(&self, def_id: DefId, local1: Local, local2: Local) -> bool;
fn collect_equivalent_locals(&self, def_id: DefId, local: Local) -> HashSet<Local>;
fn get_fn_arg2ret(&self, def_id: DefId) -> Arg2Ret;
fn get_all_arg2ret(&self) -> Arg2RetMap;
}
impl fmt::Display for Arg2RetWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let arg2ret: &Arg2Ret = &self.0;
for (local, depends) in arg2ret.iter_enumerated() {
if local.as_u32() > 0 {
if *depends {
writeln!(f, "Argument {:?} ---> Return value _0", local)?;
}
}
}
Ok(())
}
}
impl fmt::Display for Arg2RetMapWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "=== Print dataflow analysis results ===")?;
for (def_id, arg2ret) in &self.0 {
let fn_name = get_fn_name_byid(def_id);
writeln!(
f,
"Function: {:?}\n{}",
fn_name,
Arg2RetWrapper(arg2ret.clone())
)?;
}
Ok(())
}
}
impl Display for DataFlowGraphWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let graph = &self.0;
write!(
f,
"Graph statistics: {} nodes, {} edges.\n",
graph.nodes.len(),
graph.edges.len()
)?;
if graph.param_ret_deps.len() > 1 {
write!(f, "Return value dependencies: \n")?;
}
for (node_idx, deps) in graph.param_ret_deps.iter_enumerated() {
if node_idx.as_u32() > 0 {
if *deps {
write!(f, "Argument {:?} ---> Return value _0.\n", node_idx)?;
}
}
}
for (node_idx, node) in graph.nodes.iter_enumerated() {
let node_adj: Vec<Local> = node
.out_edges
.iter()
.map(|edge_idx| graph.edges[*edge_idx].dst)
.collect();
if !node_adj.is_empty() {
write!(f, "Node {:?} -> Node {:?}\n", node_idx, node_adj)?;
}
}
Ok(())
}
}
impl Debug for DataFlowGraphWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Nodes:")?;
for node in &self.0.nodes {
writeln!(f, " {:?}", node)?;
}
writeln!(f, "Edges:")?;
for edge in &self.0.edges {
writeln!(f, " {:?}", edge)?;
}
Ok(())
}
}
impl Display for DataFlowGraphMapWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "===Print dataflow analysis resuts===")?;
for (def_id, dfg) in &self.0 {
let fn_name = get_fn_name_byid(def_id);
writeln!(
f,
"Function: {:?}\n{}",
fn_name,
DataFlowGraphWrapper(dfg.clone())
)?;
}
Ok(())
}
}
impl Debug for DataFlowGraphMapWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (def_id, dfg) in &self.0 {
writeln!(
f,
"DefId: {:?}\n{:?}",
def_id,
DataFlowGraphWrapper(dfg.clone())
)?;
}
Ok(())
}
}
#[derive(Clone, Debug)]
pub enum NodeOp {
Nop,
Err,
Const(String, String),
Use,
Repeat,
Ref,
ThreadLocalRef,
AddressOf,
Len,
Cast,
BinaryOp,
CheckedBinaryOp,
NullaryOp,
UnaryOp,
Discriminant,
Aggregate(AggKind),
ShallowInitBox,
CopyForDeref,
RawPtr,
Call(DefId),
CallOperand, }
#[derive(Clone, Debug)]
pub enum EdgeOp {
Nop,
Move,
Copy,
Const,
Immut,
Mut,
Deref,
Field(usize),
Downcast(String),
Index,
ConstIndex,
SubSlice,
}
#[derive(Clone, Copy, Debug)]
pub enum AggKind {
Array,
Tuple,
Adt(DefId),
Closure(DefId),
Coroutine(DefId),
RawPtr,
}