]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/util/def_use.rs
2e41c6e493bc35b777d67e09931919c436a16f07
[rust.git] / src / librustc_mir / util / def_use.rs
1 //! Def-use analysis.
2
3 use rustc::mir::{Local, Location, Mir};
4 use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
5 use rustc_data_structures::indexed_vec::IndexVec;
6 use std::marker::PhantomData;
7 use std::mem;
8 use std::slice;
9 use std::iter;
10
11 pub struct DefUseAnalysis<'tcx> {
12     info: IndexVec<Local, Info<'tcx>>,
13 }
14
15 #[derive(Clone)]
16 pub struct Info<'tcx> {
17     pub defs_and_uses: Vec<Use<'tcx>>,
18 }
19
20 #[derive(Clone)]
21 pub struct Use<'tcx> {
22     pub context: PlaceContext<'tcx>,
23     pub location: Location,
24 }
25
26 impl<'tcx> DefUseAnalysis<'tcx> {
27     pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> {
28         DefUseAnalysis {
29             info: IndexVec::from_elem_n(Info::new(), mir.local_decls.len()),
30         }
31     }
32
33     pub fn analyze(&mut self, mir: &Mir<'tcx>) {
34         self.clear();
35
36         let mut finder = DefUseFinder {
37             info: mem::replace(&mut self.info, IndexVec::new()),
38         };
39         finder.visit_mir(mir);
40         self.info = finder.info
41     }
42
43     fn clear(&mut self) {
44         for info in &mut self.info {
45             info.clear();
46         }
47     }
48
49     pub fn local_info(&self, local: Local) -> &Info<'tcx> {
50         &self.info[local]
51     }
52
53     fn mutate_defs_and_uses<F>(&self, local: Local, mir: &mut Mir<'tcx>, mut callback: F)
54                                where F: for<'a> FnMut(&'a mut Local,
55                                                       PlaceContext<'tcx>,
56                                                       Location) {
57         for place_use in &self.info[local].defs_and_uses {
58             MutateUseVisitor::new(local,
59                                   &mut callback,
60                                   mir).visit_location(mir, place_use.location)
61         }
62     }
63
64     // FIXME(pcwalton): this should update the def-use chains.
65     pub fn replace_all_defs_and_uses_with(&self,
66                                           local: Local,
67                                           mir: &mut Mir<'tcx>,
68                                           new_local: Local) {
69         self.mutate_defs_and_uses(local, mir, |local, _, _| *local = new_local)
70     }
71 }
72
73 struct DefUseFinder<'tcx> {
74     info: IndexVec<Local, Info<'tcx>>,
75 }
76
77 impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> {
78     fn visit_local(&mut self,
79                    &local: &Local,
80                    context: PlaceContext<'tcx>,
81                    location: Location) {
82         self.info[local].defs_and_uses.push(Use {
83             context,
84             location,
85         });
86     }
87 }
88
89 impl<'tcx> Info<'tcx> {
90     fn new() -> Info<'tcx> {
91         Info {
92             defs_and_uses: vec![],
93         }
94     }
95
96     fn clear(&mut self) {
97         self.defs_and_uses.clear();
98     }
99
100     pub fn def_count(&self) -> usize {
101         self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count()
102     }
103
104     pub fn def_count_not_including_drop(&self) -> usize {
105         self.defs_not_including_drop().count()
106     }
107
108     pub fn defs_not_including_drop(
109         &self,
110     ) -> iter::Filter<slice::Iter<'_, Use<'tcx>>, fn(&&Use<'tcx>) -> bool> {
111         self.defs_and_uses.iter().filter(|place_use| {
112             place_use.context.is_mutating_use() && !place_use.context.is_drop()
113         })
114     }
115
116     pub fn use_count(&self) -> usize {
117         self.defs_and_uses.iter().filter(|place_use| {
118             place_use.context.is_nonmutating_use()
119         }).count()
120     }
121 }
122
123 struct MutateUseVisitor<'tcx, F> {
124     query: Local,
125     callback: F,
126     phantom: PhantomData<&'tcx ()>,
127 }
128
129 impl<'tcx, F> MutateUseVisitor<'tcx, F> {
130     fn new(query: Local, callback: F, _: &Mir<'tcx>)
131            -> MutateUseVisitor<'tcx, F>
132            where F: for<'a> FnMut(&'a mut Local, PlaceContext<'tcx>, Location) {
133         MutateUseVisitor {
134             query,
135             callback,
136             phantom: PhantomData,
137         }
138     }
139 }
140
141 impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F>
142               where F: for<'a> FnMut(&'a mut Local, PlaceContext<'tcx>, Location) {
143     fn visit_local(&mut self,
144                     local: &mut Local,
145                     context: PlaceContext<'tcx>,
146                     location: Location) {
147         if *local == self.query {
148             (self.callback)(local, context, location)
149         }
150     }
151 }