use log::{error, info, warn};
use rustc_middle::{
mir::Body,
ty::*,
};
use rustc_hir::{Expr, ExprKind, QPath, PatKind, Mutability, UnOp, def::*, Pat};
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
use crate::expr_visitor_utils::*;
use crate::svg_generator::data::*;
use rustc_borrowck::consumers::BodyWithBorrowckFacts;
#[derive(Debug, Clone)]
pub enum Evt {
Bind,
Copy, Move, SBorrow, MBorrow,
SDie,
MDie,
PassBySRef,
PassByMRef, }
#[derive(Debug, Clone)]
pub struct RefData {
pub lender: ResourceTy, pub assigned_at: usize, pub lifetime: usize, pub ref_mutability: bool, pub aliasing: VecDeque<String> }
#[derive(Debug, Clone)]
pub struct RapData {
pub rap: ResourceAccessPoint,
pub scope: usize,
pub is_global: bool,
pub fn_start_line: usize,
}
pub struct ExprVisitor<'a, 'tcx:'a> {
pub tcx: TyCtxt<'tcx>, pub mir_body: &'a Body<'tcx>,
pub hir_body: &'a rustc_hir::Body<'tcx>,
pub bwf: &'a BodyWithBorrowckFacts<'tcx>,
pub borrow_map: HashMap<String, RefData>,
pub raps: HashMap<String, RapData>,
pub current_scope: usize,
pub current_fn_start: usize,
pub analysis_result : HashMap<usize, Vec<String>>,
pub event_line_map: &'a mut BTreeMap<usize, Vec<ExternalEvent>>,
pub preprocessed_events: &'a mut Vec<(usize, ExternalEvent)>,
pub rap_hashes: usize,
pub source_map: & 'a BTreeMap<usize, String>,
pub annotated_lines: & 'a mut BTreeMap<usize, Vec<String>>,
pub id_map: & 'a mut HashMap<String, usize>,
pub unique_id: & 'a mut usize,
pub inside_branch: bool,
pub fn_ret: bool
}
impl<'a, 'tcx> ExprVisitor<'a, 'tcx>{
pub fn return_type_of(&self,fn_expr:&Expr)->Option<Ty<'tcx>>{
let type_check = self.tcx.typeck(fn_expr.hir_id.owner);
let type_of_path = type_check.expr_ty(fn_expr);
let mut fn_sig = type_of_path.fn_sig(self.tcx).skip_binder().output().walk();
if let Some(return_type)= fn_sig.next(){
Some(return_type.expect_ty())
}
else {
None
}
}
pub fn is_return_type_ref(&self,fn_expr:&Expr) -> bool{
if let Some(return_type)=self.return_type_of(fn_expr){
return_type.is_ref()
}
else{
false
}
}
pub fn is_return_type_copyable(&self,fn_expr:&Expr)->bool{
if let Some(return_type)=self.return_type_of(fn_expr){
if return_type.walk().fold(false,|flag,item|{flag||item.expect_ty().is_ref()}) {
false
}
else{
self.tcx.type_is_copy_modulo_regions(rustc_middle::ty::TypingEnv::post_analysis(self.tcx, fn_expr.hir_id.owner), return_type)
}
}
else{
false
}
}
pub fn update_lifetime(&mut self, name: &String, line:usize){
self.borrow_map.get_mut(name).unwrap().lifetime = line;
let aliasing = self.borrow_map.get(name).unwrap().aliasing.clone();
for r in aliasing.iter() {
self.update_lifetime(r, line);
}
}
pub fn ty_is_copy(&self, ty: Ty<'tcx>, owner: rustc_hir::OwnerId) -> bool {
self.tcx.type_is_copy_modulo_regions(
rustc_middle::ty::TypingEnv::post_analysis(self.tcx, owner),
ty,
)
}
pub fn add_owner(&mut self, name: String, mutability: bool, is_copy: bool, scope: usize, is_global: bool) {
self.add_rap(ResourceAccessPoint::Owner(Owner{name: name, hash: self.rap_hashes as u64, is_mut: mutability, is_copy}), scope, is_global);
}
pub fn add_ref(&mut self, name: String, ref_mutability: bool, lhs_mut: bool, line_num: usize, lender: ResourceTy, alia: VecDeque<String>, scope: usize, is_global: bool) {
match ref_mutability {
true => {
self.add_mut_ref(name.clone(), lhs_mut, scope, is_global);
}
false => {
self.add_static_ref(name.clone(), lhs_mut, scope, is_global);
}
}
self.borrow_map.insert(name.clone(), RefData { lender: lender.clone(), assigned_at: line_num, lifetime: line_num, ref_mutability: ref_mutability, aliasing: alia });
}
pub fn add_static_ref(&mut self, name: String, mutability: bool, scope: usize, is_global: bool) {
self.add_static_ref_member(name, mutability, scope, is_global, None);
}
pub fn add_mut_ref(&mut self, name: String, mutability: bool, scope: usize, is_global: bool) {
self.add_mut_ref_member(name, mutability, scope, is_global, None);
}
pub fn add_static_ref_member(
&mut self,
name: String,
mutability: bool,
scope: usize,
is_global: bool,
member_of: Option<u64>,
) {
self.add_rap(
ResourceAccessPoint::StaticRef(StaticRef {
name,
hash: self.rap_hashes as u64,
is_mut: mutability,
member_of,
}),
scope, is_global,
);
}
pub fn add_mut_ref_member(
&mut self,
name: String,
mutability: bool,
scope: usize,
is_global: bool,
member_of: Option<u64>,
) {
self.add_rap(
ResourceAccessPoint::MutRef(MutRef {
name,
hash: self.rap_hashes as u64,
is_mut: mutability,
member_of,
}),
scope, is_global,
);
}
pub fn add_fn(&mut self, name: String) {
self.add_rap(ResourceAccessPoint::Function(Function { name: name, hash: self.rap_hashes as u64 }), self.current_scope, true);
}
pub fn add_struct(&mut self, name: String, owner: u64, mem: bool, mutability: bool, is_copy: bool, scope: usize, is_global: bool) {
self.add_rap(ResourceAccessPoint::Struct(Struct {
name: name,
hash: self.rap_hashes as u64,
owner: owner,
is_mut: mutability,
is_member: mem,
is_copy }),
scope, is_global);
}
pub fn add_rap(&mut self, r: ResourceAccessPoint, scope: usize, is_global: bool) {
let fn_start_line = self.current_fn_start;
self.raps.entry(r.name().to_string()).or_insert_with(|| {
self.rap_hashes += 1;
RapData { rap: r, scope, is_global, fn_start_line }
});
}
pub fn update_rap(&mut self, r: &ResourceAccessPoint, line_num: usize) {
if r.is_ref() {
self.update_lifetime(r.name(), line_num);
}
}
pub fn add_external_event(&mut self, line_num: usize, event: ExternalEvent) {
self.preprocessed_events.push((line_num, event.clone()));
let resourceaccesspoint = ResourceAccessPoint_extract(&event);
match (resourceaccesspoint.0, resourceaccesspoint.1, &event) {
(ResourceTy::Value(ResourceAccessPoint::Function(_)), ResourceTy::Value(ResourceAccessPoint::Function(_)), _) => {
},
(ResourceTy::Value(ResourceAccessPoint::Function(_)),_, _) => {
},
(_, ResourceTy::Value(ResourceAccessPoint::Function(_function)),
ExternalEvent::PassByStaticReference{..}) => {
},
(_, ResourceTy::Value(ResourceAccessPoint::Function(_function)),
ExternalEvent::PassByMutableReference{..}) => {
},
(_, ResourceTy::Value(ResourceAccessPoint::Function(_)), _) => {
},
(ResourceTy::Anonymous, ResourceTy::Anonymous, _) | (_, ResourceTy::Caller, _) => {},
(ResourceTy::Value(_), ResourceTy::Value(_), _) | (ResourceTy::Deref(_), ResourceTy::Deref(_), _)
| (ResourceTy::Value(_), ResourceTy::Deref(_), _)
| (ResourceTy::Deref(_), ResourceTy::Value(_), _) => {
self.event_line_map.get_mut(&line_num).unwrap().push(event);
},
_ => ()
}
}
pub fn rap_holds_resource_now(&self, rap_name: &str) -> bool {
for (_, ev) in self.preprocessed_events.iter().rev() {
match ev {
ExternalEvent::Move { from, to, .. } => {
if to.extract_rap().map_or(false, |r| r.name() == rap_name) {
return true;
}
if from.extract_rap().map_or(false, |r| r.name() == rap_name) {
return false;
}
}
ExternalEvent::Copy { to, .. }
| ExternalEvent::Bind { to, .. } => {
if to.extract_rap().map_or(false, |r| r.name() == rap_name) {
return true;
}
}
_ => {}
}
}
false
}
pub fn ext_ev_of_evt(&self, evt: Evt, lhs: ResourceTy, rhs: ResourceTy, id: usize, is_partial: bool) -> ExternalEvent{
match evt {
Evt::Bind => ExternalEvent::Bind { from: rhs, to: lhs, id },
Evt::Copy => ExternalEvent::Copy { from: rhs, to: lhs, id, is_partial },
Evt::Move => ExternalEvent::Move { from: rhs, to: lhs, id, is_partial },
Evt::SBorrow => ExternalEvent::StaticBorrow { from: rhs, to: lhs, id, is_partial },
Evt::MBorrow => ExternalEvent::MutableBorrow { from: rhs, to: lhs, id, is_partial },
Evt::PassBySRef => ExternalEvent::PassByStaticReference { from: rhs, to: lhs, id },
Evt::PassByMRef => ExternalEvent::PassByMutableReference { from: rhs, to: lhs, id },
Evt::SDie => ExternalEvent::StaticDie { from: rhs, to: lhs, id },
Evt::MDie => ExternalEvent::MutableDie { from: rhs, to: lhs, id }
}
}
pub fn add_ev(&mut self, line_num: usize, evt: Evt, lhs: ResourceTy, rhs: ResourceTy, is_partial: bool) {
self.add_external_event(line_num, self.ext_ev_of_evt(evt, lhs, rhs, *self.unique_id, is_partial));
*self.unique_id += 1;
}
pub fn resource_of_lhs(&mut self, expr: &'tcx Expr) -> ResourceTy {
match expr.kind {
ExprKind::Path(QPath::Resolved(_, p)) => {
let name = self.tcx.hir_name(p.segments[0].hir_id).as_str().to_owned();
ResourceTy::Value(self.raps.get(&name).unwrap().rap.to_owned())
}
ExprKind::Field(expr, ident) => {
match expr {
Expr{kind: ExprKind::Path(QPath::Resolved(_,p)), ..} => {
let name = self.tcx.hir_name(p.segments[0].hir_id).as_str().to_owned();
let total_name = format!("{}.{}", name, ident.as_str());
ResourceTy::Value(self.raps.get(&total_name).unwrap().rap.to_owned())
}
_ => { panic!("unexpected field expr") }
}
}
ExprKind::Unary(UnOp::Deref, exp) => {
let rhs_rap = fetch_rap(&expr, &self.tcx, &self.raps);
let line_num = expr_to_line(&exp, &self.tcx);
match rhs_rap {
Some(x) => {
self.update_rap(&x, line_num);
ResourceTy::Deref(x)
}
None => { ResourceTy::Anonymous }
}
}
_ => panic!("invalid lhs")
}
}
pub fn match_arg(&mut self, arg: &'tcx Expr, fn_name: String) {
self.add_fn(fn_name.clone());
let line_num = expr_to_line(&arg, &self.tcx);
let tycheck_results = self.tcx.typeck(arg.hir_id.owner);
let arg_ty = tycheck_results.node_type(arg.hir_id);
let is_copyable = self.tcx.type_is_copy_modulo_regions(rustc_middle::ty::TypingEnv::post_analysis(self.tcx, arg.hir_id.owner), arg_ty);
let from_ro = get_rap(arg, &self.tcx, &self.raps);
let to_ro = ResourceTy::Value(self.raps.get(&fn_name).unwrap().rap.to_owned());
if arg_ty.is_ref() {
match arg_ty.ref_mutability().unwrap() {
Mutability::Not => self.add_ev(line_num, Evt::PassBySRef, to_ro, from_ro, false),
Mutability::Mut => self.add_ev(line_num, Evt::PassByMRef, to_ro, from_ro, false)
}
}
else {
match is_copyable {
true => self.add_ev(line_num, Evt::Copy, to_ro, from_ro, false),
false => self.add_ev(line_num, Evt::Move, to_ro, from_ro, false)
}
}
}
pub fn update_aliasing_data(& mut self, alias: &String, new_data: &BTreeMap<usize, String>, offset: usize) {
let ref_data = self.borrow_map.get_mut(alias).unwrap();
for (k, v) in new_data {
ref_data.aliasing.insert(*k + offset, v.to_owned());
}
}
pub fn get_ref_data(&self, expr: &'tcx Expr) -> (ResourceTy, VecDeque<String>){
if is_addr(&expr) {
let lender = get_rap(&expr, &self.tcx, &self.raps); let mut aliasing = get_aliasing_data(&lender, &self.borrow_map);
let ty = self.tcx.typeck(expr.hir_id.owner).node_type(expr.hir_id);
if ty.builtin_deref(false).unwrap().is_ref() {
match &lender {
ResourceTy::Anonymous | ResourceTy::Caller => { (lender, aliasing) }
ResourceTy::Value(x) | ResourceTy::Deref(x) => {
aliasing.push_front(x.name().to_owned()); (lender, aliasing)
}
}
}
else {
(lender, aliasing)
}
}
else { let lender = find_lender(&expr, &self.tcx, &self.raps, &self.borrow_map);
(find_lender(&expr, &self.tcx, &self.raps, &self.borrow_map), get_aliasing_data(&lender, &self.borrow_map))
}
}
pub fn define_lhs(&mut self, name: String, mutability: bool, expr: &'tcx Expr, ty: Ty <'tcx>) {
let is_special = ty_is_special_owner(&self.tcx, &ty);
if ty.is_ref() {
let (lender, aliasing) = self.get_ref_data(&expr);
self.add_ref(name.clone(),
bool_of_mut(ty.ref_mutability().unwrap()),
mutability,
expr_to_line(&expr, &self.tcx),
lender,
aliasing,
self.current_scope, !self.inside_branch);
}
else if ty.is_adt() && !is_special {
match ty.ty_adt_def().unwrap().adt_kind() {
AdtKind::Struct => {
let owner_hash = self.rap_hashes as u64;
let parent_is_copy = self.ty_is_copy(ty, expr.hir_id.owner);
self.add_struct(name.clone(), owner_hash, false, mutability, parent_is_copy, self.current_scope,!self.inside_branch);
let generic_args = match ty.kind() {
TyKind::Adt(_, args) => *args,
_ => unreachable!("ty.is_adt() but kind is not Adt"),
};
for field in ty.ty_adt_def().unwrap().all_fields() {
let field_name = format!("{}.{}", name.clone(), field.name.as_str());
let field_ty = field.ty(self.tcx, generic_args);
if field_ty.is_ref() {
let ref_mutability = bool_of_mut(field_ty.ref_mutability().unwrap());
if ref_mutability {
self.add_mut_ref_member(field_name.clone(), mutability,
self.current_scope, !self.inside_branch, Some(owner_hash));
} else {
self.add_static_ref_member(field_name.clone(), mutability,
self.current_scope, !self.inside_branch, Some(owner_hash));
}
self.borrow_map.insert(field_name, RefData {
lender: ResourceTy::Anonymous,
assigned_at: expr_to_line(&expr, &self.tcx),
lifetime: self.current_scope,
ref_mutability,
aliasing: VecDeque::new(),
});
} else {
let field_is_copy = self.ty_is_copy(field_ty, expr.hir_id.owner);
self.add_struct(field_name, owner_hash, true, mutability, field_is_copy,
self.current_scope, !self.inside_branch);
}
}
},
AdtKind::Union => {
warn!("lhs union not implemented yet")
},
AdtKind::Enum => {
let is_copy = self.ty_is_copy(ty, expr.hir_id.owner);
self.add_owner(name, mutability, is_copy, self.current_scope, !self.inside_branch);
}
}
}
else if ty.is_fn() {
error!("cannot have fn as lhs of expr");
}
else {
let is_copy = self.ty_is_copy(ty, expr.hir_id.owner);
self.add_owner(name, mutability, is_copy, self.current_scope, !self.inside_branch);
}
}
pub fn get_dec_of_pat2<'t>(
&mut self,
pat: &Pat,
ty_results: &'tcx TypeckResults<'tcx>,
parent: &ResourceTy,
parent_ty: &'t Ty<'tcx>,
scope: usize,
res: &'t mut Vec<(ResourceAccessPoint, Evt, Ty<'tcx>)>,
) {
match pat.kind {
PatKind::TupleStruct(_p, tuple_members, _) => {
for p in tuple_members.iter() {
self.get_dec_of_pat2(p, ty_results, parent, parent_ty, scope, res);
}
}
PatKind::Binding(mode, id, ident, _) => {
let muta = bool_of_mut(mode.1); let line_num = span_to_line(&ident.span, &self.tcx); let ty: Ty<'tcx> = ty_results.node_type(id);
let name = ident.to_string();
if ty.is_ref() {
let ref_mutability = bool_of_mut(ty.ref_mutability().unwrap()); self.add_ref(name.clone(), ref_mutability, muta, line_num, parent.clone(), VecDeque::new(), scope, false);
} else if ty.is_adt() {
match ty.ty_adt_def().unwrap().adt_kind() {
AdtKind::Struct => {
let owner_hash = self.rap_hashes as u64; let parent_is_copy = self.ty_is_copy(ty, pat.hir_id.owner);
self.add_struct(name.clone(), owner_hash, false, muta, parent_is_copy, scope, false);
let generic_args = match ty.kind() {
TyKind::Adt(_, args) => *args,
_ => unreachable!("ty.is_adt() but kind is not Adt"),
};
for field in ty.ty_adt_def().unwrap().all_fields() {
let field_name = format!("{}.{}", name, field.name.as_str());
let field_ty = field.ty(self.tcx, generic_args);
let field_is_copy = self.ty_is_copy(field_ty, pat.hir_id.owner);
self.add_struct(field_name, owner_hash, true, muta, field_is_copy, scope, false);
}
},
AdtKind::Union => {
panic!("union not implemented yet")
},
AdtKind::Enum => {
let is_copy = self.ty_is_copy(ty, pat.hir_id.owner);
self.add_owner(name.clone(), muta, is_copy, scope, false);
}
}
} else {
let is_copy = self.ty_is_copy(ty, pat.hir_id.owner);
self.add_owner(name.clone(), muta, is_copy, scope, false);
}
let evt = if parent_ty.is_ref() {
if bool_of_mut(parent_ty.ref_mutability().unwrap()) { Evt::MBorrow }
else { Evt::SBorrow }
} else {
if self.tcx.type_is_copy_modulo_regions(rustc_middle::ty::TypingEnv::post_analysis(self.tcx, pat.hir_id.owner), ty) { Evt::Copy }
else { Evt::Move }
};
res.push((self.raps.get(&name).unwrap().rap.to_owned(), evt, parent_ty.clone()));
}
_ => {}
}
}
pub fn match_rhs(&mut self, lhs: ResourceTy, rhs:&'tcx Expr, evt: Evt){
match rhs.kind {
ExprKind::Path(QPath::Resolved(_,p)) => {
let line_num = span_to_line(&p.span, &self.tcx);
let rhs_name: String = match p.res {
Res::Def(rustc_hir::def::DefKind::Ctor(_, _), _) => {
let mut name = String::new();
for (i, segment) in p.segments.iter().enumerate() {
name.push_str(self.tcx.hir_name(segment.hir_id).as_str());
if i < p.segments.len() - 1 {
name.push_str("::");
}
}
name
}
_ => {
self.tcx.hir_name(p.segments[0].hir_id).as_str().to_owned()
}
};
let rhs_rap = self.raps.get(&rhs_name).unwrap().rap.to_owned();
self.update_rap(&rhs_rap, line_num);
self.add_ev(line_num, evt, lhs, ResourceTy::Value(rhs_rap), false);
},
ExprKind::Call(fn_expr, _) => {
let line_num = span_to_line(&fn_expr.span, &self.tcx);
let fn_name = hirid_to_var_name(fn_expr.hir_id, &self.tcx).unwrap();
let rhs_rap = self.raps.get(&fn_name).unwrap().rap.to_owned();
self.add_ev(line_num, evt, lhs, ResourceTy::Value(rhs_rap), false);
},
ExprKind::Lit(_) | ExprKind::Binary(..) | ExprKind::Unary(UnOp::Neg, _) | ExprKind::Unary(UnOp::Not, _) => {
let line_num = span_to_line(&rhs.span, &self.tcx);
self.add_ev(line_num, Evt::Bind, lhs, ResourceTy::Anonymous, false);
}
ExprKind::AddrOf(_, _,expr) => {
let line_num = expr_to_line(&expr, &self.tcx);
match fetch_rap(&expr, &self.tcx, &self.raps) {
Some(rhs_rap) => {
self.update_rap(&rhs_rap, expr_to_line(&expr, &self.tcx));
}
None => {} }
let res = match fetch_rap(rhs, &self.tcx, &self.raps) {
Some(x) => ResourceTy::Value(x),
None => ResourceTy::Anonymous
};
match fetch_mutability(&rhs) { Some(Mutability::Not) => self.add_ev(line_num, Evt::SBorrow, lhs, res, false),
Some(Mutability::Mut) => self.add_ev(line_num, Evt::MBorrow, lhs, res, false),
None => panic!("Shouldn't have been able to get here")
}
}
ExprKind::Block(block, _) => {
let prev_scope = self.current_scope;
let new_scope = self.tcx.sess.source_map().lookup_char_pos(rhs.span.hi()).line;
self.current_scope = new_scope;
self.current_scope = prev_scope;
match block.expr {
Some(res_expr) => {
self.match_rhs(lhs.clone(), res_expr, evt);
}
None => {}
}
}
ExprKind::Unary(option, expr) => {
match option {
rustc_hir::UnOp::Deref => {
let line_num = expr_to_line(&expr, &self.tcx);
let rhs_rap = fetch_rap(&expr, &self.tcx, &self.raps);
let res = match rhs_rap {
Some(x) => {
self.update_rap(&x, line_num);
ResourceTy::Deref(x)
}
None => {
ResourceTy::Anonymous
}
};
self.add_ev(line_num, evt, lhs, res, false);
},
_ => {}
}
}
ExprKind::MethodCall(name_and_generic_args, rcvr, _, _) => {
let line_num = span_to_line(&rcvr.span, &self.tcx);
let chain_lender = match &lhs {
ResourceTy::Value(rap) if rap.is_ref() => {
self.borrow_map.get(rap.name()).map(|rd| rd.lender.clone())
}
_ => None,
};
if let Some(ResourceTy::Value(_)) = chain_lender {
let lender_rty = chain_lender.unwrap();
let borrow_evt = match &lhs {
ResourceTy::Value(rap) if rap.is_mutref() => Evt::MBorrow,
_ => Evt::SBorrow,
};
self.add_ev(line_num, borrow_evt, lhs, lender_rty, false);
return;
}
let fn_name = hirid_to_var_name(name_and_generic_args.hir_id, &self.tcx).unwrap();
let rhs_rap = self.raps.get(&fn_name).unwrap().rap.to_owned();
self.add_ev(line_num, evt, lhs, ResourceTy::Value(rhs_rap), false);
}
ExprKind::Struct(_qpath, expr_fields, _base) => {
let line_num = span_to_line(&rhs.span, &self.tcx);
self.add_ev(line_num, Evt::Bind, lhs.clone(), ResourceTy::Anonymous, false);
for field in expr_fields.iter() {
let new_lhs_name = format!("{}.{}", lhs.name(), field.ident.as_str());
let field_rap = self.raps.get(&new_lhs_name).unwrap().rap.to_owned();
let field_ty = self.tcx.typeck(field.expr.hir_id.owner).node_type(field.expr.hir_id);
let is_copyable = self.tcx.type_is_copy_modulo_regions(rustc_middle::ty::TypingEnv::post_analysis(self.tcx, field.expr.hir_id.owner), field_ty);
let e = if field_ty.is_ref() {
match field_ty.ref_mutability().unwrap() {
Mutability::Not => Evt::Copy,
Mutability::Mut => Evt::Move,
}
} else {
match is_copyable {
true => Evt::Copy,
false => Evt::Move
}
};
if field_ty.is_ref() {
let (lender, aliasing) = self.get_ref_data(&field.expr);
if let Some(rd) = self.borrow_map.get_mut(&new_lhs_name) {
rd.lender = lender;
rd.aliasing = aliasing;
}
}
self.match_rhs(ResourceTy::Value(field_rap), field.expr, e);
}
},
ExprKind::Field(expr, id) => {
match expr {
Expr{kind: ExprKind::Path(QPath::Resolved(_,p)), ..} => {
let line_num = span_to_line(&p.span, &self.tcx);
let name = self.tcx.hir_name(p.segments[0].hir_id).as_str().to_owned();
let total_name = format!("{}.{}", name, id.as_str());
let rhs_rap = self.raps.get(&total_name).unwrap().rap.to_owned();
self.add_ev(line_num, evt, lhs, ResourceTy::Value(rhs_rap), false);
}
_ => panic!("unexpected field expr")
}
}
ExprKind::Ret(ret) => {
match ret {
Some(ret_expr) => {
self.match_rhs(lhs, ret_expr, evt);
}
None => {}
}
},
ExprKind::If(_, if_block, else_block) => {
self.match_rhs(lhs.clone(), &if_block, evt.clone());
match else_block {
Some(e) => self.match_rhs(lhs, &e, evt),
None => {}
}
}
ExprKind::DropTemps(exp) => {
self.match_rhs(lhs, &exp, evt);
}
_ => {
warn!("unmatched rhs {:#?}", rhs);
}
}
}
pub fn print_out_of_scope(&mut self){
for (_, rap) in self.raps.clone().iter() {
if !rap.rap.is_fn() && rap.is_global {
let mut duplicate = false;
for (_l, e) in self.preprocessed_events.iter() {
match e.is_gos_ev() {
Some(r) => {
if *r == rap.rap {
duplicate = true;
break;
}
}
None => {}
}
}
if !duplicate {
self.add_external_event(rap.scope, ExternalEvent::GoOutOfScope { ro: rap.rap.clone(), id: *self.unique_id });
*self.unique_id += 1;
}
}
}
}
pub fn print_lifetimes(&mut self){
let mir_b_data = self.gather_borrow_data(&self.bwf);
for (_name, data) in self.borrow_map.iter_mut() {
for m_data in mir_b_data.iter() {
match ExprVisitor::borrow_match(data, m_data) {
Some(kill) => {
data.lifetime = kill;
break;
}
None => {}
}
}
}
info!("BORROW MAP {:#?}", self.borrow_map);
let mut ultimate_refs: HashSet<String> = HashSet::new();
let lender_to_refs = get_non_anon_lenders(&self.borrow_map);
info!("lender to refs {:#?}", lender_to_refs);
for (_, refs) in lender_to_refs.iter() {
let regions = get_regions(refs, &self.borrow_map);
for region in regions.iter() {
let mut max_lifetime: usize = 0;
for r in region {
let lifetime = self.borrow_map.get(r).unwrap().lifetime;
if lifetime > max_lifetime {
max_lifetime = lifetime;
}
}
for r in region {
if self.borrow_map.get(r).unwrap().lifetime == max_lifetime {
ultimate_refs.insert(r.to_owned());
}
}
}
}
for (name, ref_data) in self.borrow_map.iter() {
match ref_data.lender {
ResourceTy::Anonymous => {
ultimate_refs.insert(name.to_owned());
}
_ => {}
}
}
let b_map = self.borrow_map.clone();
let mut vec: Vec<(String, RefData)> = b_map.into_iter().collect();
vec.sort_by(|a, b| b.1.aliasing.len().cmp(&a.1.aliasing.len()));
for (k, RefData {lender: r_ty, assigned_at: _, lifetime, ref_mutability: ref_mut, aliasing: _}) in &vec {
let from_ro = self.raps.get(k).unwrap().rap.to_owned();
let to_ro = match r_ty {
ResourceTy::Anonymous => ResourceTy::Deref(from_ro.clone()),
_ => r_ty.clone()
};
if !ultimate_refs.contains(k) {
self.add_external_event(*lifetime, ExternalEvent::RefDie {
from: ResourceTy::Value(from_ro.clone()), to: to_ro, num_curr_borrowers: get_borrowers(from_ro.name(), &self.borrow_map).len() - 1,
id: *self.unique_id });
*self.unique_id += 1;
}
else {
match ref_mut {
true => {
self.add_ev(*lifetime, Evt::MDie, to_ro, ResourceTy::Value(from_ro), false);
}
false => {
self.add_ev(*lifetime, Evt::SDie, to_ro, ResourceTy::Value(from_ro), false);
}
}
}
}
}
}