use crate::helpers::fn_info::*;
use rustc_hir::{Safety, def_id::DefId};
use rustc_middle::mir::Local;
use std::collections::HashSet;
#[derive(Debug, Clone)]
pub struct SafetyFlowUnit {
pub caller: FnInfo,
pub callees: HashSet<FnInfo>,
pub raw_ptrs: HashSet<Local>,
pub static_muts: HashSet<DefId>,
pub caller_cons: HashSet<FnInfo>,
pub mut_methods: HashSet<DefId>,
}
#[derive(Debug, Clone, Default)]
pub struct BasicUnitCounts {
pub unsafe_fn_or_method_no_callees: u32,
pub safe_fn_call_unsafe_fn: u32,
pub safe_fn_call_unsafe_method: u32,
pub unsafe_fn_call_unsafe_fn: u32,
pub unsafe_fn_call_unsafe_method: u32,
pub unsafe_method_safe_cons_call_unsafe_fn: u32,
pub unsafe_method_unsafe_cons_call_unsafe_fn: u32,
pub unsafe_method_safe_cons_call_unsafe_method: u32,
pub unsafe_method_unsafe_cons_call_unsafe_method: u32,
pub safe_method_safe_cons_call_unsafe_fn: u32,
pub safe_method_unsafe_cons_call_unsafe_fn: u32,
pub safe_method_safe_cons_call_unsafe_method: u32,
pub safe_method_unsafe_cons_call_unsafe_method: u32,
}
impl BasicUnitCounts {
pub fn total(&self) -> u32 {
self.unsafe_fn_or_method_no_callees
+ self.safe_fn_call_unsafe_fn
+ self.safe_fn_call_unsafe_method
+ self.unsafe_fn_call_unsafe_fn
+ self.unsafe_fn_call_unsafe_method
+ self.unsafe_method_safe_cons_call_unsafe_fn
+ self.unsafe_method_unsafe_cons_call_unsafe_fn
+ self.unsafe_method_safe_cons_call_unsafe_method
+ self.unsafe_method_unsafe_cons_call_unsafe_method
+ self.safe_method_safe_cons_call_unsafe_fn
+ self.safe_method_unsafe_cons_call_unsafe_fn
+ self.safe_method_safe_cons_call_unsafe_method
+ self.safe_method_unsafe_cons_call_unsafe_method
}
}
impl SafetyFlowUnit {
pub fn new(
caller: FnInfo,
callees: HashSet<FnInfo>,
raw_ptrs: HashSet<Local>,
static_muts: HashSet<DefId>,
caller_cons: HashSet<FnInfo>,
mut_methods: HashSet<DefId>,
) -> Self {
Self {
caller,
callees,
raw_ptrs,
static_muts,
caller_cons,
mut_methods,
}
}
pub fn count_basic_units(&self, c: &mut BasicUnitCounts) {
if self.caller.fn_safety == Safety::Unsafe && self.callees.is_empty() {
c.unsafe_fn_or_method_no_callees += 1;
}
if self.caller.fn_safety == Safety::Safe && self.caller.fn_kind != FnKind::Method {
for callee in &self.callees {
if callee.fn_kind == FnKind::Method {
c.safe_fn_call_unsafe_method += 1;
} else {
c.safe_fn_call_unsafe_fn += 1;
}
}
}
if self.caller.fn_safety == Safety::Unsafe && self.caller.fn_kind != FnKind::Method {
for callee in &self.callees {
if callee.fn_kind == FnKind::Method {
c.unsafe_fn_call_unsafe_method += 1;
} else {
c.unsafe_fn_call_unsafe_fn += 1;
}
}
}
if self.caller.fn_safety == Safety::Unsafe && self.caller.fn_kind == FnKind::Method {
let mut unsafe_cons = 0;
let mut safe_cons = 0;
for cons in &self.caller_cons {
if cons.fn_safety == Safety::Unsafe {
unsafe_cons += 1;
} else {
safe_cons += 1;
}
}
if unsafe_cons == 0 && safe_cons == 0 {
safe_cons = 1;
}
for callee in &self.callees {
if callee.fn_kind == FnKind::Method {
c.unsafe_method_safe_cons_call_unsafe_method += safe_cons;
c.unsafe_method_unsafe_cons_call_unsafe_method += unsafe_cons;
} else {
c.unsafe_method_safe_cons_call_unsafe_fn += safe_cons;
c.unsafe_method_unsafe_cons_call_unsafe_fn += unsafe_cons;
}
}
}
if self.caller.fn_safety == Safety::Safe && self.caller.fn_kind == FnKind::Method {
let mut unsafe_cons = 0;
let mut safe_cons = 0;
for cons in &self.caller_cons {
if cons.fn_safety == Safety::Unsafe {
unsafe_cons += 1;
} else {
safe_cons += 1;
}
}
if unsafe_cons == 0 && safe_cons == 0 {
safe_cons = 1;
}
for callee in &self.callees {
if callee.fn_kind == FnKind::Method {
c.safe_method_safe_cons_call_unsafe_method += safe_cons;
c.safe_method_unsafe_cons_call_unsafe_method += unsafe_cons;
} else {
c.safe_method_safe_cons_call_unsafe_fn += safe_cons;
c.safe_method_unsafe_cons_call_unsafe_fn += unsafe_cons;
}
}
}
}
}