]> git.lizzy.rs Git - rust.git/blob - src/librustc_driver/pretty.rs
b6978478085d5b224607c90a0acc898c17ad712b
[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, driver};
19
20 use rustc::ty::{self, TyCtxt, GlobalArenas, Resolutions};
21 use rustc::cfg;
22 use rustc::cfg::graphviz::LabelledCFG;
23 use rustc::dep_graph::DepGraph;
24 use rustc::session::Session;
25 use rustc::session::config::Input;
26 use rustc_borrowck as borrowck;
27 use rustc_borrowck::graphviz as borrowck_dot;
28
29 use rustc_mir::pretty::write_mir_pretty;
30 use rustc_mir::graphviz::write_mir_graphviz;
31
32 use syntax::ast::{self, BlockCheckMode};
33 use syntax::fold::{self, Folder};
34 use syntax::print::{pp, pprust};
35 use syntax::print::pprust::PrintState;
36 use syntax::ptr::P;
37 use syntax::util::small_vector::SmallVector;
38 use syntax_pos;
39
40 use graphviz as dot;
41
42 use std::cell::Cell;
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;
52 use rustc::hir;
53 use rustc::hir::print as pprust_hir;
54
55 use arena::DroplessArena;
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                                            hir_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                     hir_map: hir_map.map(|m| m.clone()),
181                 };
182                 f(&annotation, payload)
183             }
184
185             PpmIdentified | PpmExpandedIdentified => {
186                 let annotation = IdentifiedAnnotation {
187                     sess: sess,
188                     hir_map: hir_map.map(|m| m.clone()),
189                 };
190                 f(&annotation, payload)
191             }
192             PpmExpandedHygiene => {
193                 let annotation = HygieneAnnotation {
194                     sess: sess,
195                 };
196                 f(&annotation, payload)
197             }
198             _ => panic!("Should use call_with_pp_support_hir"),
199         }
200     }
201     fn call_with_pp_support_hir<'tcx, A, B, F>(&self,
202                                                sess: &'tcx Session,
203                                                hir_map: &hir_map::Map<'tcx>,
204                                                analysis: &ty::CrateAnalysis,
205                                                resolutions: &Resolutions,
206                                                arena: &'tcx DroplessArena,
207                                                arenas: &'tcx GlobalArenas<'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                     hir_map: Some(hir_map.clone()),
219                 };
220                 f(&annotation, payload, hir_map.forest.krate())
221             }
222
223             PpmIdentified => {
224                 let annotation = IdentifiedAnnotation {
225                     sess: sess,
226                     hir_map: Some(hir_map.clone()),
227                 };
228                 f(&annotation, payload, hir_map.forest.krate())
229             }
230             PpmTyped => {
231                 abort_on_err(driver::phase_3_run_analysis_passes(sess,
232                                                                  hir_map.clone(),
233                                                                  analysis.clone(),
234                                                                  resolutions.clone(),
235                                                                  arena,
236                                                                  arenas,
237                                                                  id,
238                                                                  |tcx, _, _, _| {
239                     let empty_tables = ty::TypeckTables::empty();
240                     let annotation = TypedAnnotation {
241                         tcx: tcx,
242                         tables: Cell::new(&empty_tables)
243                     };
244                     let _ignore = tcx.dep_graph.in_ignore();
245                     f(&annotation, payload, hir_map.forest.krate())
246                 }),
247                              sess)
248             }
249             _ => panic!("Should use call_with_pp_support"),
250         }
251     }
252 }
253
254 trait PrinterSupport: pprust::PpAnn {
255     /// Provides a uniform interface for re-extracting a reference to a
256     /// `Session` from a value that now owns it.
257     fn sess<'a>(&'a self) -> &'a Session;
258
259     /// Produces the pretty-print annotation object.
260     ///
261     /// (Rust does not yet support upcasting from a trait object to
262     /// an object for one of its super-traits.)
263     fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn;
264 }
265
266 trait HirPrinterSupport<'hir>: pprust_hir::PpAnn {
267     /// Provides a uniform interface for re-extracting a reference to a
268     /// `Session` from a value that now owns it.
269     fn sess<'a>(&'a self) -> &'a Session;
270
271     /// Provides a uniform interface for re-extracting a reference to an
272     /// `hir_map::Map` from a value that now owns it.
273     fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>>;
274
275     /// Produces the pretty-print annotation object.
276     ///
277     /// (Rust does not yet support upcasting from a trait object to
278     /// an object for one of its super-traits.)
279     fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn;
280
281     /// Computes an user-readable representation of a path, if possible.
282     fn node_path(&self, id: ast::NodeId) -> Option<String> {
283         self.hir_map().and_then(|map| map.def_path_from_id(id)).map(|path| {
284             path.data
285                 .into_iter()
286                 .map(|elem| elem.data.to_string())
287                 .collect::<Vec<_>>()
288                 .join("::")
289         })
290     }
291 }
292
293 struct NoAnn<'hir> {
294     sess: &'hir Session,
295     hir_map: Option<hir_map::Map<'hir>>,
296 }
297
298 impl<'hir> PrinterSupport for NoAnn<'hir> {
299     fn sess<'a>(&'a self) -> &'a Session {
300         self.sess
301     }
302
303     fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn {
304         self
305     }
306 }
307
308 impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> {
309     fn sess<'a>(&'a self) -> &'a Session {
310         self.sess
311     }
312
313     fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> {
314         self.hir_map.as_ref()
315     }
316
317     fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn {
318         self
319     }
320 }
321
322 impl<'hir> pprust::PpAnn for NoAnn<'hir> {}
323 impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> {
324     fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
325               -> io::Result<()> {
326         if let Some(ref map) = self.hir_map {
327             pprust_hir::PpAnn::nested(map, state, nested)
328         } else {
329             Ok(())
330         }
331     }
332 }
333
334 struct IdentifiedAnnotation<'hir> {
335     sess: &'hir Session,
336     hir_map: Option<hir_map::Map<'hir>>,
337 }
338
339 impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> {
340     fn sess<'a>(&'a self) -> &'a Session {
341         self.sess
342     }
343
344     fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn {
345         self
346     }
347 }
348
349 impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> {
350     fn pre(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> {
351         match node {
352             pprust::NodeExpr(_) => s.popen(),
353             _ => Ok(()),
354         }
355     }
356     fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> {
357         match node {
358             pprust::NodeIdent(_) |
359             pprust::NodeName(_) => Ok(()),
360
361             pprust::NodeItem(item) => {
362                 pp::space(&mut s.s)?;
363                 s.synth_comment(item.id.to_string())
364             }
365             pprust::NodeSubItem(id) => {
366                 pp::space(&mut s.s)?;
367                 s.synth_comment(id.to_string())
368             }
369             pprust::NodeBlock(blk) => {
370                 pp::space(&mut s.s)?;
371                 s.synth_comment(format!("block {}", blk.id))
372             }
373             pprust::NodeExpr(expr) => {
374                 pp::space(&mut s.s)?;
375                 s.synth_comment(expr.id.to_string())?;
376                 s.pclose()
377             }
378             pprust::NodePat(pat) => {
379                 pp::space(&mut s.s)?;
380                 s.synth_comment(format!("pat {}", pat.id))
381             }
382         }
383     }
384 }
385
386 impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> {
387     fn sess<'a>(&'a self) -> &'a Session {
388         self.sess
389     }
390
391     fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> {
392         self.hir_map.as_ref()
393     }
394
395     fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn {
396         self
397     }
398 }
399
400 impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> {
401     fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
402               -> io::Result<()> {
403         if let Some(ref map) = self.hir_map {
404             pprust_hir::PpAnn::nested(map, state, nested)
405         } else {
406             Ok(())
407         }
408     }
409     fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
410         match node {
411             pprust_hir::NodeExpr(_) => s.popen(),
412             _ => Ok(()),
413         }
414     }
415     fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
416         match node {
417             pprust_hir::NodeName(_) => Ok(()),
418             pprust_hir::NodeItem(item) => {
419                 pp::space(&mut s.s)?;
420                 s.synth_comment(item.id.to_string())
421             }
422             pprust_hir::NodeSubItem(id) => {
423                 pp::space(&mut s.s)?;
424                 s.synth_comment(id.to_string())
425             }
426             pprust_hir::NodeBlock(blk) => {
427                 pp::space(&mut s.s)?;
428                 s.synth_comment(format!("block {}", blk.id))
429             }
430             pprust_hir::NodeExpr(expr) => {
431                 pp::space(&mut s.s)?;
432                 s.synth_comment(expr.id.to_string())?;
433                 s.pclose()
434             }
435             pprust_hir::NodePat(pat) => {
436                 pp::space(&mut s.s)?;
437                 s.synth_comment(format!("pat {}", pat.id))
438             }
439         }
440     }
441 }
442
443 struct HygieneAnnotation<'a> {
444     sess: &'a Session
445 }
446
447 impl<'a> PrinterSupport for HygieneAnnotation<'a> {
448     fn sess(&self) -> &Session {
449         self.sess
450     }
451
452     fn pp_ann(&self) -> &pprust::PpAnn {
453         self
454     }
455 }
456
457 impl<'a> pprust::PpAnn for HygieneAnnotation<'a> {
458     fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> {
459         match node {
460             pprust::NodeIdent(&ast::Ident { name, ctxt }) => {
461                 pp::space(&mut s.s)?;
462                 // FIXME #16420: this doesn't display the connections
463                 // between syntax contexts
464                 s.synth_comment(format!("{}{:?}", name.as_u32(), ctxt))
465             }
466             pprust::NodeName(&name) => {
467                 pp::space(&mut s.s)?;
468                 s.synth_comment(name.as_u32().to_string())
469             }
470             _ => Ok(()),
471         }
472     }
473 }
474
475
476 struct TypedAnnotation<'a, 'tcx: 'a> {
477     tcx: TyCtxt<'a, 'tcx, 'tcx>,
478     tables: Cell<&'a ty::TypeckTables<'tcx>>,
479 }
480
481 impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> {
482     fn sess<'a>(&'a self) -> &'a Session {
483         &self.tcx.sess
484     }
485
486     fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'tcx>> {
487         Some(&self.tcx.hir)
488     }
489
490     fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn {
491         self
492     }
493
494     fn node_path(&self, id: ast::NodeId) -> Option<String> {
495         Some(self.tcx.node_path_str(id))
496     }
497 }
498
499 impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
500     fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
501               -> io::Result<()> {
502         let old_tables = self.tables.get();
503         if let pprust_hir::Nested::Body(id) = nested {
504             self.tables.set(self.tcx.body_tables(id));
505         }
506         pprust_hir::PpAnn::nested(&self.tcx.hir, state, nested)?;
507         self.tables.set(old_tables);
508         Ok(())
509     }
510     fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
511         match node {
512             pprust_hir::NodeExpr(_) => s.popen(),
513             _ => Ok(()),
514         }
515     }
516     fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
517         match node {
518             pprust_hir::NodeExpr(expr) => {
519                 pp::space(&mut s.s)?;
520                 pp::word(&mut s.s, "as")?;
521                 pp::space(&mut s.s)?;
522                 pp::word(&mut s.s, &self.tables.get().expr_ty(expr).to_string())?;
523                 s.pclose()
524             }
525             _ => Ok(()),
526         }
527     }
528 }
529
530 fn gather_flowgraph_variants(sess: &Session) -> Vec<borrowck_dot::Variant> {
531     let print_loans = sess.opts.debugging_opts.flowgraph_print_loans;
532     let print_moves = sess.opts.debugging_opts.flowgraph_print_moves;
533     let print_assigns = sess.opts.debugging_opts.flowgraph_print_assigns;
534     let print_all = sess.opts.debugging_opts.flowgraph_print_all;
535     let mut variants = Vec::new();
536     if print_all || print_loans {
537         variants.push(borrowck_dot::Loans);
538     }
539     if print_all || print_moves {
540         variants.push(borrowck_dot::Moves);
541     }
542     if print_all || print_assigns {
543         variants.push(borrowck_dot::Assigns);
544     }
545     variants
546 }
547
548 #[derive(Clone, Debug)]
549 pub enum UserIdentifiedItem {
550     ItemViaNode(ast::NodeId),
551     ItemViaPath(Vec<String>),
552 }
553
554 impl FromStr for UserIdentifiedItem {
555     type Err = ();
556     fn from_str(s: &str) -> Result<UserIdentifiedItem, ()> {
557         Ok(s.parse()
558             .map(ast::NodeId::new)
559             .map(ItemViaNode)
560             .unwrap_or_else(|_| ItemViaPath(s.split("::").map(|s| s.to_string()).collect())))
561     }
562 }
563
564 enum NodesMatchingUII<'a, 'hir: 'a> {
565     NodesMatchingDirect(option::IntoIter<ast::NodeId>),
566     NodesMatchingSuffix(hir_map::NodesMatchingSuffix<'a, 'hir>),
567 }
568
569 impl<'a, 'hir> Iterator for NodesMatchingUII<'a, 'hir> {
570     type Item = ast::NodeId;
571
572     fn next(&mut self) -> Option<ast::NodeId> {
573         match self {
574             &mut NodesMatchingDirect(ref mut iter) => iter.next(),
575             &mut NodesMatchingSuffix(ref mut iter) => iter.next(),
576         }
577     }
578 }
579
580 impl UserIdentifiedItem {
581     fn reconstructed_input(&self) -> String {
582         match *self {
583             ItemViaNode(node_id) => node_id.to_string(),
584             ItemViaPath(ref parts) => parts.join("::"),
585         }
586     }
587
588     fn all_matching_node_ids<'a, 'hir>(&'a self,
589                                        map: &'a hir_map::Map<'hir>)
590                                        -> NodesMatchingUII<'a, 'hir> {
591         match *self {
592             ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()),
593             ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts[..])),
594         }
595     }
596
597     fn to_one_node_id(self, user_option: &str, sess: &Session, map: &hir_map::Map) -> ast::NodeId {
598         let fail_because = |is_wrong_because| -> ast::NodeId {
599             let message = format!("{} needs NodeId (int) or unique path suffix (b::c::d); got \
600                                    {}, which {}",
601                                   user_option,
602                                   self.reconstructed_input(),
603                                   is_wrong_because);
604             sess.fatal(&message[..])
605         };
606
607         let mut saw_node = ast::DUMMY_NODE_ID;
608         let mut seen = 0;
609         for node in self.all_matching_node_ids(map) {
610             saw_node = node;
611             seen += 1;
612             if seen > 1 {
613                 fail_because("does not resolve uniquely");
614             }
615         }
616         if seen == 0 {
617             fail_because("does not resolve to any item");
618         }
619
620         assert!(seen == 1);
621         return saw_node;
622     }
623 }
624
625 struct ReplaceBodyWithLoop {
626     within_static_or_const: bool,
627 }
628
629 impl ReplaceBodyWithLoop {
630     fn new() -> ReplaceBodyWithLoop {
631         ReplaceBodyWithLoop { within_static_or_const: false }
632     }
633 }
634
635 impl fold::Folder for ReplaceBodyWithLoop {
636     fn fold_item_kind(&mut self, i: ast::ItemKind) -> ast::ItemKind {
637         match i {
638             ast::ItemKind::Static(..) |
639             ast::ItemKind::Const(..) => {
640                 self.within_static_or_const = true;
641                 let ret = fold::noop_fold_item_kind(i, self);
642                 self.within_static_or_const = false;
643                 return ret;
644             }
645             _ => fold::noop_fold_item_kind(i, self),
646         }
647     }
648
649     fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector<ast::TraitItem> {
650         match i.node {
651             ast::TraitItemKind::Const(..) => {
652                 self.within_static_or_const = true;
653                 let ret = fold::noop_fold_trait_item(i, self);
654                 self.within_static_or_const = false;
655                 return ret;
656             }
657             _ => fold::noop_fold_trait_item(i, self),
658         }
659     }
660
661     fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector<ast::ImplItem> {
662         match i.node {
663             ast::ImplItemKind::Const(..) => {
664                 self.within_static_or_const = true;
665                 let ret = fold::noop_fold_impl_item(i, self);
666                 self.within_static_or_const = false;
667                 return ret;
668             }
669             _ => fold::noop_fold_impl_item(i, self),
670         }
671     }
672
673     fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> {
674         fn expr_to_block(rules: ast::BlockCheckMode, e: Option<P<ast::Expr>>) -> P<ast::Block> {
675             P(ast::Block {
676                 stmts: e.map(|e| {
677                         ast::Stmt {
678                             id: ast::DUMMY_NODE_ID,
679                             span: e.span,
680                             node: ast::StmtKind::Expr(e),
681                         }
682                     })
683                     .into_iter()
684                     .collect(),
685                 rules: rules,
686                 id: ast::DUMMY_NODE_ID,
687                 span: syntax_pos::DUMMY_SP,
688             })
689         }
690
691         if !self.within_static_or_const {
692
693             let empty_block = expr_to_block(BlockCheckMode::Default, None);
694             let loop_expr = P(ast::Expr {
695                 node: ast::ExprKind::Loop(empty_block, None),
696                 id: ast::DUMMY_NODE_ID,
697                 span: syntax_pos::DUMMY_SP,
698                 attrs: ast::ThinVec::new(),
699             });
700
701             expr_to_block(b.rules, Some(loop_expr))
702
703         } else {
704             fold::noop_fold_block(b, self)
705         }
706     }
707
708     // in general the pretty printer processes unexpanded code, so
709     // we override the default `fold_mac` method which panics.
710     fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
711         fold::noop_fold_mac(mac, self)
712     }
713 }
714
715 fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>,
716                                        tcx: TyCtxt<'a, 'tcx, 'tcx>,
717                                        code: blocks::Code<'tcx>,
718                                        mode: PpFlowGraphMode,
719                                        mut out: W)
720                                        -> io::Result<()> {
721     let body_id = match code {
722         blocks::Code::Expr(expr) => {
723             // Find the function this expression is from.
724             let mut node_id = expr.id;
725             loop {
726                 let node = tcx.hir.get(node_id);
727                 if let Some(n) = hir::map::blocks::FnLikeNode::from_node(node) {
728                     break n.body();
729                 }
730                 let parent = tcx.hir.get_parent_node(node_id);
731                 assert!(node_id != parent);
732                 node_id = parent;
733             }
734         }
735         blocks::Code::FnLike(fn_like) => fn_like.body(),
736     };
737     let body = tcx.hir.body(body_id);
738     let cfg = cfg::CFG::new(tcx, &body);
739     let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
740     let lcfg = LabelledCFG {
741         hir_map: &tcx.hir,
742         cfg: &cfg,
743         name: format!("node_{}", code.id()),
744         labelled_edges: labelled_edges,
745     };
746
747     match code {
748         _ if variants.is_empty() => {
749             let r = dot::render(&lcfg, &mut out);
750             return expand_err_details(r);
751         }
752         blocks::Code::Expr(_) => {
753             tcx.sess.err("--pretty flowgraph with -Z flowgraph-print annotations requires \
754                           fn-like node id.");
755             return Ok(());
756         }
757         blocks::Code::FnLike(fn_like) => {
758             let (bccx, analysis_data) =
759                 borrowck::build_borrowck_dataflow_data_for_fn(tcx, fn_like.body(), &cfg);
760
761             let lcfg = borrowck_dot::DataflowLabeller {
762                 inner: lcfg,
763                 variants: variants,
764                 borrowck_ctxt: &bccx,
765                 analysis_data: &analysis_data,
766             };
767             let r = dot::render(&lcfg, &mut out);
768             return expand_err_details(r);
769         }
770     }
771
772     fn expand_err_details(r: io::Result<()>) -> io::Result<()> {
773         r.map_err(|ioerr| {
774             io::Error::new(io::ErrorKind::Other,
775                            &format!("graphviz::render failed: {}", ioerr)[..])
776         })
777     }
778 }
779
780 pub fn fold_crate(krate: ast::Crate, ppm: PpMode) -> ast::Crate {
781     if let PpmSource(PpmEveryBodyLoops) = ppm {
782         let mut fold = ReplaceBodyWithLoop::new();
783         fold.fold_crate(krate)
784     } else {
785         krate
786     }
787 }
788
789 fn get_source(input: &Input, sess: &Session) -> (Vec<u8>, String) {
790     let src_name = driver::source_name(input);
791     let src = sess.codemap()
792         .get_filemap(&src_name)
793         .unwrap()
794         .src
795         .as_ref()
796         .unwrap()
797         .as_bytes()
798         .to_vec();
799     (src, src_name)
800 }
801
802 fn write_output(out: Vec<u8>, ofile: Option<&Path>) {
803     match ofile {
804         None => print!("{}", String::from_utf8(out).unwrap()),
805         Some(p) => {
806             match File::create(p) {
807                 Ok(mut w) => w.write_all(&out).unwrap(),
808                 Err(e) => panic!("print-print failed to open {} due to {}", p.display(), e),
809             }
810         }
811     }
812 }
813
814 pub fn print_after_parsing(sess: &Session,
815                            input: &Input,
816                            krate: &ast::Crate,
817                            ppm: PpMode,
818                            ofile: Option<&Path>) {
819     let dep_graph = DepGraph::new(false);
820     let _ignore = dep_graph.in_ignore();
821
822     let (src, src_name) = get_source(input, sess);
823
824     let mut rdr = &*src;
825     let mut out = Vec::new();
826
827     if let PpmSource(s) = ppm {
828         // Silently ignores an identified node.
829         let out: &mut Write = &mut out;
830         s.call_with_pp_support(sess, None, box out, |annotation, out| {
831                 debug!("pretty printing source code {:?}", s);
832                 let sess = annotation.sess();
833                 pprust::print_crate(sess.codemap(),
834                                     &sess.parse_sess,
835                                     krate,
836                                     src_name.to_string(),
837                                     &mut rdr,
838                                     out,
839                                     annotation.pp_ann(),
840                                     false)
841             })
842             .unwrap()
843     } else {
844         unreachable!();
845     };
846
847     write_output(out, ofile);
848 }
849
850 pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
851                                                 hir_map: &hir_map::Map<'tcx>,
852                                                 analysis: &ty::CrateAnalysis,
853                                                 resolutions: &Resolutions,
854                                                 input: &Input,
855                                                 krate: &ast::Crate,
856                                                 crate_name: &str,
857                                                 ppm: PpMode,
858                                                 arena: &'tcx DroplessArena,
859                                                 arenas: &'tcx GlobalArenas<'tcx>,
860                                                 opt_uii: Option<UserIdentifiedItem>,
861                                                 ofile: Option<&Path>) {
862     let dep_graph = DepGraph::new(false);
863     let _ignore = dep_graph.in_ignore();
864
865     if ppm.needs_analysis() {
866         print_with_analysis(sess,
867                             hir_map,
868                             analysis,
869                             resolutions,
870                             crate_name,
871                             arena,
872                             arenas,
873                             ppm,
874                             opt_uii,
875                             ofile);
876         return;
877     }
878
879     let (src, src_name) = get_source(input, sess);
880
881     let mut rdr = &src[..];
882     let mut out = Vec::new();
883
884     match (ppm, opt_uii) {
885             (PpmSource(s), _) => {
886                 // Silently ignores an identified node.
887                 let out: &mut Write = &mut out;
888                 s.call_with_pp_support(sess, Some(hir_map), box out, |annotation, out| {
889                     debug!("pretty printing source code {:?}", s);
890                     let sess = annotation.sess();
891                     pprust::print_crate(sess.codemap(),
892                                         &sess.parse_sess,
893                                         krate,
894                                         src_name.to_string(),
895                                         &mut rdr,
896                                         out,
897                                         annotation.pp_ann(),
898                                         true)
899                 })
900             }
901
902             (PpmHir(s), None) => {
903                 let out: &mut Write = &mut out;
904                 s.call_with_pp_support_hir(sess,
905                                            hir_map,
906                                            analysis,
907                                            resolutions,
908                                            arena,
909                                            arenas,
910                                            crate_name,
911                                            box out,
912                                            |annotation, out, krate| {
913                     debug!("pretty printing source code {:?}", s);
914                     let sess = annotation.sess();
915                     pprust_hir::print_crate(sess.codemap(),
916                                             &sess.parse_sess,
917                                             krate,
918                                             src_name.to_string(),
919                                             &mut rdr,
920                                             out,
921                                             annotation.pp_ann(),
922                                             true)
923                 })
924             }
925
926             (PpmHir(s), Some(uii)) => {
927                 let out: &mut Write = &mut out;
928                 s.call_with_pp_support_hir(sess,
929                                            hir_map,
930                                            analysis,
931                                            resolutions,
932                                            arena,
933                                            arenas,
934                                            crate_name,
935                                            (out, uii),
936                                            |annotation, (out, uii), _| {
937                     debug!("pretty printing source code {:?}", s);
938                     let sess = annotation.sess();
939                     let hir_map = annotation.hir_map().expect("--unpretty missing HIR map");
940                     let mut pp_state = pprust_hir::State::new_from_input(sess.codemap(),
941                                                                          &sess.parse_sess,
942                                                                          src_name.to_string(),
943                                                                          &mut rdr,
944                                                                          box out,
945                                                                          annotation.pp_ann(),
946                                                                          true);
947                     for node_id in uii.all_matching_node_ids(hir_map) {
948                         let node = hir_map.get(node_id);
949                         pp_state.print_node(node)?;
950                         pp::space(&mut pp_state.s)?;
951                         let path = annotation.node_path(node_id)
952                             .expect("--unpretty missing node paths");
953                         pp_state.synth_comment(path)?;
954                         pp::hardbreak(&mut pp_state.s)?;
955                     }
956                     pp::eof(&mut pp_state.s)
957                 })
958             }
959             _ => unreachable!(),
960         }
961         .unwrap();
962
963     write_output(out, ofile);
964 }
965
966 // In an ideal world, this would be a public function called by the driver after
967 // analsysis is performed. However, we want to call `phase_3_run_analysis_passes`
968 // with a different callback than the standard driver, so that isn't easy.
969 // Instead, we call that function ourselves.
970 fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
971                                        hir_map: &hir_map::Map<'tcx>,
972                                        analysis: &ty::CrateAnalysis,
973                                        resolutions: &Resolutions,
974                                        crate_name: &str,
975                                        arena: &'tcx DroplessArena,
976                                        arenas: &'tcx GlobalArenas<'tcx>,
977                                        ppm: PpMode,
978                                        uii: Option<UserIdentifiedItem>,
979                                        ofile: Option<&Path>) {
980     let nodeid = if let Some(uii) = uii {
981         debug!("pretty printing for {:?}", uii);
982         Some(uii.to_one_node_id("--unpretty", sess, &hir_map))
983     } else {
984         debug!("pretty printing for whole crate");
985         None
986     };
987
988     let mut out = Vec::new();
989
990     abort_on_err(driver::phase_3_run_analysis_passes(sess,
991                                                      hir_map.clone(),
992                                                      analysis.clone(),
993                                                      resolutions.clone(),
994                                                      arena,
995                                                      arenas,
996                                                      crate_name,
997                                                      |tcx, _, _, _| {
998         match ppm {
999             PpmMir | PpmMirCFG => {
1000                 if let Some(nodeid) = nodeid {
1001                     let def_id = tcx.hir.local_def_id(nodeid);
1002                     match ppm {
1003                         PpmMir => write_mir_pretty(tcx, iter::once(def_id), &mut out),
1004                         PpmMirCFG => write_mir_graphviz(tcx, iter::once(def_id), &mut out),
1005                         _ => unreachable!(),
1006                     }?;
1007                 } else {
1008                     match ppm {
1009                         PpmMir => {
1010                             write_mir_pretty(tcx,
1011                                              tcx.maps.mir.borrow().keys().into_iter(),
1012                                              &mut out)
1013                         }
1014                         PpmMirCFG => {
1015                             write_mir_graphviz(tcx,
1016                                                tcx.maps.mir.borrow().keys().into_iter(),
1017                                                &mut out)
1018                         }
1019                         _ => unreachable!(),
1020                     }?;
1021                 }
1022                 Ok(())
1023             }
1024             PpmFlowGraph(mode) => {
1025                 let nodeid =
1026                     nodeid.expect("`pretty flowgraph=..` needs NodeId (int) or unique path \
1027                                    suffix (b::c::d)");
1028                 let node = tcx.hir.find(nodeid).unwrap_or_else(|| {
1029                     tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid))
1030                 });
1031
1032                 match blocks::Code::from_node(&tcx.hir, nodeid) {
1033                     Some(code) => {
1034                         let variants = gather_flowgraph_variants(tcx.sess);
1035
1036                         let out: &mut Write = &mut out;
1037
1038                         print_flowgraph(variants, tcx, code, mode, out)
1039                     }
1040                     None => {
1041                         let message = format!("--pretty=flowgraph needs block, fn, or method; \
1042                                                got {:?}",
1043                                               node);
1044
1045                         tcx.sess.span_fatal(tcx.hir.span(nodeid), &message)
1046                     }
1047                 }
1048             }
1049             _ => unreachable!(),
1050         }
1051     }),
1052                  sess)
1053         .unwrap();
1054
1055     write_output(out, ofile);
1056 }