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.
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.
11 //! The various pretty print routines.
13 pub use self::UserIdentifiedItem
::*;
14 pub use self::PpSourceMode
::*;
15 pub use self::PpMode
::*;
16 use self::NodesMatchingUII
::*;
18 use {abort_on_err, driver}
;
20 use rustc
::ty
::{self, TyCtxt, Resolutions, AllArenas}
;
22 use rustc
::cfg
::graphviz
::LabelledCFG
;
23 use rustc
::middle
::cstore
::CrateStore
;
24 use rustc
::session
::Session
;
25 use rustc
::session
::config
::{Input, OutputFilenames}
;
26 use rustc_borrowck
as borrowck
;
27 use rustc_borrowck
::graphviz
as borrowck_dot
;
29 use rustc_mir
::util
::{write_mir_pretty, write_mir_graphviz}
;
31 use syntax
::ast
::{self, BlockCheckMode}
;
32 use syntax
::fold
::{self, Folder}
;
33 use syntax
::print
::{pprust}
;
34 use syntax
::print
::pprust
::PrintState
;
36 use syntax
::util
::small_vector
::SmallVector
;
37 use syntax_pos
::{self, FileName}
;
43 use std
::io
::{self, Write}
;
46 use std
::str::FromStr
;
49 use rustc
::hir
::map
as hir_map
;
50 use rustc
::hir
::map
::blocks
;
52 use rustc
::hir
::print
as pprust_hir
;
54 #[derive(Copy, Clone, PartialEq, Debug)]
55 pub enum PpSourceMode
{
60 PpmExpandedIdentified
,
65 #[derive(Copy, Clone, PartialEq, Debug)]
66 pub enum PpFlowGraphMode
{
68 /// Drops the labels from the edges in the flowgraph output. This
69 /// is mostly for use in the -Z unpretty flowgraph run-make tests,
70 /// since the labels are largely uninteresting in those cases and
71 /// have become a pain to maintain.
74 #[derive(Copy, Clone, PartialEq, Debug)]
76 PpmSource(PpSourceMode
),
78 PpmHirTree(PpSourceMode
),
79 PpmFlowGraph(PpFlowGraphMode
),
85 pub fn needs_ast_map(&self, opt_uii
: &Option
<UserIdentifiedItem
>) -> bool
{
87 PpmSource(PpmNormal
) |
88 PpmSource(PpmEveryBodyLoops
) |
89 PpmSource(PpmIdentified
) => opt_uii
.is_some(),
91 PpmSource(PpmExpanded
) |
92 PpmSource(PpmExpandedIdentified
) |
93 PpmSource(PpmExpandedHygiene
) |
98 PpmFlowGraph(_
) => true,
99 PpmSource(PpmTyped
) => panic
!("invalid state"),
103 pub fn needs_analysis(&self) -> bool
{
105 PpmMir
| PpmMirCFG
| PpmFlowGraph(_
) => true,
111 pub fn parse_pretty(sess
: &Session
,
114 -> (PpMode
, Option
<UserIdentifiedItem
>) {
115 let mut split
= name
.splitn(2, '
='
);
116 let first
= split
.next().unwrap();
117 let opt_second
= split
.next();
118 let first
= match (first
, extended
) {
119 ("normal", _
) => PpmSource(PpmNormal
),
120 ("identified", _
) => PpmSource(PpmIdentified
),
121 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops
),
122 ("expanded", _
) => PpmSource(PpmExpanded
),
123 ("expanded,identified", _
) => PpmSource(PpmExpandedIdentified
),
124 ("expanded,hygiene", _
) => PpmSource(PpmExpandedHygiene
),
125 ("hir", true) => PpmHir(PpmNormal
),
126 ("hir,identified", true) => PpmHir(PpmIdentified
),
127 ("hir,typed", true) => PpmHir(PpmTyped
),
128 ("hir-tree", true) => PpmHirTree(PpmNormal
),
129 ("mir", true) => PpmMir
,
130 ("mir-cfg", true) => PpmMirCFG
,
131 ("flowgraph", true) => PpmFlowGraph(PpFlowGraphMode
::Default
),
132 ("flowgraph,unlabelled", true) => PpmFlowGraph(PpFlowGraphMode
::UnlabelledEdges
),
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 {}",
141 sess
.fatal(&format
!("argument to `pretty` must be one of `normal`, `expanded`, \
142 `identified`, or `expanded,identified`; got {}",
147 let opt_second
= opt_second
.and_then(|s
| s
.parse
::<UserIdentifiedItem
>().ok());
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
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`.
163 // (The `use_once_payload` is working around the current lack of once
164 // functions in the compiler.)
167 /// Constructs a `PrinterSupport` object and passes it to `f`.
168 fn call_with_pp_support
<'tcx
, A
, F
>(&self,
170 hir_map
: Option
<&hir_map
::Map
<'tcx
>>,
173 where F
: FnOnce(&PrinterSupport
) -> A
176 PpmNormal
| PpmEveryBodyLoops
| PpmExpanded
=> {
177 let annotation
= NoAnn
{
179 hir_map
: hir_map
.map(|m
| m
.clone()),
184 PpmIdentified
| PpmExpandedIdentified
=> {
185 let annotation
= IdentifiedAnnotation
{
187 hir_map
: hir_map
.map(|m
| m
.clone()),
191 PpmExpandedHygiene
=> {
192 let annotation
= HygieneAnnotation
{
197 _
=> panic
!("Should use call_with_pp_support_hir"),
200 fn call_with_pp_support_hir
<'tcx
, A
, F
>(&self,
202 cstore
: &'tcx CrateStore
,
203 hir_map
: &hir_map
::Map
<'tcx
>,
204 analysis
: &ty
::CrateAnalysis
,
205 resolutions
: &Resolutions
,
206 arenas
: &'tcx AllArenas
<'tcx
>,
207 output_filenames
: &OutputFilenames
,
211 where F
: FnOnce(&HirPrinterSupport
, &hir
::Crate
) -> A
215 let annotation
= NoAnn
{
217 hir_map
: Some(hir_map
.clone()),
219 f(&annotation
, hir_map
.forest
.krate())
223 let annotation
= IdentifiedAnnotation
{
225 hir_map
: Some(hir_map
.clone()),
227 f(&annotation
, hir_map
.forest
.krate())
230 let control
= &driver
::CompileController
::basic();
231 let trans
= ::get_trans(sess
);
232 abort_on_err(driver
::phase_3_run_analysis_passes(&*trans
,
243 let empty_tables
= ty
::TypeckTables
::empty(None
);
244 let annotation
= TypedAnnotation
{
246 tables
: Cell
::new(&empty_tables
)
248 tcx
.dep_graph
.with_ignore(|| {
249 f(&annotation
, hir_map
.forest
.krate())
254 _
=> panic
!("Should use call_with_pp_support"),
259 trait PrinterSupport
: pprust
::PpAnn
{
260 /// Provides a uniform interface for re-extracting a reference to a
261 /// `Session` from a value that now owns it.
262 fn sess
<'a
>(&'a
self) -> &'a Session
;
264 /// Produces the pretty-print annotation object.
266 /// (Rust does not yet support upcasting from a trait object to
267 /// an object for one of its super-traits.)
268 fn pp_ann
<'a
>(&'a
self) -> &'a pprust
::PpAnn
;
271 trait HirPrinterSupport
<'hir
>: pprust_hir
::PpAnn
{
272 /// Provides a uniform interface for re-extracting a reference to a
273 /// `Session` from a value that now owns it.
274 fn sess
<'a
>(&'a
self) -> &'a Session
;
276 /// Provides a uniform interface for re-extracting a reference to an
277 /// `hir_map::Map` from a value that now owns it.
278 fn hir_map
<'a
>(&'a
self) -> Option
<&'a hir_map
::Map
<'hir
>>;
280 /// Produces the pretty-print annotation object.
282 /// (Rust does not yet support upcasting from a trait object to
283 /// an object for one of its super-traits.)
284 fn pp_ann
<'a
>(&'a
self) -> &'a pprust_hir
::PpAnn
;
286 /// Computes an user-readable representation of a path, if possible.
287 fn node_path(&self, id
: ast
::NodeId
) -> Option
<String
> {
288 self.hir_map().and_then(|map
| map
.def_path_from_id(id
)).map(|path
| {
291 .map(|elem
| elem
.data
.to_string())
300 hir_map
: Option
<hir_map
::Map
<'hir
>>,
303 impl<'hir
> PrinterSupport
for NoAnn
<'hir
> {
304 fn sess
<'a
>(&'a
self) -> &'a Session
{
308 fn pp_ann
<'a
>(&'a
self) -> &'a pprust
::PpAnn
{
313 impl<'hir
> HirPrinterSupport
<'hir
> for NoAnn
<'hir
> {
314 fn sess
<'a
>(&'a
self) -> &'a Session
{
318 fn hir_map
<'a
>(&'a
self) -> Option
<&'a hir_map
::Map
<'hir
>> {
319 self.hir_map
.as_ref()
322 fn pp_ann
<'a
>(&'a
self) -> &'a pprust_hir
::PpAnn
{
327 impl<'hir
> pprust
::PpAnn
for NoAnn
<'hir
> {}
328 impl<'hir
> pprust_hir
::PpAnn
for NoAnn
<'hir
> {
329 fn nested(&self, state
: &mut pprust_hir
::State
, nested
: pprust_hir
::Nested
)
331 if let Some(ref map
) = self.hir_map
{
332 pprust_hir
::PpAnn
::nested(map
, state
, nested
)
339 struct IdentifiedAnnotation
<'hir
> {
341 hir_map
: Option
<hir_map
::Map
<'hir
>>,
344 impl<'hir
> PrinterSupport
for IdentifiedAnnotation
<'hir
> {
345 fn sess
<'a
>(&'a
self) -> &'a Session
{
349 fn pp_ann
<'a
>(&'a
self) -> &'a pprust
::PpAnn
{
354 impl<'hir
> pprust
::PpAnn
for IdentifiedAnnotation
<'hir
> {
355 fn pre(&self, s
: &mut pprust
::State
, node
: pprust
::AnnNode
) -> io
::Result
<()> {
357 pprust
::NodeExpr(_
) => s
.popen(),
361 fn post(&self, s
: &mut pprust
::State
, node
: pprust
::AnnNode
) -> io
::Result
<()> {
363 pprust
::NodeIdent(_
) |
364 pprust
::NodeName(_
) => Ok(()),
366 pprust
::NodeItem(item
) => {
368 s
.synth_comment(item
.id
.to_string())
370 pprust
::NodeSubItem(id
) => {
372 s
.synth_comment(id
.to_string())
374 pprust
::NodeBlock(blk
) => {
376 s
.synth_comment(format
!("block {}", blk
.id
))
378 pprust
::NodeExpr(expr
) => {
380 s
.synth_comment(expr
.id
.to_string())?
;
383 pprust
::NodePat(pat
) => {
385 s
.synth_comment(format
!("pat {}", pat
.id
))
391 impl<'hir
> HirPrinterSupport
<'hir
> for IdentifiedAnnotation
<'hir
> {
392 fn sess
<'a
>(&'a
self) -> &'a Session
{
396 fn hir_map
<'a
>(&'a
self) -> Option
<&'a hir_map
::Map
<'hir
>> {
397 self.hir_map
.as_ref()
400 fn pp_ann
<'a
>(&'a
self) -> &'a pprust_hir
::PpAnn
{
405 impl<'hir
> pprust_hir
::PpAnn
for IdentifiedAnnotation
<'hir
> {
406 fn nested(&self, state
: &mut pprust_hir
::State
, nested
: pprust_hir
::Nested
)
408 if let Some(ref map
) = self.hir_map
{
409 pprust_hir
::PpAnn
::nested(map
, state
, nested
)
414 fn pre(&self, s
: &mut pprust_hir
::State
, node
: pprust_hir
::AnnNode
) -> io
::Result
<()> {
416 pprust_hir
::NodeExpr(_
) => s
.popen(),
420 fn post(&self, s
: &mut pprust_hir
::State
, node
: pprust_hir
::AnnNode
) -> io
::Result
<()> {
422 pprust_hir
::NodeName(_
) => Ok(()),
423 pprust_hir
::NodeItem(item
) => {
425 s
.synth_comment(format
!("node_id: {} hir local_id: {}",
426 item
.id
, item
.hir_id
.local_id
.0))
428 pprust_hir
::NodeSubItem(id
) => {
430 s
.synth_comment(id
.to_string())
432 pprust_hir
::NodeBlock(blk
) => {
434 s
.synth_comment(format
!("block node_id: {} hir local_id: {}",
435 blk
.id
, blk
.hir_id
.local_id
.0))
437 pprust_hir
::NodeExpr(expr
) => {
439 s
.synth_comment(format
!("node_id: {} hir local_id: {}",
440 expr
.id
, expr
.hir_id
.local_id
.0))?
;
443 pprust_hir
::NodePat(pat
) => {
445 s
.synth_comment(format
!("pat node_id: {} hir local_id: {}",
446 pat
.id
, pat
.hir_id
.local_id
.0))
452 struct HygieneAnnotation
<'a
> {
456 impl<'a
> PrinterSupport
for HygieneAnnotation
<'a
> {
457 fn sess(&self) -> &Session
{
461 fn pp_ann(&self) -> &pprust
::PpAnn
{
466 impl<'a
> pprust
::PpAnn
for HygieneAnnotation
<'a
> {
467 fn post(&self, s
: &mut pprust
::State
, node
: pprust
::AnnNode
) -> io
::Result
<()> {
469 pprust
::NodeIdent(&ast
::Ident { name, ctxt }
) => {
471 // FIXME #16420: this doesn't display the connections
472 // between syntax contexts
473 s
.synth_comment(format
!("{}{:?}", name
.as_u32(), ctxt
))
475 pprust
::NodeName(&name
) => {
477 s
.synth_comment(name
.as_u32().to_string())
485 struct TypedAnnotation
<'a
, 'tcx
: 'a
> {
486 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
487 tables
: Cell
<&'a ty
::TypeckTables
<'tcx
>>,
490 impl<'b
, 'tcx
> HirPrinterSupport
<'tcx
> for TypedAnnotation
<'b
, 'tcx
> {
491 fn sess
<'a
>(&'a
self) -> &'a Session
{
495 fn hir_map
<'a
>(&'a
self) -> Option
<&'a hir_map
::Map
<'tcx
>> {
499 fn pp_ann
<'a
>(&'a
self) -> &'a pprust_hir
::PpAnn
{
503 fn node_path(&self, id
: ast
::NodeId
) -> Option
<String
> {
504 Some(self.tcx
.node_path_str(id
))
508 impl<'a
, 'tcx
> pprust_hir
::PpAnn
for TypedAnnotation
<'a
, 'tcx
> {
509 fn nested(&self, state
: &mut pprust_hir
::State
, nested
: pprust_hir
::Nested
)
511 let old_tables
= self.tables
.get();
512 if let pprust_hir
::Nested
::Body(id
) = nested
{
513 self.tables
.set(self.tcx
.body_tables(id
));
515 pprust_hir
::PpAnn
::nested(&self.tcx
.hir
, state
, nested
)?
;
516 self.tables
.set(old_tables
);
519 fn pre(&self, s
: &mut pprust_hir
::State
, node
: pprust_hir
::AnnNode
) -> io
::Result
<()> {
521 pprust_hir
::NodeExpr(_
) => s
.popen(),
525 fn post(&self, s
: &mut pprust_hir
::State
, node
: pprust_hir
::AnnNode
) -> io
::Result
<()> {
527 pprust_hir
::NodeExpr(expr
) => {
531 s
.s
.word(&self.tables
.get().expr_ty(expr
).to_string())?
;
539 fn gather_flowgraph_variants(sess
: &Session
) -> Vec
<borrowck_dot
::Variant
> {
540 let print_loans
= sess
.opts
.debugging_opts
.flowgraph_print_loans
;
541 let print_moves
= sess
.opts
.debugging_opts
.flowgraph_print_moves
;
542 let print_assigns
= sess
.opts
.debugging_opts
.flowgraph_print_assigns
;
543 let print_all
= sess
.opts
.debugging_opts
.flowgraph_print_all
;
544 let mut variants
= Vec
::new();
545 if print_all
|| print_loans
{
546 variants
.push(borrowck_dot
::Loans
);
548 if print_all
|| print_moves
{
549 variants
.push(borrowck_dot
::Moves
);
551 if print_all
|| print_assigns
{
552 variants
.push(borrowck_dot
::Assigns
);
557 #[derive(Clone, Debug)]
558 pub enum UserIdentifiedItem
{
559 ItemViaNode(ast
::NodeId
),
560 ItemViaPath(Vec
<String
>),
563 impl FromStr
for UserIdentifiedItem
{
565 fn from_str(s
: &str) -> Result
<UserIdentifiedItem
, ()> {
567 .map(ast
::NodeId
::new
)
569 .unwrap_or_else(|_
| ItemViaPath(s
.split("::").map(|s
| s
.to_string()).collect())))
573 enum NodesMatchingUII
<'a
, 'hir
: 'a
> {
574 NodesMatchingDirect(option
::IntoIter
<ast
::NodeId
>),
575 NodesMatchingSuffix(hir_map
::NodesMatchingSuffix
<'a
, 'hir
>),
578 impl<'a
, 'hir
> Iterator
for NodesMatchingUII
<'a
, 'hir
> {
579 type Item
= ast
::NodeId
;
581 fn next(&mut self) -> Option
<ast
::NodeId
> {
583 &mut NodesMatchingDirect(ref mut iter
) => iter
.next(),
584 &mut NodesMatchingSuffix(ref mut iter
) => iter
.next(),
589 impl UserIdentifiedItem
{
590 fn reconstructed_input(&self) -> String
{
592 ItemViaNode(node_id
) => node_id
.to_string(),
593 ItemViaPath(ref parts
) => parts
.join("::"),
597 fn all_matching_node_ids
<'a
, 'hir
>(&'a
self,
598 map
: &'a hir_map
::Map
<'hir
>)
599 -> NodesMatchingUII
<'a
, 'hir
> {
601 ItemViaNode(node_id
) => NodesMatchingDirect(Some(node_id
).into_iter()),
602 ItemViaPath(ref parts
) => NodesMatchingSuffix(map
.nodes_matching_suffix(&parts
)),
606 fn to_one_node_id(self, user_option
: &str, sess
: &Session
, map
: &hir_map
::Map
) -> ast
::NodeId
{
607 let fail_because
= |is_wrong_because
| -> ast
::NodeId
{
608 let message
= format
!("{} needs NodeId (int) or unique path suffix (b::c::d); got \
611 self.reconstructed_input(),
616 let mut saw_node
= ast
::DUMMY_NODE_ID
;
618 for node
in self.all_matching_node_ids(map
) {
622 fail_because("does not resolve uniquely");
626 fail_because("does not resolve to any item");
634 // Note: Also used by librustdoc, see PR #43348. Consider moving this struct elsewhere.
636 // FIXME: Currently the `everybody_loops` transformation is not applied to:
637 // * `const fn`, due to issue #43636 that `loop` is not supported for const evaluation. We are
638 // waiting for miri to fix that.
639 // * `impl Trait`, due to issue #43869 that functions returning impl Trait cannot be diverging.
640 // Solving this may require `!` to implement every trait, which relies on the an even more
641 // ambitious form of the closed RFC #1637. See also [#34511].
643 // [#34511]: https://github.com/rust-lang/rust/issues/34511#issuecomment-322340401
644 pub struct ReplaceBodyWithLoop
<'a
> {
645 within_static_or_const
: bool
,
649 impl<'a
> ReplaceBodyWithLoop
<'a
> {
650 pub fn new(sess
: &'a Session
) -> ReplaceBodyWithLoop
<'a
> {
651 ReplaceBodyWithLoop { within_static_or_const: false, sess }
654 fn run
<R
, F
: FnOnce(&mut Self) -> R
>(&mut self, is_const
: bool
, action
: F
) -> R
{
655 let old_const
= mem
::replace(&mut self.within_static_or_const
, is_const
);
656 let ret
= action(self);
657 self.within_static_or_const
= old_const
;
661 fn should_ignore_fn(ret_ty
: &ast
::FnDecl
) -> bool
{
662 if let ast
::FunctionRetTy
::Ty(ref ty
) = ret_ty
.output
{
663 fn involves_impl_trait(ty
: &ast
::Ty
) -> bool
{
665 ast
::TyKind
::ImplTrait(_
) => true,
666 ast
::TyKind
::Slice(ref subty
) |
667 ast
::TyKind
::Array(ref subty
, _
) |
668 ast
::TyKind
::Ptr(ast
::MutTy { ty: ref subty, .. }
) |
669 ast
::TyKind
::Rptr(_
, ast
::MutTy { ty: ref subty, .. }
) |
670 ast
::TyKind
::Paren(ref subty
) => involves_impl_trait(subty
),
671 ast
::TyKind
::Tup(ref tys
) => any_involves_impl_trait(tys
.iter()),
672 ast
::TyKind
::Path(_
, ref path
) => path
.segments
.iter().any(|seg
| {
673 match seg
.parameters
.as_ref().map(|p
| &**p
) {
675 Some(&ast
::PathParameters
::AngleBracketed(ref data
)) =>
676 any_involves_impl_trait(data
.types
.iter()) ||
677 any_involves_impl_trait(data
.bindings
.iter().map(|b
| &b
.ty
)),
678 Some(&ast
::PathParameters
::Parenthesized(ref data
)) =>
679 any_involves_impl_trait(data
.inputs
.iter()) ||
680 any_involves_impl_trait(data
.output
.iter()),
687 fn any_involves_impl_trait
<'a
, I
: Iterator
<Item
= &'a P
<ast
::Ty
>>>(mut it
: I
) -> bool
{
688 it
.any(|subty
| involves_impl_trait(subty
))
691 involves_impl_trait(ty
)
698 impl<'a
> fold
::Folder
for ReplaceBodyWithLoop
<'a
> {
699 fn fold_item_kind(&mut self, i
: ast
::ItemKind
) -> ast
::ItemKind
{
700 let is_const
= match i
{
701 ast
::ItemKind
::Static(..) | ast
::ItemKind
::Const(..) => true,
702 ast
::ItemKind
::Fn(ref decl
, _
, ref constness
, _
, _
, _
) =>
703 constness
.node
== ast
::Constness
::Const
|| Self::should_ignore_fn(decl
),
706 self.run(is_const
, |s
| fold
::noop_fold_item_kind(i
, s
))
709 fn fold_trait_item(&mut self, i
: ast
::TraitItem
) -> SmallVector
<ast
::TraitItem
> {
710 let is_const
= match i
.node
{
711 ast
::TraitItemKind
::Const(..) => true,
712 ast
::TraitItemKind
::Method(ast
::MethodSig { ref decl, ref constness, .. }
, _
) =>
713 constness
.node
== ast
::Constness
::Const
|| Self::should_ignore_fn(decl
),
716 self.run(is_const
, |s
| fold
::noop_fold_trait_item(i
, s
))
719 fn fold_impl_item(&mut self, i
: ast
::ImplItem
) -> SmallVector
<ast
::ImplItem
> {
720 let is_const
= match i
.node
{
721 ast
::ImplItemKind
::Const(..) => true,
722 ast
::ImplItemKind
::Method(ast
::MethodSig { ref decl, ref constness, .. }
, _
) =>
723 constness
.node
== ast
::Constness
::Const
|| Self::should_ignore_fn(decl
),
726 self.run(is_const
, |s
| fold
::noop_fold_impl_item(i
, s
))
729 fn fold_block(&mut self, b
: P
<ast
::Block
>) -> P
<ast
::Block
> {
730 fn expr_to_block(rules
: ast
::BlockCheckMode
,
732 e
: Option
<P
<ast
::Expr
>>,
733 sess
: &Session
) -> P
<ast
::Block
> {
737 id
: sess
.next_node_id(),
739 node
: ast
::StmtKind
::Expr(e
),
745 id
: sess
.next_node_id(),
746 span
: syntax_pos
::DUMMY_SP
,
751 if !self.within_static_or_const
{
753 let empty_block
= expr_to_block(BlockCheckMode
::Default
, false, None
, self.sess
);
754 let loop_expr
= P(ast
::Expr
{
755 node
: ast
::ExprKind
::Loop(empty_block
, None
),
756 id
: self.sess
.next_node_id(),
757 span
: syntax_pos
::DUMMY_SP
,
758 attrs
: ast
::ThinVec
::new(),
761 expr_to_block(b
.rules
, b
.recovered
, Some(loop_expr
), self.sess
)
764 fold
::noop_fold_block(b
, self)
768 // in general the pretty printer processes unexpanded code, so
769 // we override the default `fold_mac` method which panics.
770 fn fold_mac(&mut self, mac
: ast
::Mac
) -> ast
::Mac
{
771 fold
::noop_fold_mac(mac
, self)
775 fn print_flowgraph
<'a
, 'tcx
, W
: Write
>(variants
: Vec
<borrowck_dot
::Variant
>,
776 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
777 code
: blocks
::Code
<'tcx
>,
778 mode
: PpFlowGraphMode
,
781 let body_id
= match code
{
782 blocks
::Code
::Expr(expr
) => {
783 // Find the function this expression is from.
784 let mut node_id
= expr
.id
;
786 let node
= tcx
.hir
.get(node_id
);
787 if let Some(n
) = hir
::map
::blocks
::FnLikeNode
::from_node(node
) {
790 let parent
= tcx
.hir
.get_parent_node(node_id
);
791 assert
!(node_id
!= parent
);
795 blocks
::Code
::FnLike(fn_like
) => fn_like
.body(),
797 let body
= tcx
.hir
.body(body_id
);
798 let cfg
= cfg
::CFG
::new(tcx
, &body
);
799 let labelled_edges
= mode
!= PpFlowGraphMode
::UnlabelledEdges
;
800 let lcfg
= LabelledCFG
{
803 name
: format
!("node_{}", code
.id()),
808 _
if variants
.is_empty() => {
809 let r
= dot
::render(&lcfg
, &mut out
);
810 return expand_err_details(r
);
812 blocks
::Code
::Expr(_
) => {
813 tcx
.sess
.err("--pretty flowgraph with -Z flowgraph-print annotations requires \
817 blocks
::Code
::FnLike(fn_like
) => {
818 let (bccx
, analysis_data
) =
819 borrowck
::build_borrowck_dataflow_data_for_fn(tcx
, fn_like
.body(), &cfg
);
821 let lcfg
= borrowck_dot
::DataflowLabeller
{
824 borrowck_ctxt
: &bccx
,
825 analysis_data
: &analysis_data
,
827 let r
= dot
::render(&lcfg
, &mut out
);
828 return expand_err_details(r
);
832 fn expand_err_details(r
: io
::Result
<()>) -> io
::Result
<()> {
834 io
::Error
::new(io
::ErrorKind
::Other
,
835 format
!("graphviz::render failed: {}", ioerr
))
840 pub fn fold_crate(sess
: &Session
, krate
: ast
::Crate
, ppm
: PpMode
) -> ast
::Crate
{
841 if let PpmSource(PpmEveryBodyLoops
) = ppm
{
842 let mut fold
= ReplaceBodyWithLoop
::new(sess
);
843 fold
.fold_crate(krate
)
849 fn get_source(input
: &Input
, sess
: &Session
) -> (Vec
<u8>, FileName
) {
850 let src_name
= driver
::source_name(input
);
851 let src
= sess
.codemap()
852 .get_filemap(&src_name
)
862 fn write_output(out
: Vec
<u8>, ofile
: Option
<&Path
>) {
864 None
=> print
!("{}", String
::from_utf8(out
).unwrap()),
866 match File
::create(p
) {
867 Ok(mut w
) => w
.write_all(&out
).unwrap(),
868 Err(e
) => panic
!("print-print failed to open {} due to {}", p
.display(), e
),
874 pub fn print_after_parsing(sess
: &Session
,
878 ofile
: Option
<&Path
>) {
879 let (src
, src_name
) = get_source(input
, sess
);
882 let mut out
= Vec
::new();
884 if let PpmSource(s
) = ppm
{
885 // Silently ignores an identified node.
886 let out
: &mut Write
= &mut out
;
887 s
.call_with_pp_support(sess
, None
, move |annotation
| {
888 debug
!("pretty printing source code {:?}", s
);
889 let sess
= annotation
.sess();
890 pprust
::print_crate(sess
.codemap(),
904 write_output(out
, ofile
);
907 pub fn print_after_hir_lowering
<'tcx
, 'a
: 'tcx
>(sess
: &'a Session
,
908 cstore
: &'tcx CrateStore
,
909 hir_map
: &hir_map
::Map
<'tcx
>,
910 analysis
: &ty
::CrateAnalysis
,
911 resolutions
: &Resolutions
,
916 arenas
: &'tcx AllArenas
<'tcx
>,
917 output_filenames
: &OutputFilenames
,
918 opt_uii
: Option
<UserIdentifiedItem
>,
919 ofile
: Option
<&Path
>) {
920 if ppm
.needs_analysis() {
921 print_with_analysis(sess
,
935 let (src
, src_name
) = get_source(input
, sess
);
937 let mut rdr
= &src
[..];
938 let mut out
= Vec
::new();
940 match (ppm
, opt_uii
) {
941 (PpmSource(s
), _
) => {
942 // Silently ignores an identified node.
943 let out
: &mut Write
= &mut out
;
944 s
.call_with_pp_support(sess
, Some(hir_map
), move |annotation
| {
945 debug
!("pretty printing source code {:?}", s
);
946 let sess
= annotation
.sess();
947 pprust
::print_crate(sess
.codemap(),
958 (PpmHir(s
), None
) => {
959 let out
: &mut Write
= &mut out
;
960 s
.call_with_pp_support_hir(sess
,
968 move |annotation
, krate
| {
969 debug
!("pretty printing source code {:?}", s
);
970 let sess
= annotation
.sess();
971 pprust_hir
::print_crate(sess
.codemap(),
982 (PpmHirTree(s
), None
) => {
983 let out
: &mut Write
= &mut out
;
984 s
.call_with_pp_support_hir(sess
,
992 move |_annotation
, krate
| {
993 debug
!("pretty printing source code {:?}", s
);
994 write
!(out
, "{:#?}", krate
)
998 (PpmHir(s
), Some(uii
)) => {
999 let out
: &mut Write
= &mut out
;
1000 s
.call_with_pp_support_hir(sess
,
1008 move |annotation
, _
| {
1009 debug
!("pretty printing source code {:?}", s
);
1010 let sess
= annotation
.sess();
1011 let hir_map
= annotation
.hir_map().expect("-Z unpretty missing HIR map");
1012 let mut pp_state
= pprust_hir
::State
::new_from_input(sess
.codemap(),
1017 annotation
.pp_ann(),
1019 for node_id
in uii
.all_matching_node_ids(hir_map
) {
1020 let node
= hir_map
.get(node_id
);
1021 pp_state
.print_node(node
)?
;
1022 pp_state
.s
.space()?
;
1023 let path
= annotation
.node_path(node_id
)
1024 .expect("-Z unpretty missing node paths");
1025 pp_state
.synth_comment(path
)?
;
1026 pp_state
.s
.hardbreak()?
;
1032 (PpmHirTree(s
), Some(uii
)) => {
1033 let out
: &mut Write
= &mut out
;
1034 s
.call_with_pp_support_hir(sess
,
1042 move |_annotation
, _krate
| {
1043 debug
!("pretty printing source code {:?}", s
);
1044 for node_id
in uii
.all_matching_node_ids(hir_map
) {
1045 let node
= hir_map
.get(node_id
);
1046 write
!(out
, "{:#?}", node
)?
;
1052 _
=> unreachable
!(),
1056 write_output(out
, ofile
);
1059 // In an ideal world, this would be a public function called by the driver after
1060 // analsysis is performed. However, we want to call `phase_3_run_analysis_passes`
1061 // with a different callback than the standard driver, so that isn't easy.
1062 // Instead, we call that function ourselves.
1063 fn print_with_analysis
<'tcx
, 'a
: 'tcx
>(sess
: &'a Session
,
1064 cstore
: &'a CrateStore
,
1065 hir_map
: &hir_map
::Map
<'tcx
>,
1066 analysis
: &ty
::CrateAnalysis
,
1067 resolutions
: &Resolutions
,
1069 arenas
: &'tcx AllArenas
<'tcx
>,
1070 output_filenames
: &OutputFilenames
,
1072 uii
: Option
<UserIdentifiedItem
>,
1073 ofile
: Option
<&Path
>) {
1074 let nodeid
= if let Some(uii
) = uii
{
1075 debug
!("pretty printing for {:?}", uii
);
1076 Some(uii
.to_one_node_id("-Z unpretty", sess
, &hir_map
))
1078 debug
!("pretty printing for whole crate");
1082 let mut out
= Vec
::new();
1084 let control
= &driver
::CompileController
::basic();
1085 let trans
= ::get_trans(sess
);
1086 abort_on_err(driver
::phase_3_run_analysis_passes(&*trans
,
1092 resolutions
.clone(),
1098 PpmMir
| PpmMirCFG
=> {
1099 if let Some(nodeid
) = nodeid
{
1100 let def_id
= tcx
.hir
.local_def_id(nodeid
);
1102 PpmMir
=> write_mir_pretty(tcx
, Some(def_id
), &mut out
),
1103 PpmMirCFG
=> write_mir_graphviz(tcx
, Some(def_id
), &mut out
),
1104 _
=> unreachable
!(),
1108 PpmMir
=> write_mir_pretty(tcx
, None
, &mut out
),
1109 PpmMirCFG
=> write_mir_graphviz(tcx
, None
, &mut out
),
1110 _
=> unreachable
!(),
1115 PpmFlowGraph(mode
) => {
1117 nodeid
.expect("`pretty flowgraph=..` needs NodeId (int) or unique path \
1119 let node
= tcx
.hir
.find(nodeid
).unwrap_or_else(|| {
1120 tcx
.sess
.fatal(&format
!("--pretty flowgraph couldn't find id: {}", nodeid
))
1123 match blocks
::Code
::from_node(&tcx
.hir
, nodeid
) {
1125 let variants
= gather_flowgraph_variants(tcx
.sess
);
1127 let out
: &mut Write
= &mut out
;
1129 print_flowgraph(variants
, tcx
, code
, mode
, out
)
1132 let message
= format
!("--pretty=flowgraph needs block, fn, or method; \
1136 tcx
.sess
.span_fatal(tcx
.hir
.span(nodeid
), &message
)
1140 _
=> unreachable
!(),
1146 write_output(out
, ofile
);