]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 | ||
32a655c1 | 18 | use {abort_on_err, driver}; |
1a4d82fc | 19 | |
32a655c1 | 20 | use rustc::ty::{self, TyCtxt, GlobalArenas, Resolutions}; |
54a0048b SL |
21 | use rustc::cfg; |
22 | use rustc::cfg::graphviz::LabelledCFG; | |
ea8adc8c | 23 | use rustc::middle::cstore::CrateStore; |
1a4d82fc | 24 | use rustc::session::Session; |
ea8adc8c | 25 | use rustc::session::config::{Input, OutputFilenames}; |
1a4d82fc JJ |
26 | use rustc_borrowck as borrowck; |
27 | use rustc_borrowck::graphviz as borrowck_dot; | |
28 | ||
cc61c64b | 29 | use rustc_mir::util::{write_mir_pretty, write_mir_graphviz}; |
7453a54e SL |
30 | |
31 | use syntax::ast::{self, BlockCheckMode}; | |
1a4d82fc | 32 | use syntax::fold::{self, Folder}; |
041b39d2 | 33 | use syntax::print::{pprust}; |
b039eaaf | 34 | use syntax::print::pprust::PrintState; |
1a4d82fc | 35 | use syntax::ptr::P; |
d9579d0f | 36 | use syntax::util::small_vector::SmallVector; |
3157f602 | 37 | use syntax_pos; |
1a4d82fc JJ |
38 | |
39 | use graphviz as dot; | |
40 | ||
32a655c1 | 41 | use std::cell::Cell; |
c34b1796 AL |
42 | use std::fs::File; |
43 | use std::io::{self, Write}; | |
1a4d82fc | 44 | use std::option; |
a7813a04 | 45 | use std::path::Path; |
1a4d82fc | 46 | use std::str::FromStr; |
3b2f2976 | 47 | use std::mem; |
1a4d82fc | 48 | |
54a0048b | 49 | use rustc::hir::map as hir_map; |
32a655c1 | 50 | use rustc::hir::map::blocks; |
54a0048b | 51 | use rustc::hir; |
54a0048b SL |
52 | use rustc::hir::print as pprust_hir; |
53 | ||
32a655c1 SL |
54 | use arena::DroplessArena; |
55 | ||
c34b1796 | 56 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
57 | pub enum PpSourceMode { |
58 | PpmNormal, | |
59 | PpmEveryBodyLoops, | |
60 | PpmExpanded, | |
1a4d82fc JJ |
61 | PpmIdentified, |
62 | PpmExpandedIdentified, | |
63 | PpmExpandedHygiene, | |
e9174d1e | 64 | PpmTyped, |
1a4d82fc JJ |
65 | } |
66 | ||
c34b1796 | 67 | #[derive(Copy, Clone, PartialEq, Debug)] |
85aaf69f SL |
68 | pub enum PpFlowGraphMode { |
69 | Default, | |
70 | /// Drops the labels from the edges in the flowgraph output. This | |
c1a9b12d | 71 | /// is mostly for use in the --unpretty flowgraph run-make tests, |
85aaf69f SL |
72 | /// since the labels are largely uninteresting in those cases and |
73 | /// have become a pain to maintain. | |
74 | UnlabelledEdges, | |
75 | } | |
c34b1796 | 76 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
77 | pub enum PpMode { |
78 | PpmSource(PpSourceMode), | |
e9174d1e | 79 | PpmHir(PpSourceMode), |
85aaf69f | 80 | PpmFlowGraph(PpFlowGraphMode), |
7453a54e | 81 | PpmMir, |
54a0048b | 82 | PpmMirCFG, |
1a4d82fc JJ |
83 | } |
84 | ||
a7813a04 XL |
85 | impl PpMode { |
86 | pub fn needs_ast_map(&self, opt_uii: &Option<UserIdentifiedItem>) -> bool { | |
87 | match *self { | |
88 | PpmSource(PpmNormal) | | |
89 | PpmSource(PpmEveryBodyLoops) | | |
90 | PpmSource(PpmIdentified) => opt_uii.is_some(), | |
91 | ||
92 | PpmSource(PpmExpanded) | | |
93 | PpmSource(PpmExpandedIdentified) | | |
94 | PpmSource(PpmExpandedHygiene) | | |
95 | PpmHir(_) | | |
96 | PpmMir | | |
97 | PpmMirCFG | | |
98 | PpmFlowGraph(_) => true, | |
99 | PpmSource(PpmTyped) => panic!("invalid state"), | |
100 | } | |
101 | } | |
102 | ||
103 | pub fn needs_analysis(&self) -> bool { | |
104 | match *self { | |
c30ab7b3 SL |
105 | PpmMir | PpmMirCFG | PpmFlowGraph(_) => true, |
106 | _ => false, | |
a7813a04 XL |
107 | } |
108 | } | |
109 | } | |
110 | ||
1a4d82fc JJ |
111 | pub fn parse_pretty(sess: &Session, |
112 | name: &str, | |
92a42be0 SL |
113 | extended: bool) |
114 | -> (PpMode, Option<UserIdentifiedItem>) { | |
c34b1796 | 115 | let mut split = name.splitn(2, '='); |
1a4d82fc JJ |
116 | let first = split.next().unwrap(); |
117 | let opt_second = split.next(); | |
118 | let first = match (first, extended) { | |
92a42be0 SL |
119 | ("normal", _) => PpmSource(PpmNormal), |
120 | ("identified", _) => PpmSource(PpmIdentified), | |
1a4d82fc | 121 | ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops), |
92a42be0 | 122 | ("expanded", _) => PpmSource(PpmExpanded), |
1a4d82fc JJ |
123 | ("expanded,identified", _) => PpmSource(PpmExpandedIdentified), |
124 | ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene), | |
92a42be0 | 125 | ("hir", true) => PpmHir(PpmNormal), |
e9174d1e | 126 | ("hir,identified", true) => PpmHir(PpmIdentified), |
92a42be0 | 127 | ("hir,typed", true) => PpmHir(PpmTyped), |
7453a54e | 128 | ("mir", true) => PpmMir, |
54a0048b | 129 | ("mir-cfg", true) => PpmMirCFG, |
92a42be0 SL |
130 | ("flowgraph", true) => PpmFlowGraph(PpFlowGraphMode::Default), |
131 | ("flowgraph,unlabelled", true) => PpmFlowGraph(PpFlowGraphMode::UnlabelledEdges), | |
1a4d82fc JJ |
132 | _ => { |
133 | if extended { | |
92a42be0 SL |
134 | sess.fatal(&format!("argument to `unpretty` must be one of `normal`, \ |
135 | `expanded`, `flowgraph[,unlabelled]=<nodeid>`, \ | |
136 | `identified`, `expanded,identified`, `everybody_loops`, \ | |
7453a54e | 137 | `hir`, `hir,identified`, `hir,typed`, or `mir`; got {}", |
92a42be0 | 138 | name)); |
1a4d82fc | 139 | } else { |
92a42be0 SL |
140 | sess.fatal(&format!("argument to `pretty` must be one of `normal`, `expanded`, \ |
141 | `identified`, or `expanded,identified`; got {}", | |
142 | name)); | |
1a4d82fc JJ |
143 | } |
144 | } | |
145 | }; | |
85aaf69f | 146 | let opt_second = opt_second.and_then(|s| s.parse::<UserIdentifiedItem>().ok()); |
1a4d82fc JJ |
147 | (first, opt_second) |
148 | } | |
149 | ||
150 | ||
151 | ||
152 | // This slightly awkward construction is to allow for each PpMode to | |
153 | // choose whether it needs to do analyses (which can consume the | |
154 | // Session) and then pass through the session (now attached to the | |
155 | // analysis results) on to the chosen pretty-printer, along with the | |
156 | // `&PpAnn` object. | |
157 | // | |
158 | // Note that since the `&PrinterSupport` is freshly constructed on each | |
159 | // call, it would not make sense to try to attach the lifetime of `self` | |
160 | // to the lifetime of the `&PrinterObject`. | |
161 | // | |
162 | // (The `use_once_payload` is working around the current lack of once | |
163 | // functions in the compiler.) | |
164 | ||
165 | impl PpSourceMode { | |
166 | /// Constructs a `PrinterSupport` object and passes it to `f`. | |
041b39d2 | 167 | fn call_with_pp_support<'tcx, A, F>(&self, |
b039eaaf | 168 | sess: &'tcx Session, |
32a655c1 | 169 | hir_map: Option<&hir_map::Map<'tcx>>, |
92a42be0 SL |
170 | f: F) |
171 | -> A | |
041b39d2 | 172 | where F: FnOnce(&PrinterSupport) -> A |
1a4d82fc JJ |
173 | { |
174 | match *self { | |
175 | PpmNormal | PpmEveryBodyLoops | PpmExpanded => { | |
92a42be0 | 176 | let annotation = NoAnn { |
3b2f2976 | 177 | sess, |
32a655c1 | 178 | hir_map: hir_map.map(|m| m.clone()), |
92a42be0 | 179 | }; |
041b39d2 | 180 | f(&annotation) |
1a4d82fc JJ |
181 | } |
182 | ||
183 | PpmIdentified | PpmExpandedIdentified => { | |
92a42be0 | 184 | let annotation = IdentifiedAnnotation { |
3b2f2976 | 185 | sess, |
32a655c1 | 186 | hir_map: hir_map.map(|m| m.clone()), |
92a42be0 | 187 | }; |
041b39d2 | 188 | f(&annotation) |
1a4d82fc JJ |
189 | } |
190 | PpmExpandedHygiene => { | |
92a42be0 | 191 | let annotation = HygieneAnnotation { |
3b2f2976 | 192 | sess, |
92a42be0 | 193 | }; |
041b39d2 | 194 | f(&annotation) |
1a4d82fc | 195 | } |
e9174d1e SL |
196 | _ => panic!("Should use call_with_pp_support_hir"), |
197 | } | |
198 | } | |
041b39d2 | 199 | fn call_with_pp_support_hir<'tcx, A, F>(&self, |
b039eaaf | 200 | sess: &'tcx Session, |
ea8adc8c | 201 | cstore: &'tcx CrateStore, |
32a655c1 | 202 | hir_map: &hir_map::Map<'tcx>, |
8bb4bdeb | 203 | analysis: &ty::CrateAnalysis, |
a7813a04 | 204 | resolutions: &Resolutions, |
32a655c1 SL |
205 | arena: &'tcx DroplessArena, |
206 | arenas: &'tcx GlobalArenas<'tcx>, | |
ea8adc8c | 207 | output_filenames: &OutputFilenames, |
b039eaaf | 208 | id: &str, |
92a42be0 SL |
209 | f: F) |
210 | -> A | |
041b39d2 | 211 | where F: FnOnce(&HirPrinterSupport, &hir::Crate) -> A |
e9174d1e SL |
212 | { |
213 | match *self { | |
214 | PpmNormal => { | |
92a42be0 | 215 | let annotation = NoAnn { |
3b2f2976 | 216 | sess, |
32a655c1 | 217 | hir_map: Some(hir_map.clone()), |
92a42be0 | 218 | }; |
041b39d2 | 219 | f(&annotation, hir_map.forest.krate()) |
e9174d1e SL |
220 | } |
221 | ||
222 | PpmIdentified => { | |
223 | let annotation = IdentifiedAnnotation { | |
3b2f2976 | 224 | sess, |
32a655c1 | 225 | hir_map: Some(hir_map.clone()), |
e9174d1e | 226 | }; |
041b39d2 | 227 | f(&annotation, hir_map.forest.krate()) |
e9174d1e | 228 | } |
1a4d82fc | 229 | PpmTyped => { |
7453a54e | 230 | abort_on_err(driver::phase_3_run_analysis_passes(sess, |
ea8adc8c | 231 | cstore, |
32a655c1 | 232 | hir_map.clone(), |
a7813a04 XL |
233 | analysis.clone(), |
234 | resolutions.clone(), | |
32a655c1 | 235 | arena, |
7453a54e SL |
236 | arenas, |
237 | id, | |
ea8adc8c | 238 | output_filenames, |
c30ab7b3 | 239 | |tcx, _, _, _| { |
3b2f2976 | 240 | let empty_tables = ty::TypeckTables::empty(None); |
32a655c1 | 241 | let annotation = TypedAnnotation { |
3b2f2976 | 242 | tcx, |
32a655c1 SL |
243 | tables: Cell::new(&empty_tables) |
244 | }; | |
7453a54e | 245 | let _ignore = tcx.dep_graph.in_ignore(); |
041b39d2 | 246 | f(&annotation, hir_map.forest.krate()) |
c30ab7b3 SL |
247 | }), |
248 | sess) | |
1a4d82fc | 249 | } |
e9174d1e | 250 | _ => panic!("Should use call_with_pp_support"), |
1a4d82fc JJ |
251 | } |
252 | } | |
253 | } | |
254 | ||
32a655c1 | 255 | trait PrinterSupport: pprust::PpAnn { |
1a4d82fc JJ |
256 | /// Provides a uniform interface for re-extracting a reference to a |
257 | /// `Session` from a value that now owns it. | |
258 | fn sess<'a>(&'a self) -> &'a Session; | |
259 | ||
1a4d82fc JJ |
260 | /// Produces the pretty-print annotation object. |
261 | /// | |
262 | /// (Rust does not yet support upcasting from a trait object to | |
263 | /// an object for one of its super-traits.) | |
264 | fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn; | |
265 | } | |
266 | ||
32a655c1 | 267 | trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { |
e9174d1e SL |
268 | /// Provides a uniform interface for re-extracting a reference to a |
269 | /// `Session` from a value that now owns it. | |
270 | fn sess<'a>(&'a self) -> &'a Session; | |
271 | ||
272 | /// Provides a uniform interface for re-extracting a reference to an | |
273 | /// `hir_map::Map` from a value that now owns it. | |
32a655c1 | 274 | fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>>; |
e9174d1e SL |
275 | |
276 | /// Produces the pretty-print annotation object. | |
277 | /// | |
278 | /// (Rust does not yet support upcasting from a trait object to | |
279 | /// an object for one of its super-traits.) | |
280 | fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn; | |
54a0048b SL |
281 | |
282 | /// Computes an user-readable representation of a path, if possible. | |
283 | fn node_path(&self, id: ast::NodeId) -> Option<String> { | |
32a655c1 | 284 | self.hir_map().and_then(|map| map.def_path_from_id(id)).map(|path| { |
c30ab7b3 SL |
285 | path.data |
286 | .into_iter() | |
287 | .map(|elem| elem.data.to_string()) | |
288 | .collect::<Vec<_>>() | |
289 | .join("::") | |
54a0048b SL |
290 | }) |
291 | } | |
e9174d1e SL |
292 | } |
293 | ||
32a655c1 SL |
294 | struct NoAnn<'hir> { |
295 | sess: &'hir Session, | |
296 | hir_map: Option<hir_map::Map<'hir>>, | |
1a4d82fc JJ |
297 | } |
298 | ||
32a655c1 | 299 | impl<'hir> PrinterSupport for NoAnn<'hir> { |
92a42be0 SL |
300 | fn sess<'a>(&'a self) -> &'a Session { |
301 | self.sess | |
302 | } | |
1a4d82fc | 303 | |
92a42be0 SL |
304 | fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { |
305 | self | |
306 | } | |
1a4d82fc JJ |
307 | } |
308 | ||
32a655c1 | 309 | impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> { |
92a42be0 SL |
310 | fn sess<'a>(&'a self) -> &'a Session { |
311 | self.sess | |
312 | } | |
e9174d1e | 313 | |
32a655c1 SL |
314 | fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> { |
315 | self.hir_map.as_ref() | |
e9174d1e SL |
316 | } |
317 | ||
92a42be0 SL |
318 | fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { |
319 | self | |
320 | } | |
e9174d1e SL |
321 | } |
322 | ||
32a655c1 SL |
323 | impl<'hir> pprust::PpAnn for NoAnn<'hir> {} |
324 | impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> { | |
325 | fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested) | |
326 | -> io::Result<()> { | |
327 | if let Some(ref map) = self.hir_map { | |
328 | pprust_hir::PpAnn::nested(map, state, nested) | |
329 | } else { | |
330 | Ok(()) | |
331 | } | |
332 | } | |
333 | } | |
1a4d82fc | 334 | |
32a655c1 SL |
335 | struct IdentifiedAnnotation<'hir> { |
336 | sess: &'hir Session, | |
337 | hir_map: Option<hir_map::Map<'hir>>, | |
1a4d82fc JJ |
338 | } |
339 | ||
32a655c1 | 340 | impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> { |
92a42be0 SL |
341 | fn sess<'a>(&'a self) -> &'a Session { |
342 | self.sess | |
343 | } | |
1a4d82fc | 344 | |
92a42be0 SL |
345 | fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { |
346 | self | |
347 | } | |
1a4d82fc JJ |
348 | } |
349 | ||
32a655c1 | 350 | impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> { |
92a42be0 | 351 | fn pre(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { |
1a4d82fc JJ |
352 | match node { |
353 | pprust::NodeExpr(_) => s.popen(), | |
92a42be0 | 354 | _ => Ok(()), |
1a4d82fc JJ |
355 | } |
356 | } | |
92a42be0 | 357 | fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { |
1a4d82fc | 358 | match node { |
c30ab7b3 SL |
359 | pprust::NodeIdent(_) | |
360 | pprust::NodeName(_) => Ok(()), | |
1a4d82fc JJ |
361 | |
362 | pprust::NodeItem(item) => { | |
041b39d2 | 363 | s.s.space()?; |
1a4d82fc JJ |
364 | s.synth_comment(item.id.to_string()) |
365 | } | |
c34b1796 | 366 | pprust::NodeSubItem(id) => { |
041b39d2 | 367 | s.s.space()?; |
c34b1796 AL |
368 | s.synth_comment(id.to_string()) |
369 | } | |
1a4d82fc | 370 | pprust::NodeBlock(blk) => { |
041b39d2 | 371 | s.s.space()?; |
1a4d82fc JJ |
372 | s.synth_comment(format!("block {}", blk.id)) |
373 | } | |
374 | pprust::NodeExpr(expr) => { | |
041b39d2 | 375 | s.s.space()?; |
54a0048b | 376 | s.synth_comment(expr.id.to_string())?; |
1a4d82fc JJ |
377 | s.pclose() |
378 | } | |
379 | pprust::NodePat(pat) => { | |
041b39d2 | 380 | s.s.space()?; |
1a4d82fc JJ |
381 | s.synth_comment(format!("pat {}", pat.id)) |
382 | } | |
383 | } | |
384 | } | |
385 | } | |
386 | ||
32a655c1 | 387 | impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> { |
92a42be0 SL |
388 | fn sess<'a>(&'a self) -> &'a Session { |
389 | self.sess | |
390 | } | |
e9174d1e | 391 | |
32a655c1 SL |
392 | fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> { |
393 | self.hir_map.as_ref() | |
e9174d1e SL |
394 | } |
395 | ||
92a42be0 SL |
396 | fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { |
397 | self | |
398 | } | |
e9174d1e SL |
399 | } |
400 | ||
32a655c1 SL |
401 | impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { |
402 | fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested) | |
403 | -> io::Result<()> { | |
404 | if let Some(ref map) = self.hir_map { | |
405 | pprust_hir::PpAnn::nested(map, state, nested) | |
406 | } else { | |
407 | Ok(()) | |
408 | } | |
409 | } | |
92a42be0 | 410 | fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { |
e9174d1e SL |
411 | match node { |
412 | pprust_hir::NodeExpr(_) => s.popen(), | |
92a42be0 | 413 | _ => Ok(()), |
e9174d1e SL |
414 | } |
415 | } | |
92a42be0 | 416 | fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { |
e9174d1e | 417 | match node { |
b039eaaf | 418 | pprust_hir::NodeName(_) => Ok(()), |
e9174d1e | 419 | pprust_hir::NodeItem(item) => { |
041b39d2 | 420 | s.s.space()?; |
e9174d1e SL |
421 | s.synth_comment(item.id.to_string()) |
422 | } | |
423 | pprust_hir::NodeSubItem(id) => { | |
041b39d2 | 424 | s.s.space()?; |
e9174d1e SL |
425 | s.synth_comment(id.to_string()) |
426 | } | |
427 | pprust_hir::NodeBlock(blk) => { | |
041b39d2 | 428 | s.s.space()?; |
e9174d1e SL |
429 | s.synth_comment(format!("block {}", blk.id)) |
430 | } | |
431 | pprust_hir::NodeExpr(expr) => { | |
041b39d2 | 432 | s.s.space()?; |
54a0048b | 433 | s.synth_comment(expr.id.to_string())?; |
e9174d1e SL |
434 | s.pclose() |
435 | } | |
436 | pprust_hir::NodePat(pat) => { | |
041b39d2 | 437 | s.s.space()?; |
e9174d1e SL |
438 | s.synth_comment(format!("pat {}", pat.id)) |
439 | } | |
440 | } | |
441 | } | |
442 | } | |
443 | ||
32a655c1 SL |
444 | struct HygieneAnnotation<'a> { |
445 | sess: &'a Session | |
1a4d82fc JJ |
446 | } |
447 | ||
32a655c1 SL |
448 | impl<'a> PrinterSupport for HygieneAnnotation<'a> { |
449 | fn sess(&self) -> &Session { | |
92a42be0 SL |
450 | self.sess |
451 | } | |
1a4d82fc | 452 | |
32a655c1 | 453 | fn pp_ann(&self) -> &pprust::PpAnn { |
92a42be0 SL |
454 | self |
455 | } | |
1a4d82fc JJ |
456 | } |
457 | ||
32a655c1 | 458 | impl<'a> pprust::PpAnn for HygieneAnnotation<'a> { |
92a42be0 | 459 | fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { |
1a4d82fc | 460 | match node { |
476ff2be | 461 | pprust::NodeIdent(&ast::Ident { name, ctxt }) => { |
041b39d2 | 462 | s.s.space()?; |
1a4d82fc JJ |
463 | // FIXME #16420: this doesn't display the connections |
464 | // between syntax contexts | |
476ff2be | 465 | s.synth_comment(format!("{}{:?}", name.as_u32(), ctxt)) |
1a4d82fc | 466 | } |
476ff2be | 467 | pprust::NodeName(&name) => { |
041b39d2 | 468 | s.s.space()?; |
476ff2be | 469 | s.synth_comment(name.as_u32().to_string()) |
1a4d82fc | 470 | } |
92a42be0 | 471 | _ => Ok(()), |
1a4d82fc JJ |
472 | } |
473 | } | |
474 | } | |
475 | ||
476 | ||
62682a34 | 477 | struct TypedAnnotation<'a, 'tcx: 'a> { |
a7813a04 | 478 | tcx: TyCtxt<'a, 'tcx, 'tcx>, |
32a655c1 | 479 | tables: Cell<&'a ty::TypeckTables<'tcx>>, |
1a4d82fc JJ |
480 | } |
481 | ||
e9174d1e | 482 | impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> { |
92a42be0 SL |
483 | fn sess<'a>(&'a self) -> &'a Session { |
484 | &self.tcx.sess | |
485 | } | |
1a4d82fc | 486 | |
32a655c1 SL |
487 | fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'tcx>> { |
488 | Some(&self.tcx.hir) | |
1a4d82fc JJ |
489 | } |
490 | ||
92a42be0 SL |
491 | fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { |
492 | self | |
493 | } | |
54a0048b SL |
494 | |
495 | fn node_path(&self, id: ast::NodeId) -> Option<String> { | |
496 | Some(self.tcx.node_path_str(id)) | |
497 | } | |
1a4d82fc JJ |
498 | } |
499 | ||
e9174d1e | 500 | impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> { |
32a655c1 SL |
501 | fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested) |
502 | -> io::Result<()> { | |
503 | let old_tables = self.tables.get(); | |
504 | if let pprust_hir::Nested::Body(id) = nested { | |
505 | self.tables.set(self.tcx.body_tables(id)); | |
506 | } | |
507 | pprust_hir::PpAnn::nested(&self.tcx.hir, state, nested)?; | |
508 | self.tables.set(old_tables); | |
509 | Ok(()) | |
510 | } | |
92a42be0 | 511 | fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { |
1a4d82fc | 512 | match node { |
e9174d1e | 513 | pprust_hir::NodeExpr(_) => s.popen(), |
92a42be0 | 514 | _ => Ok(()), |
1a4d82fc JJ |
515 | } |
516 | } | |
92a42be0 | 517 | fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { |
1a4d82fc | 518 | match node { |
e9174d1e | 519 | pprust_hir::NodeExpr(expr) => { |
041b39d2 XL |
520 | s.s.space()?; |
521 | s.s.word("as")?; | |
522 | s.s.space()?; | |
523 | s.s.word(&self.tables.get().expr_ty(expr).to_string())?; | |
1a4d82fc JJ |
524 | s.pclose() |
525 | } | |
92a42be0 | 526 | _ => Ok(()), |
1a4d82fc JJ |
527 | } |
528 | } | |
529 | } | |
530 | ||
531 | fn gather_flowgraph_variants(sess: &Session) -> Vec<borrowck_dot::Variant> { | |
532 | let print_loans = sess.opts.debugging_opts.flowgraph_print_loans; | |
533 | let print_moves = sess.opts.debugging_opts.flowgraph_print_moves; | |
534 | let print_assigns = sess.opts.debugging_opts.flowgraph_print_assigns; | |
535 | let print_all = sess.opts.debugging_opts.flowgraph_print_all; | |
536 | let mut variants = Vec::new(); | |
537 | if print_all || print_loans { | |
538 | variants.push(borrowck_dot::Loans); | |
539 | } | |
540 | if print_all || print_moves { | |
541 | variants.push(borrowck_dot::Moves); | |
542 | } | |
543 | if print_all || print_assigns { | |
544 | variants.push(borrowck_dot::Assigns); | |
545 | } | |
546 | variants | |
547 | } | |
548 | ||
85aaf69f | 549 | #[derive(Clone, Debug)] |
1a4d82fc JJ |
550 | pub enum UserIdentifiedItem { |
551 | ItemViaNode(ast::NodeId), | |
552 | ItemViaPath(Vec<String>), | |
553 | } | |
554 | ||
555 | impl FromStr for UserIdentifiedItem { | |
85aaf69f SL |
556 | type Err = (); |
557 | fn from_str(s: &str) -> Result<UserIdentifiedItem, ()> { | |
92a42be0 | 558 | Ok(s.parse() |
9e0c209e | 559 | .map(ast::NodeId::new) |
92a42be0 SL |
560 | .map(ItemViaNode) |
561 | .unwrap_or_else(|_| ItemViaPath(s.split("::").map(|s| s.to_string()).collect()))) | |
1a4d82fc JJ |
562 | } |
563 | } | |
564 | ||
32a655c1 | 565 | enum NodesMatchingUII<'a, 'hir: 'a> { |
1a4d82fc | 566 | NodesMatchingDirect(option::IntoIter<ast::NodeId>), |
32a655c1 | 567 | NodesMatchingSuffix(hir_map::NodesMatchingSuffix<'a, 'hir>), |
1a4d82fc JJ |
568 | } |
569 | ||
32a655c1 | 570 | impl<'a, 'hir> Iterator for NodesMatchingUII<'a, 'hir> { |
1a4d82fc JJ |
571 | type Item = ast::NodeId; |
572 | ||
573 | fn next(&mut self) -> Option<ast::NodeId> { | |
574 | match self { | |
575 | &mut NodesMatchingDirect(ref mut iter) => iter.next(), | |
576 | &mut NodesMatchingSuffix(ref mut iter) => iter.next(), | |
577 | } | |
578 | } | |
579 | } | |
580 | ||
581 | impl UserIdentifiedItem { | |
582 | fn reconstructed_input(&self) -> String { | |
583 | match *self { | |
584 | ItemViaNode(node_id) => node_id.to_string(), | |
c1a9b12d | 585 | ItemViaPath(ref parts) => parts.join("::"), |
1a4d82fc JJ |
586 | } |
587 | } | |
588 | ||
32a655c1 SL |
589 | fn all_matching_node_ids<'a, 'hir>(&'a self, |
590 | map: &'a hir_map::Map<'hir>) | |
591 | -> NodesMatchingUII<'a, 'hir> { | |
1a4d82fc | 592 | match *self { |
92a42be0 | 593 | ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()), |
cc61c64b | 594 | ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts)), |
1a4d82fc JJ |
595 | } |
596 | } | |
597 | ||
e9174d1e | 598 | fn to_one_node_id(self, user_option: &str, sess: &Session, map: &hir_map::Map) -> ast::NodeId { |
85aaf69f | 599 | let fail_because = |is_wrong_because| -> ast::NodeId { |
92a42be0 SL |
600 | let message = format!("{} needs NodeId (int) or unique path suffix (b::c::d); got \ |
601 | {}, which {}", | |
602 | user_option, | |
603 | self.reconstructed_input(), | |
604 | is_wrong_because); | |
cc61c64b | 605 | sess.fatal(&message) |
1a4d82fc JJ |
606 | }; |
607 | ||
608 | let mut saw_node = ast::DUMMY_NODE_ID; | |
85aaf69f | 609 | let mut seen = 0; |
1a4d82fc JJ |
610 | for node in self.all_matching_node_ids(map) { |
611 | saw_node = node; | |
612 | seen += 1; | |
613 | if seen > 1 { | |
614 | fail_because("does not resolve uniquely"); | |
615 | } | |
616 | } | |
617 | if seen == 0 { | |
618 | fail_because("does not resolve to any item"); | |
619 | } | |
620 | ||
621 | assert!(seen == 1); | |
622 | return saw_node; | |
623 | } | |
624 | } | |
625 | ||
3b2f2976 XL |
626 | // Note: Also used by librustdoc, see PR #43348. Consider moving this struct elsewhere. |
627 | // | |
628 | // FIXME: Currently the `everybody_loops` transformation is not applied to: | |
629 | // * `const fn`, due to issue #43636 that `loop` is not supported for const evaluation. We are | |
630 | // waiting for miri to fix that. | |
631 | // * `impl Trait`, due to issue #43869 that functions returning impl Trait cannot be diverging. | |
632 | // Solving this may require `!` to implement every trait, which relies on the an even more | |
633 | // ambitious form of the closed RFC #1637. See also [#34511]. | |
634 | // | |
635 | // [#34511]: https://github.com/rust-lang/rust/issues/34511#issuecomment-322340401 | |
636 | pub struct ReplaceBodyWithLoop { | |
1a4d82fc JJ |
637 | within_static_or_const: bool, |
638 | } | |
639 | ||
640 | impl ReplaceBodyWithLoop { | |
3b2f2976 | 641 | pub fn new() -> ReplaceBodyWithLoop { |
1a4d82fc JJ |
642 | ReplaceBodyWithLoop { within_static_or_const: false } |
643 | } | |
3b2f2976 XL |
644 | |
645 | fn run<R, F: FnOnce(&mut Self) -> R>(&mut self, is_const: bool, action: F) -> R { | |
646 | let old_const = mem::replace(&mut self.within_static_or_const, is_const); | |
647 | let ret = action(self); | |
648 | self.within_static_or_const = old_const; | |
649 | ret | |
650 | } | |
651 | ||
652 | fn should_ignore_fn(ret_ty: &ast::FnDecl) -> bool { | |
653 | if let ast::FunctionRetTy::Ty(ref ty) = ret_ty.output { | |
654 | fn involves_impl_trait(ty: &ast::Ty) -> bool { | |
655 | match ty.node { | |
656 | ast::TyKind::ImplTrait(_) => true, | |
657 | ast::TyKind::Slice(ref subty) | | |
658 | ast::TyKind::Array(ref subty, _) | | |
659 | ast::TyKind::Ptr(ast::MutTy { ty: ref subty, .. }) | | |
660 | ast::TyKind::Rptr(_, ast::MutTy { ty: ref subty, .. }) | | |
661 | ast::TyKind::Paren(ref subty) => involves_impl_trait(subty), | |
ea8adc8c XL |
662 | ast::TyKind::Tup(ref tys) => any_involves_impl_trait(tys.iter()), |
663 | ast::TyKind::Path(_, ref path) => path.segments.iter().any(|seg| { | |
664 | match seg.parameters.as_ref().map(|p| &**p) { | |
665 | None => false, | |
666 | Some(&ast::PathParameters::AngleBracketed(ref data)) => | |
667 | any_involves_impl_trait(data.types.iter()) || | |
668 | any_involves_impl_trait(data.bindings.iter().map(|b| &b.ty)), | |
669 | Some(&ast::PathParameters::Parenthesized(ref data)) => | |
670 | any_involves_impl_trait(data.inputs.iter()) || | |
671 | any_involves_impl_trait(data.output.iter()), | |
672 | } | |
673 | }), | |
3b2f2976 XL |
674 | _ => false, |
675 | } | |
676 | } | |
ea8adc8c XL |
677 | |
678 | fn any_involves_impl_trait<'a, I: Iterator<Item = &'a P<ast::Ty>>>(mut it: I) -> bool { | |
679 | it.any(|subty| involves_impl_trait(subty)) | |
680 | } | |
681 | ||
3b2f2976 XL |
682 | involves_impl_trait(ty) |
683 | } else { | |
684 | false | |
685 | } | |
686 | } | |
1a4d82fc JJ |
687 | } |
688 | ||
689 | impl fold::Folder for ReplaceBodyWithLoop { | |
7453a54e | 690 | fn fold_item_kind(&mut self, i: ast::ItemKind) -> ast::ItemKind { |
3b2f2976 XL |
691 | let is_const = match i { |
692 | ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true, | |
693 | ast::ItemKind::Fn(ref decl, _, ref constness, _, _, _) => | |
694 | constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), | |
695 | _ => false, | |
696 | }; | |
697 | self.run(is_const, |s| fold::noop_fold_item_kind(i, s)) | |
1a4d82fc JJ |
698 | } |
699 | ||
7453a54e | 700 | fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector<ast::TraitItem> { |
3b2f2976 XL |
701 | let is_const = match i.node { |
702 | ast::TraitItemKind::Const(..) => true, | |
703 | ast::TraitItemKind::Method(ast::MethodSig { ref decl, ref constness, .. }, _) => | |
704 | constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), | |
705 | _ => false, | |
706 | }; | |
707 | self.run(is_const, |s| fold::noop_fold_trait_item(i, s)) | |
d9579d0f AL |
708 | } |
709 | ||
7453a54e | 710 | fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector<ast::ImplItem> { |
3b2f2976 XL |
711 | let is_const = match i.node { |
712 | ast::ImplItemKind::Const(..) => true, | |
713 | ast::ImplItemKind::Method(ast::MethodSig { ref decl, ref constness, .. }, _) => | |
714 | constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), | |
715 | _ => false, | |
716 | }; | |
717 | self.run(is_const, |s| fold::noop_fold_impl_item(i, s)) | |
d9579d0f | 718 | } |
1a4d82fc JJ |
719 | |
720 | fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> { | |
92a42be0 | 721 | fn expr_to_block(rules: ast::BlockCheckMode, e: Option<P<ast::Expr>>) -> P<ast::Block> { |
1a4d82fc | 722 | P(ast::Block { |
c30ab7b3 SL |
723 | stmts: e.map(|e| { |
724 | ast::Stmt { | |
725 | id: ast::DUMMY_NODE_ID, | |
726 | span: e.span, | |
727 | node: ast::StmtKind::Expr(e), | |
728 | } | |
729 | }) | |
730 | .into_iter() | |
731 | .collect(), | |
3b2f2976 | 732 | rules, |
92a42be0 | 733 | id: ast::DUMMY_NODE_ID, |
3157f602 | 734 | span: syntax_pos::DUMMY_SP, |
1a4d82fc JJ |
735 | }) |
736 | } | |
737 | ||
738 | if !self.within_static_or_const { | |
739 | ||
7453a54e | 740 | let empty_block = expr_to_block(BlockCheckMode::Default, None); |
1a4d82fc | 741 | let loop_expr = P(ast::Expr { |
7453a54e | 742 | node: ast::ExprKind::Loop(empty_block, None), |
92a42be0 | 743 | id: ast::DUMMY_NODE_ID, |
3157f602 XL |
744 | span: syntax_pos::DUMMY_SP, |
745 | attrs: ast::ThinVec::new(), | |
1a4d82fc JJ |
746 | }); |
747 | ||
748 | expr_to_block(b.rules, Some(loop_expr)) | |
749 | ||
750 | } else { | |
751 | fold::noop_fold_block(b, self) | |
752 | } | |
753 | } | |
754 | ||
755 | // in general the pretty printer processes unexpanded code, so | |
756 | // we override the default `fold_mac` method which panics. | |
757 | fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { | |
758 | fold::noop_fold_mac(mac, self) | |
759 | } | |
760 | } | |
761 | ||
a7813a04 XL |
762 | fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>, |
763 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
476ff2be | 764 | code: blocks::Code<'tcx>, |
a7813a04 XL |
765 | mode: PpFlowGraphMode, |
766 | mut out: W) | |
767 | -> io::Result<()> { | |
8bb4bdeb XL |
768 | let body_id = match code { |
769 | blocks::Code::Expr(expr) => { | |
770 | // Find the function this expression is from. | |
771 | let mut node_id = expr.id; | |
772 | loop { | |
773 | let node = tcx.hir.get(node_id); | |
774 | if let Some(n) = hir::map::blocks::FnLikeNode::from_node(node) { | |
775 | break n.body(); | |
776 | } | |
777 | let parent = tcx.hir.get_parent_node(node_id); | |
778 | assert!(node_id != parent); | |
779 | node_id = parent; | |
780 | } | |
781 | } | |
782 | blocks::Code::FnLike(fn_like) => fn_like.body(), | |
a7813a04 | 783 | }; |
8bb4bdeb XL |
784 | let body = tcx.hir.body(body_id); |
785 | let cfg = cfg::CFG::new(tcx, &body); | |
a7813a04 XL |
786 | let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; |
787 | let lcfg = LabelledCFG { | |
ea8adc8c | 788 | tcx, |
a7813a04 XL |
789 | cfg: &cfg, |
790 | name: format!("node_{}", code.id()), | |
3b2f2976 | 791 | labelled_edges, |
1a4d82fc JJ |
792 | }; |
793 | ||
a7813a04 XL |
794 | match code { |
795 | _ if variants.is_empty() => { | |
796 | let r = dot::render(&lcfg, &mut out); | |
797 | return expand_err_details(r); | |
798 | } | |
476ff2be | 799 | blocks::Code::Expr(_) => { |
a7813a04 XL |
800 | tcx.sess.err("--pretty flowgraph with -Z flowgraph-print annotations requires \ |
801 | fn-like node id."); | |
802 | return Ok(()); | |
803 | } | |
476ff2be | 804 | blocks::Code::FnLike(fn_like) => { |
a7813a04 | 805 | let (bccx, analysis_data) = |
32a655c1 | 806 | borrowck::build_borrowck_dataflow_data_for_fn(tcx, fn_like.body(), &cfg); |
1a4d82fc | 807 | |
a7813a04 XL |
808 | let lcfg = borrowck_dot::DataflowLabeller { |
809 | inner: lcfg, | |
3b2f2976 | 810 | variants, |
a7813a04 XL |
811 | borrowck_ctxt: &bccx, |
812 | analysis_data: &analysis_data, | |
813 | }; | |
814 | let r = dot::render(&lcfg, &mut out); | |
815 | return expand_err_details(r); | |
1a4d82fc | 816 | } |
a7813a04 | 817 | } |
1a4d82fc | 818 | |
a7813a04 XL |
819 | fn expand_err_details(r: io::Result<()>) -> io::Result<()> { |
820 | r.map_err(|ioerr| { | |
821 | io::Error::new(io::ErrorKind::Other, | |
cc61c64b | 822 | format!("graphviz::render failed: {}", ioerr)) |
a7813a04 XL |
823 | }) |
824 | } | |
825 | } | |
826 | ||
827 | pub fn fold_crate(krate: ast::Crate, ppm: PpMode) -> ast::Crate { | |
828 | if let PpmSource(PpmEveryBodyLoops) = ppm { | |
829 | let mut fold = ReplaceBodyWithLoop::new(); | |
830 | fold.fold_crate(krate) | |
1a4d82fc | 831 | } else { |
a7813a04 XL |
832 | krate |
833 | } | |
834 | } | |
1a4d82fc | 835 | |
a7813a04 | 836 | fn get_source(input: &Input, sess: &Session) -> (Vec<u8>, String) { |
1a4d82fc | 837 | let src_name = driver::source_name(input); |
92a42be0 | 838 | let src = sess.codemap() |
c30ab7b3 SL |
839 | .get_filemap(&src_name) |
840 | .unwrap() | |
841 | .src | |
842 | .as_ref() | |
843 | .unwrap() | |
844 | .as_bytes() | |
845 | .to_vec(); | |
a7813a04 XL |
846 | (src, src_name) |
847 | } | |
848 | ||
849 | fn write_output(out: Vec<u8>, ofile: Option<&Path>) { | |
850 | match ofile { | |
851 | None => print!("{}", String::from_utf8(out).unwrap()), | |
852 | Some(p) => { | |
853 | match File::create(p) { | |
854 | Ok(mut w) => w.write_all(&out).unwrap(), | |
855 | Err(e) => panic!("print-print failed to open {} due to {}", p.display(), e), | |
856 | } | |
857 | } | |
858 | } | |
859 | } | |
1a4d82fc | 860 | |
a7813a04 XL |
861 | pub fn print_after_parsing(sess: &Session, |
862 | input: &Input, | |
863 | krate: &ast::Crate, | |
864 | ppm: PpMode, | |
865 | ofile: Option<&Path>) { | |
a7813a04 XL |
866 | let (src, src_name) = get_source(input, sess); |
867 | ||
868 | let mut rdr = &*src; | |
869 | let mut out = Vec::new(); | |
870 | ||
871 | if let PpmSource(s) = ppm { | |
872 | // Silently ignores an identified node. | |
873 | let out: &mut Write = &mut out; | |
041b39d2 | 874 | s.call_with_pp_support(sess, None, move |annotation| { |
c30ab7b3 SL |
875 | debug!("pretty printing source code {:?}", s); |
876 | let sess = annotation.sess(); | |
877 | pprust::print_crate(sess.codemap(), | |
32a655c1 | 878 | &sess.parse_sess, |
c30ab7b3 SL |
879 | krate, |
880 | src_name.to_string(), | |
881 | &mut rdr, | |
041b39d2 | 882 | box out, |
c30ab7b3 SL |
883 | annotation.pp_ann(), |
884 | false) | |
885 | }) | |
886 | .unwrap() | |
a7813a04 XL |
887 | } else { |
888 | unreachable!(); | |
889 | }; | |
890 | ||
891 | write_output(out, ofile); | |
892 | } | |
893 | ||
894 | pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, | |
ea8adc8c | 895 | cstore: &'tcx CrateStore, |
32a655c1 | 896 | hir_map: &hir_map::Map<'tcx>, |
8bb4bdeb | 897 | analysis: &ty::CrateAnalysis, |
a7813a04 XL |
898 | resolutions: &Resolutions, |
899 | input: &Input, | |
900 | krate: &ast::Crate, | |
901 | crate_name: &str, | |
902 | ppm: PpMode, | |
32a655c1 SL |
903 | arena: &'tcx DroplessArena, |
904 | arenas: &'tcx GlobalArenas<'tcx>, | |
ea8adc8c | 905 | output_filenames: &OutputFilenames, |
a7813a04 XL |
906 | opt_uii: Option<UserIdentifiedItem>, |
907 | ofile: Option<&Path>) { | |
a7813a04 | 908 | if ppm.needs_analysis() { |
c30ab7b3 | 909 | print_with_analysis(sess, |
ea8adc8c | 910 | cstore, |
32a655c1 | 911 | hir_map, |
c30ab7b3 SL |
912 | analysis, |
913 | resolutions, | |
914 | crate_name, | |
32a655c1 | 915 | arena, |
c30ab7b3 | 916 | arenas, |
ea8adc8c | 917 | output_filenames, |
c30ab7b3 SL |
918 | ppm, |
919 | opt_uii, | |
920 | ofile); | |
a7813a04 XL |
921 | return; |
922 | } | |
923 | ||
924 | let (src, src_name) = get_source(input, sess); | |
925 | ||
926 | let mut rdr = &src[..]; | |
c34b1796 | 927 | let mut out = Vec::new(); |
1a4d82fc JJ |
928 | |
929 | match (ppm, opt_uii) { | |
c30ab7b3 SL |
930 | (PpmSource(s), _) => { |
931 | // Silently ignores an identified node. | |
932 | let out: &mut Write = &mut out; | |
041b39d2 | 933 | s.call_with_pp_support(sess, Some(hir_map), move |annotation| { |
c30ab7b3 SL |
934 | debug!("pretty printing source code {:?}", s); |
935 | let sess = annotation.sess(); | |
936 | pprust::print_crate(sess.codemap(), | |
32a655c1 | 937 | &sess.parse_sess, |
c30ab7b3 SL |
938 | krate, |
939 | src_name.to_string(), | |
940 | &mut rdr, | |
041b39d2 | 941 | box out, |
c30ab7b3 SL |
942 | annotation.pp_ann(), |
943 | true) | |
944 | }) | |
945 | } | |
1a4d82fc | 946 | |
c30ab7b3 SL |
947 | (PpmHir(s), None) => { |
948 | let out: &mut Write = &mut out; | |
949 | s.call_with_pp_support_hir(sess, | |
ea8adc8c | 950 | cstore, |
32a655c1 | 951 | hir_map, |
c30ab7b3 SL |
952 | analysis, |
953 | resolutions, | |
32a655c1 | 954 | arena, |
c30ab7b3 | 955 | arenas, |
ea8adc8c | 956 | output_filenames, |
c30ab7b3 | 957 | crate_name, |
041b39d2 | 958 | move |annotation, krate| { |
c30ab7b3 SL |
959 | debug!("pretty printing source code {:?}", s); |
960 | let sess = annotation.sess(); | |
961 | pprust_hir::print_crate(sess.codemap(), | |
32a655c1 | 962 | &sess.parse_sess, |
c30ab7b3 SL |
963 | krate, |
964 | src_name.to_string(), | |
965 | &mut rdr, | |
041b39d2 | 966 | box out, |
c30ab7b3 SL |
967 | annotation.pp_ann(), |
968 | true) | |
969 | }) | |
970 | } | |
e9174d1e | 971 | |
c30ab7b3 SL |
972 | (PpmHir(s), Some(uii)) => { |
973 | let out: &mut Write = &mut out; | |
974 | s.call_with_pp_support_hir(sess, | |
ea8adc8c | 975 | cstore, |
32a655c1 | 976 | hir_map, |
c30ab7b3 SL |
977 | analysis, |
978 | resolutions, | |
32a655c1 | 979 | arena, |
c30ab7b3 | 980 | arenas, |
ea8adc8c | 981 | output_filenames, |
c30ab7b3 | 982 | crate_name, |
041b39d2 | 983 | move |annotation, _| { |
c30ab7b3 SL |
984 | debug!("pretty printing source code {:?}", s); |
985 | let sess = annotation.sess(); | |
32a655c1 | 986 | let hir_map = annotation.hir_map().expect("--unpretty missing HIR map"); |
c30ab7b3 | 987 | let mut pp_state = pprust_hir::State::new_from_input(sess.codemap(), |
32a655c1 | 988 | &sess.parse_sess, |
c30ab7b3 SL |
989 | src_name.to_string(), |
990 | &mut rdr, | |
991 | box out, | |
992 | annotation.pp_ann(), | |
32a655c1 SL |
993 | true); |
994 | for node_id in uii.all_matching_node_ids(hir_map) { | |
995 | let node = hir_map.get(node_id); | |
996 | pp_state.print_node(node)?; | |
041b39d2 | 997 | pp_state.s.space()?; |
c30ab7b3 SL |
998 | let path = annotation.node_path(node_id) |
999 | .expect("--unpretty missing node paths"); | |
1000 | pp_state.synth_comment(path)?; | |
041b39d2 | 1001 | pp_state.s.hardbreak()?; |
c30ab7b3 | 1002 | } |
041b39d2 | 1003 | pp_state.s.eof() |
c30ab7b3 SL |
1004 | }) |
1005 | } | |
1006 | _ => unreachable!(), | |
1007 | } | |
1008 | .unwrap(); | |
a7813a04 XL |
1009 | |
1010 | write_output(out, ofile); | |
1011 | } | |
1012 | ||
1013 | // In an ideal world, this would be a public function called by the driver after | |
1014 | // analsysis is performed. However, we want to call `phase_3_run_analysis_passes` | |
1015 | // with a different callback than the standard driver, so that isn't easy. | |
1016 | // Instead, we call that function ourselves. | |
1017 | fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, | |
ea8adc8c | 1018 | cstore: &'a CrateStore, |
32a655c1 | 1019 | hir_map: &hir_map::Map<'tcx>, |
8bb4bdeb | 1020 | analysis: &ty::CrateAnalysis, |
a7813a04 XL |
1021 | resolutions: &Resolutions, |
1022 | crate_name: &str, | |
32a655c1 SL |
1023 | arena: &'tcx DroplessArena, |
1024 | arenas: &'tcx GlobalArenas<'tcx>, | |
ea8adc8c | 1025 | output_filenames: &OutputFilenames, |
a7813a04 XL |
1026 | ppm: PpMode, |
1027 | uii: Option<UserIdentifiedItem>, | |
1028 | ofile: Option<&Path>) { | |
1029 | let nodeid = if let Some(uii) = uii { | |
1030 | debug!("pretty printing for {:?}", uii); | |
32a655c1 | 1031 | Some(uii.to_one_node_id("--unpretty", sess, &hir_map)) |
a7813a04 XL |
1032 | } else { |
1033 | debug!("pretty printing for whole crate"); | |
1034 | None | |
1035 | }; | |
1a4d82fc | 1036 | |
a7813a04 XL |
1037 | let mut out = Vec::new(); |
1038 | ||
1039 | abort_on_err(driver::phase_3_run_analysis_passes(sess, | |
ea8adc8c | 1040 | cstore, |
32a655c1 | 1041 | hir_map.clone(), |
a7813a04 XL |
1042 | analysis.clone(), |
1043 | resolutions.clone(), | |
32a655c1 | 1044 | arena, |
a7813a04 XL |
1045 | arenas, |
1046 | crate_name, | |
ea8adc8c | 1047 | output_filenames, |
c30ab7b3 | 1048 | |tcx, _, _, _| { |
a7813a04 XL |
1049 | match ppm { |
1050 | PpmMir | PpmMirCFG => { | |
c30ab7b3 | 1051 | if let Some(nodeid) = nodeid { |
32a655c1 | 1052 | let def_id = tcx.hir.local_def_id(nodeid); |
c30ab7b3 | 1053 | match ppm { |
7cac9316 XL |
1054 | PpmMir => write_mir_pretty(tcx, Some(def_id), &mut out), |
1055 | PpmMirCFG => write_mir_graphviz(tcx, Some(def_id), &mut out), | |
c30ab7b3 SL |
1056 | _ => unreachable!(), |
1057 | }?; | |
1058 | } else { | |
1059 | match ppm { | |
7cac9316 XL |
1060 | PpmMir => write_mir_pretty(tcx, None, &mut out), |
1061 | PpmMirCFG => write_mir_graphviz(tcx, None, &mut out), | |
c30ab7b3 SL |
1062 | _ => unreachable!(), |
1063 | }?; | |
7453a54e SL |
1064 | } |
1065 | Ok(()) | |
a7813a04 XL |
1066 | } |
1067 | PpmFlowGraph(mode) => { | |
c30ab7b3 SL |
1068 | let nodeid = |
1069 | nodeid.expect("`pretty flowgraph=..` needs NodeId (int) or unique path \ | |
1070 | suffix (b::c::d)"); | |
32a655c1 | 1071 | let node = tcx.hir.find(nodeid).unwrap_or_else(|| { |
a7813a04 XL |
1072 | tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid)) |
1073 | }); | |
1a4d82fc | 1074 | |
32a655c1 | 1075 | match blocks::Code::from_node(&tcx.hir, nodeid) { |
a7813a04 XL |
1076 | Some(code) => { |
1077 | let variants = gather_flowgraph_variants(tcx.sess); | |
1a4d82fc | 1078 | |
a7813a04 | 1079 | let out: &mut Write = &mut out; |
1a4d82fc | 1080 | |
c30ab7b3 | 1081 | print_flowgraph(variants, tcx, code, mode, out) |
a7813a04 XL |
1082 | } |
1083 | None => { | |
c30ab7b3 SL |
1084 | let message = format!("--pretty=flowgraph needs block, fn, or method; \ |
1085 | got {:?}", | |
a7813a04 XL |
1086 | node); |
1087 | ||
32a655c1 | 1088 | tcx.sess.span_fatal(tcx.hir.span(nodeid), &message) |
1a4d82fc JJ |
1089 | } |
1090 | } | |
1091 | } | |
a7813a04 | 1092 | _ => unreachable!(), |
1a4d82fc | 1093 | } |
c30ab7b3 SL |
1094 | }), |
1095 | sess) | |
1096 | .unwrap(); | |
c34b1796 | 1097 | |
a7813a04 | 1098 | write_output(out, ofile); |
1a4d82fc | 1099 | } |