diff options
Diffstat (limited to 'crates/ra_syntax/src/ast/extensions.rs')
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 229 |
1 files changed, 68 insertions, 161 deletions
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index 33fe60762..63e272fbf 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -2,16 +2,12 @@ | |||
2 | //! Extensions for various expressions live in a sibling `expr_extensions` module. | 2 | //! Extensions for various expressions live in a sibling `expr_extensions` module. |
3 | 3 | ||
4 | use itertools::Itertools; | 4 | use itertools::Itertools; |
5 | use ra_parser::SyntaxKind; | ||
5 | 6 | ||
6 | use crate::{ | 7 | use crate::{ |
7 | ast::{ | 8 | ast::{self, support, AstNode, AttrInput, NameOwner, SyntaxNode}, |
8 | self, child_opt, children, support, AstNode, AstToken, AttrInput, NameOwner, SyntaxNode, | 9 | SmolStr, SyntaxElement, SyntaxToken, T, |
9 | }, | ||
10 | SmolStr, SyntaxElement, | ||
11 | SyntaxKind::*, | ||
12 | SyntaxToken, T, | ||
13 | }; | 10 | }; |
14 | use ra_parser::SyntaxKind; | ||
15 | 11 | ||
16 | impl ast::Name { | 12 | impl ast::Name { |
17 | pub fn text(&self) -> &SmolStr { | 13 | pub fn text(&self) -> &SmolStr { |
@@ -25,13 +21,7 @@ impl ast::NameRef { | |||
25 | } | 21 | } |
26 | 22 | ||
27 | pub fn as_tuple_field(&self) -> Option<usize> { | 23 | pub fn as_tuple_field(&self) -> Option<usize> { |
28 | self.syntax().children_with_tokens().find_map(|c| { | 24 | self.text().parse().ok() |
29 | if c.kind() == SyntaxKind::INT_NUMBER { | ||
30 | c.as_token().and_then(|tok| tok.text().as_str().parse().ok()) | ||
31 | } else { | ||
32 | None | ||
33 | } | ||
34 | }) | ||
35 | } | 25 | } |
36 | } | 26 | } |
37 | 27 | ||
@@ -87,7 +77,7 @@ impl ast::Attr { | |||
87 | first_token.and_then(|token| token.next_token()).as_ref().map(SyntaxToken::kind); | 77 | first_token.and_then(|token| token.next_token()).as_ref().map(SyntaxToken::kind); |
88 | 78 | ||
89 | match (first_token_kind, second_token_kind) { | 79 | match (first_token_kind, second_token_kind) { |
90 | (Some(SyntaxKind::POUND), Some(SyntaxKind::EXCL)) => AttrKind::Inner, | 80 | (Some(SyntaxKind::POUND), Some(T![!])) => AttrKind::Inner, |
91 | _ => AttrKind::Outer, | 81 | _ => AttrKind::Outer, |
92 | } | 82 | } |
93 | } | 83 | } |
@@ -140,15 +130,6 @@ impl ast::Path { | |||
140 | } | 130 | } |
141 | } | 131 | } |
142 | 132 | ||
143 | impl ast::Module { | ||
144 | pub fn has_semi(&self) -> bool { | ||
145 | match self.syntax().last_child_or_token() { | ||
146 | None => false, | ||
147 | Some(node) => node.kind() == T![;], | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | |||
152 | impl ast::UseTreeList { | 133 | impl ast::UseTreeList { |
153 | pub fn parent_use_tree(&self) -> ast::UseTree { | 134 | pub fn parent_use_tree(&self) -> ast::UseTree { |
154 | self.syntax() | 135 | self.syntax() |
@@ -174,15 +155,11 @@ impl ast::ImplDef { | |||
174 | } | 155 | } |
175 | 156 | ||
176 | fn target(&self) -> (Option<ast::TypeRef>, Option<ast::TypeRef>) { | 157 | fn target(&self) -> (Option<ast::TypeRef>, Option<ast::TypeRef>) { |
177 | let mut types = children(self); | 158 | let mut types = support::children(self.syntax()); |
178 | let first = types.next(); | 159 | let first = types.next(); |
179 | let second = types.next(); | 160 | let second = types.next(); |
180 | (first, second) | 161 | (first, second) |
181 | } | 162 | } |
182 | |||
183 | pub fn is_negative(&self) -> bool { | ||
184 | self.syntax().children_with_tokens().any(|t| t.kind() == T![!]) | ||
185 | } | ||
186 | } | 163 | } |
187 | 164 | ||
188 | #[derive(Debug, Clone, PartialEq, Eq)] | 165 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -194,9 +171,9 @@ pub enum StructKind { | |||
194 | 171 | ||
195 | impl StructKind { | 172 | impl StructKind { |
196 | fn from_node<N: AstNode>(node: &N) -> StructKind { | 173 | fn from_node<N: AstNode>(node: &N) -> StructKind { |
197 | if let Some(nfdl) = child_opt::<_, ast::RecordFieldDefList>(node) { | 174 | if let Some(nfdl) = support::child::<ast::RecordFieldDefList>(node.syntax()) { |
198 | StructKind::Record(nfdl) | 175 | StructKind::Record(nfdl) |
199 | } else if let Some(pfl) = child_opt::<_, ast::TupleFieldDefList>(node) { | 176 | } else if let Some(pfl) = support::child::<ast::TupleFieldDefList>(node.syntax()) { |
200 | StructKind::Tuple(pfl) | 177 | StructKind::Tuple(pfl) |
201 | } else { | 178 | } else { |
202 | StructKind::Unit | 179 | StructKind::Unit |
@@ -210,6 +187,36 @@ impl ast::StructDef { | |||
210 | } | 187 | } |
211 | } | 188 | } |
212 | 189 | ||
190 | impl ast::RecordField { | ||
191 | pub fn for_field_name(field_name: &ast::NameRef) -> Option<ast::RecordField> { | ||
192 | let candidate = | ||
193 | field_name.syntax().parent().and_then(ast::RecordField::cast).or_else(|| { | ||
194 | field_name.syntax().ancestors().nth(4).and_then(ast::RecordField::cast) | ||
195 | })?; | ||
196 | if candidate.field_name().as_ref() == Some(field_name) { | ||
197 | Some(candidate) | ||
198 | } else { | ||
199 | None | ||
200 | } | ||
201 | } | ||
202 | |||
203 | /// Deals with field init shorthand | ||
204 | pub fn field_name(&self) -> Option<ast::NameRef> { | ||
205 | if let Some(name_ref) = self.name_ref() { | ||
206 | return Some(name_ref); | ||
207 | } | ||
208 | if let Some(ast::Expr::PathExpr(expr)) = self.expr() { | ||
209 | let path = expr.path()?; | ||
210 | let segment = path.segment()?; | ||
211 | let name_ref = segment.name_ref()?; | ||
212 | if path.qualifier().is_none() { | ||
213 | return Some(name_ref); | ||
214 | } | ||
215 | } | ||
216 | None | ||
217 | } | ||
218 | } | ||
219 | |||
213 | impl ast::EnumVariant { | 220 | impl ast::EnumVariant { |
214 | pub fn parent_enum(&self) -> ast::EnumDef { | 221 | pub fn parent_enum(&self) -> ast::EnumDef { |
215 | self.syntax() | 222 | self.syntax() |
@@ -223,41 +230,6 @@ impl ast::EnumVariant { | |||
223 | } | 230 | } |
224 | } | 231 | } |
225 | 232 | ||
226 | impl ast::FnDef { | ||
227 | pub fn semicolon_token(&self) -> Option<SyntaxToken> { | ||
228 | self.syntax() | ||
229 | .last_child_or_token() | ||
230 | .and_then(|it| it.into_token()) | ||
231 | .filter(|it| it.kind() == T![;]) | ||
232 | } | ||
233 | |||
234 | pub fn is_async(&self) -> bool { | ||
235 | self.syntax().children_with_tokens().any(|it| it.kind() == T![async]) | ||
236 | } | ||
237 | } | ||
238 | |||
239 | impl ast::LetStmt { | ||
240 | pub fn has_semi(&self) -> bool { | ||
241 | match self.syntax().last_child_or_token() { | ||
242 | None => false, | ||
243 | Some(node) => node.kind() == T![;], | ||
244 | } | ||
245 | } | ||
246 | |||
247 | pub fn eq_token(&self) -> Option<SyntaxToken> { | ||
248 | self.syntax().children_with_tokens().find(|t| t.kind() == EQ).and_then(|it| it.into_token()) | ||
249 | } | ||
250 | } | ||
251 | |||
252 | impl ast::ExprStmt { | ||
253 | pub fn has_semi(&self) -> bool { | ||
254 | match self.syntax().last_child_or_token() { | ||
255 | None => false, | ||
256 | Some(node) => node.kind() == T![;], | ||
257 | } | ||
258 | } | ||
259 | } | ||
260 | |||
261 | #[derive(Debug, Clone, PartialEq, Eq)] | 233 | #[derive(Debug, Clone, PartialEq, Eq)] |
262 | pub enum FieldKind { | 234 | pub enum FieldKind { |
263 | Name(ast::NameRef), | 235 | Name(ast::NameRef), |
@@ -286,25 +258,6 @@ impl ast::FieldExpr { | |||
286 | } | 258 | } |
287 | } | 259 | } |
288 | 260 | ||
289 | impl ast::RefPat { | ||
290 | pub fn is_mut(&self) -> bool { | ||
291 | self.syntax().children_with_tokens().any(|n| n.kind() == T![mut]) | ||
292 | } | ||
293 | } | ||
294 | |||
295 | impl ast::BindPat { | ||
296 | pub fn is_mutable(&self) -> bool { | ||
297 | self.syntax().children_with_tokens().any(|n| n.kind() == T![mut]) | ||
298 | } | ||
299 | |||
300 | pub fn is_ref(&self) -> bool { | ||
301 | self.syntax().children_with_tokens().any(|n| n.kind() == T![ref]) | ||
302 | } | ||
303 | pub fn has_at(&self) -> bool { | ||
304 | self.syntax().children_with_tokens().any(|it| it.kind() == T![@]) | ||
305 | } | ||
306 | } | ||
307 | |||
308 | pub struct SlicePatComponents { | 261 | pub struct SlicePatComponents { |
309 | pub prefix: Vec<ast::Pat>, | 262 | pub prefix: Vec<ast::Pat>, |
310 | pub slice: Option<ast::Pat>, | 263 | pub slice: Option<ast::Pat>, |
@@ -339,18 +292,6 @@ impl ast::SlicePat { | |||
339 | } | 292 | } |
340 | } | 293 | } |
341 | 294 | ||
342 | impl ast::PointerType { | ||
343 | pub fn is_mut(&self) -> bool { | ||
344 | self.syntax().children_with_tokens().any(|n| n.kind() == T![mut]) | ||
345 | } | ||
346 | } | ||
347 | |||
348 | impl ast::ReferenceType { | ||
349 | pub fn is_mut(&self) -> bool { | ||
350 | self.syntax().children_with_tokens().any(|n| n.kind() == T![mut]) | ||
351 | } | ||
352 | } | ||
353 | |||
354 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | 295 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] |
355 | pub enum SelfParamKind { | 296 | pub enum SelfParamKind { |
356 | /// self | 297 | /// self |
@@ -363,8 +304,8 @@ pub enum SelfParamKind { | |||
363 | 304 | ||
364 | impl ast::SelfParam { | 305 | impl ast::SelfParam { |
365 | pub fn kind(&self) -> SelfParamKind { | 306 | pub fn kind(&self) -> SelfParamKind { |
366 | if self.amp().is_some() { | 307 | if self.amp_token().is_some() { |
367 | if self.amp_mut_kw().is_some() { | 308 | if self.mut_token().is_some() { |
368 | SelfParamKind::MutRef | 309 | SelfParamKind::MutRef |
369 | } else { | 310 | } else { |
370 | SelfParamKind::Ref | 311 | SelfParamKind::Ref |
@@ -373,24 +314,6 @@ impl ast::SelfParam { | |||
373 | SelfParamKind::Owned | 314 | SelfParamKind::Owned |
374 | } | 315 | } |
375 | } | 316 | } |
376 | |||
377 | /// the "mut" in "mut self", not the one in "&mut self" | ||
378 | pub fn mut_kw(&self) -> Option<ast::MutKw> { | ||
379 | self.syntax() | ||
380 | .children_with_tokens() | ||
381 | .filter_map(|it| it.into_token()) | ||
382 | .take_while(|it| it.kind() != T![&]) | ||
383 | .find_map(ast::MutKw::cast) | ||
384 | } | ||
385 | |||
386 | /// the "mut" in "&mut self", not the one in "mut self" | ||
387 | pub fn amp_mut_kw(&self) -> Option<ast::MutKw> { | ||
388 | self.syntax() | ||
389 | .children_with_tokens() | ||
390 | .filter_map(|it| it.into_token()) | ||
391 | .skip_while(|it| it.kind() != T![&]) | ||
392 | .find_map(ast::MutKw::cast) | ||
393 | } | ||
394 | } | 317 | } |
395 | 318 | ||
396 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | 319 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] |
@@ -400,53 +323,43 @@ pub enum TypeBoundKind { | |||
400 | /// for<'a> ... | 323 | /// for<'a> ... |
401 | ForType(ast::ForType), | 324 | ForType(ast::ForType), |
402 | /// 'a | 325 | /// 'a |
403 | Lifetime(ast::Lifetime), | 326 | Lifetime(SyntaxToken), |
404 | } | 327 | } |
405 | 328 | ||
406 | impl ast::TypeBound { | 329 | impl ast::TypeBound { |
407 | pub fn kind(&self) -> TypeBoundKind { | 330 | pub fn kind(&self) -> TypeBoundKind { |
408 | if let Some(path_type) = children(self).next() { | 331 | if let Some(path_type) = support::children(self.syntax()).next() { |
409 | TypeBoundKind::PathType(path_type) | 332 | TypeBoundKind::PathType(path_type) |
410 | } else if let Some(for_type) = children(self).next() { | 333 | } else if let Some(for_type) = support::children(self.syntax()).next() { |
411 | TypeBoundKind::ForType(for_type) | 334 | TypeBoundKind::ForType(for_type) |
412 | } else if let Some(lifetime) = self.lifetime() { | 335 | } else if let Some(lifetime) = self.lifetime_token() { |
413 | TypeBoundKind::Lifetime(lifetime) | 336 | TypeBoundKind::Lifetime(lifetime) |
414 | } else { | 337 | } else { |
415 | unreachable!() | 338 | unreachable!() |
416 | } | 339 | } |
417 | } | 340 | } |
418 | 341 | ||
419 | pub fn has_question_mark(&self) -> bool { | 342 | pub fn const_question_token(&self) -> Option<SyntaxToken> { |
420 | self.question().is_some() | ||
421 | } | ||
422 | |||
423 | pub fn const_question(&self) -> Option<ast::Question> { | ||
424 | self.syntax() | 343 | self.syntax() |
425 | .children_with_tokens() | 344 | .children_with_tokens() |
426 | .filter_map(|it| it.into_token()) | 345 | .filter_map(|it| it.into_token()) |
427 | .take_while(|it| it.kind() != T![const]) | 346 | .take_while(|it| it.kind() != T![const]) |
428 | .find_map(ast::Question::cast) | 347 | .find(|it| it.kind() == T![?]) |
429 | } | 348 | } |
430 | 349 | ||
431 | pub fn question(&self) -> Option<ast::Question> { | 350 | pub fn question_token(&self) -> Option<SyntaxToken> { |
432 | if self.const_kw().is_some() { | 351 | if self.const_token().is_some() { |
433 | self.syntax() | 352 | self.syntax() |
434 | .children_with_tokens() | 353 | .children_with_tokens() |
435 | .filter_map(|it| it.into_token()) | 354 | .filter_map(|it| it.into_token()) |
436 | .skip_while(|it| it.kind() != T![const]) | 355 | .skip_while(|it| it.kind() != T![const]) |
437 | .find_map(ast::Question::cast) | 356 | .find(|it| it.kind() == T![?]) |
438 | } else { | 357 | } else { |
439 | support::token(&self.syntax) | 358 | support::token(&self.syntax, T![?]) |
440 | } | 359 | } |
441 | } | 360 | } |
442 | } | 361 | } |
443 | 362 | ||
444 | impl ast::TraitDef { | ||
445 | pub fn is_auto(&self) -> bool { | ||
446 | self.syntax().children_with_tokens().any(|t| t.kind() == T![auto]) | ||
447 | } | ||
448 | } | ||
449 | |||
450 | pub enum VisibilityKind { | 363 | pub enum VisibilityKind { |
451 | In(ast::Path), | 364 | In(ast::Path), |
452 | PubCrate, | 365 | PubCrate, |
@@ -457,30 +370,18 @@ pub enum VisibilityKind { | |||
457 | 370 | ||
458 | impl ast::Visibility { | 371 | impl ast::Visibility { |
459 | pub fn kind(&self) -> VisibilityKind { | 372 | pub fn kind(&self) -> VisibilityKind { |
460 | if let Some(path) = children(self).next() { | 373 | if let Some(path) = support::children(self.syntax()).next() { |
461 | VisibilityKind::In(path) | 374 | VisibilityKind::In(path) |
462 | } else if self.is_pub_crate() { | 375 | } else if self.crate_token().is_some() { |
463 | VisibilityKind::PubCrate | 376 | VisibilityKind::PubCrate |
464 | } else if self.is_pub_super() { | 377 | } else if self.super_token().is_some() { |
465 | VisibilityKind::PubSuper | 378 | VisibilityKind::PubSuper |
466 | } else if self.is_pub_self() { | 379 | } else if self.self_token().is_some() { |
467 | VisibilityKind::PubSuper | 380 | VisibilityKind::PubSuper |
468 | } else { | 381 | } else { |
469 | VisibilityKind::Pub | 382 | VisibilityKind::Pub |
470 | } | 383 | } |
471 | } | 384 | } |
472 | |||
473 | fn is_pub_crate(&self) -> bool { | ||
474 | self.syntax().children_with_tokens().any(|it| it.kind() == T![crate]) | ||
475 | } | ||
476 | |||
477 | fn is_pub_super(&self) -> bool { | ||
478 | self.syntax().children_with_tokens().any(|it| it.kind() == T![super]) | ||
479 | } | ||
480 | |||
481 | fn is_pub_self(&self) -> bool { | ||
482 | self.syntax().children_with_tokens().any(|it| it.kind() == T![self]) | ||
483 | } | ||
484 | } | 385 | } |
485 | 386 | ||
486 | impl ast::MacroCall { | 387 | impl ast::MacroCall { |
@@ -495,12 +396,12 @@ impl ast::MacroCall { | |||
495 | } | 396 | } |
496 | 397 | ||
497 | impl ast::LifetimeParam { | 398 | impl ast::LifetimeParam { |
498 | pub fn lifetime_bounds(&self) -> impl Iterator<Item = ast::Lifetime> { | 399 | pub fn lifetime_bounds(&self) -> impl Iterator<Item = SyntaxToken> { |
499 | self.syntax() | 400 | self.syntax() |
500 | .children_with_tokens() | 401 | .children_with_tokens() |
501 | .filter_map(|it| it.into_token()) | 402 | .filter_map(|it| it.into_token()) |
502 | .skip_while(|x| x.kind() != T![:]) | 403 | .skip_while(|x| x.kind() != T![:]) |
503 | .filter_map(ast::Lifetime::cast) | 404 | .filter(|it| it.kind() == T![lifetime]) |
504 | } | 405 | } |
505 | } | 406 | } |
506 | 407 | ||
@@ -508,7 +409,7 @@ impl ast::RangePat { | |||
508 | pub fn start(&self) -> Option<ast::Pat> { | 409 | pub fn start(&self) -> Option<ast::Pat> { |
509 | self.syntax() | 410 | self.syntax() |
510 | .children_with_tokens() | 411 | .children_with_tokens() |
511 | .take_while(|it| !ast::RangeSeparator::can_cast(it.kind())) | 412 | .take_while(|it| !(it.kind() == T![..] || it.kind() == T![..=])) |
512 | .filter_map(|it| it.into_node()) | 413 | .filter_map(|it| it.into_node()) |
513 | .find_map(ast::Pat::cast) | 414 | .find_map(ast::Pat::cast) |
514 | } | 415 | } |
@@ -516,18 +417,24 @@ impl ast::RangePat { | |||
516 | pub fn end(&self) -> Option<ast::Pat> { | 417 | pub fn end(&self) -> Option<ast::Pat> { |
517 | self.syntax() | 418 | self.syntax() |
518 | .children_with_tokens() | 419 | .children_with_tokens() |
519 | .skip_while(|it| !ast::RangeSeparator::can_cast(it.kind())) | 420 | .skip_while(|it| !(it.kind() == T![..] || it.kind() == T![..=])) |
520 | .filter_map(|it| it.into_node()) | 421 | .filter_map(|it| it.into_node()) |
521 | .find_map(ast::Pat::cast) | 422 | .find_map(ast::Pat::cast) |
522 | } | 423 | } |
523 | } | 424 | } |
524 | 425 | ||
525 | impl ast::TokenTree { | 426 | impl ast::TokenTree { |
526 | pub fn left_delimiter(&self) -> Option<ast::LeftDelimiter> { | 427 | pub fn left_delimiter_token(&self) -> Option<SyntaxToken> { |
527 | self.syntax().first_child_or_token()?.into_token().and_then(ast::LeftDelimiter::cast) | 428 | self.syntax().first_child_or_token()?.into_token().filter(|it| match it.kind() { |
429 | T!['{'] | T!['('] | T!['['] => true, | ||
430 | _ => false, | ||
431 | }) | ||
528 | } | 432 | } |
529 | 433 | ||
530 | pub fn right_delimiter(&self) -> Option<ast::RightDelimiter> { | 434 | pub fn right_delimiter_token(&self) -> Option<SyntaxToken> { |
531 | self.syntax().last_child_or_token()?.into_token().and_then(ast::RightDelimiter::cast) | 435 | self.syntax().last_child_or_token()?.into_token().filter(|it| match it.kind() { |
436 | T!['{'] | T!['('] | T!['['] => true, | ||
437 | _ => false, | ||
438 | }) | ||
532 | } | 439 | } |
533 | } | 440 | } |