diff options
Diffstat (limited to 'crates/ra_syntax/src/ast.rs')
-rw-r--r-- | crates/ra_syntax/src/ast.rs | 317 |
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 | ||
8 | pub use self::generated::*; | 8 | pub use self::generated::*; |
9 | use crate::{ | 9 | use 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 | ||
28 | pub trait AstToken: AstNode { | 28 | pub 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 | ||
114 | pub trait TypeBoundsOwner: AstNode { | ||
115 | fn type_bound_list(&self) -> Option<&TypeBoundList> { | ||
116 | child_opt(self) | ||
117 | } | ||
118 | } | ||
119 | |||
113 | pub trait AttrsOwner: AstNode { | 120 | pub 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 | ||
122 | pub trait DocCommentsOwner: AstNode { | 129 | pub 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 | ||
206 | impl Comment { | 213 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
214 | pub struct Comment<'a>(SyntaxToken<'a>); | ||
215 | |||
216 | impl<'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 = &()> { | 255 | pub 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 { | 259 | impl<'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 | ||
264 | impl Whitespace { | 293 | pub 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(|_| &()) | 295 | impl<'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 | ||
274 | impl Name { | 318 | impl 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 | ||
281 | impl NameRef { | 325 | impl 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 | ||
311 | impl Module { | 355 | impl 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 | ||
320 | impl LetStmt { | 364 | impl 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 | ||
355 | impl ExprStmt { | 399 | impl 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 | ||
405 | impl UseTree { | 449 | impl 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 | ||
420 | impl RefPat { | 464 | impl 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 | ||
495 | impl PointerType { | 539 | impl 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 | ||
501 | impl ReferenceType { | 545 | impl 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 | ||
507 | impl RefExpr { | 551 | impl 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 | ||
523 | impl PrefixExpr { | 567 | impl 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 | ||
604 | impl BinExpr { | 648 | impl 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 | ||
676 | impl SelfParam { | 722 | impl 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 | ||
704 | impl LiteralExpr { | 762 | impl 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 | ||
745 | impl BindPat { | 809 | impl 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 | |||
819 | impl 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 | |||
828 | impl 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] | ||
880 | fn 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#" | ||
887 | fn foo() | ||
888 | where | ||
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 | } | ||