1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 use rustc::mir::{Local, Location, Lvalue, Mir};
14 use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
15 use rustc_data_structures::indexed_vec::IndexVec;
16 use std::marker::PhantomData;
19 pub struct DefUseAnalysis<'tcx> {
20 info: IndexVec<Local, Info<'tcx>>,
24 pub struct Info<'tcx> {
25 pub defs_and_uses: Vec<Use<'tcx>>,
29 pub struct Use<'tcx> {
30 pub context: LvalueContext<'tcx>,
31 pub location: Location,
34 impl<'tcx> DefUseAnalysis<'tcx> {
35 pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> {
37 info: IndexVec::from_elem_n(Info::new(), mir.local_decls.len()),
41 pub fn analyze(&mut self, mir: &Mir<'tcx>) {
42 let mut finder = DefUseFinder {
43 info: mem::replace(&mut self.info, IndexVec::new()),
45 finder.visit_mir(mir);
46 self.info = finder.info
49 pub fn local_info(&self, local: Local) -> &Info<'tcx> {
53 pub fn local_info_mut(&mut self, local: Local) -> &mut Info<'tcx> {
57 fn mutate_defs_and_uses<F>(&self, local: Local, mir: &mut Mir<'tcx>, mut callback: F)
58 where F: for<'a> FnMut(&'a mut Lvalue<'tcx>,
61 for lvalue_use in &self.info[local].defs_and_uses {
62 MutateUseVisitor::new(local,
64 mir).visit_location(mir, lvalue_use.location)
68 /// FIXME(pcwalton): This should update the def-use chains.
69 pub fn replace_all_defs_and_uses_with(&self,
72 new_lvalue: Lvalue<'tcx>) {
73 self.mutate_defs_and_uses(local, mir, |lvalue, _, _| *lvalue = new_lvalue.clone())
77 struct DefUseFinder<'tcx> {
78 info: IndexVec<Local, Info<'tcx>>,
81 impl<'tcx> DefUseFinder<'tcx> {
82 fn lvalue_mut_info(&mut self, lvalue: &Lvalue<'tcx>) -> Option<&mut Info<'tcx>> {
83 let info = &mut self.info;
85 if let Lvalue::Local(local) = *lvalue {
86 Some(&mut info[local])
93 impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> {
94 fn visit_lvalue(&mut self,
95 lvalue: &Lvalue<'tcx>,
96 context: LvalueContext<'tcx>,
98 if let Some(ref mut info) = self.lvalue_mut_info(lvalue) {
99 info.defs_and_uses.push(Use {
104 self.super_lvalue(lvalue, context, location)
108 impl<'tcx> Info<'tcx> {
109 fn new() -> Info<'tcx> {
111 defs_and_uses: vec![],
115 pub fn def_count(&self) -> usize {
116 self.defs_and_uses.iter().filter(|lvalue_use| lvalue_use.context.is_mutating_use()).count()
119 pub fn def_count_not_including_drop(&self) -> usize {
120 self.defs_and_uses.iter().filter(|lvalue_use| {
121 lvalue_use.context.is_mutating_use() && !lvalue_use.context.is_drop()
125 pub fn use_count(&self) -> usize {
126 self.defs_and_uses.iter().filter(|lvalue_use| {
127 lvalue_use.context.is_nonmutating_use()
132 struct MutateUseVisitor<'tcx, F> {
135 phantom: PhantomData<&'tcx ()>,
138 impl<'tcx, F> MutateUseVisitor<'tcx, F> {
139 fn new(query: Local, callback: F, _: &Mir<'tcx>)
140 -> MutateUseVisitor<'tcx, F>
141 where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
145 phantom: PhantomData,
150 impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F>
151 where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) {
152 fn visit_lvalue(&mut self,
153 lvalue: &mut Lvalue<'tcx>,
154 context: LvalueContext<'tcx>,
155 location: Location) {
156 if let Lvalue::Local(local) = *lvalue {
157 if local == self.query {
158 (self.callback)(lvalue, context, location)
161 self.super_lvalue(lvalue, context, location)