]>
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 | |
ff7c6d11 | 20 | use rustc::ty::{self, TyCtxt, Resolutions, AllArenas}; |
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; |
ff7c6d11 | 37 | use syntax_pos::{self, FileName}; |
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 | ||
c34b1796 | 54 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
55 | pub enum PpSourceMode { |
56 | PpmNormal, | |
57 | PpmEveryBodyLoops, | |
58 | PpmExpanded, | |
1a4d82fc JJ |
59 | PpmIdentified, |
60 | PpmExpandedIdentified, | |
61 | PpmExpandedHygiene, | |
e9174d1e | 62 | PpmTyped, |
1a4d82fc JJ |
63 | } |
64 | ||
c34b1796 | 65 | #[derive(Copy, Clone, PartialEq, Debug)] |
85aaf69f SL |
66 | pub enum PpFlowGraphMode { |
67 | Default, | |
68 | /// Drops the labels from the edges in the flowgraph output. This | |
2c00a5a8 | 69 | /// is mostly for use in the -Z unpretty flowgraph run-make tests, |
85aaf69f SL |
70 | /// since the labels are largely uninteresting in those cases and |
71 | /// have become a pain to maintain. | |
72 | UnlabelledEdges, | |
73 | } | |
c34b1796 | 74 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
75 | pub enum PpMode { |
76 | PpmSource(PpSourceMode), | |
e9174d1e | 77 | PpmHir(PpSourceMode), |
ff7c6d11 | 78 | PpmHirTree(PpSourceMode), |
85aaf69f | 79 | PpmFlowGraph(PpFlowGraphMode), |
7453a54e | 80 | PpmMir, |
54a0048b | 81 | PpmMirCFG, |
1a4d82fc JJ |
82 | } |
83 | ||
a7813a04 XL |
84 | impl PpMode { |
85 | pub fn needs_ast_map(&self, opt_uii: &Option<UserIdentifiedItem>) -> bool { | |
86 | match *self { | |
87 | PpmSource(PpmNormal) | | |
88 | PpmSource(PpmEveryBodyLoops) | | |
89 | PpmSource(PpmIdentified) => opt_uii.is_some(), | |
90 | ||
91 | PpmSource(PpmExpanded) | | |
92 | PpmSource(PpmExpandedIdentified) | | |
93 | PpmSource(PpmExpandedHygiene) | | |
94 | PpmHir(_) | | |
ff7c6d11 | 95 | PpmHirTree(_) | |
a7813a04 XL |
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), |
ff7c6d11 | 128 | ("hir-tree", true) => PpmHirTree(PpmNormal), |
7453a54e | 129 | ("mir", true) => PpmMir, |
54a0048b | 130 | ("mir-cfg", true) => PpmMirCFG, |
92a42be0 SL |
131 | ("flowgraph", true) => PpmFlowGraph(PpFlowGraphMode::Default), |
132 | ("flowgraph,unlabelled", true) => PpmFlowGraph(PpFlowGraphMode::UnlabelledEdges), | |
1a4d82fc JJ |
133 | _ => { |
134 | if extended { | |
92a42be0 SL |
135 | sess.fatal(&format!("argument to `unpretty` must be one of `normal`, \ |
136 | `expanded`, `flowgraph[,unlabelled]=<nodeid>`, \ | |
137 | `identified`, `expanded,identified`, `everybody_loops`, \ | |
7453a54e | 138 | `hir`, `hir,identified`, `hir,typed`, or `mir`; got {}", |
92a42be0 | 139 | name)); |
1a4d82fc | 140 | } else { |
92a42be0 SL |
141 | sess.fatal(&format!("argument to `pretty` must be one of `normal`, `expanded`, \ |
142 | `identified`, or `expanded,identified`; got {}", | |
143 | name)); | |
1a4d82fc JJ |
144 | } |
145 | } | |
146 | }; | |
85aaf69f | 147 | let opt_second = opt_second.and_then(|s| s.parse::<UserIdentifiedItem>().ok()); |
1a4d82fc JJ |
148 | (first, opt_second) |
149 | } | |
150 | ||
151 | ||
152 | ||
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 | |
157 | // `&PpAnn` object. | |
158 | // | |
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`. | |
162 | // | |
163 | // (The `use_once_payload` is working around the current lack of once | |
164 | // functions in the compiler.) | |
165 | ||
166 | impl PpSourceMode { | |
167 | /// Constructs a `PrinterSupport` object and passes it to `f`. | |
041b39d2 | 168 | fn call_with_pp_support<'tcx, A, F>(&self, |
b039eaaf | 169 | sess: &'tcx Session, |
32a655c1 | 170 | hir_map: Option<&hir_map::Map<'tcx>>, |
92a42be0 SL |
171 | f: F) |
172 | -> A | |
041b39d2 | 173 | where F: FnOnce(&PrinterSupport) -> A |
1a4d82fc JJ |
174 | { |
175 | match *self { | |
176 | PpmNormal | PpmEveryBodyLoops | PpmExpanded => { | |
92a42be0 | 177 | let annotation = NoAnn { |
3b2f2976 | 178 | sess, |
32a655c1 | 179 | hir_map: hir_map.map(|m| m.clone()), |
92a42be0 | 180 | }; |
041b39d2 | 181 | f(&annotation) |
1a4d82fc JJ |
182 | } |
183 | ||
184 | PpmIdentified | PpmExpandedIdentified => { | |
92a42be0 | 185 | let annotation = IdentifiedAnnotation { |
3b2f2976 | 186 | sess, |
32a655c1 | 187 | hir_map: hir_map.map(|m| m.clone()), |
92a42be0 | 188 | }; |
041b39d2 | 189 | f(&annotation) |
1a4d82fc JJ |
190 | } |
191 | PpmExpandedHygiene => { | |
92a42be0 | 192 | let annotation = HygieneAnnotation { |
3b2f2976 | 193 | sess, |
92a42be0 | 194 | }; |
041b39d2 | 195 | f(&annotation) |
1a4d82fc | 196 | } |
e9174d1e SL |
197 | _ => panic!("Should use call_with_pp_support_hir"), |
198 | } | |
199 | } | |
041b39d2 | 200 | fn call_with_pp_support_hir<'tcx, A, F>(&self, |
b039eaaf | 201 | sess: &'tcx Session, |
ea8adc8c | 202 | cstore: &'tcx CrateStore, |
32a655c1 | 203 | hir_map: &hir_map::Map<'tcx>, |
8bb4bdeb | 204 | analysis: &ty::CrateAnalysis, |
a7813a04 | 205 | resolutions: &Resolutions, |
ff7c6d11 | 206 | arenas: &'tcx AllArenas<'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 => { |
abe05a73 | 230 | let control = &driver::CompileController::basic(); |
2c00a5a8 XL |
231 | let trans = ::get_trans(sess); |
232 | abort_on_err(driver::phase_3_run_analysis_passes(&*trans, | |
233 | control, | |
abe05a73 | 234 | sess, |
ea8adc8c | 235 | cstore, |
32a655c1 | 236 | hir_map.clone(), |
a7813a04 XL |
237 | analysis.clone(), |
238 | resolutions.clone(), | |
7453a54e SL |
239 | arenas, |
240 | id, | |
ea8adc8c | 241 | output_filenames, |
c30ab7b3 | 242 | |tcx, _, _, _| { |
3b2f2976 | 243 | let empty_tables = ty::TypeckTables::empty(None); |
32a655c1 | 244 | let annotation = TypedAnnotation { |
3b2f2976 | 245 | tcx, |
32a655c1 SL |
246 | tables: Cell::new(&empty_tables) |
247 | }; | |
2c00a5a8 XL |
248 | tcx.dep_graph.with_ignore(|| { |
249 | f(&annotation, hir_map.forest.krate()) | |
250 | }) | |
c30ab7b3 SL |
251 | }), |
252 | sess) | |
1a4d82fc | 253 | } |
e9174d1e | 254 | _ => panic!("Should use call_with_pp_support"), |
1a4d82fc JJ |
255 | } |
256 | } | |
257 | } | |
258 | ||
32a655c1 | 259 | trait PrinterSupport: pprust::PpAnn { |
1a4d82fc JJ |
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; | |
263 | ||
1a4d82fc JJ |
264 | /// Produces the pretty-print annotation object. |
265 | /// | |
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; | |
269 | } | |
270 | ||
32a655c1 | 271 | trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { |
e9174d1e SL |
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; | |
275 | ||
276 | /// Provides a uniform interface for re-extracting a reference to an | |
277 | /// `hir_map::Map` from a value that now owns it. | |
32a655c1 | 278 | fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>>; |
e9174d1e SL |
279 | |
280 | /// Produces the pretty-print annotation object. | |
281 | /// | |
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; | |
54a0048b SL |
285 | |
286 | /// Computes an user-readable representation of a path, if possible. | |
287 | fn node_path(&self, id: ast::NodeId) -> Option<String> { | |
32a655c1 | 288 | self.hir_map().and_then(|map| map.def_path_from_id(id)).map(|path| { |
c30ab7b3 SL |
289 | path.data |
290 | .into_iter() | |
291 | .map(|elem| elem.data.to_string()) | |
292 | .collect::<Vec<_>>() | |
293 | .join("::") | |
54a0048b SL |
294 | }) |
295 | } | |
e9174d1e SL |
296 | } |
297 | ||
32a655c1 SL |
298 | struct NoAnn<'hir> { |
299 | sess: &'hir Session, | |
300 | hir_map: Option<hir_map::Map<'hir>>, | |
1a4d82fc JJ |
301 | } |
302 | ||
32a655c1 | 303 | impl<'hir> PrinterSupport for NoAnn<'hir> { |
92a42be0 SL |
304 | fn sess<'a>(&'a self) -> &'a Session { |
305 | self.sess | |
306 | } | |
1a4d82fc | 307 | |
92a42be0 SL |
308 | fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { |
309 | self | |
310 | } | |
1a4d82fc JJ |
311 | } |
312 | ||
32a655c1 | 313 | impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> { |
92a42be0 SL |
314 | fn sess<'a>(&'a self) -> &'a Session { |
315 | self.sess | |
316 | } | |
e9174d1e | 317 | |
32a655c1 SL |
318 | fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> { |
319 | self.hir_map.as_ref() | |
e9174d1e SL |
320 | } |
321 | ||
92a42be0 SL |
322 | fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { |
323 | self | |
324 | } | |
e9174d1e SL |
325 | } |
326 | ||
32a655c1 SL |
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) | |
330 | -> io::Result<()> { | |
331 | if let Some(ref map) = self.hir_map { | |
332 | pprust_hir::PpAnn::nested(map, state, nested) | |
333 | } else { | |
334 | Ok(()) | |
335 | } | |
336 | } | |
337 | } | |
1a4d82fc | 338 | |
32a655c1 SL |
339 | struct IdentifiedAnnotation<'hir> { |
340 | sess: &'hir Session, | |
341 | hir_map: Option<hir_map::Map<'hir>>, | |
1a4d82fc JJ |
342 | } |
343 | ||
32a655c1 | 344 | impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> { |
92a42be0 SL |
345 | fn sess<'a>(&'a self) -> &'a Session { |
346 | self.sess | |
347 | } | |
1a4d82fc | 348 | |
92a42be0 SL |
349 | fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { |
350 | self | |
351 | } | |
1a4d82fc JJ |
352 | } |
353 | ||
32a655c1 | 354 | impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> { |
92a42be0 | 355 | fn pre(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { |
1a4d82fc JJ |
356 | match node { |
357 | pprust::NodeExpr(_) => s.popen(), | |
92a42be0 | 358 | _ => Ok(()), |
1a4d82fc JJ |
359 | } |
360 | } | |
92a42be0 | 361 | fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { |
1a4d82fc | 362 | match node { |
c30ab7b3 SL |
363 | pprust::NodeIdent(_) | |
364 | pprust::NodeName(_) => Ok(()), | |
1a4d82fc JJ |
365 | |
366 | pprust::NodeItem(item) => { | |
041b39d2 | 367 | s.s.space()?; |
1a4d82fc JJ |
368 | s.synth_comment(item.id.to_string()) |
369 | } | |
c34b1796 | 370 | pprust::NodeSubItem(id) => { |
041b39d2 | 371 | s.s.space()?; |
c34b1796 AL |
372 | s.synth_comment(id.to_string()) |
373 | } | |
1a4d82fc | 374 | pprust::NodeBlock(blk) => { |
041b39d2 | 375 | s.s.space()?; |
1a4d82fc JJ |
376 | s.synth_comment(format!("block {}", blk.id)) |
377 | } | |
378 | pprust::NodeExpr(expr) => { | |
041b39d2 | 379 | s.s.space()?; |
54a0048b | 380 | s.synth_comment(expr.id.to_string())?; |
1a4d82fc JJ |
381 | s.pclose() |
382 | } | |
383 | pprust::NodePat(pat) => { | |
041b39d2 | 384 | s.s.space()?; |
1a4d82fc JJ |
385 | s.synth_comment(format!("pat {}", pat.id)) |
386 | } | |
387 | } | |
388 | } | |
389 | } | |
390 | ||
32a655c1 | 391 | impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> { |
92a42be0 SL |
392 | fn sess<'a>(&'a self) -> &'a Session { |
393 | self.sess | |
394 | } | |
e9174d1e | 395 | |
32a655c1 SL |
396 | fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'hir>> { |
397 | self.hir_map.as_ref() | |
e9174d1e SL |
398 | } |
399 | ||
92a42be0 SL |
400 | fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { |
401 | self | |
402 | } | |
e9174d1e SL |
403 | } |
404 | ||
32a655c1 SL |
405 | impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { |
406 | fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested) | |
407 | -> io::Result<()> { | |
408 | if let Some(ref map) = self.hir_map { | |
409 | pprust_hir::PpAnn::nested(map, state, nested) | |
410 | } else { | |
411 | Ok(()) | |
412 | } | |
413 | } | |
92a42be0 | 414 | fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { |
e9174d1e SL |
415 | match node { |
416 | pprust_hir::NodeExpr(_) => s.popen(), | |
92a42be0 | 417 | _ => Ok(()), |
e9174d1e SL |
418 | } |
419 | } | |
92a42be0 | 420 | fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { |
e9174d1e | 421 | match node { |
b039eaaf | 422 | pprust_hir::NodeName(_) => Ok(()), |
e9174d1e | 423 | pprust_hir::NodeItem(item) => { |
041b39d2 | 424 | s.s.space()?; |
ff7c6d11 XL |
425 | s.synth_comment(format!("node_id: {} hir local_id: {}", |
426 | item.id, item.hir_id.local_id.0)) | |
e9174d1e SL |
427 | } |
428 | pprust_hir::NodeSubItem(id) => { | |
041b39d2 | 429 | s.s.space()?; |
e9174d1e SL |
430 | s.synth_comment(id.to_string()) |
431 | } | |
432 | pprust_hir::NodeBlock(blk) => { | |
041b39d2 | 433 | s.s.space()?; |
ff7c6d11 XL |
434 | s.synth_comment(format!("block node_id: {} hir local_id: {}", |
435 | blk.id, blk.hir_id.local_id.0)) | |
e9174d1e SL |
436 | } |
437 | pprust_hir::NodeExpr(expr) => { | |
041b39d2 | 438 | s.s.space()?; |
ff7c6d11 XL |
439 | s.synth_comment(format!("node_id: {} hir local_id: {}", |
440 | expr.id, expr.hir_id.local_id.0))?; | |
e9174d1e SL |
441 | s.pclose() |
442 | } | |
443 | pprust_hir::NodePat(pat) => { | |
041b39d2 | 444 | s.s.space()?; |
ff7c6d11 XL |
445 | s.synth_comment(format!("pat node_id: {} hir local_id: {}", |
446 | pat.id, pat.hir_id.local_id.0)) | |
e9174d1e SL |
447 | } |
448 | } | |
449 | } | |
450 | } | |
451 | ||
32a655c1 SL |
452 | struct HygieneAnnotation<'a> { |
453 | sess: &'a Session | |
1a4d82fc JJ |
454 | } |
455 | ||
32a655c1 SL |
456 | impl<'a> PrinterSupport for HygieneAnnotation<'a> { |
457 | fn sess(&self) -> &Session { | |
92a42be0 SL |
458 | self.sess |
459 | } | |
1a4d82fc | 460 | |
32a655c1 | 461 | fn pp_ann(&self) -> &pprust::PpAnn { |
92a42be0 SL |
462 | self |
463 | } | |
1a4d82fc JJ |
464 | } |
465 | ||
32a655c1 | 466 | impl<'a> pprust::PpAnn for HygieneAnnotation<'a> { |
92a42be0 | 467 | fn post(&self, s: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { |
1a4d82fc | 468 | match node { |
476ff2be | 469 | pprust::NodeIdent(&ast::Ident { name, ctxt }) => { |
041b39d2 | 470 | s.s.space()?; |
1a4d82fc JJ |
471 | // FIXME #16420: this doesn't display the connections |
472 | // between syntax contexts | |
476ff2be | 473 | s.synth_comment(format!("{}{:?}", name.as_u32(), ctxt)) |
1a4d82fc | 474 | } |
476ff2be | 475 | pprust::NodeName(&name) => { |
041b39d2 | 476 | s.s.space()?; |
476ff2be | 477 | s.synth_comment(name.as_u32().to_string()) |
1a4d82fc | 478 | } |
92a42be0 | 479 | _ => Ok(()), |
1a4d82fc JJ |
480 | } |
481 | } | |
482 | } | |
483 | ||
484 | ||
62682a34 | 485 | struct TypedAnnotation<'a, 'tcx: 'a> { |
a7813a04 | 486 | tcx: TyCtxt<'a, 'tcx, 'tcx>, |
32a655c1 | 487 | tables: Cell<&'a ty::TypeckTables<'tcx>>, |
1a4d82fc JJ |
488 | } |
489 | ||
e9174d1e | 490 | impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> { |
92a42be0 SL |
491 | fn sess<'a>(&'a self) -> &'a Session { |
492 | &self.tcx.sess | |
493 | } | |
1a4d82fc | 494 | |
32a655c1 SL |
495 | fn hir_map<'a>(&'a self) -> Option<&'a hir_map::Map<'tcx>> { |
496 | Some(&self.tcx.hir) | |
1a4d82fc JJ |
497 | } |
498 | ||
92a42be0 SL |
499 | fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { |
500 | self | |
501 | } | |
54a0048b SL |
502 | |
503 | fn node_path(&self, id: ast::NodeId) -> Option<String> { | |
504 | Some(self.tcx.node_path_str(id)) | |
505 | } | |
1a4d82fc JJ |
506 | } |
507 | ||
e9174d1e | 508 | impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> { |
32a655c1 SL |
509 | fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested) |
510 | -> io::Result<()> { | |
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)); | |
514 | } | |
515 | pprust_hir::PpAnn::nested(&self.tcx.hir, state, nested)?; | |
516 | self.tables.set(old_tables); | |
517 | Ok(()) | |
518 | } | |
92a42be0 | 519 | fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { |
1a4d82fc | 520 | match node { |
e9174d1e | 521 | pprust_hir::NodeExpr(_) => s.popen(), |
92a42be0 | 522 | _ => Ok(()), |
1a4d82fc JJ |
523 | } |
524 | } | |
92a42be0 | 525 | fn post(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> { |
1a4d82fc | 526 | match node { |
e9174d1e | 527 | pprust_hir::NodeExpr(expr) => { |
041b39d2 XL |
528 | s.s.space()?; |
529 | s.s.word("as")?; | |
530 | s.s.space()?; | |
531 | s.s.word(&self.tables.get().expr_ty(expr).to_string())?; | |
1a4d82fc JJ |
532 | s.pclose() |
533 | } | |
92a42be0 | 534 | _ => Ok(()), |
1a4d82fc JJ |
535 | } |
536 | } | |
537 | } | |
538 | ||
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); | |
547 | } | |
548 | if print_all || print_moves { | |
549 | variants.push(borrowck_dot::Moves); | |
550 | } | |
551 | if print_all || print_assigns { | |
552 | variants.push(borrowck_dot::Assigns); | |
553 | } | |
554 | variants | |
555 | } | |
556 | ||
85aaf69f | 557 | #[derive(Clone, Debug)] |
1a4d82fc JJ |
558 | pub enum UserIdentifiedItem { |
559 | ItemViaNode(ast::NodeId), | |
560 | ItemViaPath(Vec<String>), | |
561 | } | |
562 | ||
563 | impl FromStr for UserIdentifiedItem { | |
85aaf69f SL |
564 | type Err = (); |
565 | fn from_str(s: &str) -> Result<UserIdentifiedItem, ()> { | |
92a42be0 | 566 | Ok(s.parse() |
9e0c209e | 567 | .map(ast::NodeId::new) |
92a42be0 SL |
568 | .map(ItemViaNode) |
569 | .unwrap_or_else(|_| ItemViaPath(s.split("::").map(|s| s.to_string()).collect()))) | |
1a4d82fc JJ |
570 | } |
571 | } | |
572 | ||
32a655c1 | 573 | enum NodesMatchingUII<'a, 'hir: 'a> { |
1a4d82fc | 574 | NodesMatchingDirect(option::IntoIter<ast::NodeId>), |
32a655c1 | 575 | NodesMatchingSuffix(hir_map::NodesMatchingSuffix<'a, 'hir>), |
1a4d82fc JJ |
576 | } |
577 | ||
32a655c1 | 578 | impl<'a, 'hir> Iterator for NodesMatchingUII<'a, 'hir> { |
1a4d82fc JJ |
579 | type Item = ast::NodeId; |
580 | ||
581 | fn next(&mut self) -> Option<ast::NodeId> { | |
582 | match self { | |
583 | &mut NodesMatchingDirect(ref mut iter) => iter.next(), | |
584 | &mut NodesMatchingSuffix(ref mut iter) => iter.next(), | |
585 | } | |
586 | } | |
587 | } | |
588 | ||
589 | impl UserIdentifiedItem { | |
590 | fn reconstructed_input(&self) -> String { | |
591 | match *self { | |
592 | ItemViaNode(node_id) => node_id.to_string(), | |
c1a9b12d | 593 | ItemViaPath(ref parts) => parts.join("::"), |
1a4d82fc JJ |
594 | } |
595 | } | |
596 | ||
32a655c1 SL |
597 | fn all_matching_node_ids<'a, 'hir>(&'a self, |
598 | map: &'a hir_map::Map<'hir>) | |
599 | -> NodesMatchingUII<'a, 'hir> { | |
1a4d82fc | 600 | match *self { |
92a42be0 | 601 | ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()), |
cc61c64b | 602 | ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts)), |
1a4d82fc JJ |
603 | } |
604 | } | |
605 | ||
e9174d1e | 606 | fn to_one_node_id(self, user_option: &str, sess: &Session, map: &hir_map::Map) -> ast::NodeId { |
85aaf69f | 607 | let fail_because = |is_wrong_because| -> ast::NodeId { |
92a42be0 SL |
608 | let message = format!("{} needs NodeId (int) or unique path suffix (b::c::d); got \ |
609 | {}, which {}", | |
610 | user_option, | |
611 | self.reconstructed_input(), | |
612 | is_wrong_because); | |
cc61c64b | 613 | sess.fatal(&message) |
1a4d82fc JJ |
614 | }; |
615 | ||
616 | let mut saw_node = ast::DUMMY_NODE_ID; | |
85aaf69f | 617 | let mut seen = 0; |
1a4d82fc JJ |
618 | for node in self.all_matching_node_ids(map) { |
619 | saw_node = node; | |
620 | seen += 1; | |
621 | if seen > 1 { | |
622 | fail_because("does not resolve uniquely"); | |
623 | } | |
624 | } | |
625 | if seen == 0 { | |
626 | fail_because("does not resolve to any item"); | |
627 | } | |
628 | ||
629 | assert!(seen == 1); | |
630 | return saw_node; | |
631 | } | |
632 | } | |
633 | ||
3b2f2976 XL |
634 | // Note: Also used by librustdoc, see PR #43348. Consider moving this struct elsewhere. |
635 | // | |
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]. | |
642 | // | |
643 | // [#34511]: https://github.com/rust-lang/rust/issues/34511#issuecomment-322340401 | |
ff7c6d11 | 644 | pub struct ReplaceBodyWithLoop<'a> { |
1a4d82fc | 645 | within_static_or_const: bool, |
ff7c6d11 | 646 | sess: &'a Session, |
1a4d82fc JJ |
647 | } |
648 | ||
ff7c6d11 XL |
649 | impl<'a> ReplaceBodyWithLoop<'a> { |
650 | pub fn new(sess: &'a Session) -> ReplaceBodyWithLoop<'a> { | |
651 | ReplaceBodyWithLoop { within_static_or_const: false, sess } | |
1a4d82fc | 652 | } |
3b2f2976 XL |
653 | |
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; | |
658 | ret | |
659 | } | |
660 | ||
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 { | |
664 | match ty.node { | |
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), | |
ea8adc8c XL |
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) { | |
674 | None => false, | |
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()), | |
681 | } | |
682 | }), | |
3b2f2976 XL |
683 | _ => false, |
684 | } | |
685 | } | |
ea8adc8c XL |
686 | |
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)) | |
689 | } | |
690 | ||
3b2f2976 XL |
691 | involves_impl_trait(ty) |
692 | } else { | |
693 | false | |
694 | } | |
695 | } | |
1a4d82fc JJ |
696 | } |
697 | ||
ff7c6d11 | 698 | impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { |
7453a54e | 699 | fn fold_item_kind(&mut self, i: ast::ItemKind) -> ast::ItemKind { |
3b2f2976 XL |
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), | |
704 | _ => false, | |
705 | }; | |
706 | self.run(is_const, |s| fold::noop_fold_item_kind(i, s)) | |
1a4d82fc JJ |
707 | } |
708 | ||
7453a54e | 709 | fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector<ast::TraitItem> { |
3b2f2976 XL |
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), | |
714 | _ => false, | |
715 | }; | |
716 | self.run(is_const, |s| fold::noop_fold_trait_item(i, s)) | |
d9579d0f AL |
717 | } |
718 | ||
7453a54e | 719 | fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector<ast::ImplItem> { |
3b2f2976 XL |
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), | |
724 | _ => false, | |
725 | }; | |
726 | self.run(is_const, |s| fold::noop_fold_impl_item(i, s)) | |
d9579d0f | 727 | } |
1a4d82fc JJ |
728 | |
729 | fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> { | |
ff7c6d11 XL |
730 | fn expr_to_block(rules: ast::BlockCheckMode, |
731 | recovered: bool, | |
732 | e: Option<P<ast::Expr>>, | |
733 | sess: &Session) -> P<ast::Block> { | |
1a4d82fc | 734 | P(ast::Block { |
c30ab7b3 SL |
735 | stmts: e.map(|e| { |
736 | ast::Stmt { | |
ff7c6d11 | 737 | id: sess.next_node_id(), |
c30ab7b3 SL |
738 | span: e.span, |
739 | node: ast::StmtKind::Expr(e), | |
740 | } | |
741 | }) | |
742 | .into_iter() | |
743 | .collect(), | |
3b2f2976 | 744 | rules, |
ff7c6d11 | 745 | id: sess.next_node_id(), |
3157f602 | 746 | span: syntax_pos::DUMMY_SP, |
ff7c6d11 | 747 | recovered, |
1a4d82fc JJ |
748 | }) |
749 | } | |
750 | ||
751 | if !self.within_static_or_const { | |
752 | ||
ff7c6d11 | 753 | let empty_block = expr_to_block(BlockCheckMode::Default, false, None, self.sess); |
1a4d82fc | 754 | let loop_expr = P(ast::Expr { |
7453a54e | 755 | node: ast::ExprKind::Loop(empty_block, None), |
ff7c6d11 | 756 | id: self.sess.next_node_id(), |
3157f602 XL |
757 | span: syntax_pos::DUMMY_SP, |
758 | attrs: ast::ThinVec::new(), | |
1a4d82fc JJ |
759 | }); |
760 | ||
ff7c6d11 | 761 | expr_to_block(b.rules, b.recovered, Some(loop_expr), self.sess) |
1a4d82fc JJ |
762 | |
763 | } else { | |
764 | fold::noop_fold_block(b, self) | |
765 | } | |
766 | } | |
767 | ||
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) | |
772 | } | |
773 | } | |
774 | ||
a7813a04 XL |
775 | fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec<borrowck_dot::Variant>, |
776 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
476ff2be | 777 | code: blocks::Code<'tcx>, |
a7813a04 XL |
778 | mode: PpFlowGraphMode, |
779 | mut out: W) | |
780 | -> io::Result<()> { | |
8bb4bdeb XL |
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; | |
785 | loop { | |
786 | let node = tcx.hir.get(node_id); | |
787 | if let Some(n) = hir::map::blocks::FnLikeNode::from_node(node) { | |
788 | break n.body(); | |
789 | } | |
790 | let parent = tcx.hir.get_parent_node(node_id); | |
791 | assert!(node_id != parent); | |
792 | node_id = parent; | |
793 | } | |
794 | } | |
795 | blocks::Code::FnLike(fn_like) => fn_like.body(), | |
a7813a04 | 796 | }; |
8bb4bdeb XL |
797 | let body = tcx.hir.body(body_id); |
798 | let cfg = cfg::CFG::new(tcx, &body); | |
a7813a04 XL |
799 | let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges; |
800 | let lcfg = LabelledCFG { | |
ea8adc8c | 801 | tcx, |
a7813a04 XL |
802 | cfg: &cfg, |
803 | name: format!("node_{}", code.id()), | |
3b2f2976 | 804 | labelled_edges, |
1a4d82fc JJ |
805 | }; |
806 | ||
a7813a04 XL |
807 | match code { |
808 | _ if variants.is_empty() => { | |
809 | let r = dot::render(&lcfg, &mut out); | |
810 | return expand_err_details(r); | |
811 | } | |
476ff2be | 812 | blocks::Code::Expr(_) => { |
a7813a04 XL |
813 | tcx.sess.err("--pretty flowgraph with -Z flowgraph-print annotations requires \ |
814 | fn-like node id."); | |
815 | return Ok(()); | |
816 | } | |
476ff2be | 817 | blocks::Code::FnLike(fn_like) => { |
a7813a04 | 818 | let (bccx, analysis_data) = |
32a655c1 | 819 | borrowck::build_borrowck_dataflow_data_for_fn(tcx, fn_like.body(), &cfg); |
1a4d82fc | 820 | |
a7813a04 XL |
821 | let lcfg = borrowck_dot::DataflowLabeller { |
822 | inner: lcfg, | |
3b2f2976 | 823 | variants, |
a7813a04 XL |
824 | borrowck_ctxt: &bccx, |
825 | analysis_data: &analysis_data, | |
826 | }; | |
827 | let r = dot::render(&lcfg, &mut out); | |
828 | return expand_err_details(r); | |
1a4d82fc | 829 | } |
a7813a04 | 830 | } |
1a4d82fc | 831 | |
a7813a04 XL |
832 | fn expand_err_details(r: io::Result<()>) -> io::Result<()> { |
833 | r.map_err(|ioerr| { | |
834 | io::Error::new(io::ErrorKind::Other, | |
cc61c64b | 835 | format!("graphviz::render failed: {}", ioerr)) |
a7813a04 XL |
836 | }) |
837 | } | |
838 | } | |
839 | ||
ff7c6d11 | 840 | pub fn fold_crate(sess: &Session, krate: ast::Crate, ppm: PpMode) -> ast::Crate { |
a7813a04 | 841 | if let PpmSource(PpmEveryBodyLoops) = ppm { |
ff7c6d11 | 842 | let mut fold = ReplaceBodyWithLoop::new(sess); |
a7813a04 | 843 | fold.fold_crate(krate) |
1a4d82fc | 844 | } else { |
a7813a04 XL |
845 | krate |
846 | } | |
847 | } | |
1a4d82fc | 848 | |
ff7c6d11 | 849 | fn get_source(input: &Input, sess: &Session) -> (Vec<u8>, FileName) { |
1a4d82fc | 850 | let src_name = driver::source_name(input); |
92a42be0 | 851 | let src = sess.codemap() |
c30ab7b3 SL |
852 | .get_filemap(&src_name) |
853 | .unwrap() | |
854 | .src | |
855 | .as_ref() | |
856 | .unwrap() | |
857 | .as_bytes() | |
858 | .to_vec(); | |
a7813a04 XL |
859 | (src, src_name) |
860 | } | |
861 | ||
862 | fn write_output(out: Vec<u8>, ofile: Option<&Path>) { | |
863 | match ofile { | |
864 | None => print!("{}", String::from_utf8(out).unwrap()), | |
865 | Some(p) => { | |
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), | |
869 | } | |
870 | } | |
871 | } | |
872 | } | |
1a4d82fc | 873 | |
a7813a04 XL |
874 | pub fn print_after_parsing(sess: &Session, |
875 | input: &Input, | |
876 | krate: &ast::Crate, | |
877 | ppm: PpMode, | |
878 | ofile: Option<&Path>) { | |
a7813a04 XL |
879 | let (src, src_name) = get_source(input, sess); |
880 | ||
881 | let mut rdr = &*src; | |
882 | let mut out = Vec::new(); | |
883 | ||
884 | if let PpmSource(s) = ppm { | |
885 | // Silently ignores an identified node. | |
886 | let out: &mut Write = &mut out; | |
041b39d2 | 887 | s.call_with_pp_support(sess, None, move |annotation| { |
c30ab7b3 SL |
888 | debug!("pretty printing source code {:?}", s); |
889 | let sess = annotation.sess(); | |
890 | pprust::print_crate(sess.codemap(), | |
32a655c1 | 891 | &sess.parse_sess, |
c30ab7b3 | 892 | krate, |
ff7c6d11 | 893 | src_name, |
c30ab7b3 | 894 | &mut rdr, |
041b39d2 | 895 | box out, |
c30ab7b3 SL |
896 | annotation.pp_ann(), |
897 | false) | |
898 | }) | |
899 | .unwrap() | |
a7813a04 XL |
900 | } else { |
901 | unreachable!(); | |
902 | }; | |
903 | ||
904 | write_output(out, ofile); | |
905 | } | |
906 | ||
907 | pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, | |
ea8adc8c | 908 | cstore: &'tcx CrateStore, |
32a655c1 | 909 | hir_map: &hir_map::Map<'tcx>, |
8bb4bdeb | 910 | analysis: &ty::CrateAnalysis, |
a7813a04 XL |
911 | resolutions: &Resolutions, |
912 | input: &Input, | |
913 | krate: &ast::Crate, | |
914 | crate_name: &str, | |
915 | ppm: PpMode, | |
ff7c6d11 | 916 | arenas: &'tcx AllArenas<'tcx>, |
ea8adc8c | 917 | output_filenames: &OutputFilenames, |
a7813a04 XL |
918 | opt_uii: Option<UserIdentifiedItem>, |
919 | ofile: Option<&Path>) { | |
a7813a04 | 920 | if ppm.needs_analysis() { |
c30ab7b3 | 921 | print_with_analysis(sess, |
ea8adc8c | 922 | cstore, |
32a655c1 | 923 | hir_map, |
c30ab7b3 SL |
924 | analysis, |
925 | resolutions, | |
926 | crate_name, | |
927 | arenas, | |
ea8adc8c | 928 | output_filenames, |
c30ab7b3 SL |
929 | ppm, |
930 | opt_uii, | |
931 | ofile); | |
a7813a04 XL |
932 | return; |
933 | } | |
934 | ||
935 | let (src, src_name) = get_source(input, sess); | |
936 | ||
937 | let mut rdr = &src[..]; | |
c34b1796 | 938 | let mut out = Vec::new(); |
1a4d82fc JJ |
939 | |
940 | match (ppm, opt_uii) { | |
c30ab7b3 SL |
941 | (PpmSource(s), _) => { |
942 | // Silently ignores an identified node. | |
943 | let out: &mut Write = &mut out; | |
041b39d2 | 944 | s.call_with_pp_support(sess, Some(hir_map), move |annotation| { |
c30ab7b3 SL |
945 | debug!("pretty printing source code {:?}", s); |
946 | let sess = annotation.sess(); | |
947 | pprust::print_crate(sess.codemap(), | |
32a655c1 | 948 | &sess.parse_sess, |
c30ab7b3 | 949 | krate, |
ff7c6d11 | 950 | src_name, |
c30ab7b3 | 951 | &mut rdr, |
041b39d2 | 952 | box out, |
c30ab7b3 SL |
953 | annotation.pp_ann(), |
954 | true) | |
955 | }) | |
956 | } | |
1a4d82fc | 957 | |
c30ab7b3 SL |
958 | (PpmHir(s), None) => { |
959 | let out: &mut Write = &mut out; | |
960 | s.call_with_pp_support_hir(sess, | |
ea8adc8c | 961 | cstore, |
32a655c1 | 962 | hir_map, |
c30ab7b3 SL |
963 | analysis, |
964 | resolutions, | |
965 | arenas, | |
ea8adc8c | 966 | output_filenames, |
c30ab7b3 | 967 | crate_name, |
041b39d2 | 968 | move |annotation, krate| { |
c30ab7b3 SL |
969 | debug!("pretty printing source code {:?}", s); |
970 | let sess = annotation.sess(); | |
971 | pprust_hir::print_crate(sess.codemap(), | |
32a655c1 | 972 | &sess.parse_sess, |
c30ab7b3 | 973 | krate, |
ff7c6d11 | 974 | src_name, |
c30ab7b3 | 975 | &mut rdr, |
041b39d2 | 976 | box out, |
c30ab7b3 SL |
977 | annotation.pp_ann(), |
978 | true) | |
979 | }) | |
980 | } | |
e9174d1e | 981 | |
ff7c6d11 XL |
982 | (PpmHirTree(s), None) => { |
983 | let out: &mut Write = &mut out; | |
984 | s.call_with_pp_support_hir(sess, | |
985 | cstore, | |
986 | hir_map, | |
987 | analysis, | |
988 | resolutions, | |
989 | arenas, | |
990 | output_filenames, | |
991 | crate_name, | |
992 | move |_annotation, krate| { | |
993 | debug!("pretty printing source code {:?}", s); | |
994 | write!(out, "{:#?}", krate) | |
995 | }) | |
996 | } | |
997 | ||
c30ab7b3 SL |
998 | (PpmHir(s), Some(uii)) => { |
999 | let out: &mut Write = &mut out; | |
1000 | s.call_with_pp_support_hir(sess, | |
ea8adc8c | 1001 | cstore, |
32a655c1 | 1002 | hir_map, |
c30ab7b3 SL |
1003 | analysis, |
1004 | resolutions, | |
1005 | arenas, | |
ea8adc8c | 1006 | output_filenames, |
c30ab7b3 | 1007 | crate_name, |
041b39d2 | 1008 | move |annotation, _| { |
c30ab7b3 SL |
1009 | debug!("pretty printing source code {:?}", s); |
1010 | let sess = annotation.sess(); | |
2c00a5a8 | 1011 | let hir_map = annotation.hir_map().expect("-Z unpretty missing HIR map"); |
c30ab7b3 | 1012 | let mut pp_state = pprust_hir::State::new_from_input(sess.codemap(), |
32a655c1 | 1013 | &sess.parse_sess, |
ff7c6d11 | 1014 | src_name, |
c30ab7b3 SL |
1015 | &mut rdr, |
1016 | box out, | |
1017 | annotation.pp_ann(), | |
32a655c1 SL |
1018 | true); |
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)?; | |
041b39d2 | 1022 | pp_state.s.space()?; |
c30ab7b3 | 1023 | let path = annotation.node_path(node_id) |
2c00a5a8 | 1024 | .expect("-Z unpretty missing node paths"); |
c30ab7b3 | 1025 | pp_state.synth_comment(path)?; |
041b39d2 | 1026 | pp_state.s.hardbreak()?; |
c30ab7b3 | 1027 | } |
041b39d2 | 1028 | pp_state.s.eof() |
c30ab7b3 SL |
1029 | }) |
1030 | } | |
ff7c6d11 XL |
1031 | |
1032 | (PpmHirTree(s), Some(uii)) => { | |
1033 | let out: &mut Write = &mut out; | |
1034 | s.call_with_pp_support_hir(sess, | |
1035 | cstore, | |
1036 | hir_map, | |
1037 | analysis, | |
1038 | resolutions, | |
1039 | arenas, | |
1040 | output_filenames, | |
1041 | crate_name, | |
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)?; | |
1047 | } | |
1048 | Ok(()) | |
1049 | }) | |
1050 | } | |
1051 | ||
c30ab7b3 SL |
1052 | _ => unreachable!(), |
1053 | } | |
1054 | .unwrap(); | |
a7813a04 XL |
1055 | |
1056 | write_output(out, ofile); | |
1057 | } | |
1058 | ||
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, | |
ea8adc8c | 1064 | cstore: &'a CrateStore, |
32a655c1 | 1065 | hir_map: &hir_map::Map<'tcx>, |
8bb4bdeb | 1066 | analysis: &ty::CrateAnalysis, |
a7813a04 XL |
1067 | resolutions: &Resolutions, |
1068 | crate_name: &str, | |
ff7c6d11 | 1069 | arenas: &'tcx AllArenas<'tcx>, |
ea8adc8c | 1070 | output_filenames: &OutputFilenames, |
a7813a04 XL |
1071 | ppm: PpMode, |
1072 | uii: Option<UserIdentifiedItem>, | |
1073 | ofile: Option<&Path>) { | |
1074 | let nodeid = if let Some(uii) = uii { | |
1075 | debug!("pretty printing for {:?}", uii); | |
2c00a5a8 | 1076 | Some(uii.to_one_node_id("-Z unpretty", sess, &hir_map)) |
a7813a04 XL |
1077 | } else { |
1078 | debug!("pretty printing for whole crate"); | |
1079 | None | |
1080 | }; | |
1a4d82fc | 1081 | |
a7813a04 XL |
1082 | let mut out = Vec::new(); |
1083 | ||
abe05a73 | 1084 | let control = &driver::CompileController::basic(); |
2c00a5a8 XL |
1085 | let trans = ::get_trans(sess); |
1086 | abort_on_err(driver::phase_3_run_analysis_passes(&*trans, | |
1087 | control, | |
abe05a73 | 1088 | sess, |
ea8adc8c | 1089 | cstore, |
32a655c1 | 1090 | hir_map.clone(), |
a7813a04 XL |
1091 | analysis.clone(), |
1092 | resolutions.clone(), | |
1093 | arenas, | |
1094 | crate_name, | |
ea8adc8c | 1095 | output_filenames, |
c30ab7b3 | 1096 | |tcx, _, _, _| { |
a7813a04 XL |
1097 | match ppm { |
1098 | PpmMir | PpmMirCFG => { | |
c30ab7b3 | 1099 | if let Some(nodeid) = nodeid { |
32a655c1 | 1100 | let def_id = tcx.hir.local_def_id(nodeid); |
c30ab7b3 | 1101 | match ppm { |
7cac9316 XL |
1102 | PpmMir => write_mir_pretty(tcx, Some(def_id), &mut out), |
1103 | PpmMirCFG => write_mir_graphviz(tcx, Some(def_id), &mut out), | |
c30ab7b3 SL |
1104 | _ => unreachable!(), |
1105 | }?; | |
1106 | } else { | |
1107 | match ppm { | |
7cac9316 XL |
1108 | PpmMir => write_mir_pretty(tcx, None, &mut out), |
1109 | PpmMirCFG => write_mir_graphviz(tcx, None, &mut out), | |
c30ab7b3 SL |
1110 | _ => unreachable!(), |
1111 | }?; | |
7453a54e SL |
1112 | } |
1113 | Ok(()) | |
a7813a04 XL |
1114 | } |
1115 | PpmFlowGraph(mode) => { | |
c30ab7b3 SL |
1116 | let nodeid = |
1117 | nodeid.expect("`pretty flowgraph=..` needs NodeId (int) or unique path \ | |
1118 | suffix (b::c::d)"); | |
32a655c1 | 1119 | let node = tcx.hir.find(nodeid).unwrap_or_else(|| { |
a7813a04 XL |
1120 | tcx.sess.fatal(&format!("--pretty flowgraph couldn't find id: {}", nodeid)) |
1121 | }); | |
1a4d82fc | 1122 | |
32a655c1 | 1123 | match blocks::Code::from_node(&tcx.hir, nodeid) { |
a7813a04 XL |
1124 | Some(code) => { |
1125 | let variants = gather_flowgraph_variants(tcx.sess); | |
1a4d82fc | 1126 | |
a7813a04 | 1127 | let out: &mut Write = &mut out; |
1a4d82fc | 1128 | |
c30ab7b3 | 1129 | print_flowgraph(variants, tcx, code, mode, out) |
a7813a04 XL |
1130 | } |
1131 | None => { | |
c30ab7b3 SL |
1132 | let message = format!("--pretty=flowgraph needs block, fn, or method; \ |
1133 | got {:?}", | |
a7813a04 XL |
1134 | node); |
1135 | ||
32a655c1 | 1136 | tcx.sess.span_fatal(tcx.hir.span(nodeid), &message) |
1a4d82fc JJ |
1137 | } |
1138 | } | |
1139 | } | |
a7813a04 | 1140 | _ => unreachable!(), |
1a4d82fc | 1141 | } |
c30ab7b3 SL |
1142 | }), |
1143 | sess) | |
1144 | .unwrap(); | |
c34b1796 | 1145 | |
a7813a04 | 1146 | write_output(out, ofile); |
1a4d82fc | 1147 | } |