clippy_utils/mir/
possible_origin.rs

1use super::transitive_relation::TransitiveRelation;
2use crate::ty::is_copy;
3use rustc_data_structures::fx::FxHashMap;
4use rustc_index::bit_set::DenseBitSet;
5use rustc_lint::LateContext;
6use rustc_middle::mir;
7
8/// Collect possible borrowed for every `&mut` local.
9/// For example, `_1 = &mut _2` generate _1: {_2,...}
10/// Known Problems: not sure all borrowed are tracked
11#[allow(clippy::module_name_repetitions)]
12pub(super) struct PossibleOriginVisitor<'a, 'tcx> {
13    possible_origin: TransitiveRelation,
14    body: &'a mir::Body<'tcx>,
15}
16
17impl<'a, 'tcx> PossibleOriginVisitor<'a, 'tcx> {
18    pub fn new(body: &'a mir::Body<'tcx>) -> Self {
19        Self {
20            possible_origin: TransitiveRelation::default(),
21            body,
22        }
23    }
24
25    pub fn into_map(self, cx: &LateContext<'tcx>) -> FxHashMap<mir::Local, DenseBitSet<mir::Local>> {
26        let mut map = FxHashMap::default();
27        for row in (1..self.body.local_decls.len()).map(mir::Local::from_usize) {
28            if is_copy(cx, self.body.local_decls[row].ty) {
29                continue;
30            }
31
32            let mut borrowers = self.possible_origin.reachable_from(row, self.body.local_decls.len());
33            borrowers.remove(mir::Local::from_usize(0));
34            if !borrowers.is_empty() {
35                map.insert(row, borrowers);
36            }
37        }
38        map
39    }
40}
41
42impl<'tcx> mir::visit::Visitor<'tcx> for PossibleOriginVisitor<'_, 'tcx> {
43    fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _location: mir::Location) {
44        let lhs = place.local;
45        match rvalue {
46            // Only consider `&mut`, which can modify origin place
47            mir::Rvalue::Ref(_, mir::BorrowKind::Mut { .. }, borrowed) |
48            // _2: &mut _;
49            // _3 = move _2
50            mir::Rvalue::Use(mir::Operand::Move(borrowed))  |
51            // _3 = move _2 as &mut _;
52            mir::Rvalue::Cast(_, mir::Operand::Move(borrowed), _)
53                => {
54                self.possible_origin.add(lhs, borrowed.local);
55            },
56            _ => {},
57        }
58    }
59}