1 //! `ItemTree` debug printer.
3 use std::fmt::{self, Write};
7 generics::{WherePredicate, WherePredicateTypeTarget},
9 visibility::RawVisibility,
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 };
17 if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
18 p.print_attrs(attrs, true);
22 for item in tree.top_level_items() {
23 p.print_mod_item(*item);
26 let mut s = p.buf.trim_end_matches('\n').to_string();
32 ($dst:expr, $($arg:tt)*) => {
33 drop(write!($dst, $($arg)*))
41 ($dst:expr, $($arg:tt)*) => {
42 drop(writeln!($dst, $($arg)*))
53 impl<'a> Printer<'a> {
54 fn indented(&mut self, f: impl FnOnce(&mut Self)) {
55 self.indent_level += 1;
58 self.indent_level -= 1;
59 self.buf = self.buf.trim_end_matches('\n').to_string();
62 /// Ensures that a blank line is output before the next text.
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(_)) => {
74 (None, Some(_)) => unreachable!(),
78 fn whitespace(&mut self) {
79 match self.buf.chars().next_back() {
80 None | Some('\n') | Some(' ') => {}
81 _ => self.buf.push(' '),
85 fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool) {
86 let inner = if inner { "!" } else { "" };
87 for attr in &**attrs {
93 attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(),
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);
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 "),
112 fn print_fields(&mut self, fields: &Fields) {
114 Fields::Record(fields) => {
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);
129 Fields::Tuple(fields) => {
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);
147 fn print_fields_and_where_clause(&mut self, fields: &Fields, params: &GenericParams) {
149 Fields::Record(_) => {
150 if self.print_where_clause(params) {
153 self.print_fields(fields);
156 self.print_where_clause(params);
157 self.print_fields(fields);
159 Fields::Tuple(_) => {
160 self.print_fields(fields);
161 self.print_where_clause(params);
166 fn print_mod_item(&mut self, item: ModItem) {
167 self.print_attrs_of(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);
177 if let Some(alias) = alias {
178 w!(self, " as {}", alias);
180 wln!(self, "; // {}", index);
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);
191 ModItem::ExternBlock(it) => {
192 let ExternBlock { abi, ast_id: _, children } = &self.tree[it];
194 if let Some(abi) = abi {
195 w!(self, "\"{}\" ", abi);
198 self.indented(|this| {
199 for child in &**children {
200 this.print_mod_item(*child);
205 ModItem::Function(it) => {
217 wln!(self, "// flags = 0x{:X}", flags.bits);
219 self.print_visibility(*visibility);
220 if let Some(abi) = abi {
221 w!(self, "extern \"{}\" ", abi);
223 w!(self, "fn {}", name);
224 self.print_generic_params(generic_params);
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) => {
233 this.print_type_ref(ty);
244 self.print_type_ref(ret_type);
245 self.print_where_clause(generic_params);
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(_)) {
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(_)) {
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);
289 ModItem::Const(it) => {
290 let Const { name, visibility, type_ref, ast_id: _ } = &self.tree[it];
291 self.print_visibility(*visibility);
294 Some(name) => w!(self, "{}", name),
295 None => w!(self, "_"),
298 self.print_type_ref(type_ref);
301 ModItem::Static(it) => {
302 let Static { name, visibility, mutable, is_extern, type_ref, ast_id: _ } =
304 self.print_visibility(*visibility);
309 w!(self, "{}: ", name);
310 self.print_type_ref(type_ref);
313 w!(self, " // extern");
317 ModItem::Trait(it) => {
328 self.print_visibility(*visibility);
335 w!(self, "trait {}", name);
336 self.print_generic_params(generic_params);
337 if !bounds.is_empty() {
339 self.print_type_bounds(bounds);
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());
349 ModItem::Impl(it) => {
350 let Impl { target_trait, self_ty, is_negative, items, generic_params, ast_id: _ } =
353 self.print_generic_params(generic_params);
358 if let Some(tr) = target_trait {
359 self.print_path(&tr.path);
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());
371 ModItem::TypeAlias(it) => {
381 self.print_visibility(*visibility);
382 w!(self, "type {}", name);
383 self.print_generic_params(generic_params);
384 if !bounds.is_empty() {
386 self.print_type_bounds(bounds);
388 if let Some(ty) = type_ref {
390 self.print_type_ref(ty);
392 self.print_where_clause(generic_params);
395 w!(self, " // extern");
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);
404 ModKind::Inline { items } => {
406 self.indented(|this| {
407 for item in &**items {
408 this.print_mod_item((*item).into());
413 ModKind::Outline {} => {
418 ModItem::MacroCall(it) => {
419 let MacroCall { path, ast_id: _, fragment: _ } = &self.tree[it];
420 wln!(self, "{}!(...);", path);
422 ModItem::MacroRules(it) => {
423 let MacroRules { name, ast_id: _ } = &self.tree[it];
424 wln!(self, "macro_rules! {} {{ ... }}", name);
426 ModItem::MacroDef(it) => {
427 let MacroDef { name, visibility, ast_id: _ } = &self.tree[it];
428 self.print_visibility(*visibility);
429 wln!(self, "macro {} {{ ... }}", name);
436 fn print_type_ref(&mut self, type_ref: &TypeRef) {
437 // FIXME: deduplicate with `HirDisplay` impl
439 TypeRef::Never => w!(self, "!"),
440 TypeRef::Placeholder => w!(self, "_"),
441 TypeRef::Tuple(fields) => {
443 for (i, field) in fields.iter().enumerate() {
447 self.print_type_ref(field);
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",
457 w!(self, "{} ", mtbl);
458 self.print_type_ref(pointee);
460 TypeRef::Reference(pointee, lt, mtbl) => {
461 let mtbl = match mtbl {
462 Mutability::Shared => "",
463 Mutability::Mut => "mut ",
466 if let Some(lt) = lt {
467 w!(self, "{} ", lt.name);
469 w!(self, "{}", mtbl);
470 self.print_type_ref(pointee);
472 TypeRef::Array(elem, len) => {
474 self.print_type_ref(elem);
475 w!(self, "; {}]", len);
477 TypeRef::Slice(elem) => {
479 self.print_type_ref(elem);
482 TypeRef::Fn(args_and_ret, varargs) => {
484 args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
486 for (i, arg) in args.iter().enumerate() {
490 self.print_type_ref(arg);
493 if !args.is_empty() {
499 self.print_type_ref(ret);
501 TypeRef::Macro(_ast_id) => {
504 TypeRef::Error => w!(self, "{{unknown}}"),
505 TypeRef::ImplTrait(bounds) => {
507 self.print_type_bounds(bounds);
509 TypeRef::DynTrait(bounds) => {
511 self.print_type_bounds(bounds);
516 fn print_type_bounds(&mut self, bounds: &[TypeBound]) {
517 for (i, bound) in bounds.iter().enumerate() {
523 TypeBound::Path(path) => self.print_path(path),
524 TypeBound::Lifetime(lt) => w!(self, "{}", lt.name),
525 TypeBound::Error => w!(self, "{{unknown}}"),
530 fn print_path(&mut self, path: &Path) {
531 match path.type_anchor() {
534 self.print_type_ref(anchor);
537 None => match path.kind() {
538 PathKind::Plain => {}
539 PathKind::Super(0) => w!(self, "self::"),
540 PathKind::Super(n) => {
545 PathKind::Crate => w!(self, "crate::"),
546 PathKind::Abs => w!(self, "::"),
547 PathKind::DollarCrate(_) => w!(self, "$crate::"),
551 for (i, segment) in path.segments().iter().enumerate() {
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
560 let mut first = true;
561 let args = if generics.has_self_type {
562 let (self_ty, args) = generics.args.split_first().unwrap();
564 self.print_generic_arg(self_ty);
575 self.print_generic_arg(arg);
577 for binding in &generics.bindings {
582 w!(self, "{}", binding.name);
583 if !binding.bounds.is_empty() {
585 self.print_type_bounds(&binding.bounds);
587 if let Some(ty) = &binding.type_ref {
589 self.print_type_ref(ty);
598 fn print_generic_arg(&mut self, arg: &GenericArg) {
600 GenericArg::Type(ty) => self.print_type_ref(ty),
601 GenericArg::Lifetime(lt) => w!(self, "{}", lt.name),
605 fn print_generic_params(&mut self, params: &GenericParams) {
606 if params.types.is_empty() && params.lifetimes.is_empty() && params.consts.is_empty() {
611 let mut first = true;
612 for (_, lt) in params.lifetimes.iter() {
617 w!(self, "{}", lt.name);
619 for (idx, ty) in params.types.iter() {
625 Some(name) => w!(self, "{}", name),
626 None => w!(self, "_anon_{}", idx.into_raw()),
629 for (_, konst) in params.consts.iter() {
634 w!(self, "const {}: ", konst.name);
635 self.print_type_ref(&konst.ty);
640 fn print_where_clause_and_opening_brace(&mut self, params: &GenericParams) {
641 if self.print_where_clause(params) {
649 fn print_where_clause(&mut self, params: &GenericParams) -> bool {
650 if params.where_predicates.is_empty() {
655 self.indented(|this| {
656 for (i, pred) in params.where_predicates.iter().enumerate() {
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);
667 WherePredicate::ForLifetime { lifetimes, target, bound } => {
669 for (i, lt) in lifetimes.iter().enumerate() {
681 WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
682 WherePredicateTypeTarget::TypeParam(id) => match ¶ms.types[*id].name {
683 Some(name) => w!(this, "{}", name),
684 None => w!(this, "_anon_{}", id.into_raw()),
688 this.print_type_bounds(std::slice::from_ref(bound));
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'),
703 self.buf.push_str(&" ".repeat(self.indent_level));
704 self.needs_indent = false;
707 self.buf.push_str(line);
708 self.needs_indent = line.ends_with('\n');