]> git.lizzy.rs Git - rust.git/blob - src/librustc_driver/pretty.rs
Auto merge of #33450 - SiegeLord:dep_info_no_analysis, r=nrc
[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::dep_graph::DepGraph;
22 use rustc::ty::{self, TyCtxt};
23 use rustc::cfg;
24 use rustc::cfg::graphviz::LabelledCFG;
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::codemap;
35 use syntax::fold::{self, Folder};
36 use syntax::print::{pp, pprust};
37 use syntax::print::pprust::PrintState;
38 use syntax::ptr::P;
39 use syntax::util::small_vector::SmallVector;
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: codemap::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: codemap::DUMMY_SP,
675                 attrs: None,
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                   .src
761                   .as_ref()
762                   .unwrap()
763                   .as_bytes()
764                   .to_vec();
765     (src, src_name)
766 }
767
768 fn write_output(out: Vec<u8>, ofile: Option<&Path>) {
769     match ofile {
770         None => print!("{}", String::from_utf8(out).unwrap()),
771         Some(p) => {
772             match File::create(p) {
773                 Ok(mut w) => w.write_all(&out).unwrap(),
774                 Err(e) => panic!("print-print failed to open {} due to {}", p.display(), e),
775             }
776         }
777     }
778 }
779
780 pub fn print_after_parsing(sess: &Session,
781                            input: &Input,
782                            krate: &ast::Crate,
783                            ppm: PpMode,
784                            ofile: Option<&Path>) {
785     let dep_graph = DepGraph::new(false);
786     let _ignore = dep_graph.in_ignore();
787
788     let (src, src_name) = get_source(input, sess);
789
790     let mut rdr = &*src;
791     let mut out = Vec::new();
792
793     if let PpmSource(s) = ppm {
794         // Silently ignores an identified node.
795         let out: &mut Write = &mut out;
796         s.call_with_pp_support(sess, None, box out, |annotation, out| {
797             debug!("pretty printing source code {:?}", s);
798             let sess = annotation.sess();
799             pprust::print_crate(sess.codemap(),
800                                 sess.diagnostic(),
801                                 krate,
802                                 src_name.to_string(),
803                                 &mut rdr,
804                                 out,
805                                 annotation.pp_ann(),
806                                 false)
807         }).unwrap()
808     } else {
809         unreachable!();
810     };
811
812     write_output(out, ofile);
813 }
814
815 pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
816                                                 ast_map: &hir_map::Map<'tcx>,
817                                                 analysis: &ty::CrateAnalysis,
818                                                 resolutions: &Resolutions,
819                                                 input: &Input,
820                                                 krate: &ast::Crate,
821                                                 crate_name: &str,
822                                                 ppm: PpMode,
823                                                 arenas: &'tcx ty::CtxtArenas<'tcx>,
824                                                 opt_uii: Option<UserIdentifiedItem>,
825                                                 ofile: Option<&Path>) {
826     let dep_graph = DepGraph::new(false);
827     let _ignore = dep_graph.in_ignore();
828
829     if ppm.needs_analysis() {
830         print_with_analysis(sess, ast_map, analysis, resolutions,
831                             crate_name, arenas, ppm, opt_uii, ofile);
832         return;
833     }
834
835     let (src, src_name) = get_source(input, sess);
836
837     let mut rdr = &src[..];
838     let mut out = Vec::new();
839
840     match (ppm, opt_uii) {
841         (PpmSource(s), _) => {
842             // Silently ignores an identified node.
843             let out: &mut Write = &mut out;
844             s.call_with_pp_support(sess, Some(ast_map), box out, |annotation, out| {
845                 debug!("pretty printing source code {:?}", s);
846                 let sess = annotation.sess();
847                 pprust::print_crate(sess.codemap(),
848                                     sess.diagnostic(),
849                                     krate,
850                                     src_name.to_string(),
851                                     &mut rdr,
852                                     out,
853                                     annotation.pp_ann(),
854                                     true)
855             })
856         }
857
858         (PpmHir(s), None) => {
859             let out: &mut Write = &mut out;
860             s.call_with_pp_support_hir(sess,
861                                        ast_map,
862                                        analysis,
863                                        resolutions,
864                                        arenas,
865                                        crate_name,
866                                        box out,
867                                        |annotation, out, krate| {
868                                            debug!("pretty printing source code {:?}", s);
869                                            let sess = annotation.sess();
870                                            pprust_hir::print_crate(sess.codemap(),
871                                                                    sess.diagnostic(),
872                                                                    krate,
873                                                                    src_name.to_string(),
874                                                                    &mut rdr,
875                                                                    out,
876                                                                    annotation.pp_ann(),
877                                                                    true)
878                                        })
879         }
880
881         (PpmHir(s), Some(uii)) => {
882             let out: &mut Write = &mut out;
883             s.call_with_pp_support_hir(sess,
884                                        ast_map,
885                                        analysis,
886                                        resolutions,
887                                        arenas,
888                                        crate_name,
889                                        (out,uii),
890                                        |annotation, (out,uii), _| {
891                 debug!("pretty printing source code {:?}", s);
892                 let sess = annotation.sess();
893                 let ast_map = annotation.ast_map().expect("--unpretty missing HIR map");
894                 let mut pp_state =
895                     pprust_hir::State::new_from_input(sess.codemap(),
896                                                       sess.diagnostic(),
897                                                       src_name.to_string(),
898                                                       &mut rdr,
899                                                       box out,
900                                                       annotation.pp_ann(),
901                                                       true,
902                                                       Some(ast_map.krate()));
903                 for node_id in uii.all_matching_node_ids(ast_map) {
904                     let node = ast_map.get(node_id);
905                     pp_state.print_node(&node)?;
906                     pp::space(&mut pp_state.s)?;
907                     let path = annotation.node_path(node_id)
908                                          .expect("--unpretty missing node paths");
909                     pp_state.synth_comment(path)?;
910                     pp::hardbreak(&mut pp_state.s)?;
911                 }
912                 pp::eof(&mut pp_state.s)
913             })
914        }
915        _ => unreachable!(),
916     }.unwrap();
917
918     write_output(out, ofile);
919 }
920
921 // In an ideal world, this would be a public function called by the driver after
922 // analsysis is performed. However, we want to call `phase_3_run_analysis_passes`
923 // with a different callback than the standard driver, so that isn't easy.
924 // Instead, we call that function ourselves.
925 fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
926                                        ast_map: &hir_map::Map<'tcx>,
927                                        analysis: &ty::CrateAnalysis,
928                                        resolutions: &Resolutions,
929                                        crate_name: &str,
930                                        arenas: &'tcx ty::CtxtArenas<'tcx>,
931                                        ppm: PpMode,
932                                        uii: Option<UserIdentifiedItem>,
933                                        ofile: Option<&Path>) {
934     let nodeid = if let Some(uii) = uii {
935         debug!("pretty printing for {:?}", uii);
936         Some(uii.to_one_node_id("--unpretty", sess, &ast_map))
937     } else {
938         debug!("pretty printing for whole crate");
939         None
940     };
941
942     let mut out = Vec::new();
943
944     abort_on_err(driver::phase_3_run_analysis_passes(sess,
945                                                      ast_map.clone(),
946                                                      analysis.clone(),
947                                                      resolutions.clone(),
948                                                      arenas,
949                                                      crate_name,
950                                                      |tcx, mir_map, _, _| {
951         match ppm {
952             PpmMir | PpmMirCFG => {
953                 if let Some(mir_map) = mir_map {
954                     if let Some(nodeid) = nodeid {
955                         let mir = mir_map.map.get(&nodeid).unwrap_or_else(|| {
956                             sess.fatal(&format!("no MIR map entry for node {}", nodeid))
957                         });
958                         match ppm {
959                             PpmMir => write_mir_pretty(tcx, iter::once((&nodeid, mir)), &mut out),
960                             PpmMirCFG => {
961                                 write_mir_graphviz(tcx, iter::once((&nodeid, mir)), &mut out)
962                             }
963                             _ => unreachable!(),
964                         }?;
965                     } else {
966                         match ppm {
967                             PpmMir => write_mir_pretty(tcx, mir_map.map.iter(), &mut out),
968                             PpmMirCFG => write_mir_graphviz(tcx, mir_map.map.iter(), &mut out),
969                             _ => unreachable!(),
970                         }?;
971                     }
972                 }
973                 Ok(())
974             }
975             PpmFlowGraph(mode) => {
976                 let nodeid = nodeid.expect("`pretty flowgraph=..` needs NodeId (int) or \
977                                             unique path suffix (b::c::d)");
978                 let node = tcx.map.find(nodeid).unwrap_or_else(|| {
979                     tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid))
980                 });
981
982                 let code = blocks::Code::from_node(node);
983                 match code {
984                     Some(code) => {
985                         let variants = gather_flowgraph_variants(tcx.sess);
986
987                         let out: &mut Write = &mut out;
988
989                         print_flowgraph(variants,
990                                         tcx,
991                                         mir_map.as_ref(),
992                                         code,
993                                         mode,
994                                         out)
995                     }
996                     None => {
997                         let message = format!("--pretty=flowgraph needs block, fn, or method; got \
998                                                {:?}",
999                                               node);
1000
1001                         // Point to what was found, if there's an accessible span.
1002                         match tcx.map.opt_span(nodeid) {
1003                             Some(sp) => tcx.sess.span_fatal(sp, &message),
1004                             None => tcx.sess.fatal(&message),
1005                         }
1006                     }
1007                 }
1008             }
1009             _ => unreachable!(),
1010         }
1011     }), sess).unwrap();
1012
1013     write_output(out, ofile);
1014 }