• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! `ItemTree` debug printer.
2 
3 use std::fmt::{self, Write};
4 
5 use hir_expand::db::ExpandDatabase;
6 
7 use crate::{
8     generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
9     pretty::{print_path, print_type_bounds, print_type_ref},
10     visibility::RawVisibility,
11 };
12 
13 use super::*;
14 
print_item_tree(db: &dyn ExpandDatabase, tree: &ItemTree) -> String15 pub(super) fn print_item_tree(db: &dyn ExpandDatabase, tree: &ItemTree) -> String {
16     let mut p = Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true };
17 
18     if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
19         p.print_attrs(attrs, true);
20     }
21     p.blank();
22 
23     for item in tree.top_level_items() {
24         p.print_mod_item(*item);
25     }
26 
27     let mut s = p.buf.trim_end_matches('\n').to_string();
28     s.push('\n');
29     s
30 }
31 
32 macro_rules! w {
33     ($dst:expr, $($arg:tt)*) => {
34         { let _ = write!($dst, $($arg)*); }
35     };
36 }
37 
38 macro_rules! wln {
39     ($dst:expr) => {
40         { let _ = writeln!($dst); }
41     };
42     ($dst:expr, $($arg:tt)*) => {
43         { let _ = writeln!($dst, $($arg)*); }
44     };
45 }
46 
47 struct Printer<'a> {
48     db: &'a dyn ExpandDatabase,
49     tree: &'a ItemTree,
50     buf: String,
51     indent_level: usize,
52     needs_indent: bool,
53 }
54 
55 impl<'a> Printer<'a> {
indented(&mut self, f: impl FnOnce(&mut Self))56     fn indented(&mut self, f: impl FnOnce(&mut Self)) {
57         self.indent_level += 1;
58         wln!(self);
59         f(self);
60         self.indent_level -= 1;
61         self.buf = self.buf.trim_end_matches('\n').to_string();
62     }
63 
64     /// Ensures that a blank line is output before the next text.
blank(&mut self)65     fn blank(&mut self) {
66         let mut iter = self.buf.chars().rev().fuse();
67         match (iter.next(), iter.next()) {
68             (Some('\n'), Some('\n') | None) | (None, None) => {}
69             (Some('\n'), Some(_)) => {
70                 self.buf.push('\n');
71             }
72             (Some(_), _) => {
73                 self.buf.push('\n');
74                 self.buf.push('\n');
75             }
76             (None, Some(_)) => unreachable!(),
77         }
78     }
79 
whitespace(&mut self)80     fn whitespace(&mut self) {
81         match self.buf.chars().next_back() {
82             None | Some('\n' | ' ') => {}
83             _ => self.buf.push(' '),
84         }
85     }
86 
print_attrs(&mut self, attrs: &RawAttrs, inner: bool)87     fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool) {
88         let inner = if inner { "!" } else { "" };
89         for attr in &**attrs {
90             wln!(
91                 self,
92                 "#{}[{}{}]",
93                 inner,
94                 attr.path.display(self.db),
95                 attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(),
96             );
97         }
98     }
99 
print_attrs_of(&mut self, of: impl Into<AttrOwner>)100     fn print_attrs_of(&mut self, of: impl Into<AttrOwner>) {
101         if let Some(attrs) = self.tree.attrs.get(&of.into()) {
102             self.print_attrs(attrs, false);
103         }
104     }
105 
print_visibility(&mut self, vis: RawVisibilityId)106     fn print_visibility(&mut self, vis: RawVisibilityId) {
107         match &self.tree[vis] {
108             RawVisibility::Module(path) => w!(self, "pub({}) ", path.display(self.db)),
109             RawVisibility::Public => w!(self, "pub "),
110         };
111     }
112 
print_fields(&mut self, fields: &Fields)113     fn print_fields(&mut self, fields: &Fields) {
114         match fields {
115             Fields::Record(fields) => {
116                 self.whitespace();
117                 w!(self, "{{");
118                 self.indented(|this| {
119                     for field in fields.clone() {
120                         let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
121                         this.print_attrs_of(field);
122                         this.print_visibility(*visibility);
123                         w!(this, "{}: ", name.display(self.db));
124                         this.print_type_ref(type_ref);
125                         wln!(this, ",");
126                     }
127                 });
128                 w!(self, "}}");
129             }
130             Fields::Tuple(fields) => {
131                 w!(self, "(");
132                 self.indented(|this| {
133                     for field in fields.clone() {
134                         let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
135                         this.print_attrs_of(field);
136                         this.print_visibility(*visibility);
137                         w!(this, "{}: ", name.display(self.db));
138                         this.print_type_ref(type_ref);
139                         wln!(this, ",");
140                     }
141                 });
142                 w!(self, ")");
143             }
144             Fields::Unit => {}
145         }
146     }
147 
print_fields_and_where_clause(&mut self, fields: &Fields, params: &GenericParams)148     fn print_fields_and_where_clause(&mut self, fields: &Fields, params: &GenericParams) {
149         match fields {
150             Fields::Record(_) => {
151                 if self.print_where_clause(params) {
152                     wln!(self);
153                 }
154                 self.print_fields(fields);
155             }
156             Fields::Unit => {
157                 self.print_where_clause(params);
158                 self.print_fields(fields);
159             }
160             Fields::Tuple(_) => {
161                 self.print_fields(fields);
162                 self.print_where_clause(params);
163             }
164         }
165     }
166 
print_use_tree(&mut self, use_tree: &UseTree)167     fn print_use_tree(&mut self, use_tree: &UseTree) {
168         match &use_tree.kind {
169             UseTreeKind::Single { path, alias } => {
170                 w!(self, "{}", path.display(self.db));
171                 if let Some(alias) = alias {
172                     w!(self, " as {}", alias);
173                 }
174             }
175             UseTreeKind::Glob { path } => {
176                 if let Some(path) = path {
177                     w!(self, "{}::", path.display(self.db));
178                 }
179                 w!(self, "*");
180             }
181             UseTreeKind::Prefixed { prefix, list } => {
182                 if let Some(prefix) = prefix {
183                     w!(self, "{}::", prefix.display(self.db));
184                 }
185                 w!(self, "{{");
186                 for (i, tree) in list.iter().enumerate() {
187                     if i != 0 {
188                         w!(self, ", ");
189                     }
190                     self.print_use_tree(tree);
191                 }
192                 w!(self, "}}");
193             }
194         }
195     }
196 
print_mod_item(&mut self, item: ModItem)197     fn print_mod_item(&mut self, item: ModItem) {
198         self.print_attrs_of(item);
199 
200         match item {
201             ModItem::Import(it) => {
202                 let Import { visibility, use_tree, ast_id: _ } = &self.tree[it];
203                 self.print_visibility(*visibility);
204                 w!(self, "use ");
205                 self.print_use_tree(use_tree);
206                 wln!(self, ";");
207             }
208             ModItem::ExternCrate(it) => {
209                 let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it];
210                 self.print_visibility(*visibility);
211                 w!(self, "extern crate {}", name.display(self.db));
212                 if let Some(alias) = alias {
213                     w!(self, " as {}", alias);
214                 }
215                 wln!(self, ";");
216             }
217             ModItem::ExternBlock(it) => {
218                 let ExternBlock { abi, ast_id: _, children } = &self.tree[it];
219                 w!(self, "extern ");
220                 if let Some(abi) = abi {
221                     w!(self, "\"{}\" ", abi);
222                 }
223                 w!(self, "{{");
224                 self.indented(|this| {
225                     for child in &**children {
226                         this.print_mod_item(*child);
227                     }
228                 });
229                 wln!(self, "}}");
230             }
231             ModItem::Function(it) => {
232                 let Function {
233                     name,
234                     visibility,
235                     explicit_generic_params,
236                     abi,
237                     params,
238                     ret_type,
239                     ast_id: _,
240                     flags,
241                 } = &self.tree[it];
242                 self.print_visibility(*visibility);
243                 if flags.contains(FnFlags::HAS_DEFAULT_KW) {
244                     w!(self, "default ");
245                 }
246                 if flags.contains(FnFlags::HAS_CONST_KW) {
247                     w!(self, "const ");
248                 }
249                 if flags.contains(FnFlags::HAS_ASYNC_KW) {
250                     w!(self, "async ");
251                 }
252                 if flags.contains(FnFlags::HAS_UNSAFE_KW) {
253                     w!(self, "unsafe ");
254                 }
255                 if let Some(abi) = abi {
256                     w!(self, "extern \"{}\" ", abi);
257                 }
258                 w!(self, "fn {}", name.display(self.db));
259                 self.print_generic_params(explicit_generic_params);
260                 w!(self, "(");
261                 if !params.is_empty() {
262                     self.indented(|this| {
263                         for param in params.clone() {
264                             this.print_attrs_of(param);
265                             match &this.tree[param] {
266                                 Param::Normal(ty) => {
267                                     if flags.contains(FnFlags::HAS_SELF_PARAM) {
268                                         w!(this, "self: ");
269                                     }
270                                     this.print_type_ref(ty);
271                                     wln!(this, ",");
272                                 }
273                                 Param::Varargs => {
274                                     wln!(this, "...");
275                                 }
276                             };
277                         }
278                     });
279                 }
280                 w!(self, ") -> ");
281                 self.print_type_ref(ret_type);
282                 self.print_where_clause(explicit_generic_params);
283                 if flags.contains(FnFlags::HAS_BODY) {
284                     wln!(self, " {{ ... }}");
285                 } else {
286                     wln!(self, ";");
287                 }
288             }
289             ModItem::Struct(it) => {
290                 let Struct { visibility, name, fields, generic_params, ast_id: _ } = &self.tree[it];
291                 self.print_visibility(*visibility);
292                 w!(self, "struct {}", name.display(self.db));
293                 self.print_generic_params(generic_params);
294                 self.print_fields_and_where_clause(fields, generic_params);
295                 if matches!(fields, Fields::Record(_)) {
296                     wln!(self);
297                 } else {
298                     wln!(self, ";");
299                 }
300             }
301             ModItem::Union(it) => {
302                 let Union { name, visibility, fields, generic_params, ast_id: _ } = &self.tree[it];
303                 self.print_visibility(*visibility);
304                 w!(self, "union {}", name.display(self.db));
305                 self.print_generic_params(generic_params);
306                 self.print_fields_and_where_clause(fields, generic_params);
307                 if matches!(fields, Fields::Record(_)) {
308                     wln!(self);
309                 } else {
310                     wln!(self, ";");
311                 }
312             }
313             ModItem::Enum(it) => {
314                 let Enum { name, visibility, variants, generic_params, ast_id: _ } = &self.tree[it];
315                 self.print_visibility(*visibility);
316                 w!(self, "enum {}", name.display(self.db));
317                 self.print_generic_params(generic_params);
318                 self.print_where_clause_and_opening_brace(generic_params);
319                 self.indented(|this| {
320                     for variant in variants.clone() {
321                         let Variant { name, fields, ast_id: _ } = &this.tree[variant];
322                         this.print_attrs_of(variant);
323                         w!(this, "{}", name.display(self.db));
324                         this.print_fields(fields);
325                         wln!(this, ",");
326                     }
327                 });
328                 wln!(self, "}}");
329             }
330             ModItem::Const(it) => {
331                 let Const { name, visibility, type_ref, ast_id: _ } = &self.tree[it];
332                 self.print_visibility(*visibility);
333                 w!(self, "const ");
334                 match name {
335                     Some(name) => w!(self, "{}", name.display(self.db)),
336                     None => w!(self, "_"),
337                 }
338                 w!(self, ": ");
339                 self.print_type_ref(type_ref);
340                 wln!(self, " = _;");
341             }
342             ModItem::Static(it) => {
343                 let Static { name, visibility, mutable, type_ref, ast_id: _ } = &self.tree[it];
344                 self.print_visibility(*visibility);
345                 w!(self, "static ");
346                 if *mutable {
347                     w!(self, "mut ");
348                 }
349                 w!(self, "{}: ", name.display(self.db));
350                 self.print_type_ref(type_ref);
351                 w!(self, " = _;");
352                 wln!(self);
353             }
354             ModItem::Trait(it) => {
355                 let Trait {
356                     name,
357                     visibility,
358                     is_auto,
359                     is_unsafe,
360                     items,
361                     generic_params,
362                     ast_id: _,
363                 } = &self.tree[it];
364                 self.print_visibility(*visibility);
365                 if *is_unsafe {
366                     w!(self, "unsafe ");
367                 }
368                 if *is_auto {
369                     w!(self, "auto ");
370                 }
371                 w!(self, "trait {}", name.display(self.db));
372                 self.print_generic_params(generic_params);
373                 self.print_where_clause_and_opening_brace(generic_params);
374                 self.indented(|this| {
375                     for item in &**items {
376                         this.print_mod_item((*item).into());
377                     }
378                 });
379                 wln!(self, "}}");
380             }
381             ModItem::TraitAlias(it) => {
382                 let TraitAlias { name, visibility, generic_params, ast_id: _ } = &self.tree[it];
383                 self.print_visibility(*visibility);
384                 w!(self, "trait {}", name.display(self.db));
385                 self.print_generic_params(generic_params);
386                 w!(self, " = ");
387                 self.print_where_clause(generic_params);
388                 w!(self, ";");
389                 wln!(self);
390             }
391             ModItem::Impl(it) => {
392                 let Impl { target_trait, self_ty, is_negative, items, generic_params, ast_id: _ } =
393                     &self.tree[it];
394                 w!(self, "impl");
395                 self.print_generic_params(generic_params);
396                 w!(self, " ");
397                 if *is_negative {
398                     w!(self, "!");
399                 }
400                 if let Some(tr) = target_trait {
401                     self.print_path(&tr.path);
402                     w!(self, " for ");
403                 }
404                 self.print_type_ref(self_ty);
405                 self.print_where_clause_and_opening_brace(generic_params);
406                 self.indented(|this| {
407                     for item in &**items {
408                         this.print_mod_item((*item).into());
409                     }
410                 });
411                 wln!(self, "}}");
412             }
413             ModItem::TypeAlias(it) => {
414                 let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id: _ } =
415                     &self.tree[it];
416                 self.print_visibility(*visibility);
417                 w!(self, "type {}", name.display(self.db));
418                 self.print_generic_params(generic_params);
419                 if !bounds.is_empty() {
420                     w!(self, ": ");
421                     self.print_type_bounds(bounds);
422                 }
423                 if let Some(ty) = type_ref {
424                     w!(self, " = ");
425                     self.print_type_ref(ty);
426                 }
427                 self.print_where_clause(generic_params);
428                 w!(self, ";");
429                 wln!(self);
430             }
431             ModItem::Mod(it) => {
432                 let Mod { name, visibility, kind, ast_id: _ } = &self.tree[it];
433                 self.print_visibility(*visibility);
434                 w!(self, "mod {}", name.display(self.db));
435                 match kind {
436                     ModKind::Inline { items } => {
437                         w!(self, " {{");
438                         self.indented(|this| {
439                             for item in &**items {
440                                 this.print_mod_item(*item);
441                             }
442                         });
443                         wln!(self, "}}");
444                     }
445                     ModKind::Outline => {
446                         wln!(self, ";");
447                     }
448                 }
449             }
450             ModItem::MacroCall(it) => {
451                 let MacroCall { path, ast_id: _, expand_to: _ } = &self.tree[it];
452                 wln!(self, "{}!(...);", path.display(self.db));
453             }
454             ModItem::MacroRules(it) => {
455                 let MacroRules { name, ast_id: _ } = &self.tree[it];
456                 wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db));
457             }
458             ModItem::MacroDef(it) => {
459                 let MacroDef { name, visibility, ast_id: _ } = &self.tree[it];
460                 self.print_visibility(*visibility);
461                 wln!(self, "macro {} {{ ... }}", name.display(self.db));
462             }
463         }
464 
465         self.blank();
466     }
467 
print_type_ref(&mut self, type_ref: &TypeRef)468     fn print_type_ref(&mut self, type_ref: &TypeRef) {
469         print_type_ref(self.db, type_ref, self).unwrap();
470     }
471 
print_type_bounds(&mut self, bounds: &[Interned<TypeBound>])472     fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
473         print_type_bounds(self.db, bounds, self).unwrap();
474     }
475 
print_path(&mut self, path: &Path)476     fn print_path(&mut self, path: &Path) {
477         print_path(self.db, path, self).unwrap();
478     }
479 
print_generic_params(&mut self, params: &GenericParams)480     fn print_generic_params(&mut self, params: &GenericParams) {
481         if params.type_or_consts.is_empty() && params.lifetimes.is_empty() {
482             return;
483         }
484 
485         w!(self, "<");
486         let mut first = true;
487         for (_, lt) in params.lifetimes.iter() {
488             if !first {
489                 w!(self, ", ");
490             }
491             first = false;
492             w!(self, "{}", lt.name.display(self.db));
493         }
494         for (idx, x) in params.type_or_consts.iter() {
495             if !first {
496                 w!(self, ", ");
497             }
498             first = false;
499             match x {
500                 TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
501                     Some(name) => w!(self, "{}", name.display(self.db)),
502                     None => w!(self, "_anon_{}", idx.into_raw()),
503                 },
504                 TypeOrConstParamData::ConstParamData(konst) => {
505                     w!(self, "const {}: ", konst.name.display(self.db));
506                     self.print_type_ref(&konst.ty);
507                 }
508             }
509         }
510         w!(self, ">");
511     }
512 
print_where_clause_and_opening_brace(&mut self, params: &GenericParams)513     fn print_where_clause_and_opening_brace(&mut self, params: &GenericParams) {
514         if self.print_where_clause(params) {
515             w!(self, "\n{{");
516         } else {
517             self.whitespace();
518             w!(self, "{{");
519         }
520     }
521 
print_where_clause(&mut self, params: &GenericParams) -> bool522     fn print_where_clause(&mut self, params: &GenericParams) -> bool {
523         if params.where_predicates.is_empty() {
524             return false;
525         }
526 
527         w!(self, "\nwhere");
528         self.indented(|this| {
529             for (i, pred) in params.where_predicates.iter().enumerate() {
530                 if i != 0 {
531                     wln!(this, ",");
532                 }
533 
534                 let (target, bound) = match pred {
535                     WherePredicate::TypeBound { target, bound } => (target, bound),
536                     WherePredicate::Lifetime { target, bound } => {
537                         wln!(
538                             this,
539                             "{}: {},",
540                             target.name.display(self.db),
541                             bound.name.display(self.db)
542                         );
543                         continue;
544                     }
545                     WherePredicate::ForLifetime { lifetimes, target, bound } => {
546                         w!(this, "for<");
547                         for (i, lt) in lifetimes.iter().enumerate() {
548                             if i != 0 {
549                                 w!(this, ", ");
550                             }
551                             w!(this, "{}", lt.display(self.db));
552                         }
553                         w!(this, "> ");
554                         (target, bound)
555                     }
556                 };
557 
558                 match target {
559                     WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
560                     WherePredicateTypeTarget::TypeOrConstParam(id) => {
561                         match &params.type_or_consts[*id].name() {
562                             Some(name) => w!(this, "{}", name.display(self.db)),
563                             None => w!(this, "_anon_{}", id.into_raw()),
564                         }
565                     }
566                 }
567                 w!(this, ": ");
568                 this.print_type_bounds(std::slice::from_ref(bound));
569             }
570         });
571         true
572     }
573 }
574 
575 impl<'a> Write for Printer<'a> {
write_str(&mut self, s: &str) -> fmt::Result576     fn write_str(&mut self, s: &str) -> fmt::Result {
577         for line in s.split_inclusive('\n') {
578             if self.needs_indent {
579                 match self.buf.chars().last() {
580                     Some('\n') | None => {}
581                     _ => self.buf.push('\n'),
582                 }
583                 self.buf.push_str(&"    ".repeat(self.indent_level));
584                 self.needs_indent = false;
585             }
586 
587             self.buf.push_str(line);
588             self.needs_indent = line.ends_with('\n');
589         }
590 
591         Ok(())
592     }
593 }
594