]> git.proxmox.com Git - rustc.git/blob - src/librustc_driver/pretty.rs
Imported Upstream version 1.6.0+dfsg1
[rustc.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 rustc_trans::back::link;
19
20 use driver;
21
22 use rustc::middle::ty;
23 use rustc::middle::cfg;
24 use rustc::middle::cfg::graphviz::LabelledCFG;
25 use rustc::session::Session;
26 use rustc::session::config::Input;
27 use rustc_borrowck as borrowck;
28 use rustc_borrowck::graphviz as borrowck_dot;
29 use rustc_resolve as resolve;
30 use rustc_metadata::cstore::CStore;
31
32 use syntax::ast;
33 use syntax::codemap;
34 use syntax::fold::{self, Folder};
35 use syntax::print::{pp, pprust};
36 use syntax::print::pprust::PrintState;
37 use syntax::ptr::P;
38 use syntax::util::small_vector::SmallVector;
39
40 use graphviz as dot;
41
42 use std::fs::File;
43 use std::io::{self, Write};
44 use std::option;
45 use std::path::PathBuf;
46 use std::str::FromStr;
47
48 use rustc::front::map as hir_map;
49 use rustc::front::map::{blocks, NodePrinter};
50 use rustc_front::hir;
51 use rustc_front::lowering::{lower_crate, LoweringContext};
52 use rustc_front::print::pprust as pprust_hir;
53
54 #[derive(Copy, Clone, PartialEq, Debug)]
55 pub enum PpSourceMode {
56 PpmNormal,
57 PpmEveryBodyLoops,
58 PpmExpanded,
59 PpmIdentified,
60 PpmExpandedIdentified,
61 PpmExpandedHygiene,
62 PpmTyped,
63 }
64
65 #[derive(Copy, Clone, PartialEq, Debug)]
66 pub enum PpFlowGraphMode {
67 Default,
68 /// Drops the labels from the edges in the flowgraph output. This
69 /// is mostly for use in the --unpretty flowgraph run-make tests,
70 /// since the labels are largely uninteresting in those cases and
71 /// have become a pain to maintain.
72 UnlabelledEdges,
73 }
74 #[derive(Copy, Clone, PartialEq, Debug)]
75 pub enum PpMode {
76 PpmSource(PpSourceMode),
77 PpmHir(PpSourceMode),
78 PpmFlowGraph(PpFlowGraphMode),
79 }
80
81 pub fn parse_pretty(sess: &Session,
82 name: &str,
83 extended: bool)
84 -> (PpMode, Option<UserIdentifiedItem>) {
85 let mut split = name.splitn(2, '=');
86 let first = split.next().unwrap();
87 let opt_second = split.next();
88 let first = match (first, extended) {
89 ("normal", _) => PpmSource(PpmNormal),
90 ("identified", _) => PpmSource(PpmIdentified),
91 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
92 ("expanded", _) => PpmSource(PpmExpanded),
93 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
94 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
95 ("hir", true) => PpmHir(PpmNormal),
96 ("hir,identified", true) => PpmHir(PpmIdentified),
97 ("hir,typed", true) => PpmHir(PpmTyped),
98 ("flowgraph", true) => PpmFlowGraph(PpFlowGraphMode::Default),
99 ("flowgraph,unlabelled", true) => PpmFlowGraph(PpFlowGraphMode::UnlabelledEdges),
100 _ => {
101 if extended {
102 sess.fatal(&format!("argument to `unpretty` must be one of `normal`, \
103 `expanded`, `flowgraph[,unlabelled]=<nodeid>`, \
104 `identified`, `expanded,identified`, `everybody_loops`, \
105 `hir`, `hir,identified`, or `hir,typed`; got {}",
106 name));
107 } else {
108 sess.fatal(&format!("argument to `pretty` must be one of `normal`, `expanded`, \
109 `identified`, or `expanded,identified`; got {}",
110 name));
111 }
112 }
113 };
114 let opt_second = opt_second.and_then(|s| s.parse::<UserIdentifiedItem>().ok());
115 (first, opt_second)
116 }
117
118
119
120 // This slightly awkward construction is to allow for each PpMode to
121 // choose whether it needs to do analyses (which can consume the
122 // Session) and then pass through the session (now attached to the
123 // analysis results) on to the chosen pretty-printer, along with the
124 // `&PpAnn` object.
125 //
126 // Note that since the `&PrinterSupport` is freshly constructed on each
127 // call, it would not make sense to try to attach the lifetime of `self`
128 // to the lifetime of the `&PrinterObject`.
129 //
130 // (The `use_once_payload` is working around the current lack of once
131 // functions in the compiler.)
132
133 impl PpSourceMode {
134 /// Constructs a `PrinterSupport` object and passes it to `f`.
135 fn call_with_pp_support<'tcx, A, B, F>(&self,
136 sess: &'tcx Session,
137 ast_map: Option<hir_map::Map<'tcx>>,
138 payload: B,
139 f: F)
140 -> A
141 where F: FnOnce(&PrinterSupport, B) -> A
142 {
143 match *self {
144 PpmNormal | PpmEveryBodyLoops | PpmExpanded => {
145 let annotation = NoAnn {
146 sess: sess,
147 ast_map: ast_map,
148 };
149 f(&annotation, payload)
150 }
151
152 PpmIdentified | PpmExpandedIdentified => {
153 let annotation = IdentifiedAnnotation {
154 sess: sess,
155 ast_map: ast_map,
156 };
157 f(&annotation, payload)
158 }
159 PpmExpandedHygiene => {
160 let annotation = HygieneAnnotation {
161 sess: sess,
162 ast_map: ast_map,
163 };
164 f(&annotation, payload)
165 }
166 _ => panic!("Should use call_with_pp_support_hir"),
167 }
168 }
169 fn call_with_pp_support_hir<'tcx, A, B, F>(&self,
170 sess: &'tcx Session,
171 cstore: &CStore,
172 ast_map: &hir_map::Map<'tcx>,
173 arenas: &'tcx ty::CtxtArenas<'tcx>,
174 id: &str,
175 payload: B,
176 f: F)
177 -> A
178 where F: FnOnce(&HirPrinterSupport, B, &hir::Crate) -> A
179 {
180 match *self {
181 PpmNormal => {
182 let annotation = NoAnn {
183 sess: sess,
184 ast_map: Some(ast_map.clone()),
185 };
186 f(&annotation, payload, &ast_map.forest.krate)
187 }
188
189 PpmIdentified => {
190 let annotation = IdentifiedAnnotation {
191 sess: sess,
192 ast_map: Some(ast_map.clone()),
193 };
194 f(&annotation, payload, &ast_map.forest.krate)
195 }
196 PpmTyped => {
197 driver::phase_3_run_analysis_passes(sess,
198 cstore,
199 ast_map.clone(),
200 arenas,
201 id,
202 resolve::MakeGlobMap::No,
203 |tcx, _, _| {
204 let annotation = TypedAnnotation {
205 tcx: tcx,
206 };
207 f(&annotation,
208 payload,
209 &ast_map.forest.krate)
210 })
211 }
212 _ => panic!("Should use call_with_pp_support"),
213 }
214 }
215 }
216
217 trait PrinterSupport<'ast>: pprust::PpAnn {
218 /// Provides a uniform interface for re-extracting a reference to a
219 /// `Session` from a value that now owns it.
220 fn sess<'a>(&'a self) -> &'a Session;
221
222 /// Provides a uniform interface for re-extracting a reference to an
223 /// `hir_map::Map` from a value that now owns it.
224 fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>>;
225
226 /// Produces the pretty-print annotation object.
227 ///
228 /// (Rust does not yet support upcasting from a trait object to
229 /// an object for one of its super-traits.)
230 fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn;
231 }
232
233 trait HirPrinterSupport<'ast>: pprust_hir::PpAnn {
234 /// Provides a uniform interface for re-extracting a reference to a
235 /// `Session` from a value that now owns it.
236 fn sess<'a>(&'a self) -> &'a Session;
237
238 /// Provides a uniform interface for re-extracting a reference to an
239 /// `hir_map::Map` from a value that now owns it.
240 fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>>;
241
242 /// Produces the pretty-print annotation object.
243 ///
244 /// (Rust does not yet support upcasting from a trait object to
245 /// an object for one of its super-traits.)
246 fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn;
247 }
248
249 struct NoAnn<'ast> {
250 sess: &'ast Session,
251 ast_map: Option<hir_map::Map<'ast>>,
252 }
253
254 impl<'ast> PrinterSupport<'ast> for NoAnn<'ast> {
255 fn sess<'a>(&'a self) -> &'a Session {
256 self.sess
257 }
258
259 fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
260 self.ast_map.as_ref()
261 }
262
263 fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn {
264 self
265 }
266 }
267
268 impl<'ast> HirPrinterSupport<'ast> for NoAnn<'ast> {
269 fn sess<'a>(&'a self) -> &'a Session {
270 self.sess
271 }
272
273 fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
274 self.ast_map.as_ref()
275 }
276
277 fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn {
278 self
279 }
280 }
281
282 impl<'ast> pprust::PpAnn for NoAnn<'ast> {}
283 impl<'ast> pprust_hir::PpAnn for NoAnn<'ast> {}
284
285 struct IdentifiedAnnotation<'ast> {
286 sess: &'ast Session,
287 ast_map: Option<hir_map::Map<'ast>>,
288 }
289
290 impl<'ast> PrinterSupport<'ast> for IdentifiedAnnotation<'ast> {
291 fn sess<'a>(&'a self) -> &'a Session {
292 self.sess
293 }
294
295 fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
296 self.ast_map.as_ref()
297 }
298
299 fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn {
300 self
301 }
302 }
303
304 impl<'ast> pprust::PpAnn for IdentifiedAnnotation<'ast> {
305 fn pre(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> {
306 match node {
307 pprust::NodeExpr(_) => s.popen(),
308 _ => Ok(()),
309 }
310 }
311 fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> {
312 match node {
313 pprust::NodeIdent(_) | pprust::NodeName(_) => Ok(()),
314
315 pprust::NodeItem(item) => {
316 try!(pp::space(&mut s.s));
317 s.synth_comment(item.id.to_string())
318 }
319 pprust::NodeSubItem(id) => {
320 try!(pp::space(&mut s.s));
321 s.synth_comment(id.to_string())
322 }
323 pprust::NodeBlock(blk) => {
324 try!(pp::space(&mut s.s));
325 s.synth_comment(format!("block {}", blk.id))
326 }
327 pprust::NodeExpr(expr) => {
328 try!(pp::space(&mut s.s));
329 try!(s.synth_comment(expr.id.to_string()));
330 s.pclose()
331 }
332 pprust::NodePat(pat) => {
333 try!(pp::space(&mut s.s));
334 s.synth_comment(format!("pat {}", pat.id))
335 }
336 }
337 }
338 }
339
340 impl<'ast> HirPrinterSupport<'ast> for IdentifiedAnnotation<'ast> {
341 fn sess<'a>(&'a self) -> &'a Session {
342 self.sess
343 }
344
345 fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
346 self.ast_map.as_ref()
347 }
348
349 fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn {
350 self
351 }
352 }
353
354 impl<'ast> pprust_hir::PpAnn for IdentifiedAnnotation<'ast> {
355 fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
356 match node {
357 pprust_hir::NodeExpr(_) => s.popen(),
358 _ => Ok(()),
359 }
360 }
361 fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
362 match node {
363 pprust_hir::NodeName(_) => Ok(()),
364 pprust_hir::NodeItem(item) => {
365 try!(pp::space(&mut s.s));
366 s.synth_comment(item.id.to_string())
367 }
368 pprust_hir::NodeSubItem(id) => {
369 try!(pp::space(&mut s.s));
370 s.synth_comment(id.to_string())
371 }
372 pprust_hir::NodeBlock(blk) => {
373 try!(pp::space(&mut s.s));
374 s.synth_comment(format!("block {}", blk.id))
375 }
376 pprust_hir::NodeExpr(expr) => {
377 try!(pp::space(&mut s.s));
378 try!(s.synth_comment(expr.id.to_string()));
379 s.pclose()
380 }
381 pprust_hir::NodePat(pat) => {
382 try!(pp::space(&mut s.s));
383 s.synth_comment(format!("pat {}", pat.id))
384 }
385 }
386 }
387 }
388
389 struct HygieneAnnotation<'ast> {
390 sess: &'ast Session,
391 ast_map: Option<hir_map::Map<'ast>>,
392 }
393
394 impl<'ast> PrinterSupport<'ast> for HygieneAnnotation<'ast> {
395 fn sess<'a>(&'a self) -> &'a Session {
396 self.sess
397 }
398
399 fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
400 self.ast_map.as_ref()
401 }
402
403 fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn {
404 self
405 }
406 }
407
408 impl<'ast> pprust::PpAnn for HygieneAnnotation<'ast> {
409 fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> {
410 match node {
411 pprust::NodeIdent(&ast::Ident { name: ast::Name(nm), ctxt }) => {
412 try!(pp::space(&mut s.s));
413 // FIXME #16420: this doesn't display the connections
414 // between syntax contexts
415 s.synth_comment(format!("{}#{}", nm, ctxt.0))
416 }
417 pprust::NodeName(&ast::Name(nm)) => {
418 try!(pp::space(&mut s.s));
419 s.synth_comment(nm.to_string())
420 }
421 _ => Ok(()),
422 }
423 }
424 }
425
426
427 struct TypedAnnotation<'a, 'tcx: 'a> {
428 tcx: &'a ty::ctxt<'tcx>,
429 }
430
431 impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> {
432 fn sess<'a>(&'a self) -> &'a Session {
433 &self.tcx.sess
434 }
435
436 fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'tcx>> {
437 Some(&self.tcx.map)
438 }
439
440 fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn {
441 self
442 }
443 }
444
445 impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
446 fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
447 match node {
448 pprust_hir::NodeExpr(_) => s.popen(),
449 _ => Ok(()),
450 }
451 }
452 fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
453 match node {
454 pprust_hir::NodeExpr(expr) => {
455 try!(pp::space(&mut s.s));
456 try!(pp::word(&mut s.s, "as"));
457 try!(pp::space(&mut s.s));
458 try!(pp::word(&mut s.s, &self.tcx.expr_ty(expr).to_string()));
459 s.pclose()
460 }
461 _ => Ok(()),
462 }
463 }
464 }
465
466 fn gather_flowgraph_variants(sess: &Session) -> Vec<borrowck_dot::Variant> {
467 let print_loans = sess.opts.debugging_opts.flowgraph_print_loans;
468 let print_moves = sess.opts.debugging_opts.flowgraph_print_moves;
469 let print_assigns = sess.opts.debugging_opts.flowgraph_print_assigns;
470 let print_all = sess.opts.debugging_opts.flowgraph_print_all;
471 let mut variants = Vec::new();
472 if print_all || print_loans {
473 variants.push(borrowck_dot::Loans);
474 }
475 if print_all || print_moves {
476 variants.push(borrowck_dot::Moves);
477 }
478 if print_all || print_assigns {
479 variants.push(borrowck_dot::Assigns);
480 }
481 variants
482 }
483
484 #[derive(Clone, Debug)]
485 pub enum UserIdentifiedItem {
486 ItemViaNode(ast::NodeId),
487 ItemViaPath(Vec<String>),
488 }
489
490 impl FromStr for UserIdentifiedItem {
491 type Err = ();
492 fn from_str(s: &str) -> Result<UserIdentifiedItem, ()> {
493 Ok(s.parse()
494 .map(ItemViaNode)
495 .unwrap_or_else(|_| ItemViaPath(s.split("::").map(|s| s.to_string()).collect())))
496 }
497 }
498
499 enum NodesMatchingUII<'a, 'ast: 'a> {
500 NodesMatchingDirect(option::IntoIter<ast::NodeId>),
501 NodesMatchingSuffix(hir_map::NodesMatchingSuffix<'a, 'ast>),
502 }
503
504 impl<'a, 'ast> Iterator for NodesMatchingUII<'a, 'ast> {
505 type Item = ast::NodeId;
506
507 fn next(&mut self) -> Option<ast::NodeId> {
508 match self {
509 &mut NodesMatchingDirect(ref mut iter) => iter.next(),
510 &mut NodesMatchingSuffix(ref mut iter) => iter.next(),
511 }
512 }
513 }
514
515 impl UserIdentifiedItem {
516 fn reconstructed_input(&self) -> String {
517 match *self {
518 ItemViaNode(node_id) => node_id.to_string(),
519 ItemViaPath(ref parts) => parts.join("::"),
520 }
521 }
522
523 fn all_matching_node_ids<'a, 'ast>(&'a self,
524 map: &'a hir_map::Map<'ast>)
525 -> NodesMatchingUII<'a, 'ast> {
526 match *self {
527 ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()),
528 ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts[..])),
529 }
530 }
531
532 fn to_one_node_id(self, user_option: &str, sess: &Session, map: &hir_map::Map) -> ast::NodeId {
533 let fail_because = |is_wrong_because| -> ast::NodeId {
534 let message = format!("{} needs NodeId (int) or unique path suffix (b::c::d); got \
535 {}, which {}",
536 user_option,
537 self.reconstructed_input(),
538 is_wrong_because);
539 sess.fatal(&message[..])
540 };
541
542 let mut saw_node = ast::DUMMY_NODE_ID;
543 let mut seen = 0;
544 for node in self.all_matching_node_ids(map) {
545 saw_node = node;
546 seen += 1;
547 if seen > 1 {
548 fail_because("does not resolve uniquely");
549 }
550 }
551 if seen == 0 {
552 fail_because("does not resolve to any item");
553 }
554
555 assert!(seen == 1);
556 return saw_node;
557 }
558 }
559
560 fn needs_ast_map(ppm: &PpMode, opt_uii: &Option<UserIdentifiedItem>) -> bool {
561 match *ppm {
562 PpmSource(PpmNormal) |
563 PpmSource(PpmEveryBodyLoops) |
564 PpmSource(PpmIdentified) => opt_uii.is_some(),
565
566 PpmSource(PpmExpanded) |
567 PpmSource(PpmExpandedIdentified) |
568 PpmSource(PpmExpandedHygiene) |
569 PpmHir(_) |
570 PpmFlowGraph(_) => true,
571 PpmSource(PpmTyped) => panic!("invalid state"),
572 }
573 }
574
575 fn needs_expansion(ppm: &PpMode) -> bool {
576 match *ppm {
577 PpmSource(PpmNormal) |
578 PpmSource(PpmEveryBodyLoops) |
579 PpmSource(PpmIdentified) => false,
580
581 PpmSource(PpmExpanded) |
582 PpmSource(PpmExpandedIdentified) |
583 PpmSource(PpmExpandedHygiene) |
584 PpmHir(_) |
585 PpmFlowGraph(_) => true,
586 PpmSource(PpmTyped) => panic!("invalid state"),
587 }
588 }
589
590 struct ReplaceBodyWithLoop {
591 within_static_or_const: bool,
592 }
593
594 impl ReplaceBodyWithLoop {
595 fn new() -> ReplaceBodyWithLoop {
596 ReplaceBodyWithLoop { within_static_or_const: false }
597 }
598 }
599
600 impl fold::Folder for ReplaceBodyWithLoop {
601 fn fold_item_underscore(&mut self, i: ast::Item_) -> ast::Item_ {
602 match i {
603 ast::ItemStatic(..) | ast::ItemConst(..) => {
604 self.within_static_or_const = true;
605 let ret = fold::noop_fold_item_underscore(i, self);
606 self.within_static_or_const = false;
607 return ret;
608 }
609 _ => {
610 fold::noop_fold_item_underscore(i, self)
611 }
612 }
613 }
614
615 fn fold_trait_item(&mut self, i: P<ast::TraitItem>) -> SmallVector<P<ast::TraitItem>> {
616 match i.node {
617 ast::ConstTraitItem(..) => {
618 self.within_static_or_const = true;
619 let ret = fold::noop_fold_trait_item(i, self);
620 self.within_static_or_const = false;
621 return ret;
622 }
623 _ => fold::noop_fold_trait_item(i, self),
624 }
625 }
626
627 fn fold_impl_item(&mut self, i: P<ast::ImplItem>) -> SmallVector<P<ast::ImplItem>> {
628 match i.node {
629 ast::ImplItemKind::Const(..) => {
630 self.within_static_or_const = true;
631 let ret = fold::noop_fold_impl_item(i, self);
632 self.within_static_or_const = false;
633 return ret;
634 }
635 _ => fold::noop_fold_impl_item(i, self),
636 }
637 }
638
639 fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> {
640 fn expr_to_block(rules: ast::BlockCheckMode, e: Option<P<ast::Expr>>) -> P<ast::Block> {
641 P(ast::Block {
642 expr: e,
643 stmts: vec![],
644 rules: rules,
645 id: ast::DUMMY_NODE_ID,
646 span: codemap::DUMMY_SP,
647 })
648 }
649
650 if !self.within_static_or_const {
651
652 let empty_block = expr_to_block(ast::DefaultBlock, None);
653 let loop_expr = P(ast::Expr {
654 node: ast::ExprLoop(empty_block, None),
655 id: ast::DUMMY_NODE_ID,
656 span: codemap::DUMMY_SP,
657 attrs: None,
658 });
659
660 expr_to_block(b.rules, Some(loop_expr))
661
662 } else {
663 fold::noop_fold_block(b, self)
664 }
665 }
666
667 // in general the pretty printer processes unexpanded code, so
668 // we override the default `fold_mac` method which panics.
669 fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
670 fold::noop_fold_mac(mac, self)
671 }
672 }
673
674 pub fn pretty_print_input(sess: Session,
675 cstore: &CStore,
676 cfg: ast::CrateConfig,
677 input: &Input,
678 ppm: PpMode,
679 opt_uii: Option<UserIdentifiedItem>,
680 ofile: Option<PathBuf>) {
681 let krate = driver::phase_1_parse_input(&sess, cfg, input);
682
683 let krate = if let PpmSource(PpmEveryBodyLoops) = ppm {
684 let mut fold = ReplaceBodyWithLoop::new();
685 fold.fold_crate(krate)
686 } else {
687 krate
688 };
689
690 let id = link::find_crate_name(Some(&sess), &krate.attrs, input);
691
692 let is_expanded = needs_expansion(&ppm);
693 let compute_ast_map = needs_ast_map(&ppm, &opt_uii);
694 let krate = if compute_ast_map {
695 match driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id[..], None) {
696 None => return,
697 Some(k) => driver::assign_node_ids(&sess, k),
698 }
699 } else {
700 krate
701 };
702
703 // There is some twisted, god-forsaken tangle of lifetimes here which makes
704 // the ordering of stuff super-finicky.
705 let mut hir_forest;
706 let lcx = LoweringContext::new(&sess, Some(&krate));
707 let arenas = ty::CtxtArenas::new();
708 let ast_map = if compute_ast_map {
709 hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate));
710 let map = driver::make_map(&sess, &mut hir_forest);
711 Some(map)
712 } else {
713 None
714 };
715
716 let src_name = driver::source_name(input);
717 let src = sess.codemap()
718 .get_filemap(&src_name[..])
719 .src
720 .as_ref()
721 .unwrap()
722 .as_bytes()
723 .to_vec();
724 let mut rdr = &src[..];
725
726 let mut out = Vec::new();
727
728 match (ppm, opt_uii) {
729 (PpmSource(s), _) => {
730 // Silently ignores an identified node.
731 let out: &mut Write = &mut out;
732 s.call_with_pp_support(&sess, ast_map, box out, |annotation, out| {
733 debug!("pretty printing source code {:?}", s);
734 let sess = annotation.sess();
735 pprust::print_crate(sess.codemap(),
736 sess.diagnostic(),
737 &krate,
738 src_name.to_string(),
739 &mut rdr,
740 out,
741 annotation.pp_ann(),
742 is_expanded)
743 })
744 }
745
746 (PpmHir(s), None) => {
747 let out: &mut Write = &mut out;
748 s.call_with_pp_support_hir(&sess,
749 cstore,
750 &ast_map.unwrap(),
751 &arenas,
752 &id,
753 box out,
754 |annotation, out, krate| {
755 debug!("pretty printing source code {:?}", s);
756 let sess = annotation.sess();
757 pprust_hir::print_crate(sess.codemap(),
758 sess.diagnostic(),
759 krate,
760 src_name.to_string(),
761 &mut rdr,
762 out,
763 annotation.pp_ann(),
764 is_expanded)
765 })
766 }
767
768 (PpmHir(s), Some(uii)) => {
769 let out: &mut Write = &mut out;
770 s.call_with_pp_support_hir(&sess,
771 cstore,
772 &ast_map.unwrap(),
773 &arenas,
774 &id,
775 (out,uii),
776 |annotation, (out,uii), _| {
777 debug!("pretty printing source code {:?}", s);
778 let sess = annotation.sess();
779 let ast_map = annotation.ast_map().expect("--pretty missing ast_map");
780 let mut pp_state =
781 pprust_hir::State::new_from_input(sess.codemap(),
782 sess.diagnostic(),
783 src_name.to_string(),
784 &mut rdr,
785 box out,
786 annotation.pp_ann(),
787 true,
788 Some(ast_map.krate()));
789 for node_id in uii.all_matching_node_ids(ast_map) {
790 let node = ast_map.get(node_id);
791 try!(pp_state.print_node(&node));
792 try!(pp::space(&mut pp_state.s));
793 try!(pp_state.synth_comment(ast_map.path_to_string(node_id)));
794 try!(pp::hardbreak(&mut pp_state.s));
795 }
796 pp::eof(&mut pp_state.s)
797 })
798 }
799
800 (PpmFlowGraph(mode), opt_uii) => {
801 debug!("pretty printing flow graph for {:?}", opt_uii);
802 let uii = opt_uii.unwrap_or_else(|| {
803 sess.fatal(&format!("`pretty flowgraph=..` needs NodeId (int) or
804 \
805 unique path suffix (b::c::d)"))
806
807 });
808 let ast_map = ast_map.expect("--pretty flowgraph missing ast_map");
809 let nodeid = uii.to_one_node_id("--pretty", &sess, &ast_map);
810
811 let node = ast_map.find(nodeid).unwrap_or_else(|| {
812 sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid))
813 });
814
815 let code = blocks::Code::from_node(node);
816 let out: &mut Write = &mut out;
817 match code {
818 Some(code) => {
819 let variants = gather_flowgraph_variants(&sess);
820 driver::phase_3_run_analysis_passes(&sess,
821 &cstore,
822 ast_map,
823 &arenas,
824 &id,
825 resolve::MakeGlobMap::No,
826 |tcx, _, _| {
827 print_flowgraph(variants,
828 tcx,
829 code,
830 mode,
831 out)
832 })
833 }
834 None => {
835 let message = format!("--pretty=flowgraph needs block, fn, or method; got \
836 {:?}",
837 node);
838
839 // point to what was found, if there's an
840 // accessible span.
841 match ast_map.opt_span(nodeid) {
842 Some(sp) => sess.span_fatal(sp, &message[..]),
843 None => sess.fatal(&message[..]),
844 }
845 }
846 }
847 }
848 }
849 .unwrap();
850
851 match ofile {
852 None => print!("{}", String::from_utf8(out).unwrap()),
853 Some(p) => {
854 match File::create(&p) {
855 Ok(mut w) => w.write_all(&out).unwrap(),
856 Err(e) => panic!("print-print failed to open {} due to {}", p.display(), e),
857 }
858 }
859 }
860 }
861
862 fn print_flowgraph<W: Write>(variants: Vec<borrowck_dot::Variant>,
863 tcx: &ty::ctxt,
864 code: blocks::Code,
865 mode: PpFlowGraphMode,
866 mut out: W)
867 -> io::Result<()> {
868 let cfg = match code {
869 blocks::BlockCode(block) => cfg::CFG::new(tcx, &*block),
870 blocks::FnLikeCode(fn_like) => cfg::CFG::new(tcx, &*fn_like.body()),
871 };
872 let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
873 let lcfg = LabelledCFG {
874 ast_map: &tcx.map,
875 cfg: &cfg,
876 name: format!("node_{}", code.id()),
877 labelled_edges: labelled_edges,
878 };
879
880 match code {
881 _ if variants.is_empty() => {
882 let r = dot::render(&lcfg, &mut out);
883 return expand_err_details(r);
884 }
885 blocks::BlockCode(_) => {
886 tcx.sess.err("--pretty flowgraph with -Z flowgraph-print annotations requires \
887 fn-like node id.");
888 return Ok(());
889 }
890 blocks::FnLikeCode(fn_like) => {
891 let (bccx, analysis_data) =
892 borrowck::build_borrowck_dataflow_data_for_fn(tcx,
893 fn_like.to_fn_parts(),
894 &cfg);
895
896 let lcfg = borrowck_dot::DataflowLabeller {
897 inner: lcfg,
898 variants: variants,
899 borrowck_ctxt: &bccx,
900 analysis_data: &analysis_data,
901 };
902 let r = dot::render(&lcfg, &mut out);
903 return expand_err_details(r);
904 }
905 }
906
907 fn expand_err_details(r: io::Result<()>) -> io::Result<()> {
908 r.map_err(|ioerr| {
909 io::Error::new(io::ErrorKind::Other,
910 &format!("graphviz::render failed: {}", ioerr)[..])
911 })
912 }
913 }