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_session
::config
::{Input, PpMode, PpSourceMode}
;
13 use rustc_session
::Session
;
14 use rustc_span
::FileName
;
21 pub use self::PpMode
::*;
22 pub use self::PpSourceMode
::*;
23 use crate::abort_on_err
;
25 // This slightly awkward construction is to allow for each PpMode to
26 // choose whether it needs to do analyses (which can consume the
27 // Session) and then pass through the session (now attached to the
28 // analysis results) on to the chosen pretty-printer, along with the
31 // Note that since the `&PrinterSupport` is freshly constructed on each
32 // call, it would not make sense to try to attach the lifetime of `self`
33 // to the lifetime of the `&PrinterObject`.
35 // (The `use_once_payload` is working around the current lack of once
36 // functions in the compiler.)
38 /// Constructs a `PrinterSupport` object and passes it to `f`.
39 fn call_with_pp_support
<'tcx
, A
, F
>(
40 ppmode
: &PpSourceMode
,
42 tcx
: Option
<TyCtxt
<'tcx
>>,
46 F
: FnOnce(&dyn PrinterSupport
) -> A
,
49 PpmNormal
| PpmEveryBodyLoops
| PpmExpanded
=> {
50 let annotation
= NoAnn { sess, tcx }
;
54 PpmIdentified
| PpmExpandedIdentified
=> {
55 let annotation
= IdentifiedAnnotation { sess, tcx }
;
58 PpmExpandedHygiene
=> {
59 let annotation
= HygieneAnnotation { sess }
;
62 _
=> panic
!("Should use call_with_pp_support_hir"),
65 fn call_with_pp_support_hir
<A
, F
>(ppmode
: &PpSourceMode
, tcx
: TyCtxt
<'_
>, f
: F
) -> A
67 F
: FnOnce(&dyn HirPrinterSupport
<'_
>, &hir
::Crate
<'_
>) -> A
,
71 let annotation
= NoAnn { sess: tcx.sess, tcx: Some(tcx) }
;
72 f(&annotation
, tcx
.hir().krate())
76 let annotation
= IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) }
;
77 f(&annotation
, tcx
.hir().krate())
80 abort_on_err(tcx
.analysis(LOCAL_CRATE
), tcx
.sess
);
82 let empty_tables
= ty
::TypeckTables
::empty(None
);
83 let annotation
= TypedAnnotation { tcx, tables: Cell::new(&empty_tables) }
;
84 tcx
.dep_graph
.with_ignore(|| f(&annotation
, tcx
.hir().krate()))
86 _
=> panic
!("Should use call_with_pp_support"),
90 trait PrinterSupport
: pprust
::PpAnn
{
91 /// Provides a uniform interface for re-extracting a reference to a
92 /// `Session` from a value that now owns it.
93 fn sess(&self) -> &Session
;
95 /// Produces the pretty-print annotation object.
97 /// (Rust does not yet support upcasting from a trait object to
98 /// an object for one of its super-traits.)
99 fn pp_ann(&self) -> &dyn pprust
::PpAnn
;
102 trait HirPrinterSupport
<'hir
>: pprust_hir
::PpAnn
{
103 /// Provides a uniform interface for re-extracting a reference to a
104 /// `Session` from a value that now owns it.
105 fn sess(&self) -> &Session
;
107 /// Provides a uniform interface for re-extracting a reference to an
108 /// `hir_map::Map` from a value that now owns it.
109 fn hir_map(&self) -> Option
<hir_map
::Map
<'hir
>>;
111 /// Produces the pretty-print annotation object.
113 /// (Rust does not yet support upcasting from a trait object to
114 /// an object for one of its super-traits.)
115 fn pp_ann(&self) -> &dyn pprust_hir
::PpAnn
;
117 /// Computes an user-readable representation of a path, if possible.
118 fn node_path(&self, id
: hir
::HirId
) -> Option
<String
> {
119 self.hir_map().and_then(|map
| map
.def_path_from_hir_id(id
)).map(|path
| {
120 path
.data
.into_iter().map(|elem
| elem
.data
.to_string()).collect
::<Vec
<_
>>().join("::")
127 tcx
: Option
<TyCtxt
<'hir
>>,
130 impl<'hir
> PrinterSupport
for NoAnn
<'hir
> {
131 fn sess(&self) -> &Session
{
135 fn pp_ann(&self) -> &dyn pprust
::PpAnn
{
140 impl<'hir
> HirPrinterSupport
<'hir
> for NoAnn
<'hir
> {
141 fn sess(&self) -> &Session
{
145 fn hir_map(&self) -> Option
<hir_map
::Map
<'hir
>> {
146 self.tcx
.map(|tcx
| tcx
.hir())
149 fn pp_ann(&self) -> &dyn pprust_hir
::PpAnn
{
154 impl<'hir
> pprust
::PpAnn
for NoAnn
<'hir
> {}
155 impl<'hir
> pprust_hir
::PpAnn
for NoAnn
<'hir
> {
156 fn nested(&self, state
: &mut pprust_hir
::State
<'_
>, nested
: pprust_hir
::Nested
) {
157 if let Some(tcx
) = self.tcx
{
158 pprust_hir
::PpAnn
::nested(&(&tcx
.hir() as &dyn hir
::intravisit
::Map
<'_
>), state
, nested
)
163 struct IdentifiedAnnotation
<'hir
> {
165 tcx
: Option
<TyCtxt
<'hir
>>,
168 impl<'hir
> PrinterSupport
for IdentifiedAnnotation
<'hir
> {
169 fn sess(&self) -> &Session
{
173 fn pp_ann(&self) -> &dyn pprust
::PpAnn
{
178 impl<'hir
> pprust
::PpAnn
for IdentifiedAnnotation
<'hir
> {
179 fn pre(&self, s
: &mut pprust
::State
<'_
>, node
: pprust
::AnnNode
<'_
>) {
180 if let pprust
::AnnNode
::Expr(_
) = node
{
184 fn post(&self, s
: &mut pprust
::State
<'_
>, node
: pprust
::AnnNode
<'_
>) {
186 pprust
::AnnNode
::Crate(_
) | pprust
::AnnNode
::Ident(_
) | pprust
::AnnNode
::Name(_
) => {}
188 pprust
::AnnNode
::Item(item
) => {
190 s
.synth_comment(item
.id
.to_string())
192 pprust
::AnnNode
::SubItem(id
) => {
194 s
.synth_comment(id
.to_string())
196 pprust
::AnnNode
::Block(blk
) => {
198 s
.synth_comment(format
!("block {}", blk
.id
))
200 pprust
::AnnNode
::Expr(expr
) => {
202 s
.synth_comment(expr
.id
.to_string());
205 pprust
::AnnNode
::Pat(pat
) => {
207 s
.synth_comment(format
!("pat {}", pat
.id
));
213 impl<'hir
> HirPrinterSupport
<'hir
> for IdentifiedAnnotation
<'hir
> {
214 fn sess(&self) -> &Session
{
218 fn hir_map(&self) -> Option
<hir_map
::Map
<'hir
>> {
219 self.tcx
.map(|tcx
| tcx
.hir())
222 fn pp_ann(&self) -> &dyn pprust_hir
::PpAnn
{
227 impl<'hir
> pprust_hir
::PpAnn
for IdentifiedAnnotation
<'hir
> {
228 fn nested(&self, state
: &mut pprust_hir
::State
<'_
>, nested
: pprust_hir
::Nested
) {
229 if let Some(ref tcx
) = self.tcx
{
230 pprust_hir
::PpAnn
::nested(&(&tcx
.hir() as &dyn hir
::intravisit
::Map
<'_
>), state
, nested
)
233 fn pre(&self, s
: &mut pprust_hir
::State
<'_
>, node
: pprust_hir
::AnnNode
<'_
>) {
234 if let pprust_hir
::AnnNode
::Expr(_
) = node
{
238 fn post(&self, s
: &mut pprust_hir
::State
<'_
>, node
: pprust_hir
::AnnNode
<'_
>) {
240 pprust_hir
::AnnNode
::Name(_
) => {}
241 pprust_hir
::AnnNode
::Item(item
) => {
243 s
.synth_comment(format
!("hir_id: {}", item
.hir_id
));
245 pprust_hir
::AnnNode
::SubItem(id
) => {
247 s
.synth_comment(id
.to_string());
249 pprust_hir
::AnnNode
::Block(blk
) => {
251 s
.synth_comment(format
!("block hir_id: {}", blk
.hir_id
));
253 pprust_hir
::AnnNode
::Expr(expr
) => {
255 s
.synth_comment(format
!("expr hir_id: {}", expr
.hir_id
));
258 pprust_hir
::AnnNode
::Pat(pat
) => {
260 s
.synth_comment(format
!("pat hir_id: {}", pat
.hir_id
));
262 pprust_hir
::AnnNode
::Arm(arm
) => {
264 s
.synth_comment(format
!("arm hir_id: {}", arm
.hir_id
));
270 struct HygieneAnnotation
<'a
> {
274 impl<'a
> PrinterSupport
for HygieneAnnotation
<'a
> {
275 fn sess(&self) -> &Session
{
279 fn pp_ann(&self) -> &dyn pprust
::PpAnn
{
284 impl<'a
> pprust
::PpAnn
for HygieneAnnotation
<'a
> {
285 fn post(&self, s
: &mut pprust
::State
<'_
>, node
: pprust
::AnnNode
<'_
>) {
287 pprust
::AnnNode
::Ident(&ast
::Ident { name, span }
) => {
289 s
.synth_comment(format
!("{}{:?}", name
.as_u32(), span
.ctxt()))
291 pprust
::AnnNode
::Name(&name
) => {
293 s
.synth_comment(name
.as_u32().to_string())
295 pprust
::AnnNode
::Crate(_
) => {
297 let verbose
= self.sess
.verbose();
298 s
.synth_comment(rustc_span
::hygiene
::debug_hygiene_data(verbose
));
299 s
.s
.hardbreak_if_not_bol();
306 struct TypedAnnotation
<'a
, 'tcx
> {
308 tables
: Cell
<&'a ty
::TypeckTables
<'tcx
>>,
311 impl<'b
, 'tcx
> HirPrinterSupport
<'tcx
> for TypedAnnotation
<'b
, 'tcx
> {
312 fn sess(&self) -> &Session
{
316 fn hir_map(&self) -> Option
<hir_map
::Map
<'tcx
>> {
320 fn pp_ann(&self) -> &dyn pprust_hir
::PpAnn
{
324 fn node_path(&self, id
: hir
::HirId
) -> Option
<String
> {
325 Some(self.tcx
.def_path_str(self.tcx
.hir().local_def_id(id
)))
329 impl<'a
, 'tcx
> pprust_hir
::PpAnn
for TypedAnnotation
<'a
, 'tcx
> {
330 fn nested(&self, state
: &mut pprust_hir
::State
<'_
>, nested
: pprust_hir
::Nested
) {
331 let old_tables
= self.tables
.get();
332 if let pprust_hir
::Nested
::Body(id
) = nested
{
333 self.tables
.set(self.tcx
.body_tables(id
));
335 let pp_ann
= &(&self.tcx
.hir() as &dyn hir
::intravisit
::Map
<'_
>);
336 pprust_hir
::PpAnn
::nested(pp_ann
, state
, nested
);
337 self.tables
.set(old_tables
);
339 fn pre(&self, s
: &mut pprust_hir
::State
<'_
>, node
: pprust_hir
::AnnNode
<'_
>) {
340 if let pprust_hir
::AnnNode
::Expr(_
) = node
{
344 fn post(&self, s
: &mut pprust_hir
::State
<'_
>, node
: pprust_hir
::AnnNode
<'_
>) {
345 if let pprust_hir
::AnnNode
::Expr(expr
) = node
{
349 s
.s
.word(self.tables
.get().expr_ty(expr
).to_string());
355 fn get_source(input
: &Input
, sess
: &Session
) -> (String
, FileName
) {
356 let src_name
= input
.source_name();
358 String
::clone(&sess
.source_map().get_source_file(&src_name
).unwrap().src
.as_ref().unwrap());
362 fn write_output(out
: Vec
<u8>, ofile
: Option
<&Path
>) {
364 None
=> print
!("{}", String
::from_utf8(out
).unwrap()),
365 Some(p
) => match File
::create(p
) {
366 Ok(mut w
) => w
.write_all(&out
).unwrap(),
367 Err(e
) => panic
!("print-print failed to open {} 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 mut out
= String
::new();
383 if let PpmSource(s
) = ppm
{
384 // Silently ignores an identified node.
386 call_with_pp_support(&s
, sess
, None
, move |annotation
| {
387 debug
!("pretty printing source code {:?}", s
);
388 let sess
= annotation
.sess();
389 let parse
= &sess
.parse_sess
;
390 *out
= pprust
::print_crate(
398 parse
.injected_crate_name
.try_get().is_some(),
405 write_output(out
.into_bytes(), ofile
);
408 pub fn print_after_hir_lowering
<'tcx
>(
413 ofile
: Option
<&Path
>,
415 if ppm
.needs_analysis() {
416 abort_on_err(print_with_analysis(tcx
, ppm
, ofile
), tcx
.sess
);
420 let (src
, src_name
) = get_source(input
, tcx
.sess
);
422 let mut out
= String
::new();
426 // Silently ignores an identified node.
428 call_with_pp_support(&s
, tcx
.sess
, Some(tcx
), move |annotation
| {
429 debug
!("pretty printing source code {:?}", s
);
430 let sess
= annotation
.sess();
431 let parse
= &sess
.parse_sess
;
432 *out
= pprust
::print_crate(
440 parse
.injected_crate_name
.try_get().is_some(),
447 call_with_pp_support_hir(&s
, tcx
, move |annotation
, krate
| {
448 debug
!("pretty printing source code {:?}", s
);
449 let sess
= annotation
.sess();
450 let sm
= sess
.source_map();
451 *out
= pprust_hir
::print_crate(sm
, krate
, src_name
, src
, annotation
.pp_ann())
457 call_with_pp_support_hir(&s
, tcx
, move |_annotation
, krate
| {
458 debug
!("pretty printing source code {:?}", s
);
459 *out
= format
!("{:#?}", krate
);
466 write_output(out
.into_bytes(), ofile
);
469 // In an ideal world, this would be a public function called by the driver after
470 // analysis is performed. However, we want to call `phase_3_run_analysis_passes`
471 // with a different callback than the standard driver, so that isn't easy.
472 // Instead, we call that function ourselves.
473 fn print_with_analysis(
476 ofile
: Option
<&Path
>,
477 ) -> Result
<(), ErrorReported
> {
478 let mut out
= Vec
::new();
480 tcx
.analysis(LOCAL_CRATE
)?
;
483 PpmMir
| PpmMirCFG
=> match ppm
{
484 PpmMir
=> write_mir_pretty(tcx
, None
, &mut out
),
485 PpmMirCFG
=> write_mir_graphviz(tcx
, None
, &mut out
),
492 write_output(out
, ofile
);