use crate::helpers::mir_utils;
use crate::compat::Spanned;
use rustc_hir::def_id::DefId;
use rustc_middle::mir::{BasicBlock, Body, Operand, Place};
use rustc_middle::ty::{TyCtxt, TyKind};
use crate::analysis::dataflow::types::DataflowGraph;
use super::super::call_summary;
use crate::helpers::def_use::{call_args_uses_at, PlaceKey, RelevantPlaces};
use super::types::RelevantItem;
#[allow(clippy::too_many_arguments)]
pub(crate) fn visit<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: DefId,
block: BasicBlock,
func: &Operand<'tcx>,
args: &[Spanned<Operand<'tcx>>],
destination: &Place<'tcx>,
flow: &DataflowGraph,
body: &Body<'tcx>,
relevant: &mut RelevantPlaces,
items: &mut Vec<RelevantItem<'tcx>>,
) {
let mut defs = RelevantPlaces::new();
defs.insert_mir_place(destination);
let tpos = body.basic_blocks[block].statements.len();
let mut arg_uses = RelevantPlaces::new();
for &edge_idx in &flow.node(destination.local).in_edges {
let edge = &flow.edges[edge_idx];
if edge.block == block.as_usize() && edge.statement_index == tpos {
arg_uses.insert_local(edge.src);
}
}
let summary = call_summary::dependency_summary(tcx, func, args.len());
if defs.intersects(relevant) {
items.push(RelevantItem::Terminator { def_id, block, switch_succ: None });
relevant.remove_all(&defs);
relevant.extend(call_args_uses_at(args, &summary.return_depends_on_args));
return;
}
let dest_is_ptr = matches!(
body.local_decls[destination.local].ty.kind(),
TyKind::RawPtr(..) | TyKind::Ref(..)
);
if dest_is_ptr && summary.must_write_args.is_empty() {
items.push(RelevantItem::Terminator { def_id, block, switch_succ: None });
relevant.remove_all(&defs);
relevant.extend(call_args_uses_at(args, &summary.return_depends_on_args));
return;
}
let summarized_write = !summary.must_write_args.is_empty();
if summarized_write || arg_uses.intersects(relevant) {
items.push(RelevantItem::Terminator { def_id, block, switch_succ: None });
relevant.extend(call_args_uses_at(args, &summary.must_write_args));
}
if !relevant.need_len.is_empty() {
let callee = mir_utils::dep_callee_def_id(func);
if crate::verify::api_classify::is_len(callee)
&& let Some(first) = args.first() {
let arg_place = mir_utils::operand_place(&first.node);
if let Some(arg_key) = arg_place {
let matches = relevant.need_len.contains(&arg_key)
|| relevant.need_len.iter().any(|nl| {
crate::helpers::def_use::trace_place_origin(flow, nl)
== crate::helpers::def_use::trace_place_origin(flow, &arg_key)
});
if matches {
let dest_key = PlaceKey::from_mir_place(destination);
if relevant.places.insert(dest_key.clone()) {
relevant.just_added.insert(dest_key.clone());
}
if let Some(local) = dest_key.local() {
relevant.locals.insert(local);
}
items.push(RelevantItem::Terminator { def_id, block, switch_succ: None });
}
}
}
}
}