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