]> git.lizzy.rs Git - rust.git/blob - src/librustc_driver/pretty.rs
Rollup merge of #65263 - mbStavola:dedup-raw-item-fns, r=Centril
[rust.git] / src / librustc_driver / pretty.rs
1 //! The various pretty-printing routines.
2
3 use rustc::hir;
4 use rustc::hir::map as hir_map;
5 use rustc::hir::print as pprust_hir;
6 use rustc::hir::def_id::LOCAL_CRATE;
7 use rustc::session::Session;
8 use rustc::session::config::Input;
9 use rustc::ty::{self, TyCtxt};
10 use rustc::util::common::ErrorReported;
11 use rustc_interface::util::ReplaceBodyWithLoop;
12 use rustc_mir::util::{write_mir_pretty, write_mir_graphviz};
13
14 use syntax::ast;
15 use syntax::mut_visit::MutVisitor;
16 use syntax::print::{pprust};
17 use syntax_pos::FileName;
18
19 use std::cell::Cell;
20 use std::fs::File;
21 use std::io::Write;
22 use std::option;
23 use std::path::Path;
24 use std::str::FromStr;
25
26 pub use self::UserIdentifiedItem::*;
27 pub use self::PpSourceMode::*;
28 pub use self::PpMode::*;
29 use self::NodesMatchingUII::*;
30 use crate::abort_on_err;
31
32 use crate::source_name;
33
34 #[derive(Copy, Clone, PartialEq, Debug)]
35 pub enum PpSourceMode {
36     PpmNormal,
37     PpmEveryBodyLoops,
38     PpmExpanded,
39     PpmIdentified,
40     PpmExpandedIdentified,
41     PpmExpandedHygiene,
42     PpmTyped,
43 }
44
45 #[derive(Copy, Clone, PartialEq, Debug)]
46 pub enum PpMode {
47     PpmSource(PpSourceMode),
48     PpmHir(PpSourceMode),
49     PpmHirTree(PpSourceMode),
50     PpmMir,
51     PpmMirCFG,
52 }
53
54 impl PpMode {
55     pub fn needs_ast_map(&self, opt_uii: &Option<UserIdentifiedItem>) -> bool {
56         match *self {
57             PpmSource(PpmNormal) |
58             PpmSource(PpmEveryBodyLoops) |
59             PpmSource(PpmIdentified) => opt_uii.is_some(),
60
61             PpmSource(PpmExpanded) |
62             PpmSource(PpmExpandedIdentified) |
63             PpmSource(PpmExpandedHygiene) |
64             PpmHir(_) |
65             PpmHirTree(_) |
66             PpmMir |
67             PpmMirCFG => true,
68             PpmSource(PpmTyped) => panic!("invalid state"),
69         }
70     }
71
72     pub fn needs_analysis(&self) -> bool {
73         match *self {
74             PpmMir | PpmMirCFG => true,
75             _ => false,
76         }
77     }
78 }
79
80 pub fn parse_pretty(sess: &Session,
81                     name: &str,
82                     extended: bool)
83                     -> (PpMode, Option<UserIdentifiedItem>) {
84     let mut split = name.splitn(2, '=');
85     let first = split.next().unwrap();
86     let opt_second = split.next();
87     let first = match (first, extended) {
88         ("normal", _) => PpmSource(PpmNormal),
89         ("identified", _) => PpmSource(PpmIdentified),
90         ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
91         ("expanded", _) => PpmSource(PpmExpanded),
92         ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
93         ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
94         ("hir", true) => PpmHir(PpmNormal),
95         ("hir,identified", true) => PpmHir(PpmIdentified),
96         ("hir,typed", true) => PpmHir(PpmTyped),
97         ("hir-tree", true) => PpmHirTree(PpmNormal),
98         ("mir", true) => PpmMir,
99         ("mir-cfg", true) => PpmMirCFG,
100         _ => {
101             if extended {
102                 sess.fatal(&format!("argument to `unpretty` must be one of `normal`, \
103                                      `expanded`, `identified`, `expanded,identified`, \
104                                      `expanded,hygiene`, `everybody_loops`, \
105                                      `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
106                                      `mir` or `mir-cfg`; got {}",
107                                     name));
108             } else {
109                 sess.fatal(&format!("argument to `pretty` must be one of `normal`, `expanded`, \
110                                      `identified`, or `expanded,identified`; got {}",
111                                     name));
112             }
113         }
114     };
115     let opt_second = opt_second.and_then(|s| s.parse::<UserIdentifiedItem>().ok());
116     (first, opt_second)
117 }
118
119
120
121 // This slightly awkward construction is to allow for each PpMode to
122 // choose whether it needs to do analyses (which can consume the
123 // Session) and then pass through the session (now attached to the
124 // analysis results) on to the chosen pretty-printer, along with the
125 // `&PpAnn` object.
126 //
127 // Note that since the `&PrinterSupport` is freshly constructed on each
128 // call, it would not make sense to try to attach the lifetime of `self`
129 // to the lifetime of the `&PrinterObject`.
130 //
131 // (The `use_once_payload` is working around the current lack of once
132 // functions in the compiler.)
133
134 impl PpSourceMode {
135     /// Constructs a `PrinterSupport` object and passes it to `f`.
136     fn call_with_pp_support<'tcx, A, F>(
137         &self,
138         sess: &'tcx Session,
139         tcx: Option<TyCtxt<'tcx>>,
140         f: F,
141     ) -> A
142     where
143         F: FnOnce(&dyn PrinterSupport) -> A,
144     {
145         match *self {
146             PpmNormal | PpmEveryBodyLoops | PpmExpanded => {
147                 let annotation = NoAnn {
148                     sess,
149                     tcx,
150                 };
151                 f(&annotation)
152             }
153
154             PpmIdentified | PpmExpandedIdentified => {
155                 let annotation = IdentifiedAnnotation {
156                     sess,
157                     tcx,
158                 };
159                 f(&annotation)
160             }
161             PpmExpandedHygiene => {
162                 let annotation = HygieneAnnotation {
163                     sess,
164                 };
165                 f(&annotation)
166             }
167             _ => panic!("Should use call_with_pp_support_hir"),
168         }
169     }
170     fn call_with_pp_support_hir<A, F>(&self, tcx: TyCtxt<'_>, f: F) -> A
171     where
172         F: FnOnce(&dyn HirPrinterSupport<'_>, &hir::Crate) -> A,
173     {
174         match *self {
175             PpmNormal => {
176                 let annotation = NoAnn {
177                     sess: tcx.sess,
178                     tcx: Some(tcx),
179                 };
180                 f(&annotation, tcx.hir().forest.krate())
181             }
182
183             PpmIdentified => {
184                 let annotation = IdentifiedAnnotation {
185                     sess: tcx.sess,
186                     tcx: Some(tcx),
187                 };
188                 f(&annotation, tcx.hir().forest.krate())
189             }
190             PpmTyped => {
191                 abort_on_err(tcx.analysis(LOCAL_CRATE), tcx.sess);
192
193                 let empty_tables = ty::TypeckTables::empty(None);
194                 let annotation = TypedAnnotation {
195                     tcx,
196                     tables: Cell::new(&empty_tables)
197                 };
198                 tcx.dep_graph.with_ignore(|| {
199                     f(&annotation, tcx.hir().forest.krate())
200                 })
201             }
202             _ => panic!("Should use call_with_pp_support"),
203         }
204     }
205 }
206
207 trait PrinterSupport: pprust::PpAnn {
208     /// Provides a uniform interface for re-extracting a reference to a
209     /// `Session` from a value that now owns it.
210     fn sess(&self) -> &Session;
211
212     /// Produces the pretty-print annotation object.
213     ///
214     /// (Rust does not yet support upcasting from a trait object to
215     /// an object for one of its super-traits.)
216     fn pp_ann<'a>(&'a self) -> &'a dyn pprust::PpAnn;
217 }
218
219 trait HirPrinterSupport<'hir>: pprust_hir::PpAnn {
220     /// Provides a uniform interface for re-extracting a reference to a
221     /// `Session` from a value that now owns it.
222     fn sess(&self) -> &Session;
223
224     /// Provides a uniform interface for re-extracting a reference to an
225     /// `hir_map::Map` from a value that now owns it.
226     fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>>;
227
228     /// Produces the pretty-print annotation object.
229     ///
230     /// (Rust does not yet support upcasting from a trait object to
231     /// an object for one of its super-traits.)
232     fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn;
233
234     /// Computes an user-readable representation of a path, if possible.
235     fn node_path(&self, id: hir::HirId) -> Option<String> {
236         self.hir_map().and_then(|map| {
237             map.def_path_from_hir_id(id)
238         }).map(|path| {
239             path.data
240                 .into_iter()
241                 .map(|elem| elem.data.to_string())
242                 .collect::<Vec<_>>()
243                 .join("::")
244         })
245     }
246 }
247
248 struct NoAnn<'hir> {
249     sess: &'hir Session,
250     tcx: Option<TyCtxt<'hir>>,
251 }
252
253 impl<'hir> PrinterSupport for NoAnn<'hir> {
254     fn sess(&self) -> &Session {
255         self.sess
256     }
257
258     fn pp_ann<'a>(&'a self) -> &'a dyn pprust::PpAnn {
259         self
260     }
261 }
262
263 impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> {
264     fn sess(&self) -> &Session {
265         self.sess
266     }
267
268     fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> {
269         self.tcx.map(|tcx| tcx.hir())
270     }
271
272     fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn {
273         self
274     }
275 }
276
277 impl<'hir> pprust::PpAnn for NoAnn<'hir> {}
278 impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> {
279     fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
280         if let Some(tcx) = self.tcx {
281             pprust_hir::PpAnn::nested(tcx.hir(), state, nested)
282         }
283     }
284 }
285
286 struct IdentifiedAnnotation<'hir> {
287     sess: &'hir Session,
288     tcx: Option<TyCtxt<'hir>>,
289 }
290
291 impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> {
292     fn sess(&self) -> &Session {
293         self.sess
294     }
295
296     fn pp_ann<'a>(&'a self) -> &'a dyn pprust::PpAnn {
297         self
298     }
299 }
300
301 impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> {
302     fn pre(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
303         match node {
304             pprust::AnnNode::Expr(_) => s.popen(),
305             _ => {}
306         }
307     }
308     fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
309         match node {
310             pprust::AnnNode::Crate(_) |
311             pprust::AnnNode::Ident(_) |
312             pprust::AnnNode::Name(_) => {},
313
314             pprust::AnnNode::Item(item) => {
315                 s.s.space();
316                 s.synth_comment(item.id.to_string())
317             }
318             pprust::AnnNode::SubItem(id) => {
319                 s.s.space();
320                 s.synth_comment(id.to_string())
321             }
322             pprust::AnnNode::Block(blk) => {
323                 s.s.space();
324                 s.synth_comment(format!("block {}", blk.id))
325             }
326             pprust::AnnNode::Expr(expr) => {
327                 s.s.space();
328                 s.synth_comment(expr.id.to_string());
329                 s.pclose()
330             }
331             pprust::AnnNode::Pat(pat) => {
332                 s.s.space();
333                 s.synth_comment(format!("pat {}", pat.id));
334             }
335         }
336     }
337 }
338
339 impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> {
340     fn sess(&self) -> &Session {
341         self.sess
342     }
343
344     fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> {
345         self.tcx.map(|tcx| tcx.hir())
346     }
347
348     fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn {
349         self
350     }
351 }
352
353 impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> {
354     fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
355         if let Some(ref tcx) = self.tcx {
356             pprust_hir::PpAnn::nested(tcx.hir(), state, nested)
357         }
358     }
359     fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
360         match node {
361             pprust_hir::AnnNode::Expr(_) => s.popen(),
362             _ => {}
363         }
364     }
365     fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
366         match node {
367             pprust_hir::AnnNode::Name(_) => {},
368             pprust_hir::AnnNode::Item(item) => {
369                 s.s.space();
370                 s.synth_comment(format!("hir_id: {}", item.hir_id));
371             }
372             pprust_hir::AnnNode::SubItem(id) => {
373                 s.s.space();
374                 s.synth_comment(id.to_string());
375             }
376             pprust_hir::AnnNode::Block(blk) => {
377                 s.s.space();
378                 s.synth_comment(format!("block hir_id: {}", blk.hir_id));
379             }
380             pprust_hir::AnnNode::Expr(expr) => {
381                 s.s.space();
382                 s.synth_comment(format!("expr hir_id: {}", expr.hir_id));
383                 s.pclose();
384             }
385             pprust_hir::AnnNode::Pat(pat) => {
386                 s.s.space();
387                 s.synth_comment(format!("pat hir_id: {}", pat.hir_id));
388             }
389             pprust_hir::AnnNode::Arm(arm) => {
390                 s.s.space();
391                 s.synth_comment(format!("arm hir_id: {}", arm.hir_id));
392             }
393         }
394     }
395 }
396
397 struct HygieneAnnotation<'a> {
398     sess: &'a Session
399 }
400
401 impl<'a> PrinterSupport for HygieneAnnotation<'a> {
402     fn sess(&self) -> &Session {
403         self.sess
404     }
405
406     fn pp_ann(&self) -> &dyn pprust::PpAnn {
407         self
408     }
409 }
410
411 impl<'a> pprust::PpAnn for HygieneAnnotation<'a> {
412     fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
413         match node {
414             pprust::AnnNode::Ident(&ast::Ident { name, span }) => {
415                 s.s.space();
416                 s.synth_comment(format!("{}{:?}", name.as_u32(), span.ctxt()))
417             }
418             pprust::AnnNode::Name(&name) => {
419                 s.s.space();
420                 s.synth_comment(name.as_u32().to_string())
421             }
422             pprust::AnnNode::Crate(_) => {
423                 s.s.hardbreak();
424                 let verbose = self.sess.verbose();
425                 s.synth_comment(syntax_pos::hygiene::debug_hygiene_data(verbose));
426                 s.s.hardbreak_if_not_bol();
427             }
428             _ => {}
429         }
430     }
431 }
432
433 struct TypedAnnotation<'a, 'tcx> {
434     tcx: TyCtxt<'tcx>,
435     tables: Cell<&'a ty::TypeckTables<'tcx>>,
436 }
437
438 impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> {
439     fn sess(&self) -> &Session {
440         &self.tcx.sess
441     }
442
443     fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'tcx>> {
444         Some(&self.tcx.hir())
445     }
446
447     fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn {
448         self
449     }
450
451     fn node_path(&self, id: hir::HirId) -> Option<String> {
452         Some(self.tcx.def_path_str(self.tcx.hir().local_def_id(id)))
453     }
454 }
455
456 impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
457     fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
458         let old_tables = self.tables.get();
459         if let pprust_hir::Nested::Body(id) = nested {
460             self.tables.set(self.tcx.body_tables(id));
461         }
462         pprust_hir::PpAnn::nested(self.tcx.hir(), state, nested);
463         self.tables.set(old_tables);
464     }
465     fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
466         match node {
467             pprust_hir::AnnNode::Expr(_) => s.popen(),
468             _ => {}
469         }
470     }
471     fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
472         match node {
473             pprust_hir::AnnNode::Expr(expr) => {
474                 s.s.space();
475                 s.s.word("as");
476                 s.s.space();
477                 s.s.word(self.tables.get().expr_ty(expr).to_string());
478                 s.pclose();
479             }
480             _ => {},
481         }
482     }
483 }
484
485 #[derive(Clone, Debug)]
486 pub enum UserIdentifiedItem {
487     ItemViaNode(ast::NodeId),
488     ItemViaPath(Vec<String>),
489 }
490
491 impl FromStr for UserIdentifiedItem {
492     type Err = ();
493     fn from_str(s: &str) -> Result<UserIdentifiedItem, ()> {
494         Ok(s.parse()
495             .map(ast::NodeId::from_u32)
496             .map(ItemViaNode)
497             .unwrap_or_else(|_| ItemViaPath(s.split("::").map(|s| s.to_string()).collect())))
498     }
499 }
500
501 enum NodesMatchingUII<'a> {
502     NodesMatchingDirect(option::IntoIter<ast::NodeId>),
503     NodesMatchingSuffix(Box<dyn Iterator<Item = ast::NodeId> + 'a>),
504 }
505
506 impl<'a> Iterator for NodesMatchingUII<'a> {
507     type Item = ast::NodeId;
508
509     fn next(&mut self) -> Option<ast::NodeId> {
510         match self {
511             &mut NodesMatchingDirect(ref mut iter) => iter.next(),
512             &mut NodesMatchingSuffix(ref mut iter) => iter.next(),
513         }
514     }
515
516     fn size_hint(&self) -> (usize, Option<usize>) {
517         match self {
518             &NodesMatchingDirect(ref iter) => iter.size_hint(),
519             &NodesMatchingSuffix(ref iter) => iter.size_hint(),
520         }
521     }
522 }
523
524 impl UserIdentifiedItem {
525     fn reconstructed_input(&self) -> String {
526         match *self {
527             ItemViaNode(node_id) => node_id.to_string(),
528             ItemViaPath(ref parts) => parts.join("::"),
529         }
530     }
531
532     fn all_matching_node_ids<'a, 'hir>(&'a self,
533                                        map: &'a hir_map::Map<'hir>)
534                                        -> NodesMatchingUII<'a> {
535         match *self {
536             ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()),
537             ItemViaPath(ref parts) => {
538                 NodesMatchingSuffix(Box::new(map.nodes_matching_suffix(&parts)))
539             }
540         }
541     }
542
543     fn to_one_node_id(self,
544                       user_option: &str,
545                       sess: &Session,
546                       map: &hir_map::Map<'_>)
547                       -> ast::NodeId {
548         let fail_because = |is_wrong_because| -> ast::NodeId {
549             let message = format!("{} needs NodeId (int) or unique path suffix (b::c::d); got \
550                                    {}, which {}",
551                                   user_option,
552                                   self.reconstructed_input(),
553                                   is_wrong_because);
554             sess.fatal(&message)
555         };
556
557         let mut saw_node = ast::DUMMY_NODE_ID;
558         let mut seen = 0;
559         for node in self.all_matching_node_ids(map) {
560             saw_node = node;
561             seen += 1;
562             if seen > 1 {
563                 fail_because("does not resolve uniquely");
564             }
565         }
566         if seen == 0 {
567             fail_because("does not resolve to any item");
568         }
569
570         assert!(seen == 1);
571         return saw_node;
572     }
573 }
574
575 pub fn visit_crate(sess: &Session, krate: &mut ast::Crate, ppm: PpMode) {
576     if let PpmSource(PpmEveryBodyLoops) = ppm {
577         ReplaceBodyWithLoop::new(sess).visit_crate(krate);
578     }
579 }
580
581 fn get_source(input: &Input, sess: &Session) -> (String, FileName) {
582     let src_name = source_name(input);
583     let src = String::clone(&sess.source_map()
584         .get_source_file(&src_name)
585         .unwrap()
586         .src
587         .as_ref()
588         .unwrap());
589     (src, src_name)
590 }
591
592 fn write_output(out: Vec<u8>, ofile: Option<&Path>) {
593     match ofile {
594         None => print!("{}", String::from_utf8(out).unwrap()),
595         Some(p) => {
596             match File::create(p) {
597                 Ok(mut w) => w.write_all(&out).unwrap(),
598                 Err(e) => panic!("print-print failed to open {} due to {}", p.display(), e),
599             }
600         }
601     }
602 }
603
604 pub fn print_after_parsing(sess: &Session,
605                            input: &Input,
606                            krate: &ast::Crate,
607                            ppm: PpMode,
608                            ofile: Option<&Path>) {
609     let (src, src_name) = get_source(input, sess);
610
611     let mut out = String::new();
612
613     if let PpmSource(s) = ppm {
614         // Silently ignores an identified node.
615         let out = &mut out;
616         s.call_with_pp_support(sess, None, move |annotation| {
617             debug!("pretty printing source code {:?}", s);
618             let sess = annotation.sess();
619             *out = pprust::print_crate(sess.source_map(),
620                                 &sess.parse_sess,
621                                 krate,
622                                 src_name,
623                                 src,
624                                 annotation.pp_ann(),
625                                 false)
626         })
627     } else {
628         unreachable!();
629     };
630
631     write_output(out.into_bytes(), ofile);
632 }
633
634 pub fn print_after_hir_lowering<'tcx>(
635     tcx: TyCtxt<'tcx>,
636     input: &Input,
637     krate: &ast::Crate,
638     ppm: PpMode,
639     opt_uii: Option<UserIdentifiedItem>,
640     ofile: Option<&Path>,
641 ) {
642     if ppm.needs_analysis() {
643         abort_on_err(print_with_analysis(
644             tcx,
645             ppm,
646             opt_uii,
647             ofile
648         ), tcx.sess);
649         return;
650     }
651
652     let (src, src_name) = get_source(input, tcx.sess);
653
654     let mut out = String::new();
655
656     match (ppm, opt_uii) {
657             (PpmSource(s), _) => {
658                 // Silently ignores an identified node.
659                 let out = &mut out;
660                 let src = src.clone();
661                 s.call_with_pp_support(tcx.sess, Some(tcx), move |annotation| {
662                     debug!("pretty printing source code {:?}", s);
663                     let sess = annotation.sess();
664                     *out = pprust::print_crate(sess.source_map(),
665                                         &sess.parse_sess,
666                                         krate,
667                                         src_name,
668                                         src,
669                                         annotation.pp_ann(),
670                                         true)
671                 })
672             }
673
674             (PpmHir(s), None) => {
675                 let out = &mut out;
676                 let src = src.clone();
677                 s.call_with_pp_support_hir(tcx, move |annotation, krate| {
678                     debug!("pretty printing source code {:?}", s);
679                     let sess = annotation.sess();
680                     *out = pprust_hir::print_crate(sess.source_map(),
681                                             &sess.parse_sess,
682                                             krate,
683                                             src_name,
684                                             src,
685                                             annotation.pp_ann())
686                 })
687             }
688
689             (PpmHirTree(s), None) => {
690                 let out = &mut out;
691                 s.call_with_pp_support_hir(tcx, move |_annotation, krate| {
692                     debug!("pretty printing source code {:?}", s);
693                     *out = format!("{:#?}", krate);
694                 });
695             }
696
697             (PpmHir(s), Some(uii)) => {
698                 let out = &mut out;
699                 let src = src.clone();
700                 s.call_with_pp_support_hir(tcx, move |annotation, _| {
701                     debug!("pretty printing source code {:?}", s);
702                     let sess = annotation.sess();
703                     let hir_map = annotation.hir_map().expect("-Z unpretty missing HIR map");
704                     let mut pp_state = pprust_hir::State::new_from_input(sess.source_map(),
705                                                                          &sess.parse_sess,
706                                                                          src_name,
707                                                                          src,
708                                                                          annotation.pp_ann());
709                     for node_id in uii.all_matching_node_ids(hir_map) {
710                         let hir_id = tcx.hir().node_to_hir_id(node_id);
711                         let node = hir_map.get(hir_id);
712                         pp_state.print_node(node);
713                         pp_state.s.space();
714                         let path = annotation.node_path(hir_id)
715                             .expect("-Z unpretty missing node paths");
716                         pp_state.synth_comment(path);
717                         pp_state.s.hardbreak();
718                     }
719                     *out = pp_state.s.eof();
720                 })
721             }
722
723             (PpmHirTree(s), Some(uii)) => {
724                 let out = &mut out;
725                 s.call_with_pp_support_hir(tcx, move |_annotation, _krate| {
726                     debug!("pretty printing source code {:?}", s);
727                     for node_id in uii.all_matching_node_ids(tcx.hir()) {
728                         let hir_id = tcx.hir().node_to_hir_id(node_id);
729                         let node = tcx.hir().get(hir_id);
730                         out.push_str(&format!("{:#?}", node));
731                     }
732                 })
733             }
734
735             _ => unreachable!(),
736         }
737
738     write_output(out.into_bytes(), ofile);
739 }
740
741 // In an ideal world, this would be a public function called by the driver after
742 // analysis is performed. However, we want to call `phase_3_run_analysis_passes`
743 // with a different callback than the standard driver, so that isn't easy.
744 // Instead, we call that function ourselves.
745 fn print_with_analysis(
746     tcx: TyCtxt<'_>,
747     ppm: PpMode,
748     uii: Option<UserIdentifiedItem>,
749     ofile: Option<&Path>,
750 ) -> Result<(), ErrorReported> {
751     let nodeid = if let Some(uii) = uii {
752         debug!("pretty printing for {:?}", uii);
753         Some(uii.to_one_node_id("-Z unpretty", tcx.sess, tcx.hir()))
754     } else {
755         debug!("pretty printing for whole crate");
756         None
757     };
758
759     let mut out = Vec::new();
760
761     tcx.analysis(LOCAL_CRATE)?;
762
763     match ppm {
764         PpmMir | PpmMirCFG => {
765             let def_id = nodeid.map(|nid| tcx.hir().local_def_id_from_node_id(nid));
766             match ppm {
767                 PpmMir => write_mir_pretty(tcx, def_id, &mut out),
768                 PpmMirCFG => write_mir_graphviz(tcx, def_id, &mut out),
769                 _ => unreachable!(),
770             }
771         }
772         _ => unreachable!(),
773     }.unwrap();
774
775     write_output(out, ofile);
776
777     Ok(())
778 }