3 use rustc::mir::{Body, BodyCache, Local, Location, PlaceElem, ReadOnlyBodyCache, VarDebugInfo};
4 use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
6 use rustc_index::vec::IndexVec;
9 pub struct DefUseAnalysis {
10 info: IndexVec<Local, Info>,
15 // FIXME(eddyb) use smallvec where possible.
16 pub defs_and_uses: Vec<Use>,
17 var_debug_info_indices: Vec<usize>,
22 pub context: PlaceContext,
23 pub location: Location,
27 pub fn new(body: &Body<'_>) -> DefUseAnalysis {
29 info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()),
33 pub fn analyze(&mut self, body: ReadOnlyBodyCache<'_, '_>) {
36 let mut finder = DefUseFinder {
37 info: mem::take(&mut self.info),
38 var_debug_info_index: 0,
39 in_var_debug_info: false,
41 finder.visit_body(body);
42 self.info = finder.info
46 for info in &mut self.info {
51 pub fn local_info(&self, local: Local) -> &Info {
55 fn mutate_defs_and_uses(
58 body: &mut BodyCache<'tcx>,
62 let mut visitor = MutateUseVisitor::new(local, new_local, tcx);
63 let info = &self.info[local];
64 for place_use in &info.defs_and_uses {
65 visitor.visit_location(body, place_use.location)
67 // Update debuginfo as well, alongside defs/uses.
68 for &i in &info.var_debug_info_indices {
69 visitor.visit_var_debug_info(&mut body.var_debug_info[i]);
73 // FIXME(pcwalton): this should update the def-use chains.
74 pub fn replace_all_defs_and_uses_with(&self,
76 body: &mut BodyCache<'tcx>,
79 self.mutate_defs_and_uses(local, body, new_local, tcx)
84 info: IndexVec<Local, Info>,
85 var_debug_info_index: usize,
86 in_var_debug_info: bool,
89 impl Visitor<'_> for DefUseFinder {
90 fn visit_local(&mut self,
92 context: PlaceContext,
94 let info = &mut self.info[local];
95 if self.in_var_debug_info {
96 info.var_debug_info_indices.push(self.var_debug_info_index);
98 info.defs_and_uses.push(Use {
104 fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo<'tcx>) {
105 assert!(!self.in_var_debug_info);
106 self.in_var_debug_info = true;
107 self.super_var_debug_info(var_debug_info);
108 self.in_var_debug_info = false;
109 self.var_debug_info_index += 1;
116 defs_and_uses: vec![],
117 var_debug_info_indices: vec![],
121 fn clear(&mut self) {
122 self.defs_and_uses.clear();
123 self.var_debug_info_indices.clear();
126 pub fn def_count(&self) -> usize {
127 self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count()
130 pub fn def_count_not_including_drop(&self) -> usize {
131 self.defs_not_including_drop().count()
134 pub fn defs_not_including_drop(
136 ) -> impl Iterator<Item=&Use> {
137 self.defs_and_uses.iter().filter(|place_use| {
138 place_use.context.is_mutating_use() && !place_use.context.is_drop()
142 pub fn use_count(&self) -> usize {
143 self.defs_and_uses.iter().filter(|place_use| {
144 place_use.context.is_nonmutating_use()
149 struct MutateUseVisitor<'tcx> {
155 impl MutateUseVisitor<'tcx> {
160 ) -> MutateUseVisitor<'tcx> {
161 MutateUseVisitor { query, new_local, tcx }
165 impl MutVisitor<'tcx> for MutateUseVisitor<'tcx> {
166 fn tcx(&self) -> TyCtxt<'tcx> {
170 fn visit_local(&mut self,
172 _context: PlaceContext,
173 _location: Location) {
174 if *local == self.query {
175 *local = self.new_local;
179 fn process_projection_elem(
181 elem: &PlaceElem<'tcx>,
182 ) -> Option<PlaceElem<'tcx>> {
184 PlaceElem::Index(local) if *local == self.query => {
185 Some(PlaceElem::Index(self.new_local))