]> git.lizzy.rs Git - rust.git/blob - src/librustc_driver/pretty.rs
Simplify Cache wrapper to single type, impl Deref on it, fix all compilation errors...
[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::{PpMode, PpSourceMode, Input};
9 use rustc::ty::{self, TyCtxt};
10 use rustc::util::common::ErrorReported;
11 use rustc_mir::util::{write_mir_pretty, write_mir_graphviz};
12
13 use syntax::ast;
14 use syntax::print::{pprust};
15 use syntax_pos::FileName;
16
17 use std::cell::Cell;
18 use std::fs::File;
19 use std::io::Write;
20 use std::path::Path;
21
22 pub use self::PpSourceMode::*;
23 pub use self::PpMode::*;
24 use crate::abort_on_err;
25
26 // This slightly awkward construction is to allow for each PpMode to
27 // choose whether it needs to do analyses (which can consume the
28 // Session) and then pass through the session (now attached to the
29 // analysis results) on to the chosen pretty-printer, along with the
30 // `&PpAnn` object.
31 //
32 // Note that since the `&PrinterSupport` is freshly constructed on each
33 // call, it would not make sense to try to attach the lifetime of `self`
34 // to the lifetime of the `&PrinterObject`.
35 //
36 // (The `use_once_payload` is working around the current lack of once
37 // functions in the compiler.)
38
39 /// Constructs a `PrinterSupport` object and passes it to `f`.
40 fn call_with_pp_support<'tcx, A, F>(
41     ppmode: &PpSourceMode,
42     sess: &'tcx Session,
43     tcx: Option<TyCtxt<'tcx>>,
44     f: F,
45 ) -> A
46 where
47     F: FnOnce(&dyn PrinterSupport) -> A,
48 {
49     match *ppmode {
50         PpmNormal | PpmEveryBodyLoops | PpmExpanded => {
51             let annotation = NoAnn {
52                 sess,
53                 tcx,
54             };
55             f(&annotation)
56         }
57
58         PpmIdentified | PpmExpandedIdentified => {
59             let annotation = IdentifiedAnnotation {
60                 sess,
61                 tcx,
62             };
63             f(&annotation)
64         }
65         PpmExpandedHygiene => {
66             let annotation = HygieneAnnotation {
67                 sess,
68             };
69             f(&annotation)
70         }
71         _ => panic!("Should use call_with_pp_support_hir"),
72     }
73 }
74 fn call_with_pp_support_hir<A, F>(ppmode: &PpSourceMode, tcx: TyCtxt<'_>, f: F) -> A
75 where
76     F: FnOnce(&dyn HirPrinterSupport<'_>, &hir::Crate) -> A,
77 {
78     match *ppmode {
79         PpmNormal => {
80             let annotation = NoAnn {
81                 sess: tcx.sess,
82                 tcx: Some(tcx),
83             };
84             f(&annotation, tcx.hir().forest.krate())
85         }
86
87         PpmIdentified => {
88             let annotation = IdentifiedAnnotation {
89                 sess: tcx.sess,
90                 tcx: Some(tcx),
91             };
92             f(&annotation, tcx.hir().forest.krate())
93         }
94         PpmTyped => {
95             abort_on_err(tcx.analysis(LOCAL_CRATE), tcx.sess);
96
97             let empty_tables = ty::TypeckTables::empty(None);
98             let annotation = TypedAnnotation {
99                 tcx,
100                 tables: Cell::new(&empty_tables)
101             };
102             tcx.dep_graph.with_ignore(|| {
103                 f(&annotation, tcx.hir().forest.krate())
104             })
105         }
106         _ => panic!("Should use call_with_pp_support"),
107     }
108 }
109
110 trait PrinterSupport: pprust::PpAnn {
111     /// Provides a uniform interface for re-extracting a reference to a
112     /// `Session` from a value that now owns it.
113     fn sess(&self) -> &Session;
114
115     /// Produces the pretty-print annotation object.
116     ///
117     /// (Rust does not yet support upcasting from a trait object to
118     /// an object for one of its super-traits.)
119     fn pp_ann<'a>(&'a self) -> &'a dyn pprust::PpAnn;
120 }
121
122 trait HirPrinterSupport<'hir>: pprust_hir::PpAnn {
123     /// Provides a uniform interface for re-extracting a reference to a
124     /// `Session` from a value that now owns it.
125     fn sess(&self) -> &Session;
126
127     /// Provides a uniform interface for re-extracting a reference to an
128     /// `hir_map::Map` from a value that now owns it.
129     fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>>;
130
131     /// Produces the pretty-print annotation object.
132     ///
133     /// (Rust does not yet support upcasting from a trait object to
134     /// an object for one of its super-traits.)
135     fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn;
136
137     /// Computes an user-readable representation of a path, if possible.
138     fn node_path(&self, id: hir::HirId) -> Option<String> {
139         self.hir_map().and_then(|map| {
140             map.def_path_from_hir_id(id)
141         }).map(|path| {
142             path.data
143                 .into_iter()
144                 .map(|elem| elem.data.to_string())
145                 .collect::<Vec<_>>()
146                 .join("::")
147         })
148     }
149 }
150
151 struct NoAnn<'hir> {
152     sess: &'hir Session,
153     tcx: Option<TyCtxt<'hir>>,
154 }
155
156 impl<'hir> PrinterSupport for NoAnn<'hir> {
157     fn sess(&self) -> &Session {
158         self.sess
159     }
160
161     fn pp_ann<'a>(&'a self) -> &'a dyn pprust::PpAnn {
162         self
163     }
164 }
165
166 impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> {
167     fn sess(&self) -> &Session {
168         self.sess
169     }
170
171     fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> {
172         self.tcx.map(|tcx| tcx.hir())
173     }
174
175     fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn {
176         self
177     }
178 }
179
180 impl<'hir> pprust::PpAnn for NoAnn<'hir> {}
181 impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> {
182     fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
183         if let Some(tcx) = self.tcx {
184             pprust_hir::PpAnn::nested(tcx.hir(), state, nested)
185         }
186     }
187 }
188
189 struct IdentifiedAnnotation<'hir> {
190     sess: &'hir Session,
191     tcx: Option<TyCtxt<'hir>>,
192 }
193
194 impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> {
195     fn sess(&self) -> &Session {
196         self.sess
197     }
198
199     fn pp_ann<'a>(&'a self) -> &'a dyn pprust::PpAnn {
200         self
201     }
202 }
203
204 impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> {
205     fn pre(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
206         match node {
207             pprust::AnnNode::Expr(_) => s.popen(),
208             _ => {}
209         }
210     }
211     fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
212         match node {
213             pprust::AnnNode::Crate(_) |
214             pprust::AnnNode::Ident(_) |
215             pprust::AnnNode::Name(_) => {},
216
217             pprust::AnnNode::Item(item) => {
218                 s.s.space();
219                 s.synth_comment(item.id.to_string())
220             }
221             pprust::AnnNode::SubItem(id) => {
222                 s.s.space();
223                 s.synth_comment(id.to_string())
224             }
225             pprust::AnnNode::Block(blk) => {
226                 s.s.space();
227                 s.synth_comment(format!("block {}", blk.id))
228             }
229             pprust::AnnNode::Expr(expr) => {
230                 s.s.space();
231                 s.synth_comment(expr.id.to_string());
232                 s.pclose()
233             }
234             pprust::AnnNode::Pat(pat) => {
235                 s.s.space();
236                 s.synth_comment(format!("pat {}", pat.id));
237             }
238         }
239     }
240 }
241
242 impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> {
243     fn sess(&self) -> &Session {
244         self.sess
245     }
246
247     fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> {
248         self.tcx.map(|tcx| tcx.hir())
249     }
250
251     fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn {
252         self
253     }
254 }
255
256 impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> {
257     fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
258         if let Some(ref tcx) = self.tcx {
259             pprust_hir::PpAnn::nested(tcx.hir(), state, nested)
260         }
261     }
262     fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
263         match node {
264             pprust_hir::AnnNode::Expr(_) => s.popen(),
265             _ => {}
266         }
267     }
268     fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
269         match node {
270             pprust_hir::AnnNode::Name(_) => {},
271             pprust_hir::AnnNode::Item(item) => {
272                 s.s.space();
273                 s.synth_comment(format!("hir_id: {}", item.hir_id));
274             }
275             pprust_hir::AnnNode::SubItem(id) => {
276                 s.s.space();
277                 s.synth_comment(id.to_string());
278             }
279             pprust_hir::AnnNode::Block(blk) => {
280                 s.s.space();
281                 s.synth_comment(format!("block hir_id: {}", blk.hir_id));
282             }
283             pprust_hir::AnnNode::Expr(expr) => {
284                 s.s.space();
285                 s.synth_comment(format!("expr hir_id: {}", expr.hir_id));
286                 s.pclose();
287             }
288             pprust_hir::AnnNode::Pat(pat) => {
289                 s.s.space();
290                 s.synth_comment(format!("pat hir_id: {}", pat.hir_id));
291             }
292             pprust_hir::AnnNode::Arm(arm) => {
293                 s.s.space();
294                 s.synth_comment(format!("arm hir_id: {}", arm.hir_id));
295             }
296         }
297     }
298 }
299
300 struct HygieneAnnotation<'a> {
301     sess: &'a Session
302 }
303
304 impl<'a> PrinterSupport for HygieneAnnotation<'a> {
305     fn sess(&self) -> &Session {
306         self.sess
307     }
308
309     fn pp_ann(&self) -> &dyn pprust::PpAnn {
310         self
311     }
312 }
313
314 impl<'a> pprust::PpAnn for HygieneAnnotation<'a> {
315     fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) {
316         match node {
317             pprust::AnnNode::Ident(&ast::Ident { name, span }) => {
318                 s.s.space();
319                 s.synth_comment(format!("{}{:?}", name.as_u32(), span.ctxt()))
320             }
321             pprust::AnnNode::Name(&name) => {
322                 s.s.space();
323                 s.synth_comment(name.as_u32().to_string())
324             }
325             pprust::AnnNode::Crate(_) => {
326                 s.s.hardbreak();
327                 let verbose = self.sess.verbose();
328                 s.synth_comment(syntax_pos::hygiene::debug_hygiene_data(verbose));
329                 s.s.hardbreak_if_not_bol();
330             }
331             _ => {}
332         }
333     }
334 }
335
336 struct TypedAnnotation<'a, 'tcx> {
337     tcx: TyCtxt<'tcx>,
338     tables: Cell<&'a ty::TypeckTables<'tcx>>,
339 }
340
341 impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> {
342     fn sess(&self) -> &Session {
343         &self.tcx.sess
344     }
345
346     fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'tcx>> {
347         Some(&self.tcx.hir())
348     }
349
350     fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn {
351         self
352     }
353
354     fn node_path(&self, id: hir::HirId) -> Option<String> {
355         Some(self.tcx.def_path_str(self.tcx.hir().local_def_id(id)))
356     }
357 }
358
359 impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
360     fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) {
361         let old_tables = self.tables.get();
362         if let pprust_hir::Nested::Body(id) = nested {
363             self.tables.set(self.tcx.body_tables(id));
364         }
365         pprust_hir::PpAnn::nested(self.tcx.hir(), state, nested);
366         self.tables.set(old_tables);
367     }
368     fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
369         match node {
370             pprust_hir::AnnNode::Expr(_) => s.popen(),
371             _ => {}
372         }
373     }
374     fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) {
375         match node {
376             pprust_hir::AnnNode::Expr(expr) => {
377                 s.s.space();
378                 s.s.word("as");
379                 s.s.space();
380                 s.s.word(self.tables.get().expr_ty(expr).to_string());
381                 s.pclose();
382             }
383             _ => {},
384         }
385     }
386 }
387
388 fn get_source(input: &Input, sess: &Session) -> (String, FileName) {
389     let src_name = input.source_name();
390     let src = String::clone(&sess.source_map()
391         .get_source_file(&src_name)
392         .unwrap()
393         .src
394         .as_ref()
395         .unwrap());
396     (src, src_name)
397 }
398
399 fn write_output(out: Vec<u8>, ofile: Option<&Path>) {
400     match ofile {
401         None => print!("{}", String::from_utf8(out).unwrap()),
402         Some(p) => {
403             match File::create(p) {
404                 Ok(mut w) => w.write_all(&out).unwrap(),
405                 Err(e) => panic!("print-print failed to open {} due to {}", p.display(), e),
406             }
407         }
408     }
409 }
410
411 pub fn print_after_parsing(sess: &Session,
412                            input: &Input,
413                            krate: &ast::Crate,
414                            ppm: PpMode,
415                            ofile: Option<&Path>) {
416     let (src, src_name) = get_source(input, sess);
417
418     let mut out = String::new();
419
420     if let PpmSource(s) = ppm {
421         // Silently ignores an identified node.
422         let out = &mut out;
423         call_with_pp_support(&s, sess, None, move |annotation| {
424             debug!("pretty printing source code {:?}", s);
425             let sess = annotation.sess();
426             *out = pprust::print_crate(sess.source_map(),
427                                 &sess.parse_sess,
428                                 krate,
429                                 src_name,
430                                 src,
431                                 annotation.pp_ann(),
432                                 false)
433         })
434     } else {
435         unreachable!();
436     };
437
438     write_output(out.into_bytes(), ofile);
439 }
440
441 pub fn print_after_hir_lowering<'tcx>(
442     tcx: TyCtxt<'tcx>,
443     input: &Input,
444     krate: &ast::Crate,
445     ppm: PpMode,
446     ofile: Option<&Path>,
447 ) {
448     if ppm.needs_analysis() {
449         abort_on_err(print_with_analysis(
450             tcx,
451             ppm,
452             ofile
453         ), tcx.sess);
454         return;
455     }
456
457     let (src, src_name) = get_source(input, tcx.sess);
458
459     let mut out = String::new();
460
461     match ppm {
462             PpmSource(s) => {
463                 // Silently ignores an identified node.
464                 let out = &mut out;
465                 let src = src.clone();
466                 call_with_pp_support(&s, tcx.sess, Some(tcx), move |annotation| {
467                     debug!("pretty printing source code {:?}", s);
468                     let sess = annotation.sess();
469                     *out = pprust::print_crate(sess.source_map(),
470                                         &sess.parse_sess,
471                                         krate,
472                                         src_name,
473                                         src,
474                                         annotation.pp_ann(),
475                                         true)
476                 })
477             }
478
479             PpmHir(s) => {
480                 let out = &mut out;
481                 let src = src.clone();
482                 call_with_pp_support_hir(&s, tcx, move |annotation, krate| {
483                     debug!("pretty printing source code {:?}", s);
484                     let sess = annotation.sess();
485                     *out = pprust_hir::print_crate(sess.source_map(),
486                                             &sess.parse_sess,
487                                             krate,
488                                             src_name,
489                                             src,
490                                             annotation.pp_ann())
491                 })
492             }
493
494             PpmHirTree(s) => {
495                 let out = &mut out;
496                 call_with_pp_support_hir(&s, tcx, move |_annotation, krate| {
497                     debug!("pretty printing source code {:?}", s);
498                     *out = format!("{:#?}", krate);
499                 });
500             }
501
502             _ => unreachable!(),
503         }
504
505     write_output(out.into_bytes(), ofile);
506 }
507
508 // In an ideal world, this would be a public function called by the driver after
509 // analysis is performed. However, we want to call `phase_3_run_analysis_passes`
510 // with a different callback than the standard driver, so that isn't easy.
511 // Instead, we call that function ourselves.
512 fn print_with_analysis(
513     tcx: TyCtxt<'_>,
514     ppm: PpMode,
515     ofile: Option<&Path>,
516 ) -> Result<(), ErrorReported> {
517     let mut out = Vec::new();
518
519     tcx.analysis(LOCAL_CRATE)?;
520
521     match ppm {
522         PpmMir | PpmMirCFG => {
523             match ppm {
524                 PpmMir => write_mir_pretty(tcx, None, &mut out),
525                 PpmMirCFG => write_mir_graphviz(tcx, None, &mut out),
526                 _ => unreachable!(),
527             }
528         }
529         _ => unreachable!(),
530     }.unwrap();
531
532     write_output(out, ofile);
533
534     Ok(())
535 }