3 use rustc::mir::{Body, Local, Location, Place, PlaceElem};
4 use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
5 use rustc_index::vec::IndexVec;
8 pub struct DefUseAnalysis {
9 info: IndexVec<Local, Info>,
14 pub defs_and_uses: Vec<Use>,
19 pub context: PlaceContext,
20 pub location: Location,
24 pub fn new(body: &Body<'_>) -> DefUseAnalysis {
26 info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()),
30 pub fn analyze(&mut self, body: &Body<'_>) {
33 let mut finder = DefUseFinder {
34 info: mem::take(&mut self.info),
36 finder.visit_body(body);
37 self.info = finder.info
41 for info in &mut self.info {
46 pub fn local_info(&self, local: Local) -> &Info {
50 fn mutate_defs_and_uses(&self, local: Local, body: &mut Body<'_>, new_local: Local) {
51 for place_use in &self.info[local].defs_and_uses {
52 MutateUseVisitor::new(local,
54 body).visit_location(body, place_use.location)
58 // FIXME(pcwalton): this should update the def-use chains.
59 pub fn replace_all_defs_and_uses_with(&self,
63 self.mutate_defs_and_uses(local, body, new_local)
68 info: IndexVec<Local, Info>,
71 impl Visitor<'_> for DefUseFinder {
72 fn visit_local(&mut self,
74 context: PlaceContext,
76 self.info[local].defs_and_uses.push(Use {
86 defs_and_uses: vec![],
91 self.defs_and_uses.clear();
94 pub fn def_count(&self) -> usize {
95 self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count()
98 pub fn def_count_not_including_drop(&self) -> usize {
99 self.defs_not_including_drop().count()
102 pub fn defs_not_including_drop(
104 ) -> impl Iterator<Item=&Use> {
105 self.defs_and_uses.iter().filter(|place_use| {
106 place_use.context.is_mutating_use() && !place_use.context.is_drop()
110 pub fn use_count(&self) -> usize {
111 self.defs_and_uses.iter().filter(|place_use| {
112 place_use.context.is_nonmutating_use()
117 struct MutateUseVisitor {
122 impl MutateUseVisitor {
123 fn new(query: Local, new_local: Local, _: &Body<'_>) -> MutateUseVisitor {
131 impl MutVisitor<'_> for MutateUseVisitor {
132 fn visit_local(&mut self,
134 _context: PlaceContext,
135 _location: Location) {
136 if *local == self.query {
137 *local = self.new_local;
141 fn visit_place(&mut self,
142 place: &mut Place<'tcx>,
143 context: PlaceContext,
144 location: Location) {
145 self.visit_place_base(&mut place.base, context, location);
147 let new_projection: Vec<_> = place.projection.iter().map(|elem|
149 PlaceElem::Index(local) if *local == self.query => {
150 PlaceElem::Index(self.new_local)
156 place.projection = new_projection.into_boxed_slice();