aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-05-23 02:00:33 +0100
committerGitHub <[email protected]>2021-05-23 02:00:33 +0100
commite4722b6492c3a3b9636f7da6cee34b5879100de3 (patch)
tree40647077f6cfbd6481b00c5b9f6ecc14e67bd749 /crates
parentbc1ba1549d97e7d5ddceb16b7238ae8aab5794d0 (diff)
parent15ff7faf3dd7979cce2fb76106add30bb771c503 (diff)
Merge #8932
8932: internal: even prettier itemtrees r=jonas-schievink a=jonas-schievink Extends the ItemTree pretty printer to handle all `Path`s, and to print generic parameters and where-clauses. bors r+ Co-authored-by: Jonas Schievink <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/hir_def/src/item_tree/pretty.rs254
-rw-r--r--crates/hir_def/src/item_tree/tests.rs122
2 files changed, 342 insertions, 34 deletions
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index 5ec02d1be..4bc87a0e2 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -2,7 +2,12 @@
2 2
3use std::fmt::{self, Write}; 3use std::fmt::{self, Write};
4 4
5use crate::{attr::RawAttrs, visibility::RawVisibility}; 5use crate::{
6 attr::RawAttrs,
7 generics::{WherePredicate, WherePredicateTypeTarget},
8 path::GenericArg,
9 visibility::RawVisibility,
10};
6 11
7use super::*; 12use super::*;
8 13
@@ -70,6 +75,13 @@ impl<'a> Printer<'a> {
70 } 75 }
71 } 76 }
72 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
73 fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool) { 85 fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool) {
74 let inner = if inner { "!" } else { "" }; 86 let inner = if inner { "!" } else { "" };
75 for attr in &**attrs { 87 for attr in &**attrs {
@@ -100,7 +112,8 @@ impl<'a> Printer<'a> {
100 fn print_fields(&mut self, fields: &Fields) { 112 fn print_fields(&mut self, fields: &Fields) {
101 match fields { 113 match fields {
102 Fields::Record(fields) => { 114 Fields::Record(fields) => {
103 w!(self, " {{"); 115 self.whitespace();
116 w!(self, "{{");
104 self.indented(|this| { 117 self.indented(|this| {
105 for field in fields.clone() { 118 for field in fields.clone() {
106 let Field { visibility, name, type_ref } = &this.tree[field]; 119 let Field { visibility, name, type_ref } = &this.tree[field];
@@ -131,6 +144,25 @@ impl<'a> Printer<'a> {
131 } 144 }
132 } 145 }
133 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
134 fn print_mod_item(&mut self, item: ModItem) { 166 fn print_mod_item(&mut self, item: ModItem) {
135 self.print_attrs_of(item); 167 self.print_attrs_of(item);
136 168
@@ -174,7 +206,7 @@ impl<'a> Printer<'a> {
174 let Function { 206 let Function {
175 name, 207 name,
176 visibility, 208 visibility,
177 generic_params: _, // FIXME print these somehow 209 generic_params,
178 abi, 210 abi,
179 params, 211 params,
180 ret_type, 212 ret_type,
@@ -188,7 +220,9 @@ impl<'a> Printer<'a> {
188 if let Some(abi) = abi { 220 if let Some(abi) = abi {
189 w!(self, "extern \"{}\" ", abi); 221 w!(self, "extern \"{}\" ", abi);
190 } 222 }
191 w!(self, "fn {}(", name); 223 w!(self, "fn {}", name);
224 self.print_generic_params(generic_params);
225 w!(self, "(");
192 if !params.is_empty() { 226 if !params.is_empty() {
193 self.indented(|this| { 227 self.indented(|this| {
194 for param in params.clone() { 228 for param in params.clone() {
@@ -208,14 +242,15 @@ impl<'a> Printer<'a> {
208 } 242 }
209 w!(self, ") -> "); 243 w!(self, ") -> ");
210 self.print_type_ref(ret_type); 244 self.print_type_ref(ret_type);
245 self.print_where_clause(generic_params);
211 wln!(self, ";"); 246 wln!(self, ";");
212 } 247 }
213 ModItem::Struct(it) => { 248 ModItem::Struct(it) => {
214 let Struct { visibility, name, fields, generic_params: _, ast_id: _ } = 249 let Struct { visibility, name, fields, generic_params, ast_id: _ } = &self.tree[it];
215 &self.tree[it];
216 self.print_visibility(*visibility); 250 self.print_visibility(*visibility);
217 w!(self, "struct {}", name); 251 w!(self, "struct {}", name);
218 self.print_fields(fields); 252 self.print_generic_params(generic_params);
253 self.print_fields_and_where_clause(fields, generic_params);
219 if matches!(fields, Fields::Record(_)) { 254 if matches!(fields, Fields::Record(_)) {
220 wln!(self); 255 wln!(self);
221 } else { 256 } else {
@@ -223,11 +258,11 @@ impl<'a> Printer<'a> {
223 } 258 }
224 } 259 }
225 ModItem::Union(it) => { 260 ModItem::Union(it) => {
226 let Union { name, visibility, fields, generic_params: _, ast_id: _ } = 261 let Union { name, visibility, fields, generic_params, ast_id: _ } = &self.tree[it];
227 &self.tree[it];
228 self.print_visibility(*visibility); 262 self.print_visibility(*visibility);
229 w!(self, "union {}", name); 263 w!(self, "union {}", name);
230 self.print_fields(fields); 264 self.print_generic_params(generic_params);
265 self.print_fields_and_where_clause(fields, generic_params);
231 if matches!(fields, Fields::Record(_)) { 266 if matches!(fields, Fields::Record(_)) {
232 wln!(self); 267 wln!(self);
233 } else { 268 } else {
@@ -235,10 +270,11 @@ impl<'a> Printer<'a> {
235 } 270 }
236 } 271 }
237 ModItem::Enum(it) => { 272 ModItem::Enum(it) => {
238 let Enum { name, visibility, variants, generic_params: _, ast_id: _ } = 273 let Enum { name, visibility, variants, generic_params, ast_id: _ } = &self.tree[it];
239 &self.tree[it];
240 self.print_visibility(*visibility); 274 self.print_visibility(*visibility);
241 w!(self, "enum {} {{", name); 275 w!(self, "enum {}", name);
276 self.print_generic_params(generic_params);
277 self.print_where_clause_and_opening_brace(generic_params);
242 self.indented(|this| { 278 self.indented(|this| {
243 for variant in variants.clone() { 279 for variant in variants.clone() {
244 let Variant { name, fields } = &this.tree[variant]; 280 let Variant { name, fields } = &this.tree[variant];
@@ -286,7 +322,7 @@ impl<'a> Printer<'a> {
286 is_unsafe, 322 is_unsafe,
287 bounds, 323 bounds,
288 items, 324 items,
289 generic_params: _, 325 generic_params,
290 ast_id: _, 326 ast_id: _,
291 } = &self.tree[it]; 327 } = &self.tree[it];
292 self.print_visibility(*visibility); 328 self.print_visibility(*visibility);
@@ -297,11 +333,12 @@ impl<'a> Printer<'a> {
297 w!(self, "auto "); 333 w!(self, "auto ");
298 } 334 }
299 w!(self, "trait {}", name); 335 w!(self, "trait {}", name);
336 self.print_generic_params(generic_params);
300 if !bounds.is_empty() { 337 if !bounds.is_empty() {
301 w!(self, ": "); 338 w!(self, ": ");
302 self.print_type_bounds(bounds); 339 self.print_type_bounds(bounds);
303 } 340 }
304 w!(self, " {{"); 341 self.print_where_clause_and_opening_brace(generic_params);
305 self.indented(|this| { 342 self.indented(|this| {
306 for item in &**items { 343 for item in &**items {
307 this.print_mod_item((*item).into()); 344 this.print_mod_item((*item).into());
@@ -310,15 +347,11 @@ impl<'a> Printer<'a> {
310 wln!(self, "}}"); 347 wln!(self, "}}");
311 } 348 }
312 ModItem::Impl(it) => { 349 ModItem::Impl(it) => {
313 let Impl { 350 let Impl { target_trait, self_ty, is_negative, items, generic_params, ast_id: _ } =
314 target_trait, 351 &self.tree[it];
315 self_ty, 352 w!(self, "impl");
316 is_negative, 353 self.print_generic_params(generic_params);
317 items, 354 w!(self, " ");
318 generic_params: _,
319 ast_id: _,
320 } = &self.tree[it];
321 w!(self, "impl ");
322 if *is_negative { 355 if *is_negative {
323 w!(self, "!"); 356 w!(self, "!");
324 } 357 }
@@ -327,7 +360,7 @@ impl<'a> Printer<'a> {
327 w!(self, " for "); 360 w!(self, " for ");
328 } 361 }
329 self.print_type_ref(self_ty); 362 self.print_type_ref(self_ty);
330 w!(self, " {{"); 363 self.print_where_clause_and_opening_brace(generic_params);
331 self.indented(|this| { 364 self.indented(|this| {
332 for item in &**items { 365 for item in &**items {
333 this.print_mod_item((*item).into()); 366 this.print_mod_item((*item).into());
@@ -342,11 +375,12 @@ impl<'a> Printer<'a> {
342 bounds, 375 bounds,
343 type_ref, 376 type_ref,
344 is_extern, 377 is_extern,
345 generic_params: _, 378 generic_params,
346 ast_id: _, 379 ast_id: _,
347 } = &self.tree[it]; 380 } = &self.tree[it];
348 self.print_visibility(*visibility); 381 self.print_visibility(*visibility);
349 w!(self, "type {}", name); 382 w!(self, "type {}", name);
383 self.print_generic_params(generic_params);
350 if !bounds.is_empty() { 384 if !bounds.is_empty() {
351 w!(self, ": "); 385 w!(self, ": ");
352 self.print_type_bounds(bounds); 386 self.print_type_bounds(bounds);
@@ -355,6 +389,7 @@ impl<'a> Printer<'a> {
355 w!(self, " = "); 389 w!(self, " = ");
356 self.print_type_ref(ty); 390 self.print_type_ref(ty);
357 } 391 }
392 self.print_where_clause(generic_params);
358 w!(self, ";"); 393 w!(self, ";");
359 if *is_extern { 394 if *is_extern {
360 w!(self, " // extern"); 395 w!(self, " // extern");
@@ -466,7 +501,7 @@ impl<'a> Printer<'a> {
466 TypeRef::Macro(_ast_id) => { 501 TypeRef::Macro(_ast_id) => {
467 w!(self, "<macro>"); 502 w!(self, "<macro>");
468 } 503 }
469 TypeRef::Error => drop(write!(self, "{{unknown}}")), 504 TypeRef::Error => w!(self, "{{unknown}}"),
470 TypeRef::ImplTrait(bounds) => { 505 TypeRef::ImplTrait(bounds) => {
471 w!(self, "impl "); 506 w!(self, "impl ");
472 self.print_type_bounds(bounds); 507 self.print_type_bounds(bounds);
@@ -493,15 +528,168 @@ impl<'a> Printer<'a> {
493 } 528 }
494 529
495 fn print_path(&mut self, path: &Path) { 530 fn print_path(&mut self, path: &Path) {
496 if path.type_anchor().is_none() 531 match path.type_anchor() {
497 && path.segments().iter().all(|seg| seg.args_and_bindings.is_none()) 532 Some(anchor) => {
498 { 533 w!(self, "<");
499 w!(self, "{}", path.mod_path()); 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{{");
500 } else { 643 } else {
501 // too complicated, just use `Debug` 644 self.whitespace();
502 w!(self, "{:?}", path); 645 w!(self, "{{");
503 } 646 }
504 } 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 }
505} 693}
506 694
507impl<'a> Write for Printer<'a> { 695impl<'a> Write for Printer<'a> {
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index 100ae9b97..6407871b5 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -183,7 +183,11 @@ trait Tr: SuperTrait + 'lifetime {
183 _: (), 183 _: (),
184 ) -> (); 184 ) -> ();
185 185
186 pub(self) trait Tr: SuperTrait + 'lifetime { 186 pub(self) trait Tr<Self>: SuperTrait + 'lifetime
187 where
188 Self: SuperTrait,
189 Self: 'lifetime
190 {
187 pub(self) type Assoc: AssocBound = Default; 191 pub(self) type Assoc: AssocBound = Default;
188 192
189 // flags = 0x1 193 // flags = 0x1
@@ -207,6 +211,8 @@ mod inline {
207 211
208 fn fn_in_module() {} 212 fn fn_in_module() {}
209} 213}
214
215mod outline;
210 "#, 216 "#,
211 expect![[r##" 217 expect![[r##"
212 #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 } 218 #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 }
@@ -217,6 +223,8 @@ mod inline {
217 // flags = 0x2 223 // flags = 0x2
218 pub(self) fn fn_in_module() -> (); 224 pub(self) fn fn_in_module() -> ();
219 } 225 }
226
227 pub(self) mod outline;
220 "##]], 228 "##]],
221 ); 229 );
222} 230}
@@ -242,3 +250,115 @@ m!();
242 "#]], 250 "#]],
243 ); 251 );
244} 252}
253
254#[test]
255fn mod_paths() {
256 check(
257 r#"
258struct S {
259 a: self::Ty,
260 b: super::SuperTy,
261 c: super::super::SuperSuperTy,
262 d: ::abs::Path,
263 e: crate::Crate,
264 f: plain::path::Ty,
265}
266 "#,
267 expect![[r#"
268 pub(self) struct S {
269 pub(self) a: self::Ty,
270 pub(self) b: super::SuperTy,
271 pub(self) c: super::super::SuperSuperTy,
272 pub(self) d: ::abs::Path,
273 pub(self) e: crate::Crate,
274 pub(self) f: plain::path::Ty,
275 }
276 "#]],
277 )
278}
279
280#[test]
281fn types() {
282 check(
283 r#"
284struct S {
285 a: Mixed<'a, T, Item=(), OtherItem=u8>,
286 b: <Fully as Qualified>::Syntax,
287 c: <TypeAnchored>::Path::<'a>,
288}
289 "#,
290 expect![[r#"
291 pub(self) struct S {
292 pub(self) a: Mixed<'a, T, Item = (), OtherItem = u8>,
293 pub(self) b: Qualified<Self=Fully>::Syntax,
294 pub(self) c: <TypeAnchored>::Path<'a>,
295 }
296 "#]],
297 )
298}
299
300#[test]
301fn generics() {
302 check(
303 r#"
304struct S<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> {
305 field: &'a &'b T,
306}
307
308struct Tuple<T: Copy>(T);
309
310impl<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> S<'a, 'b, T, K> {
311 fn f<G: 'a>(arg: impl Copy) -> impl Copy {}
312}
313
314enum Enum<'a, T, const U: u8> {}
315union Union<'a, T, const U: u8> {}
316
317trait Tr<'a, T: 'a>: Super {}
318 "#,
319 expect![[r#"
320 pub(self) struct S<'a, 'b, T, const K: u8>
321 where
322 T: Copy,
323 T: 'a,
324 T: 'b
325 {
326 pub(self) field: &'a &'b T,
327 }
328
329 pub(self) struct Tuple<T>(
330 pub(self) 0: T,
331 )
332 where
333 T: Copy;
334
335 impl<'a, 'b, T, const K: u8> S<'a, 'b, T, K>
336 where
337 T: Copy,
338 T: 'a,
339 T: 'b
340 {
341 // flags = 0x2
342 pub(self) fn f<G, _anon_1>(
343 _: impl Copy,
344 ) -> impl Copy
345 where
346 G: 'a,
347 _anon_1: Copy;
348 }
349
350 pub(self) enum Enum<'a, T, const U: u8> {
351 }
352
353 pub(self) union Union<'a, T, const U: u8> {
354 }
355
356 pub(self) trait Tr<'a, Self, T>: Super
357 where
358 Self: Super,
359 T: 'a
360 {
361 }
362 "#]],
363 )
364}