aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/ast.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/ast.rs')
-rw-r--r--crates/ra_syntax/src/ast.rs317
1 files changed, 233 insertions, 84 deletions
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index a6fac07c4..9a44afc67 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -7,7 +7,7 @@ use itertools::Itertools;
7 7
8pub use self::generated::*; 8pub use self::generated::*;
9use crate::{ 9use crate::{
10 syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes}, 10 syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken, SyntaxElement, SyntaxElementChildren},
11 SmolStr, 11 SmolStr,
12 SyntaxKind::*, 12 SyntaxKind::*,
13}; 13};
@@ -27,7 +27,8 @@ pub trait AstNode:
27 27
28pub trait AstToken: AstNode { 28pub trait AstToken: AstNode {
29 fn text(&self) -> &SmolStr { 29 fn text(&self) -> &SmolStr {
30 self.syntax().leaf_text().unwrap() 30 // self.syntax().leaf_text().unwrap()
31 unimplemented!()
31 } 32 }
32} 33}
33 34
@@ -110,6 +111,12 @@ pub trait TypeParamsOwner: AstNode {
110 } 111 }
111} 112}
112 113
114pub trait TypeBoundsOwner: AstNode {
115 fn type_bound_list(&self) -> Option<&TypeBoundList> {
116 child_opt(self)
117 }
118}
119
113pub trait AttrsOwner: AstNode { 120pub trait AttrsOwner: AstNode {
114 fn attrs(&self) -> AstChildren<Attr> { 121 fn attrs(&self) -> AstChildren<Attr> {
115 children(self) 122 children(self)
@@ -120,8 +127,8 @@ pub trait AttrsOwner: AstNode {
120} 127}
121 128
122pub trait DocCommentsOwner: AstNode { 129pub trait DocCommentsOwner: AstNode {
123 fn doc_comments(&self) -> AstChildren<Comment> { 130 fn doc_comments(&self) -> CommentIter {
124 children(self) 131 CommentIter { iter: self.syntax().children_with_tokens() }
125 } 132 }
126 133
127 /// Returns the textual content of a doc comment block as a single string. 134 /// Returns the textual content of a doc comment block as a single string.
@@ -173,9 +180,9 @@ impl Attr {
173 180
174 pub fn as_atom(&self) -> Option<SmolStr> { 181 pub fn as_atom(&self) -> Option<SmolStr> {
175 let tt = self.value()?; 182 let tt = self.value()?;
176 let (_bra, attr, _ket) = tt.syntax().children().collect_tuple()?; 183 let (_bra, attr, _ket) = tt.syntax().children_with_tokens().collect_tuple()?;
177 if attr.kind() == IDENT { 184 if attr.kind() == IDENT {
178 Some(attr.leaf_text().unwrap().clone()) 185 Some(attr.as_token()?.text().clone())
179 } else { 186 } else {
180 None 187 None
181 } 188 }
@@ -183,10 +190,10 @@ impl Attr {
183 190
184 pub fn as_call(&self) -> Option<(SmolStr, &TokenTree)> { 191 pub fn as_call(&self) -> Option<(SmolStr, &TokenTree)> {
185 let tt = self.value()?; 192 let tt = self.value()?;
186 let (_bra, attr, args, _ket) = tt.syntax().children().collect_tuple()?; 193 let (_bra, attr, args, _ket) = tt.syntax().children_with_tokens().collect_tuple()?;
187 let args = TokenTree::cast(args)?; 194 let args = TokenTree::cast(args.as_node()?)?;
188 if attr.kind() == IDENT { 195 if attr.kind() == IDENT {
189 Some((attr.leaf_text().unwrap().clone(), args)) 196 Some((attr.as_token()?.text().clone(), args))
190 } else { 197 } else {
191 None 198 None
192 } 199 }
@@ -194,16 +201,35 @@ impl Attr {
194 201
195 pub fn as_named(&self) -> Option<SmolStr> { 202 pub fn as_named(&self) -> Option<SmolStr> {
196 let tt = self.value()?; 203 let tt = self.value()?;
197 let attr = tt.syntax().children().nth(1)?; 204 let attr = tt.syntax().children_with_tokens().nth(1)?;
198 if attr.kind() == IDENT { 205 if attr.kind() == IDENT {
199 Some(attr.leaf_text().unwrap().clone()) 206 Some(attr.as_token()?.text().clone())
200 } else { 207 } else {
201 None 208 None
202 } 209 }
203 } 210 }
204} 211}
205 212
206impl Comment { 213#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
214pub struct Comment<'a>(SyntaxToken<'a>);
215
216impl<'a> Comment<'a> {
217 pub fn cast(token: SyntaxToken<'a>) -> Option<Self> {
218 if token.kind() == COMMENT {
219 Some(Comment(token))
220 } else {
221 None
222 }
223 }
224
225 pub fn syntax(&self) -> SyntaxToken<'a> {
226 self.0
227 }
228
229 pub fn text(&self) -> &'a SmolStr {
230 self.0.text()
231 }
232
207 pub fn flavor(&self) -> CommentFlavor { 233 pub fn flavor(&self) -> CommentFlavor {
208 let text = self.text(); 234 let text = self.text();
209 if text.starts_with("///") { 235 if text.starts_with("///") {
@@ -224,13 +250,16 @@ impl Comment {
224 pub fn prefix(&self) -> &'static str { 250 pub fn prefix(&self) -> &'static str {
225 self.flavor().prefix() 251 self.flavor().prefix()
226 } 252 }
253}
227 254
228 pub fn count_newlines_lazy(&self) -> impl Iterator<Item = &()> { 255pub struct CommentIter<'a> {
229 self.text().chars().filter(|&c| c == '\n').map(|_| &()) 256 iter: SyntaxElementChildren<'a>,
230 } 257}
231 258
232 pub fn has_newlines(&self) -> bool { 259impl<'a> Iterator for CommentIter<'a> {
233 self.count_newlines_lazy().count() > 0 260 type Item = Comment<'a>;
261 fn next(&mut self) -> Option<Comment<'a>> {
262 self.iter.by_ref().find_map(|el| el.as_token().and_then(Comment::cast))
234 } 263 }
235} 264}
236 265
@@ -261,27 +290,42 @@ impl CommentFlavor {
261 } 290 }
262} 291}
263 292
264impl Whitespace { 293pub struct Whitespace<'a>(SyntaxToken<'a>);
265 pub fn count_newlines_lazy(&self) -> impl Iterator<Item = &()> { 294
266 self.text().chars().filter(|&c| c == '\n').map(|_| &()) 295impl<'a> Whitespace<'a> {
296 pub fn cast(token: SyntaxToken<'a>) -> Option<Self> {
297 if token.kind() == WHITESPACE {
298 Some(Whitespace(token))
299 } else {
300 None
301 }
267 } 302 }
268 303
269 pub fn has_newlines(&self) -> bool { 304 pub fn syntax(&self) -> SyntaxToken<'a> {
270 self.text().contains('\n') 305 self.0
306 }
307
308 pub fn text(&self) -> &'a SmolStr {
309 self.0.text()
310 }
311
312 pub fn spans_multiple_lines(&self) -> bool {
313 let text = self.text();
314 text.find('\n').map_or(false, |idx| text[idx + 1..].contains('\n'))
271 } 315 }
272} 316}
273 317
274impl Name { 318impl Name {
275 pub fn text(&self) -> &SmolStr { 319 pub fn text(&self) -> &SmolStr {
276 let ident = self.syntax().first_child().unwrap(); 320 let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap();
277 ident.leaf_text().unwrap() 321 ident.text()
278 } 322 }
279} 323}
280 324
281impl NameRef { 325impl NameRef {
282 pub fn text(&self) -> &SmolStr { 326 pub fn text(&self) -> &SmolStr {
283 let ident = self.syntax().first_child().unwrap(); 327 let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap();
284 ident.leaf_text().unwrap() 328 ident.text()
285 } 329 }
286} 330}
287 331
@@ -310,7 +354,7 @@ impl ImplBlock {
310 354
311impl Module { 355impl Module {
312 pub fn has_semi(&self) -> bool { 356 pub fn has_semi(&self) -> bool {
313 match self.syntax().last_child() { 357 match self.syntax().last_child_or_token() {
314 None => false, 358 None => false,
315 Some(node) => node.kind() == SEMI, 359 Some(node) => node.kind() == SEMI,
316 } 360 }
@@ -319,7 +363,7 @@ impl Module {
319 363
320impl LetStmt { 364impl LetStmt {
321 pub fn has_semi(&self) -> bool { 365 pub fn has_semi(&self) -> bool {
322 match self.syntax().last_child() { 366 match self.syntax().last_child_or_token() {
323 None => false, 367 None => false,
324 Some(node) => node.kind() == SEMI, 368 Some(node) => node.kind() == SEMI,
325 } 369 }
@@ -354,7 +398,7 @@ impl IfExpr {
354 398
355impl ExprStmt { 399impl ExprStmt {
356 pub fn has_semi(&self) -> bool { 400 pub fn has_semi(&self) -> bool {
357 match self.syntax().last_child() { 401 match self.syntax().last_child_or_token() {
358 None => false, 402 None => false,
359 Some(node) => node.kind() == SEMI, 403 Some(node) => node.kind() == SEMI,
360 } 404 }
@@ -378,7 +422,7 @@ impl PathSegment {
378 let res = if let Some(name_ref) = self.name_ref() { 422 let res = if let Some(name_ref) = self.name_ref() {
379 PathSegmentKind::Name(name_ref) 423 PathSegmentKind::Name(name_ref)
380 } else { 424 } else {
381 match self.syntax().first_child()?.kind() { 425 match self.syntax().first_child_or_token()?.kind() {
382 SELF_KW => PathSegmentKind::SelfKw, 426 SELF_KW => PathSegmentKind::SelfKw,
383 SUPER_KW => PathSegmentKind::SuperKw, 427 SUPER_KW => PathSegmentKind::SuperKw,
384 CRATE_KW => PathSegmentKind::CrateKw, 428 CRATE_KW => PathSegmentKind::CrateKw,
@@ -389,7 +433,7 @@ impl PathSegment {
389 } 433 }
390 434
391 pub fn has_colon_colon(&self) -> bool { 435 pub fn has_colon_colon(&self) -> bool {
392 match self.syntax.first_child().map(|s| s.kind()) { 436 match self.syntax.first_child_or_token().map(|s| s.kind()) {
393 Some(COLONCOLON) => true, 437 Some(COLONCOLON) => true,
394 _ => false, 438 _ => false,
395 } 439 }
@@ -404,7 +448,7 @@ impl Path {
404 448
405impl UseTree { 449impl UseTree {
406 pub fn has_star(&self) -> bool { 450 pub fn has_star(&self) -> bool {
407 self.syntax().children().any(|it| it.kind() == STAR) 451 self.syntax().children_with_tokens().any(|it| it.kind() == STAR)
408 } 452 }
409} 453}
410 454
@@ -419,7 +463,7 @@ impl UseTreeList {
419 463
420impl RefPat { 464impl RefPat {
421 pub fn is_mut(&self) -> bool { 465 pub fn is_mut(&self) -> bool {
422 self.syntax().children().any(|n| n.kind() == MUT_KW) 466 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
423 } 467 }
424} 468}
425 469
@@ -494,19 +538,19 @@ impl EnumVariant {
494 538
495impl PointerType { 539impl PointerType {
496 pub fn is_mut(&self) -> bool { 540 pub fn is_mut(&self) -> bool {
497 self.syntax().children().any(|n| n.kind() == MUT_KW) 541 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
498 } 542 }
499} 543}
500 544
501impl ReferenceType { 545impl ReferenceType {
502 pub fn is_mut(&self) -> bool { 546 pub fn is_mut(&self) -> bool {
503 self.syntax().children().any(|n| n.kind() == MUT_KW) 547 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
504 } 548 }
505} 549}
506 550
507impl RefExpr { 551impl RefExpr {
508 pub fn is_mut(&self) -> bool { 552 pub fn is_mut(&self) -> bool {
509 self.syntax().children().any(|n| n.kind() == MUT_KW) 553 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
510 } 554 }
511} 555}
512 556
@@ -522,7 +566,7 @@ pub enum PrefixOp {
522 566
523impl PrefixExpr { 567impl PrefixExpr {
524 pub fn op_kind(&self) -> Option<PrefixOp> { 568 pub fn op_kind(&self) -> Option<PrefixOp> {
525 match self.syntax().first_child()?.kind() { 569 match self.op_token()?.kind() {
526 STAR => Some(PrefixOp::Deref), 570 STAR => Some(PrefixOp::Deref),
527 EXCL => Some(PrefixOp::Not), 571 EXCL => Some(PrefixOp::Not),
528 MINUS => Some(PrefixOp::Neg), 572 MINUS => Some(PrefixOp::Neg),
@@ -530,8 +574,8 @@ impl PrefixExpr {
530 } 574 }
531 } 575 }
532 576
533 pub fn op(&self) -> Option<&SyntaxNode> { 577 pub fn op_token(&self) -> Option<SyntaxToken> {
534 self.syntax().first_child() 578 self.syntax().first_child_or_token()?.as_token()
535 } 579 }
536} 580}
537 581
@@ -602,40 +646,42 @@ pub enum BinOp {
602} 646}
603 647
604impl BinExpr { 648impl BinExpr {
605 fn op_details(&self) -> Option<(&SyntaxNode, BinOp)> { 649 fn op_details(&self) -> Option<(SyntaxToken, BinOp)> {
606 self.syntax().children().find_map(|c| match c.kind() { 650 self.syntax().children_with_tokens().filter_map(|it| it.as_token()).find_map(|c| {
607 PIPEPIPE => Some((c, BinOp::BooleanOr)), 651 match c.kind() {
608 AMPAMP => Some((c, BinOp::BooleanAnd)), 652 PIPEPIPE => Some((c, BinOp::BooleanOr)),
609 EQEQ => Some((c, BinOp::EqualityTest)), 653 AMPAMP => Some((c, BinOp::BooleanAnd)),
610 NEQ => Some((c, BinOp::NegatedEqualityTest)), 654 EQEQ => Some((c, BinOp::EqualityTest)),
611 LTEQ => Some((c, BinOp::LesserEqualTest)), 655 NEQ => Some((c, BinOp::NegatedEqualityTest)),
612 GTEQ => Some((c, BinOp::GreaterEqualTest)), 656 LTEQ => Some((c, BinOp::LesserEqualTest)),
613 L_ANGLE => Some((c, BinOp::LesserTest)), 657 GTEQ => Some((c, BinOp::GreaterEqualTest)),
614 R_ANGLE => Some((c, BinOp::GreaterTest)), 658 L_ANGLE => Some((c, BinOp::LesserTest)),
615 PLUS => Some((c, BinOp::Addition)), 659 R_ANGLE => Some((c, BinOp::GreaterTest)),
616 STAR => Some((c, BinOp::Multiplication)), 660 PLUS => Some((c, BinOp::Addition)),
617 MINUS => Some((c, BinOp::Subtraction)), 661 STAR => Some((c, BinOp::Multiplication)),
618 SLASH => Some((c, BinOp::Division)), 662 MINUS => Some((c, BinOp::Subtraction)),
619 PERCENT => Some((c, BinOp::Remainder)), 663 SLASH => Some((c, BinOp::Division)),
620 SHL => Some((c, BinOp::LeftShift)), 664 PERCENT => Some((c, BinOp::Remainder)),
621 SHR => Some((c, BinOp::RightShift)), 665 SHL => Some((c, BinOp::LeftShift)),
622 CARET => Some((c, BinOp::BitwiseXor)), 666 SHR => Some((c, BinOp::RightShift)),
623 PIPE => Some((c, BinOp::BitwiseOr)), 667 CARET => Some((c, BinOp::BitwiseXor)),
624 AMP => Some((c, BinOp::BitwiseAnd)), 668 PIPE => Some((c, BinOp::BitwiseOr)),
625 DOTDOT => Some((c, BinOp::RangeRightOpen)), 669 AMP => Some((c, BinOp::BitwiseAnd)),
626 DOTDOTEQ => Some((c, BinOp::RangeRightClosed)), 670 DOTDOT => Some((c, BinOp::RangeRightOpen)),
627 EQ => Some((c, BinOp::Assignment)), 671 DOTDOTEQ => Some((c, BinOp::RangeRightClosed)),
628 PLUSEQ => Some((c, BinOp::AddAssign)), 672 EQ => Some((c, BinOp::Assignment)),
629 SLASHEQ => Some((c, BinOp::DivAssign)), 673 PLUSEQ => Some((c, BinOp::AddAssign)),
630 STAREQ => Some((c, BinOp::MulAssign)), 674 SLASHEQ => Some((c, BinOp::DivAssign)),
631 PERCENTEQ => Some((c, BinOp::RemAssign)), 675 STAREQ => Some((c, BinOp::MulAssign)),
632 SHREQ => Some((c, BinOp::ShrAssign)), 676 PERCENTEQ => Some((c, BinOp::RemAssign)),
633 SHLEQ => Some((c, BinOp::ShlAssign)), 677 SHREQ => Some((c, BinOp::ShrAssign)),
634 MINUSEQ => Some((c, BinOp::SubAssign)), 678 SHLEQ => Some((c, BinOp::ShlAssign)),
635 PIPEEQ => Some((c, BinOp::BitOrAssign)), 679 MINUSEQ => Some((c, BinOp::SubAssign)),
636 AMPEQ => Some((c, BinOp::BitAndAssign)), 680 PIPEEQ => Some((c, BinOp::BitOrAssign)),
637 CARETEQ => Some((c, BinOp::BitXorAssign)), 681 AMPEQ => Some((c, BinOp::BitAndAssign)),
638 _ => None, 682 CARETEQ => Some((c, BinOp::BitXorAssign)),
683 _ => None,
684 }
639 }) 685 })
640 } 686 }
641 687
@@ -643,7 +689,7 @@ impl BinExpr {
643 self.op_details().map(|t| t.1) 689 self.op_details().map(|t| t.1)
644 } 690 }
645 691
646 pub fn op(&self) -> Option<&SyntaxNode> { 692 pub fn op_token(&self) -> Option<SyntaxToken> {
647 self.op_details().map(|t| t.0) 693 self.op_details().map(|t| t.0)
648 } 694 }
649 695
@@ -674,11 +720,23 @@ pub enum SelfParamFlavor {
674} 720}
675 721
676impl SelfParam { 722impl SelfParam {
723 pub fn self_kw_token(&self) -> SyntaxToken {
724 self.syntax()
725 .children_with_tokens()
726 .filter_map(|it| it.as_token())
727 .find(|it| it.kind() == SELF_KW)
728 .expect("invalid tree: self param must have self")
729 }
730
677 pub fn flavor(&self) -> SelfParamFlavor { 731 pub fn flavor(&self) -> SelfParamFlavor {
678 let borrowed = self.syntax().children().any(|n| n.kind() == AMP); 732 let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == AMP);
679 if borrowed { 733 if borrowed {
680 // check for a `mut` coming after the & -- `mut &self` != `&mut self` 734 // check for a `mut` coming after the & -- `mut &self` != `&mut self`
681 if self.syntax().children().skip_while(|n| n.kind() != AMP).any(|n| n.kind() == MUT_KW) 735 if self
736 .syntax()
737 .children_with_tokens()
738 .skip_while(|n| n.kind() != AMP)
739 .any(|n| n.kind() == MUT_KW)
682 { 740 {
683 SelfParamFlavor::MutRef 741 SelfParamFlavor::MutRef
684 } else { 742 } else {
@@ -701,25 +759,31 @@ pub enum LiteralFlavor {
701 Bool, 759 Bool,
702} 760}
703 761
704impl LiteralExpr { 762impl Literal {
763 pub fn token(&self) -> SyntaxToken {
764 match self.syntax().first_child_or_token().unwrap() {
765 SyntaxElement::Token(token) => token,
766 _ => unreachable!(),
767 }
768 }
769
705 pub fn flavor(&self) -> LiteralFlavor { 770 pub fn flavor(&self) -> LiteralFlavor {
706 let syntax = self.syntax(); 771 match self.token().kind() {
707 match syntax.kind() {
708 INT_NUMBER => { 772 INT_NUMBER => {
709 let allowed_suffix_list = [ 773 let allowed_suffix_list = [
710 "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32", 774 "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32",
711 "u16", "u8", 775 "u16", "u8",
712 ]; 776 ];
713 let text = syntax.text().to_string(); 777 let text = self.token().text().to_string();
714 let suffix = allowed_suffix_list 778 let suffix = allowed_suffix_list
715 .iter() 779 .iter()
716 .find(|&s| text.ends_with(s)) 780 .find(|&s| text.ends_with(s))
717 .map(|&suf| SmolStr::new(suf)); 781 .map(|&suf| SmolStr::new(suf));
718 LiteralFlavor::IntNumber { suffix: suffix } 782 LiteralFlavor::IntNumber { suffix }
719 } 783 }
720 FLOAT_NUMBER => { 784 FLOAT_NUMBER => {
721 let allowed_suffix_list = ["f64", "f32"]; 785 let allowed_suffix_list = ["f64", "f32"];
722 let text = syntax.text().to_string(); 786 let text = self.token().text().to_string();
723 let suffix = allowed_suffix_list 787 let suffix = allowed_suffix_list
724 .iter() 788 .iter()
725 .find(|&s| text.ends_with(s)) 789 .find(|&s| text.ends_with(s))
@@ -744,11 +808,29 @@ impl NamedField {
744 808
745impl BindPat { 809impl BindPat {
746 pub fn is_mutable(&self) -> bool { 810 pub fn is_mutable(&self) -> bool {
747 self.syntax().children().any(|n| n.kind() == MUT_KW) 811 self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW)
748 } 812 }
749 813
750 pub fn is_ref(&self) -> bool { 814 pub fn is_ref(&self) -> bool {
751 self.syntax().children().any(|n| n.kind() == REF_KW) 815 self.syntax().children_with_tokens().any(|n| n.kind() == REF_KW)
816 }
817}
818
819impl LifetimeParam {
820 pub fn lifetime_token(&self) -> Option<SyntaxToken> {
821 self.syntax()
822 .children_with_tokens()
823 .filter_map(|it| it.as_token())
824 .find(|it| it.kind() == LIFETIME)
825 }
826}
827
828impl WherePred {
829 pub fn lifetime_token(&self) -> Option<SyntaxToken> {
830 self.syntax()
831 .children_with_tokens()
832 .filter_map(|it| it.as_token())
833 .find(|it| it.kind() == LIFETIME)
752 } 834 }
753} 835}
754 836
@@ -793,3 +875,70 @@ fn test_doc_comment_preserves_indents() {
793 let module = file.syntax().descendants().find_map(Module::cast).unwrap(); 875 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
794 assert_eq!("doc1\n```\nfn foo() {\n // ...\n}\n```", module.doc_comment_text().unwrap()); 876 assert_eq!("doc1\n```\nfn foo() {\n // ...\n}\n```", module.doc_comment_text().unwrap());
795} 877}
878
879#[test]
880fn test_where_predicates() {
881 fn assert_bound(text: &str, bound: Option<&TypeBound>) {
882 assert_eq!(text, bound.unwrap().syntax().text().to_string());
883 }
884
885 let file = SourceFile::parse(
886 r#"
887fn foo()
888where
889 T: Clone + Copy + Debug + 'static,
890 'a: 'b + 'c,
891 Iterator::Item: 'a + Debug,
892 Iterator::Item: Debug + 'a,
893 <T as Iterator>::Item: Debug + 'a,
894 for<'a> F: Fn(&'a str)
895{}
896 "#,
897 );
898 let where_clause = file.syntax().descendants().find_map(WhereClause::cast).unwrap();
899
900 let mut predicates = where_clause.predicates();
901
902 let pred = predicates.next().unwrap();
903 let mut bounds = pred.type_bound_list().unwrap().bounds();
904
905 assert_eq!("T", pred.type_ref().unwrap().syntax().text().to_string());
906 assert_bound("Clone", bounds.next());
907 assert_bound("Copy", bounds.next());
908 assert_bound("Debug", bounds.next());
909 assert_bound("'static", bounds.next());
910
911 let pred = predicates.next().unwrap();
912 let mut bounds = pred.type_bound_list().unwrap().bounds();
913
914 assert_eq!("'a", pred.lifetime_token().unwrap().text());
915
916 assert_bound("'b", bounds.next());
917 assert_bound("'c", bounds.next());
918
919 let pred = predicates.next().unwrap();
920 let mut bounds = pred.type_bound_list().unwrap().bounds();
921
922 assert_eq!("Iterator::Item", pred.type_ref().unwrap().syntax().text().to_string());
923 assert_bound("'a", bounds.next());
924
925 let pred = predicates.next().unwrap();
926 let mut bounds = pred.type_bound_list().unwrap().bounds();
927
928 assert_eq!("Iterator::Item", pred.type_ref().unwrap().syntax().text().to_string());
929 assert_bound("Debug", bounds.next());
930 assert_bound("'a", bounds.next());
931
932 let pred = predicates.next().unwrap();
933 let mut bounds = pred.type_bound_list().unwrap().bounds();
934
935 assert_eq!("<T as Iterator>::Item", pred.type_ref().unwrap().syntax().text().to_string());
936 assert_bound("Debug", bounds.next());
937 assert_bound("'a", bounds.next());
938
939 let pred = predicates.next().unwrap();
940 let mut bounds = pred.type_bound_list().unwrap().bounds();
941
942 assert_eq!("for<'a> F", pred.type_ref().unwrap().syntax().text().to_string());
943 assert_bound("Fn(&'a str)", bounds.next());
944}