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;
11 pub struct DefUseAnalysis<'tcx> {
12 info: IndexVec<Local, Info<'tcx>>,
16 pub struct Info<'tcx> {
17 pub defs_and_uses: Vec<Use<'tcx>>,
21 pub struct Use<'tcx> {
22 pub context: PlaceContext<'tcx>,
23 pub location: Location,
26 impl<'tcx> DefUseAnalysis<'tcx> {
27 pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> {
29 info: IndexVec::from_elem_n(Info::new(), mir.local_decls.len()),
33 pub fn analyze(&mut self, mir: &Mir<'tcx>) {
36 let mut finder = DefUseFinder {
37 info: mem::replace(&mut self.info, IndexVec::new()),
39 finder.visit_mir(mir);
40 self.info = finder.info
44 for info in &mut self.info {
49 pub fn local_info(&self, local: Local) -> &Info<'tcx> {
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,
57 for place_use in &self.info[local].defs_and_uses {
58 MutateUseVisitor::new(local,
60 mir).visit_location(mir, place_use.location)
64 // FIXME(pcwalton): this should update the def-use chains.
65 pub fn replace_all_defs_and_uses_with(&self,
69 self.mutate_defs_and_uses(local, mir, |local, _, _| *local = new_local)
73 struct DefUseFinder<'tcx> {
74 info: IndexVec<Local, Info<'tcx>>,
77 impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> {
78 fn visit_local(&mut self,
80 context: PlaceContext<'tcx>,
82 self.info[local].defs_and_uses.push(Use {
89 impl<'tcx> Info<'tcx> {
90 fn new() -> Info<'tcx> {
92 defs_and_uses: vec![],
97 self.defs_and_uses.clear();
100 pub fn def_count(&self) -> usize {
101 self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count()
104 pub fn def_count_not_including_drop(&self) -> usize {
105 self.defs_not_including_drop().count()
108 pub fn defs_not_including_drop(
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()
116 pub fn use_count(&self) -> usize {
117 self.defs_and_uses.iter().filter(|place_use| {
118 place_use.context.is_nonmutating_use()
123 struct MutateUseVisitor<'tcx, F> {
126 phantom: PhantomData<&'tcx ()>,
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) {
136 phantom: PhantomData,
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,
145 context: PlaceContext<'tcx>,
146 location: Location) {
147 if *local == self.query {
148 (self.callback)(local, context, location)