]> git.proxmox.com Git - rustc.git/blame - src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / src / tools / rust-analyzer / crates / hir-def / src / body / pretty.rs
CommitLineData
f2b60f7d
FG
1//! A pretty-printer for HIR.
2
3use std::fmt::{self, Write};
4
2b03887a
FG
5use syntax::ast::HasName;
6
f2b60f7d 7use crate::{
2b03887a 8 expr::{Array, BindingAnnotation, ClosureKind, Literal, Movability, Statement},
f2b60f7d
FG
9 pretty::{print_generic_args, print_path, print_type_ref},
10 type_ref::TypeRef,
11};
12
13use super::*;
14
15pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId) -> String {
16 let needs_semi;
17 let header = match owner {
18 DefWithBodyId::FunctionId(it) => {
19 needs_semi = false;
20 let item_tree_id = it.lookup(db).id;
21 format!("fn {}(…) ", item_tree_id.item_tree(db)[item_tree_id.value].name)
22 }
23 DefWithBodyId::StaticId(it) => {
24 needs_semi = true;
25 let item_tree_id = it.lookup(db).id;
26 format!("static {} = ", item_tree_id.item_tree(db)[item_tree_id.value].name)
27 }
28 DefWithBodyId::ConstId(it) => {
29 needs_semi = true;
30 let item_tree_id = it.lookup(db).id;
31 let name = match &item_tree_id.item_tree(db)[item_tree_id.value].name {
32 Some(name) => name.to_string(),
33 None => "_".to_string(),
34 };
6522a427 35 format!("const {name} = ")
f2b60f7d 36 }
2b03887a
FG
37 DefWithBodyId::VariantId(it) => {
38 needs_semi = false;
39 let src = it.parent.child_source(db);
40 let variant = &src.value[it.local_id];
41 let name = match &variant.name() {
42 Some(name) => name.to_string(),
43 None => "_".to_string(),
44 };
6522a427 45 format!("{name}")
2b03887a 46 }
f2b60f7d
FG
47 };
48
49 let mut p = Printer { body, buf: header, indent_level: 0, needs_indent: false };
50 p.print_expr(body.body_expr);
51 if needs_semi {
52 p.buf.push(';');
53 }
54 p.buf
55}
56
57macro_rules! w {
58 ($dst:expr, $($arg:tt)*) => {
59 { let _ = write!($dst, $($arg)*); }
60 };
61}
62
63macro_rules! wln {
64 ($dst:expr) => {
65 { let _ = writeln!($dst); }
66 };
67 ($dst:expr, $($arg:tt)*) => {
68 { let _ = writeln!($dst, $($arg)*); }
69 };
70}
71
72struct Printer<'a> {
73 body: &'a Body,
74 buf: String,
75 indent_level: usize,
76 needs_indent: bool,
77}
78
79impl<'a> Write for Printer<'a> {
80 fn write_str(&mut self, s: &str) -> fmt::Result {
81 for line in s.split_inclusive('\n') {
82 if self.needs_indent {
83 match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() {
84 Some('\n') | None => {}
85 _ => self.buf.push('\n'),
86 }
87 self.buf.push_str(&" ".repeat(self.indent_level));
88 self.needs_indent = false;
89 }
90
91 self.buf.push_str(line);
92 self.needs_indent = line.ends_with('\n');
93 }
94
95 Ok(())
96 }
97}
98
99impl<'a> Printer<'a> {
100 fn indented(&mut self, f: impl FnOnce(&mut Self)) {
101 self.indent_level += 1;
102 wln!(self);
103 f(self);
104 self.indent_level -= 1;
105 self.buf = self.buf.trim_end_matches('\n').to_string();
106 }
107
108 fn whitespace(&mut self) {
109 match self.buf.chars().next_back() {
110 None | Some('\n' | ' ') => {}
111 _ => self.buf.push(' '),
112 }
113 }
114
115 fn newline(&mut self) {
116 match self.buf.chars().rev().skip_while(|ch| *ch == ' ').next() {
117 Some('\n') | None => {}
118 _ => writeln!(self).unwrap(),
119 }
120 }
121
122 fn print_expr(&mut self, expr: ExprId) {
123 let expr = &self.body[expr];
124
125 match expr {
126 Expr::Missing => w!(self, "�"),
127 Expr::Underscore => w!(self, "_"),
128 Expr::Path(path) => self.print_path(path),
129 Expr::If { condition, then_branch, else_branch } => {
130 w!(self, "if ");
131 self.print_expr(*condition);
132 w!(self, " ");
133 self.print_expr(*then_branch);
134 if let Some(els) = *else_branch {
135 w!(self, " else ");
136 self.print_expr(els);
137 }
138 }
139 Expr::Let { pat, expr } => {
140 w!(self, "let ");
141 self.print_pat(*pat);
142 w!(self, " = ");
143 self.print_expr(*expr);
144 }
145 Expr::Loop { body, label } => {
146 if let Some(lbl) = label {
147 w!(self, "{}: ", self.body[*lbl].name);
148 }
149 w!(self, "loop ");
150 self.print_expr(*body);
151 }
152 Expr::While { condition, body, label } => {
153 if let Some(lbl) = label {
154 w!(self, "{}: ", self.body[*lbl].name);
155 }
156 w!(self, "while ");
157 self.print_expr(*condition);
158 self.print_expr(*body);
159 }
160 Expr::For { iterable, pat, body, label } => {
161 if let Some(lbl) = label {
162 w!(self, "{}: ", self.body[*lbl].name);
163 }
164 w!(self, "for ");
165 self.print_pat(*pat);
166 w!(self, " in ");
167 self.print_expr(*iterable);
168 self.print_expr(*body);
169 }
170 Expr::Call { callee, args, is_assignee_expr: _ } => {
171 self.print_expr(*callee);
172 w!(self, "(");
173 if !args.is_empty() {
174 self.indented(|p| {
175 for arg in &**args {
176 p.print_expr(*arg);
177 wln!(p, ",");
178 }
179 });
180 }
181 w!(self, ")");
182 }
183 Expr::MethodCall { receiver, method_name, args, generic_args } => {
184 self.print_expr(*receiver);
185 w!(self, ".{}", method_name);
186 if let Some(args) = generic_args {
187 w!(self, "::<");
188 print_generic_args(args, self).unwrap();
189 w!(self, ">");
190 }
191 w!(self, "(");
192 if !args.is_empty() {
193 self.indented(|p| {
194 for arg in &**args {
195 p.print_expr(*arg);
196 wln!(p, ",");
197 }
198 });
199 }
200 w!(self, ")");
201 }
202 Expr::Match { expr, arms } => {
203 w!(self, "match ");
204 self.print_expr(*expr);
205 w!(self, " {{");
206 self.indented(|p| {
207 for arm in &**arms {
208 p.print_pat(arm.pat);
209 if let Some(guard) = arm.guard {
210 w!(p, " if ");
211 p.print_expr(guard);
212 }
213 w!(p, " => ");
214 p.print_expr(arm.expr);
215 wln!(p, ",");
216 }
217 });
218 wln!(self, "}}");
219 }
220 Expr::Continue { label } => {
221 w!(self, "continue");
222 if let Some(label) = label {
223 w!(self, " {}", label);
224 }
225 }
226 Expr::Break { expr, label } => {
227 w!(self, "break");
228 if let Some(label) = label {
229 w!(self, " {}", label);
230 }
231 if let Some(expr) = expr {
232 self.whitespace();
233 self.print_expr(*expr);
234 }
235 }
236 Expr::Return { expr } => {
237 w!(self, "return");
238 if let Some(expr) = expr {
239 self.whitespace();
240 self.print_expr(*expr);
241 }
242 }
243 Expr::Yield { expr } => {
244 w!(self, "yield");
245 if let Some(expr) = expr {
246 self.whitespace();
247 self.print_expr(*expr);
248 }
249 }
6522a427
EL
250 Expr::Yeet { expr } => {
251 w!(self, "do");
252 self.whitespace();
253 w!(self, "yeet");
254 if let Some(expr) = expr {
255 self.whitespace();
256 self.print_expr(*expr);
257 }
258 }
f2b60f7d
FG
259 Expr::RecordLit { path, fields, spread, ellipsis, is_assignee_expr: _ } => {
260 match path {
261 Some(path) => self.print_path(path),
262 None => w!(self, "�"),
263 }
264
265 w!(self, "{{");
266 self.indented(|p| {
267 for field in &**fields {
268 w!(p, "{}: ", field.name);
269 p.print_expr(field.expr);
270 wln!(p, ",");
271 }
272 if let Some(spread) = spread {
273 w!(p, "..");
274 p.print_expr(*spread);
275 wln!(p);
276 }
277 if *ellipsis {
278 wln!(p, "..");
279 }
280 });
281 w!(self, "}}");
282 }
283 Expr::Field { expr, name } => {
284 self.print_expr(*expr);
285 w!(self, ".{}", name);
286 }
287 Expr::Await { expr } => {
288 self.print_expr(*expr);
289 w!(self, ".await");
290 }
291 Expr::Try { expr } => {
292 self.print_expr(*expr);
293 w!(self, "?");
294 }
295 Expr::TryBlock { body } => {
296 w!(self, "try ");
297 self.print_expr(*body);
298 }
299 Expr::Async { body } => {
300 w!(self, "async ");
301 self.print_expr(*body);
302 }
303 Expr::Const { body } => {
304 w!(self, "const ");
305 self.print_expr(*body);
306 }
307 Expr::Cast { expr, type_ref } => {
308 self.print_expr(*expr);
309 w!(self, " as ");
310 self.print_type_ref(type_ref);
311 }
312 Expr::Ref { expr, rawness, mutability } => {
313 w!(self, "&");
314 if rawness.is_raw() {
315 w!(self, "raw ");
316 }
317 if mutability.is_mut() {
318 w!(self, "mut ");
319 }
320 self.print_expr(*expr);
321 }
322 Expr::Box { expr } => {
323 w!(self, "box ");
324 self.print_expr(*expr);
325 }
326 Expr::UnaryOp { expr, op } => {
327 let op = match op {
328 ast::UnaryOp::Deref => "*",
329 ast::UnaryOp::Not => "!",
330 ast::UnaryOp::Neg => "-",
331 };
332 w!(self, "{}", op);
333 self.print_expr(*expr);
334 }
335 Expr::BinaryOp { lhs, rhs, op } => {
336 let (bra, ket) = match op {
337 None | Some(ast::BinaryOp::Assignment { .. }) => ("", ""),
338 _ => ("(", ")"),
339 };
340 w!(self, "{}", bra);
341 self.print_expr(*lhs);
342 w!(self, "{} ", ket);
343 match op {
344 Some(op) => w!(self, "{}", op),
345 None => w!(self, "�"), // :)
346 }
347 w!(self, " {}", bra);
348 self.print_expr(*rhs);
349 w!(self, "{}", ket);
350 }
351 Expr::Range { lhs, rhs, range_type } => {
352 if let Some(lhs) = lhs {
353 w!(self, "(");
354 self.print_expr(*lhs);
355 w!(self, ") ");
356 }
357 let range = match range_type {
358 ast::RangeOp::Exclusive => "..",
359 ast::RangeOp::Inclusive => "..=",
360 };
361 w!(self, "{}", range);
362 if let Some(rhs) = rhs {
363 w!(self, "(");
364 self.print_expr(*rhs);
365 w!(self, ") ");
366 }
367 }
368 Expr::Index { base, index } => {
369 self.print_expr(*base);
370 w!(self, "[");
371 self.print_expr(*index);
372 w!(self, "]");
373 }
2b03887a
FG
374 Expr::Closure { args, arg_types, ret_type, body, closure_kind } => {
375 if let ClosureKind::Generator(Movability::Static) = closure_kind {
376 w!(self, "static ");
377 }
f2b60f7d
FG
378 w!(self, "|");
379 for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
380 if i != 0 {
381 w!(self, ", ");
382 }
383 self.print_pat(*pat);
384 if let Some(ty) = ty {
385 w!(self, ": ");
386 self.print_type_ref(ty);
387 }
388 }
389 w!(self, "|");
390 if let Some(ret_ty) = ret_type {
391 w!(self, " -> ");
392 self.print_type_ref(ret_ty);
393 }
394 self.whitespace();
395 self.print_expr(*body);
396 }
397 Expr::Tuple { exprs, is_assignee_expr: _ } => {
398 w!(self, "(");
399 for expr in exprs.iter() {
400 self.print_expr(*expr);
401 w!(self, ", ");
402 }
403 w!(self, ")");
404 }
405 Expr::Unsafe { body } => {
406 w!(self, "unsafe ");
407 self.print_expr(*body);
408 }
409 Expr::Array(arr) => {
410 w!(self, "[");
411 if !matches!(arr, Array::ElementList { elements, .. } if elements.is_empty()) {
412 self.indented(|p| match arr {
413 Array::ElementList { elements, is_assignee_expr: _ } => {
414 for elem in elements.iter() {
415 p.print_expr(*elem);
416 w!(p, ", ");
417 }
418 }
419 Array::Repeat { initializer, repeat } => {
420 p.print_expr(*initializer);
421 w!(p, "; ");
422 p.print_expr(*repeat);
423 }
424 });
425 self.newline();
426 }
427 w!(self, "]");
428 }
429 Expr::Literal(lit) => self.print_literal(lit),
430 Expr::Block { id: _, statements, tail, label } => {
431 self.whitespace();
432 if let Some(lbl) = label {
433 w!(self, "{}: ", self.body[*lbl].name);
434 }
435 w!(self, "{{");
436 if !statements.is_empty() || tail.is_some() {
437 self.indented(|p| {
438 for stmt in &**statements {
439 p.print_stmt(stmt);
440 }
441 if let Some(tail) = tail {
442 p.print_expr(*tail);
443 }
444 p.newline();
445 });
446 }
447 w!(self, "}}");
448 }
449 }
450 }
451
452 fn print_pat(&mut self, pat: PatId) {
453 let pat = &self.body[pat];
454
455 match pat {
456 Pat::Missing => w!(self, "�"),
457 Pat::Wild => w!(self, "_"),
458 Pat::Tuple { args, ellipsis } => {
459 w!(self, "(");
460 for (i, pat) in args.iter().enumerate() {
461 if i != 0 {
462 w!(self, ", ");
463 }
464 if *ellipsis == Some(i) {
465 w!(self, ".., ");
466 }
467 self.print_pat(*pat);
468 }
469 w!(self, ")");
470 }
471 Pat::Or(pats) => {
472 for (i, pat) in pats.iter().enumerate() {
473 if i != 0 {
474 w!(self, " | ");
475 }
476 self.print_pat(*pat);
477 }
478 }
479 Pat::Record { path, args, ellipsis } => {
480 match path {
481 Some(path) => self.print_path(path),
482 None => w!(self, "�"),
483 }
484
485 w!(self, " {{");
486 self.indented(|p| {
487 for arg in args.iter() {
488 w!(p, "{}: ", arg.name);
489 p.print_pat(arg.pat);
490 wln!(p, ",");
491 }
492 if *ellipsis {
493 wln!(p, "..");
494 }
495 });
496 w!(self, "}}");
497 }
498 Pat::Range { start, end } => {
499 self.print_expr(*start);
500 w!(self, "...");
501 self.print_expr(*end);
502 }
503 Pat::Slice { prefix, slice, suffix } => {
504 w!(self, "[");
505 for pat in prefix.iter() {
506 self.print_pat(*pat);
507 w!(self, ", ");
508 }
509 if let Some(pat) = slice {
510 self.print_pat(*pat);
511 w!(self, ", ");
512 }
513 for pat in suffix.iter() {
514 self.print_pat(*pat);
515 w!(self, ", ");
516 }
517 w!(self, "]");
518 }
519 Pat::Path(path) => self.print_path(path),
520 Pat::Lit(expr) => self.print_expr(*expr),
521 Pat::Bind { mode, name, subpat } => {
522 let mode = match mode {
523 BindingAnnotation::Unannotated => "",
524 BindingAnnotation::Mutable => "mut ",
525 BindingAnnotation::Ref => "ref ",
526 BindingAnnotation::RefMut => "ref mut ",
527 };
528 w!(self, "{}{}", mode, name);
529 if let Some(pat) = subpat {
530 self.whitespace();
531 self.print_pat(*pat);
532 }
533 }
534 Pat::TupleStruct { path, args, ellipsis } => {
535 match path {
536 Some(path) => self.print_path(path),
537 None => w!(self, "�"),
538 }
539 w!(self, "(");
540 for (i, arg) in args.iter().enumerate() {
541 if i != 0 {
542 w!(self, ", ");
543 }
544 if *ellipsis == Some(i) {
545 w!(self, ", ..");
546 }
547 self.print_pat(*arg);
548 }
549 w!(self, ")");
550 }
551 Pat::Ref { pat, mutability } => {
552 w!(self, "&");
553 if mutability.is_mut() {
554 w!(self, "mut ");
555 }
556 self.print_pat(*pat);
557 }
558 Pat::Box { inner } => {
559 w!(self, "box ");
560 self.print_pat(*inner);
561 }
562 Pat::ConstBlock(c) => {
563 w!(self, "const ");
564 self.print_expr(*c);
565 }
566 }
567 }
568
569 fn print_stmt(&mut self, stmt: &Statement) {
570 match stmt {
571 Statement::Let { pat, type_ref, initializer, else_branch } => {
572 w!(self, "let ");
573 self.print_pat(*pat);
574 if let Some(ty) = type_ref {
575 w!(self, ": ");
576 self.print_type_ref(ty);
577 }
578 if let Some(init) = initializer {
579 w!(self, " = ");
580 self.print_expr(*init);
581 }
582 if let Some(els) = else_branch {
583 w!(self, " else ");
584 self.print_expr(*els);
585 }
586 wln!(self, ";");
587 }
588 Statement::Expr { expr, has_semi } => {
589 self.print_expr(*expr);
590 if *has_semi {
591 w!(self, ";");
592 }
593 wln!(self);
594 }
595 }
596 }
597
598 fn print_literal(&mut self, literal: &Literal) {
599 match literal {
600 Literal::String(it) => w!(self, "{:?}", it),
601 Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()),
602 Literal::Char(it) => w!(self, "'{}'", it.escape_debug()),
603 Literal::Bool(it) => w!(self, "{}", it),
604 Literal::Int(i, suffix) => {
605 w!(self, "{}", i);
606 if let Some(suffix) = suffix {
607 w!(self, "{}", suffix);
608 }
609 }
610 Literal::Uint(i, suffix) => {
611 w!(self, "{}", i);
612 if let Some(suffix) = suffix {
613 w!(self, "{}", suffix);
614 }
615 }
616 Literal::Float(f, suffix) => {
617 w!(self, "{}", f);
618 if let Some(suffix) = suffix {
619 w!(self, "{}", suffix);
620 }
621 }
622 }
623 }
624
625 fn print_type_ref(&mut self, ty: &TypeRef) {
626 print_type_ref(ty, self).unwrap();
627 }
628
629 fn print_path(&mut self, path: &Path) {
630 print_path(path, self).unwrap();
631 }
632}