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