]> git.lizzy.rs Git - rust.git/blob - crates/hir_def/src/item_tree/pretty.rs
Merge #8932
[rust.git] / crates / hir_def / src / item_tree / pretty.rs
1 //! `ItemTree` debug printer.
2
3 use std::fmt::{self, Write};
4
5 use crate::{
6     attr::RawAttrs,
7     generics::{WherePredicate, WherePredicateTypeTarget},
8     path::GenericArg,
9     visibility::RawVisibility,
10 };
11
12 use super::*;
13
14 pub(super) fn print_item_tree(tree: &ItemTree) -> String {
15     let mut p = Printer { tree, buf: String::new(), indent_level: 0, needs_indent: true };
16
17     if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
18         p.print_attrs(attrs, true);
19     }
20     p.blank();
21
22     for item in tree.top_level_items() {
23         p.print_mod_item(*item);
24     }
25
26     let mut s = p.buf.trim_end_matches('\n').to_string();
27     s.push('\n');
28     s
29 }
30
31 macro_rules! w {
32     ($dst:expr, $($arg:tt)*) => {
33         drop(write!($dst, $($arg)*))
34     };
35 }
36
37 macro_rules! wln {
38     ($dst:expr) => {
39         drop(writeln!($dst))
40     };
41     ($dst:expr, $($arg:tt)*) => {
42         drop(writeln!($dst, $($arg)*))
43     };
44 }
45
46 struct Printer<'a> {
47     tree: &'a ItemTree,
48     buf: String,
49     indent_level: usize,
50     needs_indent: bool,
51 }
52
53 impl<'a> Printer<'a> {
54     fn indented(&mut self, f: impl FnOnce(&mut Self)) {
55         self.indent_level += 1;
56         wln!(self);
57         f(self);
58         self.indent_level -= 1;
59         self.buf = self.buf.trim_end_matches('\n').to_string();
60     }
61
62     /// Ensures that a blank line is output before the next text.
63     fn blank(&mut self) {
64         let mut iter = self.buf.chars().rev().fuse();
65         match (iter.next(), iter.next()) {
66             (Some('\n'), Some('\n')) | (Some('\n'), None) | (None, None) => {}
67             (Some('\n'), Some(_)) => {
68                 self.buf.push('\n');
69             }
70             (Some(_), _) => {
71                 self.buf.push('\n');
72                 self.buf.push('\n');
73             }
74             (None, Some(_)) => unreachable!(),
75         }
76     }
77
78     fn whitespace(&mut self) {
79         match self.buf.chars().next_back() {
80             None | Some('\n') | Some(' ') => {}
81             _ => self.buf.push(' '),
82         }
83     }
84
85     fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool) {
86         let inner = if inner { "!" } else { "" };
87         for attr in &**attrs {
88             wln!(
89                 self,
90                 "#{}[{}{}]  // {:?}",
91                 inner,
92                 attr.path,
93                 attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(),
94                 attr.id,
95             );
96         }
97     }
98
99     fn print_attrs_of(&mut self, of: impl Into<AttrOwner>) {
100         if let Some(attrs) = self.tree.attrs.get(&of.into()) {
101             self.print_attrs(attrs, false);
102         }
103     }
104
105     fn print_visibility(&mut self, vis: RawVisibilityId) {
106         match &self.tree[vis] {
107             RawVisibility::Module(path) => w!(self, "pub({}) ", path),
108             RawVisibility::Public => w!(self, "pub "),
109         };
110     }
111
112     fn print_fields(&mut self, fields: &Fields) {
113         match fields {
114             Fields::Record(fields) => {
115                 self.whitespace();
116                 w!(self, "{{");
117                 self.indented(|this| {
118                     for field in fields.clone() {
119                         let Field { visibility, name, type_ref } = &this.tree[field];
120                         this.print_attrs_of(field);
121                         this.print_visibility(*visibility);
122                         w!(this, "{}: ", name);
123                         this.print_type_ref(type_ref);
124                         wln!(this, ",");
125                     }
126                 });
127                 w!(self, "}}");
128             }
129             Fields::Tuple(fields) => {
130                 w!(self, "(");
131                 self.indented(|this| {
132                     for field in fields.clone() {
133                         let Field { visibility, name, type_ref } = &this.tree[field];
134                         this.print_attrs_of(field);
135                         this.print_visibility(*visibility);
136                         w!(this, "{}: ", name);
137                         this.print_type_ref(type_ref);
138                         wln!(this, ",");
139                     }
140                 });
141                 w!(self, ")");
142             }
143             Fields::Unit => {}
144         }
145     }
146
147     fn print_fields_and_where_clause(&mut self, fields: &Fields, params: &GenericParams) {
148         match fields {
149             Fields::Record(_) => {
150                 if self.print_where_clause(params) {
151                     wln!(self);
152                 }
153                 self.print_fields(fields);
154             }
155             Fields::Unit => {
156                 self.print_where_clause(params);
157                 self.print_fields(fields);
158             }
159             Fields::Tuple(_) => {
160                 self.print_fields(fields);
161                 self.print_where_clause(params);
162             }
163         }
164     }
165
166     fn print_mod_item(&mut self, item: ModItem) {
167         self.print_attrs_of(item);
168
169         match item {
170             ModItem::Import(it) => {
171                 let Import { visibility, path, is_glob, alias, ast_id: _, index } = &self.tree[it];
172                 self.print_visibility(*visibility);
173                 w!(self, "use {}", path);
174                 if *is_glob {
175                     w!(self, "::*");
176                 }
177                 if let Some(alias) = alias {
178                     w!(self, " as {}", alias);
179                 }
180                 wln!(self, ";  // {}", index);
181             }
182             ModItem::ExternCrate(it) => {
183                 let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it];
184                 self.print_visibility(*visibility);
185                 w!(self, "extern crate {}", name);
186                 if let Some(alias) = alias {
187                     w!(self, " as {}", alias);
188                 }
189                 wln!(self, ";");
190             }
191             ModItem::ExternBlock(it) => {
192                 let ExternBlock { abi, ast_id: _, children } = &self.tree[it];
193                 w!(self, "extern ");
194                 if let Some(abi) = abi {
195                     w!(self, "\"{}\" ", abi);
196                 }
197                 w!(self, "{{");
198                 self.indented(|this| {
199                     for child in &**children {
200                         this.print_mod_item(*child);
201                     }
202                 });
203                 wln!(self, "}}");
204             }
205             ModItem::Function(it) => {
206                 let Function {
207                     name,
208                     visibility,
209                     generic_params,
210                     abi,
211                     params,
212                     ret_type,
213                     ast_id: _,
214                     flags,
215                 } = &self.tree[it];
216                 if flags.bits != 0 {
217                     wln!(self, "// flags = 0x{:X}", flags.bits);
218                 }
219                 self.print_visibility(*visibility);
220                 if let Some(abi) = abi {
221                     w!(self, "extern \"{}\" ", abi);
222                 }
223                 w!(self, "fn {}", name);
224                 self.print_generic_params(generic_params);
225                 w!(self, "(");
226                 if !params.is_empty() {
227                     self.indented(|this| {
228                         for param in params.clone() {
229                             this.print_attrs_of(param);
230                             match &this.tree[param] {
231                                 Param::Normal(ty) => {
232                                     w!(this, "_: ");
233                                     this.print_type_ref(ty);
234                                     wln!(this, ",");
235                                 }
236                                 Param::Varargs => {
237                                     wln!(this, "...");
238                                 }
239                             };
240                         }
241                     });
242                 }
243                 w!(self, ") -> ");
244                 self.print_type_ref(ret_type);
245                 self.print_where_clause(generic_params);
246                 wln!(self, ";");
247             }
248             ModItem::Struct(it) => {
249                 let Struct { visibility, name, fields, generic_params, ast_id: _ } = &self.tree[it];
250                 self.print_visibility(*visibility);
251                 w!(self, "struct {}", name);
252                 self.print_generic_params(generic_params);
253                 self.print_fields_and_where_clause(fields, generic_params);
254                 if matches!(fields, Fields::Record(_)) {
255                     wln!(self);
256                 } else {
257                     wln!(self, ";");
258                 }
259             }
260             ModItem::Union(it) => {
261                 let Union { name, visibility, fields, generic_params, ast_id: _ } = &self.tree[it];
262                 self.print_visibility(*visibility);
263                 w!(self, "union {}", name);
264                 self.print_generic_params(generic_params);
265                 self.print_fields_and_where_clause(fields, generic_params);
266                 if matches!(fields, Fields::Record(_)) {
267                     wln!(self);
268                 } else {
269                     wln!(self, ";");
270                 }
271             }
272             ModItem::Enum(it) => {
273                 let Enum { name, visibility, variants, generic_params, ast_id: _ } = &self.tree[it];
274                 self.print_visibility(*visibility);
275                 w!(self, "enum {}", name);
276                 self.print_generic_params(generic_params);
277                 self.print_where_clause_and_opening_brace(generic_params);
278                 self.indented(|this| {
279                     for variant in variants.clone() {
280                         let Variant { name, fields } = &this.tree[variant];
281                         this.print_attrs_of(variant);
282                         w!(this, "{}", name);
283                         this.print_fields(fields);
284                         wln!(this, ",");
285                     }
286                 });
287                 wln!(self, "}}");
288             }
289             ModItem::Const(it) => {
290                 let Const { name, visibility, type_ref, ast_id: _ } = &self.tree[it];
291                 self.print_visibility(*visibility);
292                 w!(self, "const ");
293                 match name {
294                     Some(name) => w!(self, "{}", name),
295                     None => w!(self, "_"),
296                 }
297                 w!(self, ": ");
298                 self.print_type_ref(type_ref);
299                 wln!(self, " = _;");
300             }
301             ModItem::Static(it) => {
302                 let Static { name, visibility, mutable, is_extern, type_ref, ast_id: _ } =
303                     &self.tree[it];
304                 self.print_visibility(*visibility);
305                 w!(self, "static ");
306                 if *mutable {
307                     w!(self, "mut ");
308                 }
309                 w!(self, "{}: ", name);
310                 self.print_type_ref(type_ref);
311                 w!(self, " = _;");
312                 if *is_extern {
313                     w!(self, "  // extern");
314                 }
315                 wln!(self);
316             }
317             ModItem::Trait(it) => {
318                 let Trait {
319                     name,
320                     visibility,
321                     is_auto,
322                     is_unsafe,
323                     bounds,
324                     items,
325                     generic_params,
326                     ast_id: _,
327                 } = &self.tree[it];
328                 self.print_visibility(*visibility);
329                 if *is_unsafe {
330                     w!(self, "unsafe ");
331                 }
332                 if *is_auto {
333                     w!(self, "auto ");
334                 }
335                 w!(self, "trait {}", name);
336                 self.print_generic_params(generic_params);
337                 if !bounds.is_empty() {
338                     w!(self, ": ");
339                     self.print_type_bounds(bounds);
340                 }
341                 self.print_where_clause_and_opening_brace(generic_params);
342                 self.indented(|this| {
343                     for item in &**items {
344                         this.print_mod_item((*item).into());
345                     }
346                 });
347                 wln!(self, "}}");
348             }
349             ModItem::Impl(it) => {
350                 let Impl { target_trait, self_ty, is_negative, items, generic_params, ast_id: _ } =
351                     &self.tree[it];
352                 w!(self, "impl");
353                 self.print_generic_params(generic_params);
354                 w!(self, " ");
355                 if *is_negative {
356                     w!(self, "!");
357                 }
358                 if let Some(tr) = target_trait {
359                     self.print_path(&tr.path);
360                     w!(self, " for ");
361                 }
362                 self.print_type_ref(self_ty);
363                 self.print_where_clause_and_opening_brace(generic_params);
364                 self.indented(|this| {
365                     for item in &**items {
366                         this.print_mod_item((*item).into());
367                     }
368                 });
369                 wln!(self, "}}");
370             }
371             ModItem::TypeAlias(it) => {
372                 let TypeAlias {
373                     name,
374                     visibility,
375                     bounds,
376                     type_ref,
377                     is_extern,
378                     generic_params,
379                     ast_id: _,
380                 } = &self.tree[it];
381                 self.print_visibility(*visibility);
382                 w!(self, "type {}", name);
383                 self.print_generic_params(generic_params);
384                 if !bounds.is_empty() {
385                     w!(self, ": ");
386                     self.print_type_bounds(bounds);
387                 }
388                 if let Some(ty) = type_ref {
389                     w!(self, " = ");
390                     self.print_type_ref(ty);
391                 }
392                 self.print_where_clause(generic_params);
393                 w!(self, ";");
394                 if *is_extern {
395                     w!(self, "  // extern");
396                 }
397                 wln!(self);
398             }
399             ModItem::Mod(it) => {
400                 let Mod { name, visibility, kind, ast_id: _ } = &self.tree[it];
401                 self.print_visibility(*visibility);
402                 w!(self, "mod {}", name);
403                 match kind {
404                     ModKind::Inline { items } => {
405                         w!(self, " {{");
406                         self.indented(|this| {
407                             for item in &**items {
408                                 this.print_mod_item((*item).into());
409                             }
410                         });
411                         wln!(self, "}}");
412                     }
413                     ModKind::Outline {} => {
414                         wln!(self, ";");
415                     }
416                 }
417             }
418             ModItem::MacroCall(it) => {
419                 let MacroCall { path, ast_id: _, fragment: _ } = &self.tree[it];
420                 wln!(self, "{}!(...);", path);
421             }
422             ModItem::MacroRules(it) => {
423                 let MacroRules { name, ast_id: _ } = &self.tree[it];
424                 wln!(self, "macro_rules! {} {{ ... }}", name);
425             }
426             ModItem::MacroDef(it) => {
427                 let MacroDef { name, visibility, ast_id: _ } = &self.tree[it];
428                 self.print_visibility(*visibility);
429                 wln!(self, "macro {} {{ ... }}", name);
430             }
431         }
432
433         self.blank();
434     }
435
436     fn print_type_ref(&mut self, type_ref: &TypeRef) {
437         // FIXME: deduplicate with `HirDisplay` impl
438         match type_ref {
439             TypeRef::Never => w!(self, "!"),
440             TypeRef::Placeholder => w!(self, "_"),
441             TypeRef::Tuple(fields) => {
442                 w!(self, "(");
443                 for (i, field) in fields.iter().enumerate() {
444                     if i != 0 {
445                         w!(self, ", ");
446                     }
447                     self.print_type_ref(field);
448                 }
449                 w!(self, ")");
450             }
451             TypeRef::Path(path) => self.print_path(path),
452             TypeRef::RawPtr(pointee, mtbl) => {
453                 let mtbl = match mtbl {
454                     Mutability::Shared => "*const",
455                     Mutability::Mut => "*mut",
456                 };
457                 w!(self, "{} ", mtbl);
458                 self.print_type_ref(pointee);
459             }
460             TypeRef::Reference(pointee, lt, mtbl) => {
461                 let mtbl = match mtbl {
462                     Mutability::Shared => "",
463                     Mutability::Mut => "mut ",
464                 };
465                 w!(self, "&");
466                 if let Some(lt) = lt {
467                     w!(self, "{} ", lt.name);
468                 }
469                 w!(self, "{}", mtbl);
470                 self.print_type_ref(pointee);
471             }
472             TypeRef::Array(elem, len) => {
473                 w!(self, "[");
474                 self.print_type_ref(elem);
475                 w!(self, "; {}]", len);
476             }
477             TypeRef::Slice(elem) => {
478                 w!(self, "[");
479                 self.print_type_ref(elem);
480                 w!(self, "]");
481             }
482             TypeRef::Fn(args_and_ret, varargs) => {
483                 let (ret, args) =
484                     args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
485                 w!(self, "fn(");
486                 for (i, arg) in args.iter().enumerate() {
487                     if i != 0 {
488                         w!(self, ", ");
489                     }
490                     self.print_type_ref(arg);
491                 }
492                 if *varargs {
493                     if !args.is_empty() {
494                         w!(self, ", ");
495                     }
496                     w!(self, "...");
497                 }
498                 w!(self, ") -> ");
499                 self.print_type_ref(ret);
500             }
501             TypeRef::Macro(_ast_id) => {
502                 w!(self, "<macro>");
503             }
504             TypeRef::Error => w!(self, "{{unknown}}"),
505             TypeRef::ImplTrait(bounds) => {
506                 w!(self, "impl ");
507                 self.print_type_bounds(bounds);
508             }
509             TypeRef::DynTrait(bounds) => {
510                 w!(self, "dyn ");
511                 self.print_type_bounds(bounds);
512             }
513         }
514     }
515
516     fn print_type_bounds(&mut self, bounds: &[TypeBound]) {
517         for (i, bound) in bounds.iter().enumerate() {
518             if i != 0 {
519                 w!(self, " + ");
520             }
521
522             match bound {
523                 TypeBound::Path(path) => self.print_path(path),
524                 TypeBound::Lifetime(lt) => w!(self, "{}", lt.name),
525                 TypeBound::Error => w!(self, "{{unknown}}"),
526             }
527         }
528     }
529
530     fn print_path(&mut self, path: &Path) {
531         match path.type_anchor() {
532             Some(anchor) => {
533                 w!(self, "<");
534                 self.print_type_ref(anchor);
535                 w!(self, ">::");
536             }
537             None => match path.kind() {
538                 PathKind::Plain => {}
539                 PathKind::Super(0) => w!(self, "self::"),
540                 PathKind::Super(n) => {
541                     for _ in 0..*n {
542                         w!(self, "super::");
543                     }
544                 }
545                 PathKind::Crate => w!(self, "crate::"),
546                 PathKind::Abs => w!(self, "::"),
547                 PathKind::DollarCrate(_) => w!(self, "$crate::"),
548             },
549         }
550
551         for (i, segment) in path.segments().iter().enumerate() {
552             if i != 0 {
553                 w!(self, "::");
554             }
555
556             w!(self, "{}", segment.name);
557             if let Some(generics) = segment.args_and_bindings {
558                 // NB: these are all in type position, so `::<` turbofish syntax is not necessary
559                 w!(self, "<");
560                 let mut first = true;
561                 let args = if generics.has_self_type {
562                     let (self_ty, args) = generics.args.split_first().unwrap();
563                     w!(self, "Self=");
564                     self.print_generic_arg(self_ty);
565                     first = false;
566                     args
567                 } else {
568                     &generics.args
569                 };
570                 for arg in args {
571                     if !first {
572                         w!(self, ", ");
573                     }
574                     first = false;
575                     self.print_generic_arg(arg);
576                 }
577                 for binding in &generics.bindings {
578                     if !first {
579                         w!(self, ", ");
580                     }
581                     first = false;
582                     w!(self, "{}", binding.name);
583                     if !binding.bounds.is_empty() {
584                         w!(self, ": ");
585                         self.print_type_bounds(&binding.bounds);
586                     }
587                     if let Some(ty) = &binding.type_ref {
588                         w!(self, " = ");
589                         self.print_type_ref(ty);
590                     }
591                 }
592
593                 w!(self, ">");
594             }
595         }
596     }
597
598     fn print_generic_arg(&mut self, arg: &GenericArg) {
599         match arg {
600             GenericArg::Type(ty) => self.print_type_ref(ty),
601             GenericArg::Lifetime(lt) => w!(self, "{}", lt.name),
602         }
603     }
604
605     fn print_generic_params(&mut self, params: &GenericParams) {
606         if params.types.is_empty() && params.lifetimes.is_empty() && params.consts.is_empty() {
607             return;
608         }
609
610         w!(self, "<");
611         let mut first = true;
612         for (_, lt) in params.lifetimes.iter() {
613             if !first {
614                 w!(self, ", ");
615             }
616             first = false;
617             w!(self, "{}", lt.name);
618         }
619         for (idx, ty) in params.types.iter() {
620             if !first {
621                 w!(self, ", ");
622             }
623             first = false;
624             match &ty.name {
625                 Some(name) => w!(self, "{}", name),
626                 None => w!(self, "_anon_{}", idx.into_raw()),
627             }
628         }
629         for (_, konst) in params.consts.iter() {
630             if !first {
631                 w!(self, ", ");
632             }
633             first = false;
634             w!(self, "const {}: ", konst.name);
635             self.print_type_ref(&konst.ty);
636         }
637         w!(self, ">");
638     }
639
640     fn print_where_clause_and_opening_brace(&mut self, params: &GenericParams) {
641         if self.print_where_clause(params) {
642             w!(self, "\n{{");
643         } else {
644             self.whitespace();
645             w!(self, "{{");
646         }
647     }
648
649     fn print_where_clause(&mut self, params: &GenericParams) -> bool {
650         if params.where_predicates.is_empty() {
651             return false;
652         }
653
654         w!(self, "\nwhere");
655         self.indented(|this| {
656             for (i, pred) in params.where_predicates.iter().enumerate() {
657                 if i != 0 {
658                     wln!(this, ",");
659                 }
660
661                 let (target, bound) = match pred {
662                     WherePredicate::TypeBound { target, bound } => (target, bound),
663                     WherePredicate::Lifetime { target, bound } => {
664                         wln!(this, "{}: {},", target.name, bound.name);
665                         continue;
666                     }
667                     WherePredicate::ForLifetime { lifetimes, target, bound } => {
668                         w!(this, "for<");
669                         for (i, lt) in lifetimes.iter().enumerate() {
670                             if i != 0 {
671                                 w!(this, ", ");
672                             }
673                             w!(this, "{}", lt);
674                         }
675                         w!(this, "> ");
676                         (target, bound)
677                     }
678                 };
679
680                 match target {
681                     WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
682                     WherePredicateTypeTarget::TypeParam(id) => match &params.types[*id].name {
683                         Some(name) => w!(this, "{}", name),
684                         None => w!(this, "_anon_{}", id.into_raw()),
685                     },
686                 }
687                 w!(this, ": ");
688                 this.print_type_bounds(std::slice::from_ref(bound));
689             }
690         });
691         true
692     }
693 }
694
695 impl<'a> Write for Printer<'a> {
696     fn write_str(&mut self, s: &str) -> fmt::Result {
697         for line in s.split_inclusive('\n') {
698             if self.needs_indent {
699                 match self.buf.chars().last() {
700                     Some('\n') | None => {}
701                     _ => self.buf.push('\n'),
702                 }
703                 self.buf.push_str(&"    ".repeat(self.indent_level));
704                 self.needs_indent = false;
705             }
706
707             self.buf.push_str(line);
708             self.needs_indent = line.ends_with('\n');
709         }
710
711         Ok(())
712     }
713 }