aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/ast/extensions.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/ast/extensions.rs')
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs229
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
4use itertools::Itertools; 4use itertools::Itertools;
5use ra_parser::SyntaxKind;
5 6
6use crate::{ 7use 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};
14use ra_parser::SyntaxKind;
15 11
16impl ast::Name { 12impl 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
143impl 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
152impl ast::UseTreeList { 133impl 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
195impl StructKind { 172impl 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
190impl 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
213impl ast::EnumVariant { 220impl 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
226impl 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
239impl 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
252impl 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)]
262pub enum FieldKind { 234pub enum FieldKind {
263 Name(ast::NameRef), 235 Name(ast::NameRef),
@@ -286,25 +258,6 @@ impl ast::FieldExpr {
286 } 258 }
287} 259}
288 260
289impl ast::RefPat {
290 pub fn is_mut(&self) -> bool {
291 self.syntax().children_with_tokens().any(|n| n.kind() == T![mut])
292 }
293}
294
295impl 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
308pub struct SlicePatComponents { 261pub 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
342impl ast::PointerType {
343 pub fn is_mut(&self) -> bool {
344 self.syntax().children_with_tokens().any(|n| n.kind() == T![mut])
345 }
346}
347
348impl 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)]
355pub enum SelfParamKind { 296pub enum SelfParamKind {
356 /// self 297 /// self
@@ -363,8 +304,8 @@ pub enum SelfParamKind {
363 304
364impl ast::SelfParam { 305impl 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
406impl ast::TypeBound { 329impl 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
444impl ast::TraitDef {
445 pub fn is_auto(&self) -> bool {
446 self.syntax().children_with_tokens().any(|t| t.kind() == T![auto])
447 }
448}
449
450pub enum VisibilityKind { 363pub enum VisibilityKind {
451 In(ast::Path), 364 In(ast::Path),
452 PubCrate, 365 PubCrate,
@@ -457,30 +370,18 @@ pub enum VisibilityKind {
457 370
458impl ast::Visibility { 371impl 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
486impl ast::MacroCall { 387impl ast::MacroCall {
@@ -495,12 +396,12 @@ impl ast::MacroCall {
495} 396}
496 397
497impl ast::LifetimeParam { 398impl 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
525impl ast::TokenTree { 426impl 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}