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 ¶ms.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