]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/def_use.rs
Minor grammar fix 'can not' -> 'cannot'
[rust.git] / src / librustc_mir / def_use.rs
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.
4 //
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.
10
11 //! Def-use analysis.
12
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;
17 use std::mem;
18
19 pub struct DefUseAnalysis<'tcx> {
20     info: IndexVec<Local, Info<'tcx>>,
21 }
22
23 #[derive(Clone)]
24 pub struct Info<'tcx> {
25     pub defs_and_uses: Vec<Use<'tcx>>,
26 }
27
28 #[derive(Clone)]
29 pub struct Use<'tcx> {
30     pub context: LvalueContext<'tcx>,
31     pub location: Location,
32 }
33
34 impl<'tcx> DefUseAnalysis<'tcx> {
35     pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> {
36         DefUseAnalysis {
37             info: IndexVec::from_elem_n(Info::new(), mir.local_decls.len()),
38         }
39     }
40
41     pub fn analyze(&mut self, mir: &Mir<'tcx>) {
42         let mut finder = DefUseFinder {
43             info: mem::replace(&mut self.info, IndexVec::new()),
44         };
45         finder.visit_mir(mir);
46         self.info = finder.info
47     }
48
49     pub fn local_info(&self, local: Local) -> &Info<'tcx> {
50         &self.info[local]
51     }
52
53     pub fn local_info_mut(&mut self, local: Local) -> &mut Info<'tcx> {
54         &mut self.info[local]
55     }
56
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>,
59                                                       LvalueContext<'tcx>,
60                                                       Location) {
61         for lvalue_use in &self.info[local].defs_and_uses {
62             MutateUseVisitor::new(local,
63                                   &mut callback,
64                                   mir).visit_location(mir, lvalue_use.location)
65         }
66     }
67
68     /// FIXME(pcwalton): This should update the def-use chains.
69     pub fn replace_all_defs_and_uses_with(&self,
70                                           local: Local,
71                                           mir: &mut Mir<'tcx>,
72                                           new_lvalue: Lvalue<'tcx>) {
73         self.mutate_defs_and_uses(local, mir, |lvalue, _, _| *lvalue = new_lvalue.clone())
74     }
75 }
76
77 struct DefUseFinder<'tcx> {
78     info: IndexVec<Local, Info<'tcx>>,
79 }
80
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;
84
85         if let Lvalue::Local(local) = *lvalue {
86             Some(&mut info[local])
87         } else {
88             None
89         }
90     }
91 }
92
93 impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> {
94     fn visit_lvalue(&mut self,
95                     lvalue: &Lvalue<'tcx>,
96                     context: LvalueContext<'tcx>,
97                     location: Location) {
98         if let Some(ref mut info) = self.lvalue_mut_info(lvalue) {
99             info.defs_and_uses.push(Use {
100                 context: context,
101                 location: location,
102             })
103         }
104         self.super_lvalue(lvalue, context, location)
105     }
106 }
107
108 impl<'tcx> Info<'tcx> {
109     fn new() -> Info<'tcx> {
110         Info {
111             defs_and_uses: vec![],
112         }
113     }
114
115     pub fn def_count(&self) -> usize {
116         self.defs_and_uses.iter().filter(|lvalue_use| lvalue_use.context.is_mutating_use()).count()
117     }
118
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()
122         }).count()
123     }
124
125     pub fn use_count(&self) -> usize {
126         self.defs_and_uses.iter().filter(|lvalue_use| {
127             lvalue_use.context.is_nonmutating_use()
128         }).count()
129     }
130 }
131
132 struct MutateUseVisitor<'tcx, F> {
133     query: Local,
134     callback: F,
135     phantom: PhantomData<&'tcx ()>,
136 }
137
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) {
142         MutateUseVisitor {
143             query: query,
144             callback: callback,
145             phantom: PhantomData,
146         }
147     }
148 }
149
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)
159             }
160         }
161         self.super_lvalue(lvalue, context, location)
162     }
163 }