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