1use crate::analysis::utils::fn_info::*;
2use colorful::{Color, Colorful};
3use rustc_hir::def_id::DefId;
4use rustc_middle::mir::{
5 BasicBlockData, BasicBlocks, Body, LocalDecl, LocalDecls, Operand, Rvalue, Statement,
6 StatementKind, Terminator, TerminatorKind,
7};
8use rustc_middle::ty::{self, TyCtxt, TyKind};
9
10const NEXT_LINE: &str = "\n";
11const PADDING: &str = " ";
12const EXPLAIN: &str = " @ ";
13
14pub trait Display {
16 fn display(&self) -> String;
17}
18
19impl<'tcx> Display for Terminator<'tcx> {
20 fn display(&self) -> String {
21 let mut s = String::new();
22 s += &format!("{}{:?}{}", PADDING, self.kind, self.kind.display());
23 s
24 }
25}
26
27impl<'tcx> Display for TerminatorKind<'tcx> {
28 fn display(&self) -> String {
29 let mut s = String::new();
30 s += EXPLAIN;
31 match &self {
32 TerminatorKind::Goto { .. } => s += "Goto",
33 TerminatorKind::SwitchInt { .. } => s += "SwitchInt",
34 TerminatorKind::Return => s += "Return",
35 TerminatorKind::Unreachable => s += "Unreachable",
36 TerminatorKind::Drop { .. } => s += "Drop",
37 TerminatorKind::Assert { .. } => s += "Assert",
38 TerminatorKind::Yield { .. } => s += "Yield",
39 TerminatorKind::FalseEdge { .. } => s += "FalseEdge",
40 TerminatorKind::FalseUnwind { .. } => s += "FalseUnwind",
41 TerminatorKind::InlineAsm { .. } => s += "InlineAsm",
42 TerminatorKind::UnwindResume => s += "UnwindResume",
43 TerminatorKind::UnwindTerminate(..) => s += "UnwindTerminate",
44 TerminatorKind::CoroutineDrop => s += "CoroutineDrop",
45 TerminatorKind::Call { func, .. } => match func {
46 Operand::Constant(constant) => match constant.ty().kind() {
47 ty::FnDef(id, ..) => {
48 s += &format!("Call: FnDid: {}", id.index.as_usize()).as_str()
49 }
50 _ => (),
51 },
52 _ => (),
53 },
54 TerminatorKind::TailCall { .. } => todo!(),
55 };
56 s
57 }
58}
59
60impl<'tcx> Display for Statement<'tcx> {
61 fn display(&self) -> String {
62 let mut s = String::new();
63 s += &format!("{}{:?}{}", PADDING, self.kind, self.kind.display());
64 s
65 }
66}
67
68impl<'tcx> Display for StatementKind<'tcx> {
69 fn display(&self) -> String {
70 let mut s = String::new();
71 s += EXPLAIN;
72 match &self {
73 StatementKind::Assign(assign) => {
74 s += &format!("{:?}={:?}{}", assign.0, assign.1, assign.1.display());
75 }
76 StatementKind::FakeRead(..) => s += "FakeRead",
77 StatementKind::SetDiscriminant { .. } => s += "SetDiscriminant",
78 StatementKind::StorageLive(..) => s += "StorageLive",
79 StatementKind::StorageDead(..) => s += "StorageDead",
80 StatementKind::Retag(..) => s += "Retag",
81 StatementKind::AscribeUserType(..) => s += "AscribeUserType",
82 StatementKind::Coverage(..) => s += "Coverage",
83 StatementKind::Nop => s += "Nop",
84 StatementKind::PlaceMention(..) => s += "PlaceMention",
85 StatementKind::Intrinsic(..) => s += "Intrinsic",
86 StatementKind::ConstEvalCounter => s += "ConstEvalCounter",
87 _ => todo!(),
88 }
89 s
90 }
91}
92
93impl<'tcx> Display for Rvalue<'tcx> {
94 fn display(&self) -> String {
95 let mut s = String::new();
96 s += EXPLAIN;
97 match self {
98 Rvalue::Use(..) => s += "Use",
99 Rvalue::Repeat(..) => s += "Repeat",
100 Rvalue::Ref(..) => s += "Ref",
101 Rvalue::ThreadLocalRef(..) => s += "ThreadLocalRef",
102 Rvalue::Cast(..) => s += "Cast",
103 Rvalue::BinaryOp(..) => s += "BinaryOp",
104 Rvalue::NullaryOp(..) => s += "NullaryOp",
105 Rvalue::UnaryOp(..) => s += "UnaryOp",
106 Rvalue::Discriminant(..) => s += "Discriminant",
107 Rvalue::Aggregate(..) => s += "Aggregate",
108 Rvalue::ShallowInitBox(..) => s += "ShallowInitBox",
109 Rvalue::CopyForDeref(..) => s += "CopyForDeref",
110 Rvalue::RawPtr(_, _) => s += "RawPtr",
111 _ => todo!(),
112 }
113 s
114 }
115}
116
117impl<'tcx> Display for BasicBlocks<'tcx> {
118 fn display(&self) -> String {
119 let mut s = String::new();
120 for (index, bb) in self.iter().enumerate() {
121 s += &format!(
122 "bb {} {{{}{}}}{}",
123 index,
124 NEXT_LINE,
125 bb.display(),
126 NEXT_LINE
127 );
128 }
129 s
130 }
131}
132
133impl<'tcx> Display for BasicBlockData<'tcx> {
134 fn display(&self) -> String {
135 let mut s = String::new();
136 s += &format!("CleanUp: {}{}", self.is_cleanup, NEXT_LINE);
137 for stmt in self.statements.iter() {
138 s += &format!("{}{}", stmt.display(), NEXT_LINE);
139 }
140 s += &format!(
141 "{}{}",
142 self.terminator.clone().unwrap().display(),
143 NEXT_LINE
144 );
145 s
146 }
147}
148
149impl<'tcx> Display for LocalDecls<'tcx> {
150 fn display(&self) -> String {
151 let mut s = String::new();
152 for (index, ld) in self.iter().enumerate() {
153 s += &format!("_{}: {} {}", index, ld.display(), NEXT_LINE);
154 }
155 s
156 }
157}
158
159impl<'tcx> Display for LocalDecl<'tcx> {
160 fn display(&self) -> String {
161 let mut s = String::new();
162 s += &format!("{}{}", EXPLAIN, self.ty.kind().display());
163 s
164 }
165}
166
167impl<'tcx> Display for Body<'tcx> {
168 fn display(&self) -> String {
169 let mut s = String::new();
170 s += &self.local_decls.display();
171 s += &self.basic_blocks.display();
172 s
173 }
174}
175
176impl<'tcx> Display for TyKind<'tcx> {
177 fn display(&self) -> String {
178 let mut s = String::new();
179 s += &format!("{:?}", self);
180 s
181 }
182}
183
184impl Display for DefId {
185 fn display(&self) -> String {
186 format!("{:?}", self)
187 }
188}
189
190pub struct ShowMir<'tcx> {
191 pub tcx: TyCtxt<'tcx>,
192}
193
194pub fn display_mir(did: DefId, body: &Body) {
196 rap_info!("{}", did.display().color(Color::LightRed));
197 rap_info!("{}", body.local_decls.display().color(Color::Green));
198 rap_info!(
199 "{}",
200 body.basic_blocks.display().color(Color::LightGoldenrod2a)
201 );
202}
203
204impl<'tcx> ShowMir<'tcx> {
205 pub fn new(tcx: TyCtxt<'tcx>) -> Self {
206 Self { tcx }
207 }
208
209 pub fn start(&mut self) {
210 rap_info!("Show MIR");
211 let mir_keys = self.tcx.mir_keys(());
212 for each_mir in mir_keys {
213 let def_id = each_mir.to_def_id();
214 let body = self.tcx.instance_mir(ty::InstanceKind::Item(def_id));
215 display_mir(def_id, body);
216 }
217 }
218
219 pub fn start_generate_dot(&mut self) {
220 rap_info!("Generate MIR DOT");
221 std::process::Command::new("mkdir")
222 .args(["MIR_dot_graph"])
223 .output()
224 .expect("Failed to create directory");
225
226 let mir_keys = self.tcx.mir_keys(());
227 for each_mir in mir_keys {
228 let def_id = each_mir.to_def_id();
229 let _ = generate_mir_cfg_dot(self.tcx, def_id, &Vec::new());
230 }
231 }
232}