1 //! The various pretty-printing routines.
4 use rustc_ast_pretty
::pprust
;
5 use rustc_errors
::ErrorReported
;
7 use rustc_hir
::def_id
::LOCAL_CRATE
;
8 use rustc_hir_pretty
as pprust_hir
;
9 use rustc_middle
::hir
::map
as hir_map
;
10 use rustc_middle
::ty
::{self, TyCtxt}
;
11 use rustc_mir
::util
::{write_mir_graphviz, write_mir_pretty}
;
12 use rustc_mir_build
::thir
;
13 use rustc_session
::config
::{Input, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode}
;
14 use rustc_session
::Session
;
15 use rustc_span
::symbol
::Ident
;
16 use rustc_span
::FileName
;
22 pub use self::PpMode
::*;
23 pub use self::PpSourceMode
::*;
24 use crate::abort_on_err
;
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
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`.
36 /// Constructs a `PrinterSupport` object and passes it to `f`.
37 fn call_with_pp_support
<'tcx
, A
, F
>(
38 ppmode
: &PpSourceMode
,
40 tcx
: Option
<TyCtxt
<'tcx
>>,
44 F
: FnOnce(&dyn PrinterSupport
) -> A
,
47 Normal
| EveryBodyLoops
| Expanded
=> {
48 let annotation
= NoAnn { sess, tcx }
;
52 Identified
| ExpandedIdentified
=> {
53 let annotation
= IdentifiedAnnotation { sess, tcx }
;
57 let annotation
= HygieneAnnotation { sess }
;
62 fn call_with_pp_support_hir
<A
, F
>(ppmode
: &PpHirMode
, tcx
: TyCtxt
<'_
>, f
: F
) -> A
64 F
: FnOnce(&dyn HirPrinterSupport
<'_
>, &hir
::Crate
<'_
>) -> A
,
67 PpHirMode
::Normal
=> {
68 let annotation
= NoAnn { sess: tcx.sess, tcx: Some(tcx) }
;
69 f(&annotation
, tcx
.hir().krate())
72 PpHirMode
::Identified
=> {
73 let annotation
= IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) }
;
74 f(&annotation
, tcx
.hir().krate())
77 abort_on_err(tcx
.analysis(LOCAL_CRATE
), tcx
.sess
);
79 let annotation
= TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) }
;
80 tcx
.dep_graph
.with_ignore(|| f(&annotation
, tcx
.hir().krate()))
85 trait PrinterSupport
: pprust
::PpAnn
{
86 /// Provides a uniform interface for re-extracting a reference to a
87 /// `Session` from a value that now owns it.
88 fn sess(&self) -> &Session
;
90 /// Produces the pretty-print annotation object.
92 /// (Rust does not yet support upcasting from a trait object to
93 /// an object for one of its super-traits.)
94 fn pp_ann(&self) -> &dyn pprust
::PpAnn
;
97 trait HirPrinterSupport
<'hir
>: pprust_hir
::PpAnn
{
98 /// Provides a uniform interface for re-extracting a reference to a
99 /// `Session` from a value that now owns it.
100 fn sess(&self) -> &Session
;
102 /// Provides a uniform interface for re-extracting a reference to an
103 /// `hir_map::Map` from a value that now owns it.
104 fn hir_map(&self) -> Option
<hir_map
::Map
<'hir
>>;
106 /// Produces the pretty-print annotation object.
108 /// (Rust does not yet support upcasting from a trait object to
109 /// an object for one of its super-traits.)
110 fn pp_ann(&self) -> &dyn pprust_hir
::PpAnn
;
112 /// Computes an user-readable representation of a path, if possible.
113 fn node_path(&self, id
: hir
::HirId
) -> Option
<String
> {
114 self.hir_map().and_then(|map
| map
.def_path_from_hir_id(id
)).map(|path
| {
115 path
.data
.into_iter().map(|elem
| elem
.data
.to_string()).collect
::<Vec
<_
>>().join("::")
122 tcx
: Option
<TyCtxt
<'hir
>>,
125 impl<'hir
> PrinterSupport
for NoAnn
<'hir
> {
126 fn sess(&self) -> &Session
{
130 fn pp_ann(&self) -> &dyn pprust
::PpAnn
{
135 impl<'hir
> HirPrinterSupport
<'hir
> for NoAnn
<'hir
> {
136 fn sess(&self) -> &Session
{
140 fn hir_map(&self) -> Option
<hir_map
::Map
<'hir
>> {
141 self.tcx
.map(|tcx
| tcx
.hir())
144 fn pp_ann(&self) -> &dyn pprust_hir
::PpAnn
{
149 impl<'hir
> pprust
::PpAnn
for NoAnn
<'hir
> {}
150 impl<'hir
> pprust_hir
::PpAnn
for NoAnn
<'hir
> {
151 fn nested(&self, state
: &mut pprust_hir
::State
<'_
>, nested
: pprust_hir
::Nested
) {
152 if let Some(tcx
) = self.tcx
{
153 pprust_hir
::PpAnn
::nested(&(&tcx
.hir() as &dyn hir
::intravisit
::Map
<'_
>), state
, nested
)
158 struct IdentifiedAnnotation
<'hir
> {
160 tcx
: Option
<TyCtxt
<'hir
>>,
163 impl<'hir
> PrinterSupport
for IdentifiedAnnotation
<'hir
> {
164 fn sess(&self) -> &Session
{
168 fn pp_ann(&self) -> &dyn pprust
::PpAnn
{
173 impl<'hir
> pprust
::PpAnn
for IdentifiedAnnotation
<'hir
> {
174 fn pre(&self, s
: &mut pprust
::State
<'_
>, node
: pprust
::AnnNode
<'_
>) {
175 if let pprust
::AnnNode
::Expr(_
) = node
{
179 fn post(&self, s
: &mut pprust
::State
<'_
>, node
: pprust
::AnnNode
<'_
>) {
181 pprust
::AnnNode
::Crate(_
) | pprust
::AnnNode
::Ident(_
) | pprust
::AnnNode
::Name(_
) => {}
183 pprust
::AnnNode
::Item(item
) => {
185 s
.synth_comment(item
.id
.to_string())
187 pprust
::AnnNode
::SubItem(id
) => {
189 s
.synth_comment(id
.to_string())
191 pprust
::AnnNode
::Block(blk
) => {
193 s
.synth_comment(format
!("block {}", blk
.id
))
195 pprust
::AnnNode
::Expr(expr
) => {
197 s
.synth_comment(expr
.id
.to_string());
200 pprust
::AnnNode
::Pat(pat
) => {
202 s
.synth_comment(format
!("pat {}", pat
.id
));
208 impl<'hir
> HirPrinterSupport
<'hir
> for IdentifiedAnnotation
<'hir
> {
209 fn sess(&self) -> &Session
{
213 fn hir_map(&self) -> Option
<hir_map
::Map
<'hir
>> {
214 self.tcx
.map(|tcx
| tcx
.hir())
217 fn pp_ann(&self) -> &dyn pprust_hir
::PpAnn
{
222 impl<'hir
> pprust_hir
::PpAnn
for IdentifiedAnnotation
<'hir
> {
223 fn nested(&self, state
: &mut pprust_hir
::State
<'_
>, nested
: pprust_hir
::Nested
) {
224 if let Some(ref tcx
) = self.tcx
{
225 pprust_hir
::PpAnn
::nested(&(&tcx
.hir() as &dyn hir
::intravisit
::Map
<'_
>), state
, nested
)
228 fn pre(&self, s
: &mut pprust_hir
::State
<'_
>, node
: pprust_hir
::AnnNode
<'_
>) {
229 if let pprust_hir
::AnnNode
::Expr(_
) = node
{
233 fn post(&self, s
: &mut pprust_hir
::State
<'_
>, node
: pprust_hir
::AnnNode
<'_
>) {
235 pprust_hir
::AnnNode
::Name(_
) => {}
236 pprust_hir
::AnnNode
::Item(item
) => {
238 s
.synth_comment(format
!("hir_id: {}", item
.hir_id()));
240 pprust_hir
::AnnNode
::SubItem(id
) => {
242 s
.synth_comment(id
.to_string());
244 pprust_hir
::AnnNode
::Block(blk
) => {
246 s
.synth_comment(format
!("block hir_id: {}", blk
.hir_id
));
248 pprust_hir
::AnnNode
::Expr(expr
) => {
250 s
.synth_comment(format
!("expr hir_id: {}", expr
.hir_id
));
253 pprust_hir
::AnnNode
::Pat(pat
) => {
255 s
.synth_comment(format
!("pat hir_id: {}", pat
.hir_id
));
257 pprust_hir
::AnnNode
::Arm(arm
) => {
259 s
.synth_comment(format
!("arm hir_id: {}", arm
.hir_id
));
265 struct HygieneAnnotation
<'a
> {
269 impl<'a
> PrinterSupport
for HygieneAnnotation
<'a
> {
270 fn sess(&self) -> &Session
{
274 fn pp_ann(&self) -> &dyn pprust
::PpAnn
{
279 impl<'a
> pprust
::PpAnn
for HygieneAnnotation
<'a
> {
280 fn post(&self, s
: &mut pprust
::State
<'_
>, node
: pprust
::AnnNode
<'_
>) {
282 pprust
::AnnNode
::Ident(&Ident { name, span }
) => {
284 s
.synth_comment(format
!("{}{:?}", name
.as_u32(), span
.ctxt()))
286 pprust
::AnnNode
::Name(&name
) => {
288 s
.synth_comment(name
.as_u32().to_string())
290 pprust
::AnnNode
::Crate(_
) => {
292 let verbose
= self.sess
.verbose();
293 s
.synth_comment(rustc_span
::hygiene
::debug_hygiene_data(verbose
));
294 s
.s
.hardbreak_if_not_bol();
301 struct TypedAnnotation
<'tcx
> {
303 maybe_typeck_results
: Cell
<Option
<&'tcx ty
::TypeckResults
<'tcx
>>>,
306 impl<'tcx
> TypedAnnotation
<'tcx
> {
307 /// Gets the type-checking results for the current body.
308 /// As this will ICE if called outside bodies, only call when working with
309 /// `Expr` or `Pat` nodes (they are guaranteed to be found only in bodies).
311 fn typeck_results(&self) -> &'tcx ty
::TypeckResults
<'tcx
> {
312 self.maybe_typeck_results
314 .expect("`TypedAnnotation::typeck_results` called outside of body")
318 impl<'tcx
> HirPrinterSupport
<'tcx
> for TypedAnnotation
<'tcx
> {
319 fn sess(&self) -> &Session
{
323 fn hir_map(&self) -> Option
<hir_map
::Map
<'tcx
>> {
327 fn pp_ann(&self) -> &dyn pprust_hir
::PpAnn
{
331 fn node_path(&self, id
: hir
::HirId
) -> Option
<String
> {
332 Some(self.tcx
.def_path_str(self.tcx
.hir().local_def_id(id
).to_def_id()))
336 impl<'tcx
> pprust_hir
::PpAnn
for TypedAnnotation
<'tcx
> {
337 fn nested(&self, state
: &mut pprust_hir
::State
<'_
>, nested
: pprust_hir
::Nested
) {
338 let old_maybe_typeck_results
= self.maybe_typeck_results
.get();
339 if let pprust_hir
::Nested
::Body(id
) = nested
{
340 self.maybe_typeck_results
.set(Some(self.tcx
.typeck_body(id
)));
342 let pp_ann
= &(&self.tcx
.hir() as &dyn hir
::intravisit
::Map
<'_
>);
343 pprust_hir
::PpAnn
::nested(pp_ann
, state
, nested
);
344 self.maybe_typeck_results
.set(old_maybe_typeck_results
);
346 fn pre(&self, s
: &mut pprust_hir
::State
<'_
>, node
: pprust_hir
::AnnNode
<'_
>) {
347 if let pprust_hir
::AnnNode
::Expr(_
) = node
{
351 fn post(&self, s
: &mut pprust_hir
::State
<'_
>, node
: pprust_hir
::AnnNode
<'_
>) {
352 if let pprust_hir
::AnnNode
::Expr(expr
) = node
{
356 s
.s
.word(self.typeck_results().expr_ty(expr
).to_string());
362 fn get_source(input
: &Input
, sess
: &Session
) -> (String
, FileName
) {
363 let src_name
= input
.source_name();
364 let src
= String
::clone(
367 .get_source_file(&src_name
)
368 .expect("get_source_file")
376 fn write_or_print(out
: &str, ofile
: Option
<&Path
>) {
378 None
=> print
!("{}", out
),
380 if let Err(e
) = std
::fs
::write(p
, out
) {
381 panic
!("print-print failed to write {} due to {}", p
.display(), e
);
387 pub fn print_after_parsing(
392 ofile
: Option
<&Path
>,
394 let (src
, src_name
) = get_source(input
, sess
);
396 let out
= match ppm
{
398 // Silently ignores an identified node.
399 call_with_pp_support(&s
, sess
, None
, move |annotation
| {
400 debug
!("pretty printing source code {:?}", s
);
401 let sess
= annotation
.sess();
402 let parse
= &sess
.parse_sess
;
414 AstTree(PpAstTreeMode
::Normal
) => {
415 debug
!("pretty printing AST tree");
416 format
!("{:#?}", krate
)
421 write_or_print(&out
, ofile
);
424 pub fn print_after_hir_lowering
<'tcx
>(
429 ofile
: Option
<&Path
>,
431 if ppm
.needs_analysis() {
432 abort_on_err(print_with_analysis(tcx
, ppm
, ofile
), tcx
.sess
);
436 let (src
, src_name
) = get_source(input
, tcx
.sess
);
438 let out
= match ppm
{
440 // Silently ignores an identified node.
441 call_with_pp_support(&s
, tcx
.sess
, Some(tcx
), move |annotation
| {
442 debug
!("pretty printing source code {:?}", s
);
443 let sess
= annotation
.sess();
444 let parse
= &sess
.parse_sess
;
457 AstTree(PpAstTreeMode
::Expanded
) => {
458 debug
!("pretty-printing expanded AST");
459 format
!("{:#?}", krate
)
462 Hir(s
) => call_with_pp_support_hir(&s
, tcx
, move |annotation
, krate
| {
463 debug
!("pretty printing HIR {:?}", s
);
464 let sess
= annotation
.sess();
465 let sm
= sess
.source_map();
466 pprust_hir
::print_crate(sm
, krate
, src_name
, src
, annotation
.pp_ann())
469 HirTree
=> call_with_pp_support_hir(&PpHirMode
::Normal
, tcx
, move |_annotation
, krate
| {
470 debug
!("pretty printing HIR tree");
471 format
!("{:#?}", krate
)
475 let mut out
= String
::new();
476 abort_on_err(rustc_typeck
::check_crate(tcx
), tcx
.sess
);
477 debug
!("pretty printing THIR tree");
478 for did
in tcx
.body_owners() {
480 let body
= hir
.body(hir
.body_owned_by(hir
.local_def_id_to_hir_id(did
)));
481 let arena
= thir
::Arena
::default();
483 thir
::build_thir(tcx
, ty
::WithOptConstParam
::unknown(did
), &arena
, &body
.value
);
484 let _
= writeln
!(out
, "{:?}:\n{:#?}\n", did
, thir
);
492 write_or_print(&out
, ofile
);
495 // In an ideal world, this would be a public function called by the driver after
496 // analysis is performed. However, we want to call `phase_3_run_analysis_passes`
497 // with a different callback than the standard driver, so that isn't easy.
498 // Instead, we call that function ourselves.
499 fn print_with_analysis(
502 ofile
: Option
<&Path
>,
503 ) -> Result
<(), ErrorReported
> {
504 let mut out
= Vec
::new();
506 tcx
.analysis(LOCAL_CRATE
)?
;
509 Mir
=> write_mir_pretty(tcx
, None
, &mut out
).unwrap(),
510 MirCFG
=> write_mir_graphviz(tcx
, None
, &mut out
).unwrap(),
514 let out
= std
::str::from_utf8(&out
).unwrap();
515 write_or_print(out
, ofile
);