use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum EdgeType {
TrueBranch,
FalseBranch,
Fallthrough,
LoopBack,
LoopExit,
Exception,
Call,
Return,
}
impl EdgeType {
pub fn dot_color(&self) -> &'static str {
match self {
EdgeType::TrueBranch => "green",
EdgeType::FalseBranch => "red",
EdgeType::Fallthrough => "black",
EdgeType::LoopBack => "blue",
EdgeType::LoopExit => "orange",
EdgeType::Exception => "purple",
EdgeType::Call => "gray",
EdgeType::Return => "darkgray",
}
}
pub fn dot_label(&self) -> &'static str {
match self {
EdgeType::TrueBranch => "T",
EdgeType::FalseBranch => "F",
EdgeType::Fallthrough => "",
EdgeType::LoopBack => "loop",
EdgeType::LoopExit => "exit",
EdgeType::Exception => "unwind",
EdgeType::Call => "call",
EdgeType::Return => "ret",
}
}
}
pub fn classify_terminator(terminator: &crate::cfg::Terminator) -> Vec<(usize, EdgeType)> {
use crate::cfg::Terminator::*;
match terminator {
Goto { target } => vec![(*target, EdgeType::Fallthrough)],
SwitchInt { targets, otherwise } => {
let mut edges = targets
.iter()
.map(|&t| (t, EdgeType::TrueBranch))
.collect::<Vec<_>>();
edges.push((*otherwise, EdgeType::FalseBranch));
edges
}
Return => vec![],
Unreachable => vec![],
Call {
target: Some(t),
unwind,
} => {
let mut edges = vec![(*t, EdgeType::Call)];
if let Some(uw) = unwind {
edges.push((*uw, EdgeType::Exception));
}
edges
}
Call {
target: None,
unwind: Some(uw),
} => {
vec![(*uw, EdgeType::Exception)]
}
Call {
target: None,
unwind: None,
} => vec![],
Abort(_) => vec![],
}
}