]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2014 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 | //! The various pretty print routines. | |
12 | ||
13 | pub use self::UserIdentifiedItem::*; | |
14 | pub use self::PpSourceMode::*; | |
15 | pub use self::PpMode::*; | |
16 | use self::NodesMatchingUII::*; | |
17 | ||
a7813a04 XL |
18 | use abort_on_err; |
19 | use driver::{self, Resolutions}; | |
1a4d82fc | 20 | |
54a0048b SL |
21 | use rustc::ty::{self, TyCtxt}; |
22 | use rustc::cfg; | |
23 | use rustc::cfg::graphviz::LabelledCFG; | |
a7813a04 | 24 | use rustc::dep_graph::DepGraph; |
1a4d82fc JJ |
25 | use rustc::session::Session; |
26 | use rustc::session::config::Input; | |
1a4d82fc JJ |
27 | use rustc_borrowck as borrowck; |
28 | use rustc_borrowck::graphviz as borrowck_dot; | |
29 | ||
7453a54e | 30 | use rustc_mir::pretty::write_mir_pretty; |
54a0048b | 31 | use rustc_mir::graphviz::write_mir_graphviz; |
7453a54e SL |
32 | |
33 | use syntax::ast::{self, BlockCheckMode}; | |
1a4d82fc JJ |
34 | use syntax::fold::{self, Folder}; |
35 | use syntax::print::{pp, pprust}; | |
b039eaaf | 36 | use syntax::print::pprust::PrintState; |
1a4d82fc | 37 | use syntax::ptr::P; |
d9579d0f | 38 | use syntax::util::small_vector::SmallVector; |
3157f602 | 39 | use syntax_pos; |
1a4d82fc JJ |
40 | |
41 | use graphviz as dot; | |
42 | ||
c34b1796 AL |
43 | use std::fs::File; |
44 | use std::io::{self, Write}; | |
54a0048b | 45 | use std::iter; |
1a4d82fc | 46 | use std::option; |
a7813a04 | 47 | use std::path::Path; |
1a4d82fc JJ |
48 | use std::str::FromStr; |
49 | ||
54a0048b SL |
50 | use rustc::hir::map as hir_map; |
51 | use rustc::hir::map::{blocks, NodePrinter}; | |
52 | use rustc::hir; | |
54a0048b SL |
53 | use rustc::hir::print as pprust_hir; |
54 | ||
55 | use rustc::mir::mir_map::MirMap; | |
e9174d1e | 56 | |
c34b1796 | 57 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
58 | pub enum PpSourceMode { |
59 | PpmNormal, | |
60 | PpmEveryBodyLoops, | |
61 | PpmExpanded, | |
1a4d82fc JJ |
62 | PpmIdentified, |
63 | PpmExpandedIdentified, | |
64 | PpmExpandedHygiene, | |
e9174d1e | 65 | PpmTyped, |
1a4d82fc JJ |
66 | } |
67 | ||
c34b1796 | 68 | #[derive(Copy, Clone, PartialEq, Debug)] |
85aaf69f SL |
69 | pub enum PpFlowGraphMode { |
70 | Default, | |
71 | /// Drops the labels from the edges in the flowgraph output. This | |
c1a9b12d | 72 | /// is mostly for use in the --unpretty flowgraph run-make tests, |
85aaf69f SL |
73 | /// since the labels are largely uninteresting in those cases and |
74 | /// have become a pain to maintain. | |
75 | UnlabelledEdges, | |
76 | } | |
c34b1796 | 77 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
78 | pub enum PpMode { |
79 | PpmSource(PpSourceMode), | |
e9174d1e | 80 | PpmHir(PpSourceMode), |
85aaf69f | 81 | PpmFlowGraph(PpFlowGraphMode), |
7453a54e | 82 | PpmMir, |
54a0048b | 83 | PpmMirCFG, |
1a4d82fc JJ |
84 | } |
85 | ||
a7813a04 XL |
86 | impl PpMode { |
87 | pub fn needs_ast_map(&self, opt_uii: &Option<UserIdentifiedItem>) -> bool { | |
88 | match *self { | |
89 | PpmSource(PpmNormal) | | |
90 | PpmSource(PpmEveryBodyLoops) | | |
91 | PpmSource(PpmIdentified) => opt_uii.is_some(), | |
92 | ||
93 | PpmSource(PpmExpanded) | | |
94 | PpmSource(PpmExpandedIdentified) | | |
95 | PpmSource(PpmExpandedHygiene) | | |
96 | PpmHir(_) | | |
97 | PpmMir | | |
98 | PpmMirCFG | | |
99 | PpmFlowGraph(_) => true, | |
100 | PpmSource(PpmTyped) => panic!("invalid state"), | |
101 | } | |
102 | } | |
103 | ||
104 | pub fn needs_analysis(&self) -> bool { | |
105 | match *self { | |
106 | PpmMir | PpmMirCFG | PpmFlowGraph(_) => true, | |
107 | _ => false, | |
108 | } | |
109 | } | |
110 | } | |
111 | ||
1a4d82fc JJ |
112 | pub fn parse_pretty(sess: &Session, |
113 | name: &str, | |
92a42be0 SL |
114 | extended: bool) |
115 | -> (PpMode, Option<UserIdentifiedItem>) { | |
c34b1796 | 116 | let mut split = name.splitn(2, '='); |
1a4d82fc JJ |
117 | let first = split.next().unwrap(); |
118 | let opt_second = split.next(); | |
119 | let first = match (first, extended) { | |
92a42be0 SL |
120 | ("normal", _) => PpmSource(PpmNormal), |
121 | ("identified", _) => PpmSource(PpmIdentified), | |
1a4d82fc | 122 | ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops), |
92a42be0 | 123 | ("expanded", _) => PpmSource(PpmExpanded), |
1a4d82fc JJ |
124 | ("expanded,identified", _) => PpmSource(PpmExpandedIdentified), |
125 | ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene), | |
92a42be0 | 126 | ("hir", true) => PpmHir(PpmNormal), |
e9174d1e | 127 | ("hir,identified", true) => PpmHir(PpmIdentified), |
92a42be0 | 128 | ("hir,typed", true) => PpmHir(PpmTyped), |
7453a54e | 129 | ("mir", true) => PpmMir, |
54a0048b | 130 | ("mir-cfg", true) => PpmMirCFG, |
92a42be0 SL |
131 | ("flowgraph", true) => PpmFlowGraph(PpFlowGraphMode::Default), |
132 | ("flowgraph,unlabelled", true) => PpmFlowGraph(PpFlowGraphMode::UnlabelledEdges), | |
1a4d82fc JJ |
133 | _ => { |
134 | if extended { | |
92a42be0 SL |
135 | sess.fatal(&format!("argument to `unpretty` must be one of `normal`, \ |
136 | `expanded`, `flowgraph[,unlabelled]=<nodeid>`, \ | |
137 | `identified`, `expanded,identified`, `everybody_loops`, \ | |
7453a54e | 138 | `hir`, `hir,identified`, `hir,typed`, or `mir`; got {}", |
92a42be0 | 139 | name)); |
1a4d82fc | 140 | } else { |
92a42be0 SL |
141 | sess.fatal(&format!("argument to `pretty` must be one of `normal`, `expanded`, \ |
142 | `identified`, or `expanded,identified`; got {}", | |
143 | name)); | |
1a4d82fc JJ |
144 | } |
145 | } | |
146 | }; | |
85aaf69f | 147 | let opt_second = opt_second.and_then(|s| s.parse::<UserIdentifiedItem>().ok()); |
1a4d82fc JJ |
148 | (first, opt_second) |
149 | } | |
150 | ||
151 | ||
152 | ||
153 | // This slightly awkward construction is to allow for each PpMode to | |
154 | // choose whether it needs to do analyses (which can consume the | |
155 | // Session) and then pass through the session (now attached to the | |
156 | // analysis results) on to the chosen pretty-printer, along with the | |
157 | // `&PpAnn` object. | |
158 | // | |
159 | // Note that since the `&PrinterSupport` is freshly constructed on each | |
160 | // call, it would not make sense to try to attach the lifetime of `self` | |
161 | // to the lifetime of the `&PrinterObject`. | |
162 | // | |
163 | // (The `use_once_payload` is working around the current lack of once | |
164 | // functions in the compiler.) | |
165 | ||
166 | impl PpSourceMode { | |
167 | /// Constructs a `PrinterSupport` object and passes it to `f`. | |
168 | fn call_with_pp_support<'tcx, A, B, F>(&self, | |
b039eaaf | 169 | sess: &'tcx Session, |
a7813a04 | 170 | ast_map: Option<&hir_map::Map<'tcx>>, |
1a4d82fc | 171 | payload: B, |
92a42be0 SL |
172 | f: F) |
173 | -> A | |
174 | where F: FnOnce(&PrinterSupport, B) -> A | |
1a4d82fc JJ |
175 | { |
176 | match *self { | |
177 | PpmNormal | PpmEveryBodyLoops | PpmExpanded => { | |
92a42be0 SL |
178 | let annotation = NoAnn { |
179 | sess: sess, | |
a7813a04 | 180 | ast_map: ast_map.map(|m| m.clone()), |
92a42be0 | 181 | }; |
1a4d82fc JJ |
182 | f(&annotation, payload) |
183 | } | |
184 | ||
185 | PpmIdentified | PpmExpandedIdentified => { | |
92a42be0 SL |
186 | let annotation = IdentifiedAnnotation { |
187 | sess: sess, | |
a7813a04 | 188 | ast_map: ast_map.map(|m| m.clone()), |
92a42be0 | 189 | }; |
1a4d82fc JJ |
190 | f(&annotation, payload) |
191 | } | |
192 | PpmExpandedHygiene => { | |
92a42be0 SL |
193 | let annotation = HygieneAnnotation { |
194 | sess: sess, | |
a7813a04 | 195 | ast_map: ast_map.map(|m| m.clone()), |
92a42be0 | 196 | }; |
1a4d82fc JJ |
197 | f(&annotation, payload) |
198 | } | |
e9174d1e SL |
199 | _ => panic!("Should use call_with_pp_support_hir"), |
200 | } | |
201 | } | |
202 | fn call_with_pp_support_hir<'tcx, A, B, F>(&self, | |
b039eaaf | 203 | sess: &'tcx Session, |
e9174d1e | 204 | ast_map: &hir_map::Map<'tcx>, |
a7813a04 XL |
205 | analysis: &ty::CrateAnalysis, |
206 | resolutions: &Resolutions, | |
e9174d1e | 207 | arenas: &'tcx ty::CtxtArenas<'tcx>, |
b039eaaf | 208 | id: &str, |
e9174d1e | 209 | payload: B, |
92a42be0 SL |
210 | f: F) |
211 | -> A | |
212 | where F: FnOnce(&HirPrinterSupport, B, &hir::Crate) -> A | |
e9174d1e SL |
213 | { |
214 | match *self { | |
215 | PpmNormal => { | |
92a42be0 SL |
216 | let annotation = NoAnn { |
217 | sess: sess, | |
218 | ast_map: Some(ast_map.clone()), | |
219 | }; | |
7453a54e | 220 | f(&annotation, payload, ast_map.forest.krate()) |
e9174d1e SL |
221 | } |
222 | ||
223 | PpmIdentified => { | |
224 | let annotation = IdentifiedAnnotation { | |
225 | sess: sess, | |
92a42be0 | 226 | ast_map: Some(ast_map.clone()), |
e9174d1e | 227 | }; |
7453a54e | 228 | f(&annotation, payload, ast_map.forest.krate()) |
e9174d1e | 229 | } |
1a4d82fc | 230 | PpmTyped => { |
7453a54e | 231 | abort_on_err(driver::phase_3_run_analysis_passes(sess, |
7453a54e | 232 | ast_map.clone(), |
a7813a04 XL |
233 | analysis.clone(), |
234 | resolutions.clone(), | |
7453a54e SL |
235 | arenas, |
236 | id, | |
9e0c209e | 237 | |tcx, _, _, _, _| { |
7453a54e SL |
238 | let annotation = TypedAnnotation { |
239 | tcx: tcx, | |
240 | }; | |
241 | let _ignore = tcx.dep_graph.in_ignore(); | |
242 | f(&annotation, | |
243 | payload, | |
244 | ast_map.forest.krate()) | |
245 | }), sess) | |
1a4d82fc | 246 | } |
e9174d1e | 247 | _ => panic!("Should use call_with_pp_support"), |
1a4d82fc JJ |
248 | } |
249 | } | |
250 | } | |
251 | ||
252 | trait PrinterSupport<'ast>: pprust::PpAnn { | |
253 | /// Provides a uniform interface for re-extracting a reference to a | |
254 | /// `Session` from a value that now owns it. | |
255 | fn sess<'a>(&'a self) -> &'a Session; | |
256 | ||
257 | /// Provides a uniform interface for re-extracting a reference to an | |
e9174d1e SL |
258 | /// `hir_map::Map` from a value that now owns it. |
259 | fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>>; | |
1a4d82fc JJ |
260 | |
261 | /// Produces the pretty-print annotation object. | |
262 | /// | |
263 | /// (Rust does not yet support upcasting from a trait object to | |
264 | /// an object for one of its super-traits.) | |
265 | fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn; | |
266 | } | |
267 | ||
e9174d1e SL |
268 | trait HirPrinterSupport<'ast>: pprust_hir::PpAnn { |
269 | /// Provides a uniform interface for re-extracting a reference to a | |
270 | /// `Session` from a value that now owns it. | |
271 | fn sess<'a>(&'a self) -> &'a Session; | |
272 | ||
273 | /// Provides a uniform interface for re-extracting a reference to an | |
274 | /// `hir_map::Map` from a value that now owns it. | |
275 | fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>>; | |
276 | ||
277 | /// Produces the pretty-print annotation object. | |
278 | /// | |
279 | /// (Rust does not yet support upcasting from a trait object to | |
280 | /// an object for one of its super-traits.) | |
281 | fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn; | |
54a0048b SL |
282 | |
283 | /// Computes an user-readable representation of a path, if possible. | |
284 | fn node_path(&self, id: ast::NodeId) -> Option<String> { | |
285 | self.ast_map().and_then(|map| map.def_path_from_id(id)).map(|path| { | |
286 | path.data.into_iter().map(|elem| { | |
287 | elem.data.to_string() | |
288 | }).collect::<Vec<_>>().join("::") | |
289 | }) | |
290 | } | |
e9174d1e SL |
291 | } |
292 | ||
1a4d82fc | 293 | struct NoAnn<'ast> { |
b039eaaf | 294 | sess: &'ast Session, |
92a42be0 | 295 | ast_map: Option<hir_map::Map<'ast>>, |
1a4d82fc JJ |
296 | } |
297 | ||
298 | impl<'ast> PrinterSupport<'ast> for NoAnn<'ast> { | |
92a42be0 SL |
299 | fn sess<'a>(&'a self) -> &'a Session { |
300 | self.sess | |
301 | } | |
1a4d82fc | 302 | |
e9174d1e | 303 | fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> { |
1a4d82fc JJ |
304 | self.ast_map.as_ref() |
305 | } | |
306 | ||
92a42be0 SL |
307 | fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { |
308 | self | |
309 | } | |
1a4d82fc JJ |
310 | } |
311 | ||
e9174d1e | 312 | impl<'ast> HirPrinterSupport<'ast> for NoAnn<'ast> { |
92a42be0 SL |
313 | fn sess<'a>(&'a self) -> &'a Session { |
314 | self.sess | |
315 | } | |
e9174d1e SL |
316 | |
317 | fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> { | |
318 | self.ast_map.as_ref() | |
319 | } | |
320 | ||
92a42be0 SL |
321 | fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { |
322 | self | |
323 | } | |
e9174d1e SL |
324 | } |
325 | ||
1a4d82fc | 326 | impl<'ast> pprust::PpAnn for NoAnn<'ast> {} |
e9174d1e | 327 | impl<'ast> pprust_hir::PpAnn for NoAnn<'ast> {} |
1a4d82fc JJ |
328 | |
329 | struct IdentifiedAnnotation<'ast> { | |
b039eaaf | 330 | sess: &'ast Session, |
e9174d1e | 331 | ast_map: Option<hir_map::Map<'ast>>, |
1a4d82fc JJ |
332 | } |
333 | ||
334 | impl<'ast> PrinterSupport<'ast> for IdentifiedAnnotation<'ast> { | |
92a42be0 SL |
335 | fn sess<'a>(&'a self) -> &'a Session { |
336 | self.sess | |
337 | } | |
1a4d82fc | 338 | |
e9174d1e | 339 | fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> { |
1a4d82fc JJ |
340 | self.ast_map.as_ref() |
341 | } | |
342 | ||
92a42be0 SL |
343 | fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { |
344 | self | |
345 | } | |
1a4d82fc JJ |
346 | } |
347 | ||
348 | impl<'ast> pprust::PpAnn for IdentifiedAnnotation<'ast> { | |
92a42be0 | 349 | fn pre(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { |
1a4d82fc JJ |
350 | match node { |
351 | pprust::NodeExpr(_) => s.popen(), | |
92a42be0 | 352 | _ => Ok(()), |
1a4d82fc JJ |
353 | } |
354 | } | |
92a42be0 | 355 | fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { |
1a4d82fc JJ |
356 | match node { |
357 | pprust::NodeIdent(_) | pprust::NodeName(_) => Ok(()), | |
358 | ||
359 | pprust::NodeItem(item) => { | |
54a0048b | 360 | pp::space(&mut s.s)?; |
1a4d82fc JJ |
361 | s.synth_comment(item.id.to_string()) |
362 | } | |
c34b1796 | 363 | pprust::NodeSubItem(id) => { |
54a0048b | 364 | pp::space(&mut s.s)?; |
c34b1796 AL |
365 | s.synth_comment(id.to_string()) |
366 | } | |
1a4d82fc | 367 | pprust::NodeBlock(blk) => { |
54a0048b | 368 | pp::space(&mut s.s)?; |
1a4d82fc JJ |
369 | s.synth_comment(format!("block {}", blk.id)) |
370 | } | |
371 | pprust::NodeExpr(expr) => { | |
54a0048b SL |
372 | pp::space(&mut s.s)?; |
373 | s.synth_comment(expr.id.to_string())?; | |
1a4d82fc JJ |
374 | s.pclose() |
375 | } | |
376 | pprust::NodePat(pat) => { | |
54a0048b | 377 | pp::space(&mut s.s)?; |
1a4d82fc JJ |
378 | s.synth_comment(format!("pat {}", pat.id)) |
379 | } | |
380 | } | |
381 | } | |
382 | } | |
383 | ||
e9174d1e | 384 | impl<'ast> HirPrinterSupport<'ast> for IdentifiedAnnotation<'ast> { |
92a42be0 SL |
385 | fn sess<'a>(&'a self) -> &'a Session { |
386 | self.sess | |
387 | } | |
e9174d1e SL |
388 | |
389 | fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> { | |
390 | self.ast_map.as_ref() | |
391 | } | |
392 | ||
92a42be0 SL |
393 | fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { |
394 | self | |
395 | } | |
e9174d1e SL |
396 | } |
397 | ||
398 | impl<'ast> pprust_hir::PpAnn for IdentifiedAnnotation<'ast> { | |
92a42be0 | 399 | fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { |
e9174d1e SL |
400 | match node { |
401 | pprust_hir::NodeExpr(_) => s.popen(), | |
92a42be0 | 402 | _ => Ok(()), |
e9174d1e SL |
403 | } |
404 | } | |
92a42be0 | 405 | fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { |
e9174d1e | 406 | match node { |
b039eaaf | 407 | pprust_hir::NodeName(_) => Ok(()), |
e9174d1e | 408 | pprust_hir::NodeItem(item) => { |
54a0048b | 409 | pp::space(&mut s.s)?; |
e9174d1e SL |
410 | s.synth_comment(item.id.to_string()) |
411 | } | |
412 | pprust_hir::NodeSubItem(id) => { | |
54a0048b | 413 | pp::space(&mut s.s)?; |
e9174d1e SL |
414 | s.synth_comment(id.to_string()) |
415 | } | |
416 | pprust_hir::NodeBlock(blk) => { | |
54a0048b | 417 | pp::space(&mut s.s)?; |
e9174d1e SL |
418 | s.synth_comment(format!("block {}", blk.id)) |
419 | } | |
420 | pprust_hir::NodeExpr(expr) => { | |
54a0048b SL |
421 | pp::space(&mut s.s)?; |
422 | s.synth_comment(expr.id.to_string())?; | |
e9174d1e SL |
423 | s.pclose() |
424 | } | |
425 | pprust_hir::NodePat(pat) => { | |
54a0048b | 426 | pp::space(&mut s.s)?; |
e9174d1e SL |
427 | s.synth_comment(format!("pat {}", pat.id)) |
428 | } | |
429 | } | |
430 | } | |
431 | } | |
432 | ||
1a4d82fc | 433 | struct HygieneAnnotation<'ast> { |
b039eaaf | 434 | sess: &'ast Session, |
e9174d1e | 435 | ast_map: Option<hir_map::Map<'ast>>, |
1a4d82fc JJ |
436 | } |
437 | ||
438 | impl<'ast> PrinterSupport<'ast> for HygieneAnnotation<'ast> { | |
92a42be0 SL |
439 | fn sess<'a>(&'a self) -> &'a Session { |
440 | self.sess | |
441 | } | |
1a4d82fc | 442 | |
e9174d1e | 443 | fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> { |
1a4d82fc JJ |
444 | self.ast_map.as_ref() |
445 | } | |
446 | ||
92a42be0 SL |
447 | fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { |
448 | self | |
449 | } | |
1a4d82fc JJ |
450 | } |
451 | ||
452 | impl<'ast> pprust::PpAnn for HygieneAnnotation<'ast> { | |
92a42be0 | 453 | fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { |
1a4d82fc JJ |
454 | match node { |
455 | pprust::NodeIdent(&ast::Ident { name: ast::Name(nm), ctxt }) => { | |
54a0048b | 456 | pp::space(&mut s.s)?; |
1a4d82fc JJ |
457 | // FIXME #16420: this doesn't display the connections |
458 | // between syntax contexts | |
5bcae85e | 459 | s.synth_comment(format!("{}{:?}", nm, ctxt)) |
1a4d82fc JJ |
460 | } |
461 | pprust::NodeName(&ast::Name(nm)) => { | |
54a0048b | 462 | pp::space(&mut s.s)?; |
1a4d82fc JJ |
463 | s.synth_comment(nm.to_string()) |
464 | } | |
92a42be0 | 465 | _ => Ok(()), |
1a4d82fc JJ |
466 | } |
467 | } | |
468 | } | |
469 | ||
470 | ||
62682a34 | 471 | struct TypedAnnotation<'a, 'tcx: 'a> { |
a7813a04 | 472 | tcx: TyCtxt<'a, 'tcx, 'tcx>, |
1a4d82fc JJ |
473 | } |
474 | ||
e9174d1e | 475 | impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> { |
92a42be0 SL |
476 | fn sess<'a>(&'a self) -> &'a Session { |
477 | &self.tcx.sess | |
478 | } | |
1a4d82fc | 479 | |
e9174d1e | 480 | fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'tcx>> { |
62682a34 | 481 | Some(&self.tcx.map) |
1a4d82fc JJ |
482 | } |
483 | ||
92a42be0 SL |
484 | fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { |
485 | self | |
486 | } | |
54a0048b SL |
487 | |
488 | fn node_path(&self, id: ast::NodeId) -> Option<String> { | |
489 | Some(self.tcx.node_path_str(id)) | |
490 | } | |
1a4d82fc JJ |
491 | } |
492 | ||
e9174d1e | 493 | impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> { |
92a42be0 | 494 | fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { |
1a4d82fc | 495 | match node { |
e9174d1e | 496 | pprust_hir::NodeExpr(_) => s.popen(), |
92a42be0 | 497 | _ => Ok(()), |
1a4d82fc JJ |
498 | } |
499 | } | |
92a42be0 | 500 | fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { |
1a4d82fc | 501 | match node { |
e9174d1e | 502 | pprust_hir::NodeExpr(expr) => { |
54a0048b SL |
503 | pp::space(&mut s.s)?; |
504 | pp::word(&mut s.s, "as")?; | |
505 | pp::space(&mut s.s)?; | |
506 | pp::word(&mut s.s, &self.tcx.expr_ty(expr).to_string())?; | |
1a4d82fc JJ |
507 | s.pclose() |
508 | } | |
92a42be0 | 509 | _ => Ok(()), |
1a4d82fc JJ |
510 | } |
511 | } | |
512 | } | |
513 | ||
514 | fn gather_flowgraph_variants(sess: &Session) -> Vec<borrowck_dot::Variant> { | |
515 | let print_loans = sess.opts.debugging_opts.flowgraph_print_loans; | |
516 | let print_moves = sess.opts.debugging_opts.flowgraph_print_moves; | |
517 | let print_assigns = sess.opts.debugging_opts.flowgraph_print_assigns; | |
518 | let print_all = sess.opts.debugging_opts.flowgraph_print_all; | |
519 | let mut variants = Vec::new(); | |
520 | if print_all || print_loans { | |
521 | variants.push(borrowck_dot::Loans); | |
522 | } | |
523 | if print_all || print_moves { | |
524 | variants.push(borrowck_dot::Moves); | |
525 | } | |
526 | if print_all || print_assigns { | |
527 | variants.push(borrowck_dot::Assigns); | |
528 | } | |
529 | variants | |
530 | } | |
531 | ||
85aaf69f | 532 | #[derive(Clone, Debug)] |
1a4d82fc JJ |
533 | pub enum UserIdentifiedItem { |
534 | ItemViaNode(ast::NodeId), | |
535 | ItemViaPath(Vec<String>), | |
536 | } | |
537 | ||
538 | impl FromStr for UserIdentifiedItem { | |
85aaf69f SL |
539 | type Err = (); |
540 | fn from_str(s: &str) -> Result<UserIdentifiedItem, ()> { | |
92a42be0 | 541 | Ok(s.parse() |
9e0c209e | 542 | .map(ast::NodeId::new) |
92a42be0 SL |
543 | .map(ItemViaNode) |
544 | .unwrap_or_else(|_| ItemViaPath(s.split("::").map(|s| s.to_string()).collect()))) | |
1a4d82fc JJ |
545 | } |
546 | } | |
547 | ||
548 | enum NodesMatchingUII<'a, 'ast: 'a> { | |
549 | NodesMatchingDirect(option::IntoIter<ast::NodeId>), | |
e9174d1e | 550 | NodesMatchingSuffix(hir_map::NodesMatchingSuffix<'a, 'ast>), |
1a4d82fc JJ |
551 | } |
552 | ||
553 | impl<'a, 'ast> Iterator for NodesMatchingUII<'a, 'ast> { | |
554 | type Item = ast::NodeId; | |
555 | ||
556 | fn next(&mut self) -> Option<ast::NodeId> { | |
557 | match self { | |
558 | &mut NodesMatchingDirect(ref mut iter) => iter.next(), | |
559 | &mut NodesMatchingSuffix(ref mut iter) => iter.next(), | |
560 | } | |
561 | } | |
562 | } | |
563 | ||
564 | impl UserIdentifiedItem { | |
565 | fn reconstructed_input(&self) -> String { | |
566 | match *self { | |
567 | ItemViaNode(node_id) => node_id.to_string(), | |
c1a9b12d | 568 | ItemViaPath(ref parts) => parts.join("::"), |
1a4d82fc JJ |
569 | } |
570 | } | |
571 | ||
92a42be0 SL |
572 | fn all_matching_node_ids<'a, 'ast>(&'a self, |
573 | map: &'a hir_map::Map<'ast>) | |
1a4d82fc JJ |
574 | -> NodesMatchingUII<'a, 'ast> { |
575 | match *self { | |
92a42be0 SL |
576 | ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()), |
577 | ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts[..])), | |
1a4d82fc JJ |
578 | } |
579 | } | |
580 | ||
e9174d1e | 581 | fn to_one_node_id(self, user_option: &str, sess: &Session, map: &hir_map::Map) -> ast::NodeId { |
85aaf69f | 582 | let fail_because = |is_wrong_because| -> ast::NodeId { |
92a42be0 SL |
583 | let message = format!("{} needs NodeId (int) or unique path suffix (b::c::d); got \ |
584 | {}, which {}", | |
585 | user_option, | |
586 | self.reconstructed_input(), | |
587 | is_wrong_because); | |
85aaf69f | 588 | sess.fatal(&message[..]) |
1a4d82fc JJ |
589 | }; |
590 | ||
591 | let mut saw_node = ast::DUMMY_NODE_ID; | |
85aaf69f | 592 | let mut seen = 0; |
1a4d82fc JJ |
593 | for node in self.all_matching_node_ids(map) { |
594 | saw_node = node; | |
595 | seen += 1; | |
596 | if seen > 1 { | |
597 | fail_because("does not resolve uniquely"); | |
598 | } | |
599 | } | |
600 | if seen == 0 { | |
601 | fail_because("does not resolve to any item"); | |
602 | } | |
603 | ||
604 | assert!(seen == 1); | |
605 | return saw_node; | |
606 | } | |
607 | } | |
608 | ||
1a4d82fc JJ |
609 | struct ReplaceBodyWithLoop { |
610 | within_static_or_const: bool, | |
611 | } | |
612 | ||
613 | impl ReplaceBodyWithLoop { | |
614 | fn new() -> ReplaceBodyWithLoop { | |
615 | ReplaceBodyWithLoop { within_static_or_const: false } | |
616 | } | |
617 | } | |
618 | ||
619 | impl fold::Folder for ReplaceBodyWithLoop { | |
7453a54e | 620 | fn fold_item_kind(&mut self, i: ast::ItemKind) -> ast::ItemKind { |
1a4d82fc | 621 | match i { |
7453a54e | 622 | ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => { |
1a4d82fc | 623 | self.within_static_or_const = true; |
7453a54e | 624 | let ret = fold::noop_fold_item_kind(i, self); |
1a4d82fc JJ |
625 | self.within_static_or_const = false; |
626 | return ret; | |
627 | } | |
628 | _ => { | |
7453a54e | 629 | fold::noop_fold_item_kind(i, self) |
1a4d82fc JJ |
630 | } |
631 | } | |
632 | } | |
633 | ||
7453a54e | 634 | fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector<ast::TraitItem> { |
d9579d0f | 635 | match i.node { |
7453a54e | 636 | ast::TraitItemKind::Const(..) => { |
d9579d0f AL |
637 | self.within_static_or_const = true; |
638 | let ret = fold::noop_fold_trait_item(i, self); | |
639 | self.within_static_or_const = false; | |
640 | return ret; | |
641 | } | |
642 | _ => fold::noop_fold_trait_item(i, self), | |
643 | } | |
644 | } | |
645 | ||
7453a54e | 646 | fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector<ast::ImplItem> { |
d9579d0f | 647 | match i.node { |
92a42be0 | 648 | ast::ImplItemKind::Const(..) => { |
d9579d0f AL |
649 | self.within_static_or_const = true; |
650 | let ret = fold::noop_fold_impl_item(i, self); | |
651 | self.within_static_or_const = false; | |
652 | return ret; | |
653 | } | |
654 | _ => fold::noop_fold_impl_item(i, self), | |
655 | } | |
656 | } | |
1a4d82fc JJ |
657 | |
658 | fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> { | |
92a42be0 | 659 | fn expr_to_block(rules: ast::BlockCheckMode, e: Option<P<ast::Expr>>) -> P<ast::Block> { |
1a4d82fc | 660 | P(ast::Block { |
3157f602 XL |
661 | stmts: e.map(|e| ast::Stmt { |
662 | id: ast::DUMMY_NODE_ID, | |
663 | span: e.span, | |
664 | node: ast::StmtKind::Expr(e), | |
665 | }).into_iter().collect(), | |
92a42be0 SL |
666 | rules: rules, |
667 | id: ast::DUMMY_NODE_ID, | |
3157f602 | 668 | span: syntax_pos::DUMMY_SP, |
1a4d82fc JJ |
669 | }) |
670 | } | |
671 | ||
672 | if !self.within_static_or_const { | |
673 | ||
7453a54e | 674 | let empty_block = expr_to_block(BlockCheckMode::Default, None); |
1a4d82fc | 675 | let loop_expr = P(ast::Expr { |
7453a54e | 676 | node: ast::ExprKind::Loop(empty_block, None), |
92a42be0 | 677 | id: ast::DUMMY_NODE_ID, |
3157f602 XL |
678 | span: syntax_pos::DUMMY_SP, |
679 | attrs: ast::ThinVec::new(), | |
1a4d82fc JJ |
680 | }); |
681 | ||
682 | expr_to_block(b.rules, Some(loop_expr)) | |
683 | ||
684 | } else { | |
685 | fold::noop_fold_block(b, self) | |
686 | } | |
687 | } | |
688 | ||
689 | // in general the pretty printer processes unexpanded code, so | |
690 | // we override the default `fold_mac` method which panics. | |
691 | fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { | |
692 | fold::noop_fold_mac(mac, self) | |
693 | } | |
694 | } | |
695 | ||
a7813a04 XL |
696 | fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>, |
697 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
698 | mir_map: Option<&MirMap<'tcx>>, | |
699 | code: blocks::Code, | |
700 | mode: PpFlowGraphMode, | |
701 | mut out: W) | |
702 | -> io::Result<()> { | |
703 | let cfg = match code { | |
704 | blocks::BlockCode(block) => cfg::CFG::new(tcx, &block), | |
705 | blocks::FnLikeCode(fn_like) => cfg::CFG::new(tcx, &fn_like.body()), | |
706 | }; | |
707 | let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; | |
708 | let lcfg = LabelledCFG { | |
709 | ast_map: &tcx.map, | |
710 | cfg: &cfg, | |
711 | name: format!("node_{}", code.id()), | |
712 | labelled_edges: labelled_edges, | |
1a4d82fc JJ |
713 | }; |
714 | ||
a7813a04 XL |
715 | match code { |
716 | _ if variants.is_empty() => { | |
717 | let r = dot::render(&lcfg, &mut out); | |
718 | return expand_err_details(r); | |
719 | } | |
720 | blocks::BlockCode(_) => { | |
721 | tcx.sess.err("--pretty flowgraph with -Z flowgraph-print annotations requires \ | |
722 | fn-like node id."); | |
723 | return Ok(()); | |
724 | } | |
725 | blocks::FnLikeCode(fn_like) => { | |
726 | let (bccx, analysis_data) = | |
727 | borrowck::build_borrowck_dataflow_data_for_fn(tcx, | |
728 | mir_map, | |
729 | fn_like.to_fn_parts(), | |
730 | &cfg); | |
1a4d82fc | 731 | |
a7813a04 XL |
732 | let lcfg = borrowck_dot::DataflowLabeller { |
733 | inner: lcfg, | |
734 | variants: variants, | |
735 | borrowck_ctxt: &bccx, | |
736 | analysis_data: &analysis_data, | |
737 | }; | |
738 | let r = dot::render(&lcfg, &mut out); | |
739 | return expand_err_details(r); | |
1a4d82fc | 740 | } |
a7813a04 | 741 | } |
1a4d82fc | 742 | |
a7813a04 XL |
743 | fn expand_err_details(r: io::Result<()>) -> io::Result<()> { |
744 | r.map_err(|ioerr| { | |
745 | io::Error::new(io::ErrorKind::Other, | |
746 | &format!("graphviz::render failed: {}", ioerr)[..]) | |
747 | }) | |
748 | } | |
749 | } | |
750 | ||
751 | pub fn fold_crate(krate: ast::Crate, ppm: PpMode) -> ast::Crate { | |
752 | if let PpmSource(PpmEveryBodyLoops) = ppm { | |
753 | let mut fold = ReplaceBodyWithLoop::new(); | |
754 | fold.fold_crate(krate) | |
1a4d82fc | 755 | } else { |
a7813a04 XL |
756 | krate |
757 | } | |
758 | } | |
1a4d82fc | 759 | |
a7813a04 | 760 | fn get_source(input: &Input, sess: &Session) -> (Vec<u8>, String) { |
1a4d82fc | 761 | let src_name = driver::source_name(input); |
92a42be0 | 762 | let src = sess.codemap() |
a7813a04 | 763 | .get_filemap(&src_name) |
3157f602 | 764 | .unwrap() |
92a42be0 SL |
765 | .src |
766 | .as_ref() | |
767 | .unwrap() | |
768 | .as_bytes() | |
769 | .to_vec(); | |
a7813a04 XL |
770 | (src, src_name) |
771 | } | |
772 | ||
773 | fn write_output(out: Vec<u8>, ofile: Option<&Path>) { | |
774 | match ofile { | |
775 | None => print!("{}", String::from_utf8(out).unwrap()), | |
776 | Some(p) => { | |
777 | match File::create(p) { | |
778 | Ok(mut w) => w.write_all(&out).unwrap(), | |
779 | Err(e) => panic!("print-print failed to open {} due to {}", p.display(), e), | |
780 | } | |
781 | } | |
782 | } | |
783 | } | |
1a4d82fc | 784 | |
a7813a04 XL |
785 | pub fn print_after_parsing(sess: &Session, |
786 | input: &Input, | |
787 | krate: &ast::Crate, | |
788 | ppm: PpMode, | |
789 | ofile: Option<&Path>) { | |
790 | let dep_graph = DepGraph::new(false); | |
791 | let _ignore = dep_graph.in_ignore(); | |
792 | ||
793 | let (src, src_name) = get_source(input, sess); | |
794 | ||
795 | let mut rdr = &*src; | |
796 | let mut out = Vec::new(); | |
797 | ||
798 | if let PpmSource(s) = ppm { | |
799 | // Silently ignores an identified node. | |
800 | let out: &mut Write = &mut out; | |
801 | s.call_with_pp_support(sess, None, box out, |annotation, out| { | |
802 | debug!("pretty printing source code {:?}", s); | |
803 | let sess = annotation.sess(); | |
804 | pprust::print_crate(sess.codemap(), | |
805 | sess.diagnostic(), | |
806 | krate, | |
807 | src_name.to_string(), | |
808 | &mut rdr, | |
809 | out, | |
810 | annotation.pp_ann(), | |
811 | false) | |
812 | }).unwrap() | |
813 | } else { | |
814 | unreachable!(); | |
815 | }; | |
816 | ||
817 | write_output(out, ofile); | |
818 | } | |
819 | ||
820 | pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, | |
821 | ast_map: &hir_map::Map<'tcx>, | |
822 | analysis: &ty::CrateAnalysis, | |
823 | resolutions: &Resolutions, | |
824 | input: &Input, | |
825 | krate: &ast::Crate, | |
826 | crate_name: &str, | |
827 | ppm: PpMode, | |
828 | arenas: &'tcx ty::CtxtArenas<'tcx>, | |
829 | opt_uii: Option<UserIdentifiedItem>, | |
830 | ofile: Option<&Path>) { | |
831 | let dep_graph = DepGraph::new(false); | |
832 | let _ignore = dep_graph.in_ignore(); | |
833 | ||
834 | if ppm.needs_analysis() { | |
835 | print_with_analysis(sess, ast_map, analysis, resolutions, | |
836 | crate_name, arenas, ppm, opt_uii, ofile); | |
837 | return; | |
838 | } | |
839 | ||
840 | let (src, src_name) = get_source(input, sess); | |
841 | ||
842 | let mut rdr = &src[..]; | |
c34b1796 | 843 | let mut out = Vec::new(); |
1a4d82fc JJ |
844 | |
845 | match (ppm, opt_uii) { | |
e9174d1e SL |
846 | (PpmSource(s), _) => { |
847 | // Silently ignores an identified node. | |
c34b1796 | 848 | let out: &mut Write = &mut out; |
a7813a04 | 849 | s.call_with_pp_support(sess, Some(ast_map), box out, |annotation, out| { |
92a42be0 SL |
850 | debug!("pretty printing source code {:?}", s); |
851 | let sess = annotation.sess(); | |
852 | pprust::print_crate(sess.codemap(), | |
853 | sess.diagnostic(), | |
a7813a04 | 854 | krate, |
92a42be0 SL |
855 | src_name.to_string(), |
856 | &mut rdr, | |
857 | out, | |
858 | annotation.pp_ann(), | |
a7813a04 | 859 | true) |
c34b1796 AL |
860 | }) |
861 | } | |
1a4d82fc | 862 | |
e9174d1e | 863 | (PpmHir(s), None) => { |
c34b1796 | 864 | let out: &mut Write = &mut out; |
a7813a04 XL |
865 | s.call_with_pp_support_hir(sess, |
866 | ast_map, | |
867 | analysis, | |
868 | resolutions, | |
869 | arenas, | |
870 | crate_name, | |
92a42be0 SL |
871 | box out, |
872 | |annotation, out, krate| { | |
873 | debug!("pretty printing source code {:?}", s); | |
874 | let sess = annotation.sess(); | |
875 | pprust_hir::print_crate(sess.codemap(), | |
876 | sess.diagnostic(), | |
877 | krate, | |
878 | src_name.to_string(), | |
879 | &mut rdr, | |
880 | out, | |
881 | annotation.pp_ann(), | |
a7813a04 | 882 | true) |
92a42be0 | 883 | }) |
e9174d1e SL |
884 | } |
885 | ||
886 | (PpmHir(s), Some(uii)) => { | |
887 | let out: &mut Write = &mut out; | |
a7813a04 XL |
888 | s.call_with_pp_support_hir(sess, |
889 | ast_map, | |
890 | analysis, | |
891 | resolutions, | |
892 | arenas, | |
893 | crate_name, | |
e9174d1e SL |
894 | (out,uii), |
895 | |annotation, (out,uii), _| { | |
896 | debug!("pretty printing source code {:?}", s); | |
897 | let sess = annotation.sess(); | |
54a0048b | 898 | let ast_map = annotation.ast_map().expect("--unpretty missing HIR map"); |
e9174d1e SL |
899 | let mut pp_state = |
900 | pprust_hir::State::new_from_input(sess.codemap(), | |
1a4d82fc JJ |
901 | sess.diagnostic(), |
902 | src_name.to_string(), | |
903 | &mut rdr, | |
c34b1796 | 904 | box out, |
1a4d82fc | 905 | annotation.pp_ann(), |
92a42be0 SL |
906 | true, |
907 | Some(ast_map.krate())); | |
e9174d1e SL |
908 | for node_id in uii.all_matching_node_ids(ast_map) { |
909 | let node = ast_map.get(node_id); | |
54a0048b SL |
910 | pp_state.print_node(&node)?; |
911 | pp::space(&mut pp_state.s)?; | |
912 | let path = annotation.node_path(node_id) | |
913 | .expect("--unpretty missing node paths"); | |
914 | pp_state.synth_comment(path)?; | |
915 | pp::hardbreak(&mut pp_state.s)?; | |
e9174d1e SL |
916 | } |
917 | pp::eof(&mut pp_state.s) | |
918 | }) | |
a7813a04 XL |
919 | } |
920 | _ => unreachable!(), | |
921 | }.unwrap(); | |
922 | ||
923 | write_output(out, ofile); | |
924 | } | |
925 | ||
926 | // In an ideal world, this would be a public function called by the driver after | |
927 | // analsysis is performed. However, we want to call `phase_3_run_analysis_passes` | |
928 | // with a different callback than the standard driver, so that isn't easy. | |
929 | // Instead, we call that function ourselves. | |
930 | fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, | |
931 | ast_map: &hir_map::Map<'tcx>, | |
932 | analysis: &ty::CrateAnalysis, | |
933 | resolutions: &Resolutions, | |
934 | crate_name: &str, | |
935 | arenas: &'tcx ty::CtxtArenas<'tcx>, | |
936 | ppm: PpMode, | |
937 | uii: Option<UserIdentifiedItem>, | |
938 | ofile: Option<&Path>) { | |
939 | let nodeid = if let Some(uii) = uii { | |
940 | debug!("pretty printing for {:?}", uii); | |
941 | Some(uii.to_one_node_id("--unpretty", sess, &ast_map)) | |
942 | } else { | |
943 | debug!("pretty printing for whole crate"); | |
944 | None | |
945 | }; | |
1a4d82fc | 946 | |
a7813a04 XL |
947 | let mut out = Vec::new(); |
948 | ||
949 | abort_on_err(driver::phase_3_run_analysis_passes(sess, | |
950 | ast_map.clone(), | |
951 | analysis.clone(), | |
952 | resolutions.clone(), | |
953 | arenas, | |
954 | crate_name, | |
9e0c209e | 955 | |tcx, mir_map, _, _, _| { |
a7813a04 XL |
956 | match ppm { |
957 | PpmMir | PpmMirCFG => { | |
7453a54e | 958 | if let Some(mir_map) = mir_map { |
54a0048b | 959 | if let Some(nodeid) = nodeid { |
5bcae85e | 960 | let def_id = tcx.map.local_def_id(nodeid); |
a7813a04 | 961 | match ppm { |
5bcae85e | 962 | PpmMir => write_mir_pretty(tcx, iter::once(def_id), &mir_map, &mut out), |
a7813a04 | 963 | PpmMirCFG => { |
5bcae85e | 964 | write_mir_graphviz(tcx, iter::once(def_id), &mir_map, &mut out) |
a7813a04 XL |
965 | } |
966 | _ => unreachable!(), | |
54a0048b SL |
967 | }?; |
968 | } else { | |
a7813a04 | 969 | match ppm { |
5bcae85e SL |
970 | PpmMir => write_mir_pretty(tcx, |
971 | mir_map.map.keys().into_iter(), | |
972 | &mir_map, | |
973 | &mut out), | |
974 | PpmMirCFG => write_mir_graphviz(tcx, | |
975 | mir_map.map.keys().into_iter(), | |
976 | &mir_map, | |
977 | &mut out), | |
a7813a04 | 978 | _ => unreachable!(), |
54a0048b | 979 | }?; |
7453a54e SL |
980 | } |
981 | } | |
982 | Ok(()) | |
a7813a04 XL |
983 | } |
984 | PpmFlowGraph(mode) => { | |
985 | let nodeid = nodeid.expect("`pretty flowgraph=..` needs NodeId (int) or \ | |
986 | unique path suffix (b::c::d)"); | |
987 | let node = tcx.map.find(nodeid).unwrap_or_else(|| { | |
988 | tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid)) | |
989 | }); | |
1a4d82fc | 990 | |
a7813a04 XL |
991 | let code = blocks::Code::from_node(node); |
992 | match code { | |
993 | Some(code) => { | |
994 | let variants = gather_flowgraph_variants(tcx.sess); | |
1a4d82fc | 995 | |
a7813a04 | 996 | let out: &mut Write = &mut out; |
1a4d82fc | 997 | |
7453a54e SL |
998 | print_flowgraph(variants, |
999 | tcx, | |
54a0048b | 1000 | mir_map.as_ref(), |
7453a54e SL |
1001 | code, |
1002 | mode, | |
1003 | out) | |
a7813a04 XL |
1004 | } |
1005 | None => { | |
1006 | let message = format!("--pretty=flowgraph needs block, fn, or method; got \ | |
1007 | {:?}", | |
1008 | node); | |
1009 | ||
1010 | // Point to what was found, if there's an accessible span. | |
1011 | match tcx.map.opt_span(nodeid) { | |
1012 | Some(sp) => tcx.sess.span_fatal(sp, &message), | |
1013 | None => tcx.sess.fatal(&message), | |
1014 | } | |
1a4d82fc JJ |
1015 | } |
1016 | } | |
1017 | } | |
a7813a04 | 1018 | _ => unreachable!(), |
1a4d82fc | 1019 | } |
a7813a04 | 1020 | }), sess).unwrap(); |
c34b1796 | 1021 | |
a7813a04 | 1022 | write_output(out, ofile); |
1a4d82fc | 1023 | } |