1 //! The various pretty-printing routines.
4 use rustc_ast_pretty
::pprust
;
5 use rustc_errors
::ErrorReported
;
7 use rustc_hir_pretty
as pprust_hir
;
8 use rustc_middle
::hir
::map
as hir_map
;
9 use rustc_middle
::ty
::{self, TyCtxt}
;
10 use rustc_mir
::util
::{write_mir_graphviz, write_mir_pretty}
;
11 use rustc_session
::config
::{Input, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode}
;
12 use rustc_session
::Session
;
13 use rustc_span
::symbol
::Ident
;
14 use rustc_span
::FileName
;
20 pub use self::PpMode
::*;
21 pub use self::PpSourceMode
::*;
22 use crate::abort_on_err
;
24 // This slightly awkward construction is to allow for each PpMode to
25 // choose whether it needs to do analyses (which can consume the
26 // Session) and then pass through the session (now attached to the
27 // analysis results) on to the chosen pretty-printer, along with the
30 // Note that since the `&PrinterSupport` is freshly constructed on each
31 // call, it would not make sense to try to attach the lifetime of `self`
32 // to the lifetime of the `&PrinterObject`.
34 /// Constructs a `PrinterSupport` object and passes it to `f`.
35 fn call_with_pp_support
<'tcx
, A
, F
>(
36 ppmode
: &PpSourceMode
,
38 tcx
: Option
<TyCtxt
<'tcx
>>,
42 F
: FnOnce(&dyn PrinterSupport
) -> A
,
45 Normal
| EveryBodyLoops
| Expanded
=> {
46 let annotation
= NoAnn { sess, tcx }
;
50 Identified
| ExpandedIdentified
=> {
51 let annotation
= IdentifiedAnnotation { sess, tcx }
;
55 let annotation
= HygieneAnnotation { sess }
;
60 fn call_with_pp_support_hir
<A
, F
>(ppmode
: &PpHirMode
, tcx
: TyCtxt
<'_
>, f
: F
) -> A
62 F
: FnOnce(&dyn HirPrinterSupport
<'_
>, &hir
::Crate
<'_
>) -> A
,
65 PpHirMode
::Normal
=> {
66 let annotation
= NoAnn { sess: tcx.sess, tcx: Some(tcx) }
;
67 f(&annotation
, tcx
.hir().krate())
70 PpHirMode
::Identified
=> {
71 let annotation
= IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) }
;
72 f(&annotation
, tcx
.hir().krate())
75 abort_on_err(tcx
.analysis(()), tcx
.sess
);
77 let annotation
= TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) }
;
78 tcx
.dep_graph
.with_ignore(|| f(&annotation
, tcx
.hir().krate()))
83 trait PrinterSupport
: pprust
::PpAnn
{
84 /// Provides a uniform interface for re-extracting a reference to a
85 /// `Session` from a value that now owns it.
86 fn sess(&self) -> &Session
;
88 /// Produces the pretty-print annotation object.
90 /// (Rust does not yet support upcasting from a trait object to
91 /// an object for one of its super-traits.)
92 fn pp_ann(&self) -> &dyn pprust
::PpAnn
;
95 trait HirPrinterSupport
<'hir
>: pprust_hir
::PpAnn
{
96 /// Provides a uniform interface for re-extracting a reference to a
97 /// `Session` from a value that now owns it.
98 fn sess(&self) -> &Session
;
100 /// Provides a uniform interface for re-extracting a reference to an
101 /// `hir_map::Map` from a value that now owns it.
102 fn hir_map(&self) -> Option
<hir_map
::Map
<'hir
>>;
104 /// Produces the pretty-print annotation object.
106 /// (Rust does not yet support upcasting from a trait object to
107 /// an object for one of its super-traits.)
108 fn pp_ann(&self) -> &dyn pprust_hir
::PpAnn
;
113 tcx
: Option
<TyCtxt
<'hir
>>,
116 impl<'hir
> PrinterSupport
for NoAnn
<'hir
> {
117 fn sess(&self) -> &Session
{
121 fn pp_ann(&self) -> &dyn pprust
::PpAnn
{
126 impl<'hir
> HirPrinterSupport
<'hir
> for NoAnn
<'hir
> {
127 fn sess(&self) -> &Session
{
131 fn hir_map(&self) -> Option
<hir_map
::Map
<'hir
>> {
132 self.tcx
.map(|tcx
| tcx
.hir())
135 fn pp_ann(&self) -> &dyn pprust_hir
::PpAnn
{
140 impl<'hir
> pprust
::PpAnn
for NoAnn
<'hir
> {}
141 impl<'hir
> pprust_hir
::PpAnn
for NoAnn
<'hir
> {
142 fn nested(&self, state
: &mut pprust_hir
::State
<'_
>, nested
: pprust_hir
::Nested
) {
143 if let Some(tcx
) = self.tcx
{
144 pprust_hir
::PpAnn
::nested(&(&tcx
.hir() as &dyn hir
::intravisit
::Map
<'_
>), state
, nested
)
149 struct IdentifiedAnnotation
<'hir
> {
151 tcx
: Option
<TyCtxt
<'hir
>>,
154 impl<'hir
> PrinterSupport
for IdentifiedAnnotation
<'hir
> {
155 fn sess(&self) -> &Session
{
159 fn pp_ann(&self) -> &dyn pprust
::PpAnn
{
164 impl<'hir
> pprust
::PpAnn
for IdentifiedAnnotation
<'hir
> {
165 fn pre(&self, s
: &mut pprust
::State
<'_
>, node
: pprust
::AnnNode
<'_
>) {
166 if let pprust
::AnnNode
::Expr(_
) = node
{
170 fn post(&self, s
: &mut pprust
::State
<'_
>, node
: pprust
::AnnNode
<'_
>) {
172 pprust
::AnnNode
::Crate(_
) | pprust
::AnnNode
::Ident(_
) | pprust
::AnnNode
::Name(_
) => {}
174 pprust
::AnnNode
::Item(item
) => {
176 s
.synth_comment(item
.id
.to_string())
178 pprust
::AnnNode
::SubItem(id
) => {
180 s
.synth_comment(id
.to_string())
182 pprust
::AnnNode
::Block(blk
) => {
184 s
.synth_comment(format
!("block {}", blk
.id
))
186 pprust
::AnnNode
::Expr(expr
) => {
188 s
.synth_comment(expr
.id
.to_string());
191 pprust
::AnnNode
::Pat(pat
) => {
193 s
.synth_comment(format
!("pat {}", pat
.id
));
199 impl<'hir
> HirPrinterSupport
<'hir
> for IdentifiedAnnotation
<'hir
> {
200 fn sess(&self) -> &Session
{
204 fn hir_map(&self) -> Option
<hir_map
::Map
<'hir
>> {
205 self.tcx
.map(|tcx
| tcx
.hir())
208 fn pp_ann(&self) -> &dyn pprust_hir
::PpAnn
{
213 impl<'hir
> pprust_hir
::PpAnn
for IdentifiedAnnotation
<'hir
> {
214 fn nested(&self, state
: &mut pprust_hir
::State
<'_
>, nested
: pprust_hir
::Nested
) {
215 if let Some(ref tcx
) = self.tcx
{
216 pprust_hir
::PpAnn
::nested(&(&tcx
.hir() as &dyn hir
::intravisit
::Map
<'_
>), state
, nested
)
219 fn pre(&self, s
: &mut pprust_hir
::State
<'_
>, node
: pprust_hir
::AnnNode
<'_
>) {
220 if let pprust_hir
::AnnNode
::Expr(_
) = node
{
224 fn post(&self, s
: &mut pprust_hir
::State
<'_
>, node
: pprust_hir
::AnnNode
<'_
>) {
226 pprust_hir
::AnnNode
::Name(_
) => {}
227 pprust_hir
::AnnNode
::Item(item
) => {
229 s
.synth_comment(format
!("hir_id: {}", item
.hir_id()));
231 pprust_hir
::AnnNode
::SubItem(id
) => {
233 s
.synth_comment(id
.to_string());
235 pprust_hir
::AnnNode
::Block(blk
) => {
237 s
.synth_comment(format
!("block hir_id: {}", blk
.hir_id
));
239 pprust_hir
::AnnNode
::Expr(expr
) => {
241 s
.synth_comment(format
!("expr hir_id: {}", expr
.hir_id
));
244 pprust_hir
::AnnNode
::Pat(pat
) => {
246 s
.synth_comment(format
!("pat hir_id: {}", pat
.hir_id
));
248 pprust_hir
::AnnNode
::Arm(arm
) => {
250 s
.synth_comment(format
!("arm hir_id: {}", arm
.hir_id
));
256 struct HygieneAnnotation
<'a
> {
260 impl<'a
> PrinterSupport
for HygieneAnnotation
<'a
> {
261 fn sess(&self) -> &Session
{
265 fn pp_ann(&self) -> &dyn pprust
::PpAnn
{
270 impl<'a
> pprust
::PpAnn
for HygieneAnnotation
<'a
> {
271 fn post(&self, s
: &mut pprust
::State
<'_
>, node
: pprust
::AnnNode
<'_
>) {
273 pprust
::AnnNode
::Ident(&Ident { name, span }
) => {
275 s
.synth_comment(format
!("{}{:?}", name
.as_u32(), span
.ctxt()))
277 pprust
::AnnNode
::Name(&name
) => {
279 s
.synth_comment(name
.as_u32().to_string())
281 pprust
::AnnNode
::Crate(_
) => {
283 let verbose
= self.sess
.verbose();
284 s
.synth_comment(rustc_span
::hygiene
::debug_hygiene_data(verbose
));
285 s
.s
.hardbreak_if_not_bol();
292 struct TypedAnnotation
<'tcx
> {
294 maybe_typeck_results
: Cell
<Option
<&'tcx ty
::TypeckResults
<'tcx
>>>,
297 impl<'tcx
> HirPrinterSupport
<'tcx
> for TypedAnnotation
<'tcx
> {
298 fn sess(&self) -> &Session
{
302 fn hir_map(&self) -> Option
<hir_map
::Map
<'tcx
>> {
306 fn pp_ann(&self) -> &dyn pprust_hir
::PpAnn
{
311 impl<'tcx
> pprust_hir
::PpAnn
for TypedAnnotation
<'tcx
> {
312 fn nested(&self, state
: &mut pprust_hir
::State
<'_
>, nested
: pprust_hir
::Nested
) {
313 let old_maybe_typeck_results
= self.maybe_typeck_results
.get();
314 if let pprust_hir
::Nested
::Body(id
) = nested
{
315 self.maybe_typeck_results
.set(Some(self.tcx
.typeck_body(id
)));
317 let pp_ann
= &(&self.tcx
.hir() as &dyn hir
::intravisit
::Map
<'_
>);
318 pprust_hir
::PpAnn
::nested(pp_ann
, state
, nested
);
319 self.maybe_typeck_results
.set(old_maybe_typeck_results
);
321 fn pre(&self, s
: &mut pprust_hir
::State
<'_
>, node
: pprust_hir
::AnnNode
<'_
>) {
322 if let pprust_hir
::AnnNode
::Expr(_
) = node
{
326 fn post(&self, s
: &mut pprust_hir
::State
<'_
>, node
: pprust_hir
::AnnNode
<'_
>) {
327 if let pprust_hir
::AnnNode
::Expr(expr
) = node
{
328 let typeck_results
= self.maybe_typeck_results
.get().or_else(|| {
331 .maybe_body_owned_by(self.tcx
.hir().local_def_id_to_hir_id(expr
.hir_id
.owner
))
332 .map(|body_id
| self.tcx
.typeck_body(body_id
))
335 if let Some(typeck_results
) = typeck_results
{
339 s
.s
.word(typeck_results
.expr_ty(expr
).to_string());
347 fn get_source(input
: &Input
, sess
: &Session
) -> (String
, FileName
) {
348 let src_name
= input
.source_name();
349 let src
= String
::clone(
352 .get_source_file(&src_name
)
353 .expect("get_source_file")
361 fn write_or_print(out
: &str, ofile
: Option
<&Path
>) {
363 None
=> print
!("{}", out
),
365 if let Err(e
) = std
::fs
::write(p
, out
) {
366 panic
!("print-print failed to write {} due to {}", p
.display(), e
);
372 pub fn print_after_parsing(
377 ofile
: Option
<&Path
>,
379 let (src
, src_name
) = get_source(input
, sess
);
381 let out
= match ppm
{
383 // Silently ignores an identified node.
384 call_with_pp_support(&s
, sess
, None
, move |annotation
| {
385 debug
!("pretty printing source code {:?}", s
);
386 let sess
= annotation
.sess();
387 let parse
= &sess
.parse_sess
;
399 AstTree(PpAstTreeMode
::Normal
) => {
400 debug
!("pretty printing AST tree");
401 format
!("{:#?}", krate
)
406 write_or_print(&out
, ofile
);
409 pub fn print_after_hir_lowering
<'tcx
>(
414 ofile
: Option
<&Path
>,
416 if ppm
.needs_analysis() {
417 abort_on_err(print_with_analysis(tcx
, ppm
, ofile
), tcx
.sess
);
421 let (src
, src_name
) = get_source(input
, tcx
.sess
);
423 let out
= match ppm
{
425 // Silently ignores an identified node.
426 call_with_pp_support(&s
, tcx
.sess
, Some(tcx
), move |annotation
| {
427 debug
!("pretty printing source code {:?}", s
);
428 let sess
= annotation
.sess();
429 let parse
= &sess
.parse_sess
;
442 AstTree(PpAstTreeMode
::Expanded
) => {
443 debug
!("pretty-printing expanded AST");
444 format
!("{:#?}", krate
)
447 Hir(s
) => call_with_pp_support_hir(&s
, tcx
, move |annotation
, krate
| {
448 debug
!("pretty printing HIR {:?}", s
);
449 let sess
= annotation
.sess();
450 let sm
= sess
.source_map();
451 pprust_hir
::print_crate(sm
, krate
, src_name
, src
, annotation
.pp_ann())
454 HirTree
=> call_with_pp_support_hir(&PpHirMode
::Normal
, tcx
, move |_annotation
, krate
| {
455 debug
!("pretty printing HIR tree");
456 format
!("{:#?}", krate
)
462 write_or_print(&out
, ofile
);
465 // In an ideal world, this would be a public function called by the driver after
466 // analysis is performed. However, we want to call `phase_3_run_analysis_passes`
467 // with a different callback than the standard driver, so that isn't easy.
468 // Instead, we call that function ourselves.
469 fn print_with_analysis(
472 ofile
: Option
<&Path
>,
473 ) -> Result
<(), ErrorReported
> {
475 let out
= match ppm
{
477 let mut out
= Vec
::new();
478 write_mir_pretty(tcx
, None
, &mut out
).unwrap();
479 String
::from_utf8(out
).unwrap()
483 let mut out
= Vec
::new();
484 write_mir_graphviz(tcx
, None
, &mut out
).unwrap();
485 String
::from_utf8(out
).unwrap()
489 let mut out
= String
::new();
490 abort_on_err(rustc_typeck
::check_crate(tcx
), tcx
.sess
);
491 debug
!("pretty printing THIR tree");
492 for did
in tcx
.body_owners() {
497 tcx
.thir_tree(ty
::WithOptConstParam
::unknown(did
))
506 write_or_print(&out
, ofile
);