]> git.lizzy.rs Git - rust.git/blob - crates/hir_def/src/item_tree/pretty.rs
Merge #9264
[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') | 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' | ' ') => {}
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_use_tree(&mut self, use_tree: &UseTree) {
167         match &use_tree.kind {
168             UseTreeKind::Single { path, alias } => {
169                 w!(self, "{}", path);
170                 if let Some(alias) = alias {
171                     w!(self, " as {}", alias);
172                 }
173             }
174             UseTreeKind::Glob { path } => {
175                 if let Some(path) = path {
176                     w!(self, "{}::", path);
177                 }
178                 w!(self, "*");
179             }
180             UseTreeKind::Prefixed { prefix, list } => {
181                 if let Some(prefix) = prefix {
182                     w!(self, "{}::", prefix);
183                 }
184                 w!(self, "{{");
185                 for (i, tree) in list.iter().enumerate() {
186                     if i != 0 {
187                         w!(self, ", ");
188                     }
189                     self.print_use_tree(tree);
190                 }
191                 w!(self, "}}");
192             }
193         }
194     }
195
196     fn print_mod_item(&mut self, item: ModItem) {
197         self.print_attrs_of(item);
198
199         match item {
200             ModItem::Import(it) => {
201                 let Import { visibility, use_tree, ast_id: _ } = &self.tree[it];
202                 self.print_visibility(*visibility);
203                 w!(self, "use ");
204                 self.print_use_tree(use_tree);
205                 wln!(self, ";");
206             }
207             ModItem::ExternCrate(it) => {
208                 let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it];
209                 self.print_visibility(*visibility);
210                 w!(self, "extern crate {}", name);
211                 if let Some(alias) = alias {
212                     w!(self, " as {}", alias);
213                 }
214                 wln!(self, ";");
215             }
216             ModItem::ExternBlock(it) => {
217                 let ExternBlock { abi, ast_id: _, children } = &self.tree[it];
218                 w!(self, "extern ");
219                 if let Some(abi) = abi {
220                     w!(self, "\"{}\" ", abi);
221                 }
222                 w!(self, "{{");
223                 self.indented(|this| {
224                     for child in &**children {
225                         this.print_mod_item(*child);
226                     }
227                 });
228                 wln!(self, "}}");
229             }
230             ModItem::Function(it) => {
231                 let Function {
232                     name,
233                     visibility,
234                     generic_params,
235                     abi,
236                     params,
237                     ret_type,
238                     async_ret_type: _,
239                     ast_id: _,
240                     flags,
241                 } = &self.tree[it];
242                 if flags.bits != 0 {
243                     wln!(self, "// flags = 0x{:X}", flags.bits);
244                 }
245                 self.print_visibility(*visibility);
246                 if let Some(abi) = abi {
247                     w!(self, "extern \"{}\" ", abi);
248                 }
249                 w!(self, "fn {}", name);
250                 self.print_generic_params(generic_params);
251                 w!(self, "(");
252                 if !params.is_empty() {
253                     self.indented(|this| {
254                         for param in params.clone() {
255                             this.print_attrs_of(param);
256                             match &this.tree[param] {
257                                 Param::Normal(ty) => {
258                                     w!(this, "_: ");
259                                     this.print_type_ref(ty);
260                                     wln!(this, ",");
261                                 }
262                                 Param::Varargs => {
263                                     wln!(this, "...");
264                                 }
265                             };
266                         }
267                     });
268                 }
269                 w!(self, ") -> ");
270                 self.print_type_ref(ret_type);
271                 self.print_where_clause(generic_params);
272                 wln!(self, ";");
273             }
274             ModItem::Struct(it) => {
275                 let Struct { visibility, name, fields, generic_params, ast_id: _ } = &self.tree[it];
276                 self.print_visibility(*visibility);
277                 w!(self, "struct {}", name);
278                 self.print_generic_params(generic_params);
279                 self.print_fields_and_where_clause(fields, generic_params);
280                 if matches!(fields, Fields::Record(_)) {
281                     wln!(self);
282                 } else {
283                     wln!(self, ";");
284                 }
285             }
286             ModItem::Union(it) => {
287                 let Union { name, visibility, fields, generic_params, ast_id: _ } = &self.tree[it];
288                 self.print_visibility(*visibility);
289                 w!(self, "union {}", name);
290                 self.print_generic_params(generic_params);
291                 self.print_fields_and_where_clause(fields, generic_params);
292                 if matches!(fields, Fields::Record(_)) {
293                     wln!(self);
294                 } else {
295                     wln!(self, ";");
296                 }
297             }
298             ModItem::Enum(it) => {
299                 let Enum { name, visibility, variants, generic_params, ast_id: _ } = &self.tree[it];
300                 self.print_visibility(*visibility);
301                 w!(self, "enum {}", name);
302                 self.print_generic_params(generic_params);
303                 self.print_where_clause_and_opening_brace(generic_params);
304                 self.indented(|this| {
305                     for variant in variants.clone() {
306                         let Variant { name, fields } = &this.tree[variant];
307                         this.print_attrs_of(variant);
308                         w!(this, "{}", name);
309                         this.print_fields(fields);
310                         wln!(this, ",");
311                     }
312                 });
313                 wln!(self, "}}");
314             }
315             ModItem::Const(it) => {
316                 let Const { name, visibility, type_ref, ast_id: _ } = &self.tree[it];
317                 self.print_visibility(*visibility);
318                 w!(self, "const ");
319                 match name {
320                     Some(name) => w!(self, "{}", name),
321                     None => w!(self, "_"),
322                 }
323                 w!(self, ": ");
324                 self.print_type_ref(type_ref);
325                 wln!(self, " = _;");
326             }
327             ModItem::Static(it) => {
328                 let Static { name, visibility, mutable, is_extern, type_ref, ast_id: _ } =
329                     &self.tree[it];
330                 self.print_visibility(*visibility);
331                 w!(self, "static ");
332                 if *mutable {
333                     w!(self, "mut ");
334                 }
335                 w!(self, "{}: ", name);
336                 self.print_type_ref(type_ref);
337                 w!(self, " = _;");
338                 if *is_extern {
339                     w!(self, "  // extern");
340                 }
341                 wln!(self);
342             }
343             ModItem::Trait(it) => {
344                 let Trait {
345                     name,
346                     visibility,
347                     is_auto,
348                     is_unsafe,
349                     items,
350                     generic_params,
351                     ast_id: _,
352                 } = &self.tree[it];
353                 self.print_visibility(*visibility);
354                 if *is_unsafe {
355                     w!(self, "unsafe ");
356                 }
357                 if *is_auto {
358                     w!(self, "auto ");
359                 }
360                 w!(self, "trait {}", name);
361                 self.print_generic_params(generic_params);
362                 self.print_where_clause_and_opening_brace(generic_params);
363                 self.indented(|this| {
364                     for item in &**items {
365                         this.print_mod_item((*item).into());
366                     }
367                 });
368                 wln!(self, "}}");
369             }
370             ModItem::Impl(it) => {
371                 let Impl { target_trait, self_ty, is_negative, items, generic_params, ast_id: _ } =
372                     &self.tree[it];
373                 w!(self, "impl");
374                 self.print_generic_params(generic_params);
375                 w!(self, " ");
376                 if *is_negative {
377                     w!(self, "!");
378                 }
379                 if let Some(tr) = target_trait {
380                     self.print_path(&tr.path);
381                     w!(self, " for ");
382                 }
383                 self.print_type_ref(self_ty);
384                 self.print_where_clause_and_opening_brace(generic_params);
385                 self.indented(|this| {
386                     for item in &**items {
387                         this.print_mod_item((*item).into());
388                     }
389                 });
390                 wln!(self, "}}");
391             }
392             ModItem::TypeAlias(it) => {
393                 let TypeAlias {
394                     name,
395                     visibility,
396                     bounds,
397                     type_ref,
398                     is_extern,
399                     generic_params,
400                     ast_id: _,
401                 } = &self.tree[it];
402                 self.print_visibility(*visibility);
403                 w!(self, "type {}", name);
404                 self.print_generic_params(generic_params);
405                 if !bounds.is_empty() {
406                     w!(self, ": ");
407                     self.print_type_bounds(bounds);
408                 }
409                 if let Some(ty) = type_ref {
410                     w!(self, " = ");
411                     self.print_type_ref(ty);
412                 }
413                 self.print_where_clause(generic_params);
414                 w!(self, ";");
415                 if *is_extern {
416                     w!(self, "  // extern");
417                 }
418                 wln!(self);
419             }
420             ModItem::Mod(it) => {
421                 let Mod { name, visibility, kind, ast_id: _ } = &self.tree[it];
422                 self.print_visibility(*visibility);
423                 w!(self, "mod {}", name);
424                 match kind {
425                     ModKind::Inline { items } => {
426                         w!(self, " {{");
427                         self.indented(|this| {
428                             for item in &**items {
429                                 this.print_mod_item(*item);
430                             }
431                         });
432                         wln!(self, "}}");
433                     }
434                     ModKind::Outline {} => {
435                         wln!(self, ";");
436                     }
437                 }
438             }
439             ModItem::MacroCall(it) => {
440                 let MacroCall { path, ast_id: _, fragment: _ } = &self.tree[it];
441                 wln!(self, "{}!(...);", path);
442             }
443             ModItem::MacroRules(it) => {
444                 let MacroRules { name, ast_id: _ } = &self.tree[it];
445                 wln!(self, "macro_rules! {} {{ ... }}", name);
446             }
447             ModItem::MacroDef(it) => {
448                 let MacroDef { name, visibility, ast_id: _ } = &self.tree[it];
449                 self.print_visibility(*visibility);
450                 wln!(self, "macro {} {{ ... }}", name);
451             }
452         }
453
454         self.blank();
455     }
456
457     fn print_type_ref(&mut self, type_ref: &TypeRef) {
458         // FIXME: deduplicate with `HirDisplay` impl
459         match type_ref {
460             TypeRef::Never => w!(self, "!"),
461             TypeRef::Placeholder => w!(self, "_"),
462             TypeRef::Tuple(fields) => {
463                 w!(self, "(");
464                 for (i, field) in fields.iter().enumerate() {
465                     if i != 0 {
466                         w!(self, ", ");
467                     }
468                     self.print_type_ref(field);
469                 }
470                 w!(self, ")");
471             }
472             TypeRef::Path(path) => self.print_path(path),
473             TypeRef::RawPtr(pointee, mtbl) => {
474                 let mtbl = match mtbl {
475                     Mutability::Shared => "*const",
476                     Mutability::Mut => "*mut",
477                 };
478                 w!(self, "{} ", mtbl);
479                 self.print_type_ref(pointee);
480             }
481             TypeRef::Reference(pointee, lt, mtbl) => {
482                 let mtbl = match mtbl {
483                     Mutability::Shared => "",
484                     Mutability::Mut => "mut ",
485                 };
486                 w!(self, "&");
487                 if let Some(lt) = lt {
488                     w!(self, "{} ", lt.name);
489                 }
490                 w!(self, "{}", mtbl);
491                 self.print_type_ref(pointee);
492             }
493             TypeRef::Array(elem, len) => {
494                 w!(self, "[");
495                 self.print_type_ref(elem);
496                 w!(self, "; {}]", len);
497             }
498             TypeRef::Slice(elem) => {
499                 w!(self, "[");
500                 self.print_type_ref(elem);
501                 w!(self, "]");
502             }
503             TypeRef::Fn(args_and_ret, varargs) => {
504                 let (ret, args) =
505                     args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
506                 w!(self, "fn(");
507                 for (i, arg) in args.iter().enumerate() {
508                     if i != 0 {
509                         w!(self, ", ");
510                     }
511                     self.print_type_ref(arg);
512                 }
513                 if *varargs {
514                     if !args.is_empty() {
515                         w!(self, ", ");
516                     }
517                     w!(self, "...");
518                 }
519                 w!(self, ") -> ");
520                 self.print_type_ref(ret);
521             }
522             TypeRef::Macro(_ast_id) => {
523                 w!(self, "<macro>");
524             }
525             TypeRef::Error => w!(self, "{{unknown}}"),
526             TypeRef::ImplTrait(bounds) => {
527                 w!(self, "impl ");
528                 self.print_type_bounds(bounds);
529             }
530             TypeRef::DynTrait(bounds) => {
531                 w!(self, "dyn ");
532                 self.print_type_bounds(bounds);
533             }
534         }
535     }
536
537     fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
538         for (i, bound) in bounds.iter().enumerate() {
539             if i != 0 {
540                 w!(self, " + ");
541             }
542
543             match bound.as_ref() {
544                 TypeBound::Path(path) => self.print_path(path),
545                 TypeBound::Lifetime(lt) => w!(self, "{}", lt.name),
546                 TypeBound::Error => w!(self, "{{unknown}}"),
547             }
548         }
549     }
550
551     fn print_path(&mut self, path: &Path) {
552         match path.type_anchor() {
553             Some(anchor) => {
554                 w!(self, "<");
555                 self.print_type_ref(anchor);
556                 w!(self, ">::");
557             }
558             None => match path.kind() {
559                 PathKind::Plain => {}
560                 PathKind::Super(0) => w!(self, "self::"),
561                 PathKind::Super(n) => {
562                     for _ in 0..*n {
563                         w!(self, "super::");
564                     }
565                 }
566                 PathKind::Crate => w!(self, "crate::"),
567                 PathKind::Abs => w!(self, "::"),
568                 PathKind::DollarCrate(_) => w!(self, "$crate::"),
569             },
570         }
571
572         for (i, segment) in path.segments().iter().enumerate() {
573             if i != 0 {
574                 w!(self, "::");
575             }
576
577             w!(self, "{}", segment.name);
578             if let Some(generics) = segment.args_and_bindings {
579                 // NB: these are all in type position, so `::<` turbofish syntax is not necessary
580                 w!(self, "<");
581                 let mut first = true;
582                 let args = if generics.has_self_type {
583                     let (self_ty, args) = generics.args.split_first().unwrap();
584                     w!(self, "Self=");
585                     self.print_generic_arg(self_ty);
586                     first = false;
587                     args
588                 } else {
589                     &generics.args
590                 };
591                 for arg in args {
592                     if !first {
593                         w!(self, ", ");
594                     }
595                     first = false;
596                     self.print_generic_arg(arg);
597                 }
598                 for binding in &generics.bindings {
599                     if !first {
600                         w!(self, ", ");
601                     }
602                     first = false;
603                     w!(self, "{}", binding.name);
604                     if !binding.bounds.is_empty() {
605                         w!(self, ": ");
606                         self.print_type_bounds(&binding.bounds);
607                     }
608                     if let Some(ty) = &binding.type_ref {
609                         w!(self, " = ");
610                         self.print_type_ref(ty);
611                     }
612                 }
613
614                 w!(self, ">");
615             }
616         }
617     }
618
619     fn print_generic_arg(&mut self, arg: &GenericArg) {
620         match arg {
621             GenericArg::Type(ty) => self.print_type_ref(ty),
622             GenericArg::Lifetime(lt) => w!(self, "{}", lt.name),
623         }
624     }
625
626     fn print_generic_params(&mut self, params: &GenericParams) {
627         if params.types.is_empty() && params.lifetimes.is_empty() && params.consts.is_empty() {
628             return;
629         }
630
631         w!(self, "<");
632         let mut first = true;
633         for (_, lt) in params.lifetimes.iter() {
634             if !first {
635                 w!(self, ", ");
636             }
637             first = false;
638             w!(self, "{}", lt.name);
639         }
640         for (idx, ty) in params.types.iter() {
641             if !first {
642                 w!(self, ", ");
643             }
644             first = false;
645             match &ty.name {
646                 Some(name) => w!(self, "{}", name),
647                 None => w!(self, "_anon_{}", idx.into_raw()),
648             }
649         }
650         for (_, konst) in params.consts.iter() {
651             if !first {
652                 w!(self, ", ");
653             }
654             first = false;
655             w!(self, "const {}: ", konst.name);
656             self.print_type_ref(&konst.ty);
657         }
658         w!(self, ">");
659     }
660
661     fn print_where_clause_and_opening_brace(&mut self, params: &GenericParams) {
662         if self.print_where_clause(params) {
663             w!(self, "\n{{");
664         } else {
665             self.whitespace();
666             w!(self, "{{");
667         }
668     }
669
670     fn print_where_clause(&mut self, params: &GenericParams) -> bool {
671         if params.where_predicates.is_empty() {
672             return false;
673         }
674
675         w!(self, "\nwhere");
676         self.indented(|this| {
677             for (i, pred) in params.where_predicates.iter().enumerate() {
678                 if i != 0 {
679                     wln!(this, ",");
680                 }
681
682                 let (target, bound) = match pred {
683                     WherePredicate::TypeBound { target, bound } => (target, bound),
684                     WherePredicate::Lifetime { target, bound } => {
685                         wln!(this, "{}: {},", target.name, bound.name);
686                         continue;
687                     }
688                     WherePredicate::ForLifetime { lifetimes, target, bound } => {
689                         w!(this, "for<");
690                         for (i, lt) in lifetimes.iter().enumerate() {
691                             if i != 0 {
692                                 w!(this, ", ");
693                             }
694                             w!(this, "{}", lt);
695                         }
696                         w!(this, "> ");
697                         (target, bound)
698                     }
699                 };
700
701                 match target {
702                     WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
703                     WherePredicateTypeTarget::TypeParam(id) => match &params.types[*id].name {
704                         Some(name) => w!(this, "{}", name),
705                         None => w!(this, "_anon_{}", id.into_raw()),
706                     },
707                 }
708                 w!(this, ": ");
709                 this.print_type_bounds(std::slice::from_ref(bound));
710             }
711         });
712         true
713     }
714 }
715
716 impl<'a> Write for Printer<'a> {
717     fn write_str(&mut self, s: &str) -> fmt::Result {
718         for line in s.split_inclusive('\n') {
719             if self.needs_indent {
720                 match self.buf.chars().last() {
721                     Some('\n') | None => {}
722                     _ => self.buf.push('\n'),
723                 }
724                 self.buf.push_str(&"    ".repeat(self.indent_level));
725                 self.needs_indent = false;
726             }
727
728             self.buf.push_str(line);
729             self.needs_indent = line.ends_with('\n');
730         }
731
732         Ok(())
733     }
734 }