]> git.lizzy.rs Git - rust.git/blob - src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
Auto merge of #107843 - bjorn3:sync_cg_clif-2023-02-09, r=bjorn3
[rust.git] / src / tools / rust-analyzer / crates / hir-def / src / body / pretty.rs
1 //! A pretty-printer for HIR.
2
3 use std::fmt::{self, Write};
4
5 use syntax::ast::HasName;
6
7 use crate::{
8     expr::{Array, BindingAnnotation, ClosureKind, Literal, Movability, Statement},
9     pretty::{print_generic_args, print_path, print_type_ref},
10     type_ref::TypeRef,
11 };
12
13 use super::*;
14
15 pub(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             };
35             format!("const {name} = ")
36         }
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             };
45             format!("{name}")
46         }
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
57 macro_rules! w {
58     ($dst:expr, $($arg:tt)*) => {
59         { let _ = write!($dst, $($arg)*); }
60     };
61 }
62
63 macro_rules! wln {
64     ($dst:expr) => {
65         { let _ = writeln!($dst); }
66     };
67     ($dst:expr, $($arg:tt)*) => {
68         { let _ = writeln!($dst, $($arg)*); }
69     };
70 }
71
72 struct Printer<'a> {
73     body: &'a Body,
74     buf: String,
75     indent_level: usize,
76     needs_indent: bool,
77 }
78
79 impl<'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
99 impl<'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             }
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             }
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             }
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                 }
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 }