diff options
author | Luca Barbieri <[email protected]> | 2020-04-03 20:12:09 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-04-09 10:50:37 +0100 |
commit | 60f4d7bd8c0ecb9f23557464e824140a2be8f41a (patch) | |
tree | 00aea343b133272e1df072bd7c839fddf07f36f6 /crates/ra_syntax/src/ast | |
parent | 85956932872481cf4813c5e7794d981a9edb4623 (diff) |
Provide more complete AST accessors to support usage in rustc
Diffstat (limited to 'crates/ra_syntax/src/ast')
-rw-r--r-- | crates/ra_syntax/src/ast/edit.rs | 26 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/expr_extensions.rs | 4 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 148 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/traits.rs | 32 |
4 files changed, 107 insertions, 103 deletions
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs index b69cae234..d79310995 100644 --- a/crates/ra_syntax/src/ast/edit.rs +++ b/crates/ra_syntax/src/ast/edit.rs | |||
@@ -99,7 +99,7 @@ impl ast::ItemList { | |||
99 | None => match self.l_curly() { | 99 | None => match self.l_curly() { |
100 | Some(it) => ( | 100 | Some(it) => ( |
101 | " ".to_string() + &leading_indent(self.syntax()).unwrap_or_default(), | 101 | " ".to_string() + &leading_indent(self.syntax()).unwrap_or_default(), |
102 | InsertPosition::After(it), | 102 | InsertPosition::After(it.syntax().clone().into()), |
103 | ), | 103 | ), |
104 | None => return self.clone(), | 104 | None => return self.clone(), |
105 | }, | 105 | }, |
@@ -109,10 +109,6 @@ impl ast::ItemList { | |||
109 | [ws.ws().into(), item.syntax().clone().into()].into(); | 109 | [ws.ws().into(), item.syntax().clone().into()].into(); |
110 | self.insert_children(position, to_insert) | 110 | self.insert_children(position, to_insert) |
111 | } | 111 | } |
112 | |||
113 | fn l_curly(&self) -> Option<SyntaxElement> { | ||
114 | self.syntax().children_with_tokens().find(|it| it.kind() == T!['{']) | ||
115 | } | ||
116 | } | 112 | } |
117 | 113 | ||
118 | impl ast::RecordFieldList { | 114 | impl ast::RecordFieldList { |
@@ -147,7 +143,7 @@ impl ast::RecordFieldList { | |||
147 | macro_rules! after_l_curly { | 143 | macro_rules! after_l_curly { |
148 | () => {{ | 144 | () => {{ |
149 | let anchor = match self.l_curly() { | 145 | let anchor = match self.l_curly() { |
150 | Some(it) => it, | 146 | Some(it) => it.syntax().clone().into(), |
151 | None => return self.clone(), | 147 | None => return self.clone(), |
152 | }; | 148 | }; |
153 | InsertPosition::After(anchor) | 149 | InsertPosition::After(anchor) |
@@ -189,24 +185,20 @@ impl ast::RecordFieldList { | |||
189 | 185 | ||
190 | self.insert_children(position, to_insert) | 186 | self.insert_children(position, to_insert) |
191 | } | 187 | } |
192 | |||
193 | fn l_curly(&self) -> Option<SyntaxElement> { | ||
194 | self.syntax().children_with_tokens().find(|it| it.kind() == T!['{']) | ||
195 | } | ||
196 | } | 188 | } |
197 | 189 | ||
198 | impl ast::TypeParam { | 190 | impl ast::TypeParam { |
199 | #[must_use] | 191 | #[must_use] |
200 | pub fn remove_bounds(&self) -> ast::TypeParam { | 192 | pub fn remove_bounds(&self) -> ast::TypeParam { |
201 | let colon = match self.colon_token() { | 193 | let colon = match self.colon() { |
202 | Some(it) => it, | 194 | Some(it) => it, |
203 | None => return self.clone(), | 195 | None => return self.clone(), |
204 | }; | 196 | }; |
205 | let end = match self.type_bound_list() { | 197 | let end = match self.type_bound_list() { |
206 | Some(it) => it.syntax().clone().into(), | 198 | Some(it) => it.syntax().clone().into(), |
207 | None => colon.clone().into(), | 199 | None => colon.syntax().clone().into(), |
208 | }; | 200 | }; |
209 | self.replace_children(colon.into()..=end, iter::empty()) | 201 | self.replace_children(colon.syntax().clone().into()..=end, iter::empty()) |
210 | } | 202 | } |
211 | } | 203 | } |
212 | 204 | ||
@@ -305,8 +297,12 @@ impl ast::UseTree { | |||
305 | Some(it) => it, | 297 | Some(it) => it, |
306 | None => return self.clone(), | 298 | None => return self.clone(), |
307 | }; | 299 | }; |
308 | let use_tree = | 300 | let use_tree = make::use_tree( |
309 | make::use_tree(suffix.clone(), self.use_tree_list(), self.alias(), self.has_star()); | 301 | suffix.clone(), |
302 | self.use_tree_list(), | ||
303 | self.alias(), | ||
304 | self.star().is_some(), | ||
305 | ); | ||
310 | let nested = make::use_tree_list(iter::once(use_tree)); | 306 | let nested = make::use_tree_list(iter::once(use_tree)); |
311 | return make::use_tree(prefix.clone(), Some(nested), None, false); | 307 | return make::use_tree(prefix.clone(), Some(nested), None, false); |
312 | 308 | ||
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs index 8bbd946c0..40c8fca3b 100644 --- a/crates/ra_syntax/src/ast/expr_extensions.rs +++ b/crates/ra_syntax/src/ast/expr_extensions.rs | |||
@@ -52,6 +52,10 @@ impl ast::RefExpr { | |||
52 | pub fn is_mut(&self) -> bool { | 52 | pub fn is_mut(&self) -> bool { |
53 | self.syntax().children_with_tokens().any(|n| n.kind() == T![mut]) | 53 | self.syntax().children_with_tokens().any(|n| n.kind() == T![mut]) |
54 | } | 54 | } |
55 | |||
56 | pub fn raw_token(&self) -> Option<SyntaxToken> { | ||
57 | None // FIXME: implement &raw | ||
58 | } | ||
55 | } | 59 | } |
56 | 60 | ||
57 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | 61 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] |
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index bf7d137be..400eba210 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -4,7 +4,10 @@ | |||
4 | use itertools::Itertools; | 4 | use itertools::Itertools; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | ast::{self, child_opt, children, AstNode, AttrInput, NameOwner, SyntaxNode}, | 7 | ast::{ |
8 | self, child_opt, child_token_opt, children, AstElement, AstNode, AstToken, AttrInput, | ||
9 | NameOwner, SyntaxNode, | ||
10 | }, | ||
8 | SmolStr, SyntaxElement, | 11 | SmolStr, SyntaxElement, |
9 | SyntaxKind::*, | 12 | SyntaxKind::*, |
10 | SyntaxToken, T, | 13 | SyntaxToken, T, |
@@ -130,13 +133,6 @@ impl ast::PathSegment { | |||
130 | }; | 133 | }; |
131 | Some(res) | 134 | Some(res) |
132 | } | 135 | } |
133 | |||
134 | pub fn has_colon_colon(&self) -> bool { | ||
135 | match self.syntax.first_child_or_token().map(|s| s.kind()) { | ||
136 | Some(T![::]) => true, | ||
137 | _ => false, | ||
138 | } | ||
139 | } | ||
140 | } | 136 | } |
141 | 137 | ||
142 | impl ast::Path { | 138 | impl ast::Path { |
@@ -154,12 +150,6 @@ impl ast::Module { | |||
154 | } | 150 | } |
155 | } | 151 | } |
156 | 152 | ||
157 | impl ast::UseTree { | ||
158 | pub fn has_star(&self) -> bool { | ||
159 | self.syntax().children_with_tokens().any(|it| it.kind() == T![*]) | ||
160 | } | ||
161 | } | ||
162 | |||
163 | impl ast::UseTreeList { | 153 | impl ast::UseTreeList { |
164 | pub fn parent_use_tree(&self) -> ast::UseTree { | 154 | pub fn parent_use_tree(&self) -> ast::UseTree { |
165 | self.syntax() | 155 | self.syntax() |
@@ -167,20 +157,6 @@ impl ast::UseTreeList { | |||
167 | .and_then(ast::UseTree::cast) | 157 | .and_then(ast::UseTree::cast) |
168 | .expect("UseTreeLists are always nested in UseTrees") | 158 | .expect("UseTreeLists are always nested in UseTrees") |
169 | } | 159 | } |
170 | pub fn l_curly(&self) -> Option<SyntaxToken> { | ||
171 | self.token(T!['{']) | ||
172 | } | ||
173 | |||
174 | pub fn r_curly(&self) -> Option<SyntaxToken> { | ||
175 | self.token(T!['}']) | ||
176 | } | ||
177 | |||
178 | fn token(&self, kind: SyntaxKind) -> Option<SyntaxToken> { | ||
179 | self.syntax() | ||
180 | .children_with_tokens() | ||
181 | .filter_map(|it| it.into_token()) | ||
182 | .find(|it| it.kind() == kind) | ||
183 | } | ||
184 | } | 160 | } |
185 | 161 | ||
186 | impl ast::ImplDef { | 162 | impl ast::ImplDef { |
@@ -387,24 +363,9 @@ pub enum SelfParamKind { | |||
387 | } | 363 | } |
388 | 364 | ||
389 | impl ast::SelfParam { | 365 | impl ast::SelfParam { |
390 | pub fn self_kw_token(&self) -> SyntaxToken { | ||
391 | self.syntax() | ||
392 | .children_with_tokens() | ||
393 | .filter_map(|it| it.into_token()) | ||
394 | .find(|it| it.kind() == T![self]) | ||
395 | .expect("invalid tree: self param must have self") | ||
396 | } | ||
397 | |||
398 | pub fn kind(&self) -> SelfParamKind { | 366 | pub fn kind(&self) -> SelfParamKind { |
399 | let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == T![&]); | 367 | if self.amp().is_some() { |
400 | if borrowed { | 368 | if self.amp_mut_kw().is_some() { |
401 | // check for a `mut` coming after the & -- `mut &self` != `&mut self` | ||
402 | if self | ||
403 | .syntax() | ||
404 | .children_with_tokens() | ||
405 | .skip_while(|n| n.kind() != T![&]) | ||
406 | .any(|n| n.kind() == T![mut]) | ||
407 | { | ||
408 | SelfParamKind::MutRef | 369 | SelfParamKind::MutRef |
409 | } else { | 370 | } else { |
410 | SelfParamKind::Ref | 371 | SelfParamKind::Ref |
@@ -413,32 +374,23 @@ impl ast::SelfParam { | |||
413 | SelfParamKind::Owned | 374 | SelfParamKind::Owned |
414 | } | 375 | } |
415 | } | 376 | } |
416 | } | ||
417 | 377 | ||
418 | impl ast::LifetimeParam { | 378 | /// the "mut" in "mut self", not the one in "&mut self" |
419 | pub fn lifetime_token(&self) -> Option<SyntaxToken> { | 379 | pub fn mut_kw(&self) -> Option<ast::MutKw> { |
420 | self.syntax() | 380 | self.syntax() |
421 | .children_with_tokens() | 381 | .children_with_tokens() |
422 | .filter_map(|it| it.into_token()) | 382 | .filter_map(|it| it.into_token()) |
423 | .find(|it| it.kind() == LIFETIME) | 383 | .take_while(|it| it.kind() != T![&]) |
384 | .find_map(ast::MutKw::cast) | ||
424 | } | 385 | } |
425 | } | ||
426 | 386 | ||
427 | impl ast::TypeParam { | 387 | /// the "mut" in "&mut self", not the one in "mut self" |
428 | pub fn colon_token(&self) -> Option<SyntaxToken> { | 388 | pub fn amp_mut_kw(&self) -> Option<ast::MutKw> { |
429 | self.syntax() | 389 | self.syntax() |
430 | .children_with_tokens() | 390 | .children_with_tokens() |
431 | .filter_map(|it| it.into_token()) | 391 | .filter_map(|it| it.into_token()) |
432 | .find(|it| it.kind() == T![:]) | 392 | .skip_while(|it| it.kind() != T![&]) |
433 | } | 393 | .find_map(ast::MutKw::cast) |
434 | } | ||
435 | |||
436 | impl ast::WherePred { | ||
437 | pub fn lifetime_token(&self) -> Option<SyntaxToken> { | ||
438 | self.syntax() | ||
439 | .children_with_tokens() | ||
440 | .filter_map(|it| it.into_token()) | ||
441 | .find(|it| it.kind() == LIFETIME) | ||
442 | } | 394 | } |
443 | } | 395 | } |
444 | 396 | ||
@@ -449,7 +401,7 @@ pub enum TypeBoundKind { | |||
449 | /// for<'a> ... | 401 | /// for<'a> ... |
450 | ForType(ast::ForType), | 402 | ForType(ast::ForType), |
451 | /// 'a | 403 | /// 'a |
452 | Lifetime(ast::SyntaxToken), | 404 | Lifetime(ast::Lifetime), |
453 | } | 405 | } |
454 | 406 | ||
455 | impl ast::TypeBound { | 407 | impl ast::TypeBound { |
@@ -465,21 +417,28 @@ impl ast::TypeBound { | |||
465 | } | 417 | } |
466 | } | 418 | } |
467 | 419 | ||
468 | fn lifetime(&self) -> Option<SyntaxToken> { | 420 | pub fn has_question_mark(&self) -> bool { |
469 | self.syntax() | 421 | self.question().is_some() |
470 | .children_with_tokens() | ||
471 | .filter_map(|it| it.into_token()) | ||
472 | .find(|it| it.kind() == LIFETIME) | ||
473 | } | 422 | } |
474 | 423 | ||
475 | pub fn question_mark_token(&self) -> Option<SyntaxToken> { | 424 | pub fn const_question(&self) -> Option<ast::Question> { |
476 | self.syntax() | 425 | self.syntax() |
477 | .children_with_tokens() | 426 | .children_with_tokens() |
478 | .filter_map(|it| it.into_token()) | 427 | .filter_map(|it| it.into_token()) |
479 | .find(|it| it.kind() == T![?]) | 428 | .take_while(|it| it.kind() != T![const]) |
429 | .find_map(ast::Question::cast) | ||
480 | } | 430 | } |
481 | pub fn has_question_mark(&self) -> bool { | 431 | |
482 | self.question_mark_token().is_some() | 432 | pub fn question(&self) -> Option<ast::Question> { |
433 | if self.const_kw().is_some() { | ||
434 | self.syntax() | ||
435 | .children_with_tokens() | ||
436 | .filter_map(|it| it.into_token()) | ||
437 | .skip_while(|it| it.kind() != T![const]) | ||
438 | .find_map(ast::Question::cast) | ||
439 | } else { | ||
440 | child_token_opt(self) | ||
441 | } | ||
483 | } | 442 | } |
484 | } | 443 | } |
485 | 444 | ||
@@ -493,6 +452,7 @@ pub enum VisibilityKind { | |||
493 | In(ast::Path), | 452 | In(ast::Path), |
494 | PubCrate, | 453 | PubCrate, |
495 | PubSuper, | 454 | PubSuper, |
455 | PubSelf, | ||
496 | Pub, | 456 | Pub, |
497 | } | 457 | } |
498 | 458 | ||
@@ -504,6 +464,8 @@ impl ast::Visibility { | |||
504 | VisibilityKind::PubCrate | 464 | VisibilityKind::PubCrate |
505 | } else if self.is_pub_super() { | 465 | } else if self.is_pub_super() { |
506 | VisibilityKind::PubSuper | 466 | VisibilityKind::PubSuper |
467 | } else if self.is_pub_self() { | ||
468 | VisibilityKind::PubSuper | ||
507 | } else { | 469 | } else { |
508 | VisibilityKind::Pub | 470 | VisibilityKind::Pub |
509 | } | 471 | } |
@@ -516,6 +478,10 @@ impl ast::Visibility { | |||
516 | fn is_pub_super(&self) -> bool { | 478 | fn is_pub_super(&self) -> bool { |
517 | self.syntax().children_with_tokens().any(|it| it.kind() == T![super]) | 479 | self.syntax().children_with_tokens().any(|it| it.kind() == T![super]) |
518 | } | 480 | } |
481 | |||
482 | fn is_pub_self(&self) -> bool { | ||
483 | self.syntax().children_with_tokens().any(|it| it.kind() == T![self]) | ||
484 | } | ||
519 | } | 485 | } |
520 | 486 | ||
521 | impl ast::MacroCall { | 487 | impl ast::MacroCall { |
@@ -528,3 +494,41 @@ impl ast::MacroCall { | |||
528 | } | 494 | } |
529 | } | 495 | } |
530 | } | 496 | } |
497 | |||
498 | impl ast::LifetimeParam { | ||
499 | pub fn lifetime_bounds(&self) -> impl Iterator<Item = ast::Lifetime> { | ||
500 | self.syntax() | ||
501 | .children_with_tokens() | ||
502 | .filter_map(|it| it.into_token()) | ||
503 | .skip_while(|x| x.kind() != T![:]) | ||
504 | .filter_map(ast::Lifetime::cast) | ||
505 | } | ||
506 | } | ||
507 | |||
508 | impl ast::RangePat { | ||
509 | pub fn start(&self) -> Option<ast::Pat> { | ||
510 | self.syntax() | ||
511 | .children_with_tokens() | ||
512 | .take_while(|it| !ast::RangeSeparator::can_cast_element(it.kind())) | ||
513 | .filter_map(|it| it.into_node()) | ||
514 | .find_map(ast::Pat::cast) | ||
515 | } | ||
516 | |||
517 | pub fn end(&self) -> Option<ast::Pat> { | ||
518 | self.syntax() | ||
519 | .children_with_tokens() | ||
520 | .skip_while(|it| !ast::RangeSeparator::can_cast_element(it.kind())) | ||
521 | .filter_map(|it| it.into_node()) | ||
522 | .find_map(ast::Pat::cast) | ||
523 | } | ||
524 | } | ||
525 | |||
526 | impl ast::TokenTree { | ||
527 | pub fn left_delimiter(&self) -> Option<ast::LeftDelimiter> { | ||
528 | self.syntax().first_child_or_token().and_then(ast::LeftDelimiter::cast_element) | ||
529 | } | ||
530 | |||
531 | pub fn right_delimiter(&self) -> Option<ast::RightDelimiter> { | ||
532 | self.syntax().last_child_or_token().and_then(ast::RightDelimiter::cast_element) | ||
533 | } | ||
534 | } | ||
diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs index 576378306..e6f3a4ebb 100644 --- a/crates/ra_syntax/src/ast/traits.rs +++ b/crates/ra_syntax/src/ast/traits.rs | |||
@@ -4,9 +4,9 @@ | |||
4 | 4 | ||
5 | use itertools::Itertools; | 5 | use itertools::Itertools; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::ast::{ |
8 | ast::{self, child_opt, children, AstChildren, AstNode, AstToken}, | 8 | self, child_elements, child_opt, child_token_opt, child_tokens, children, AstChildElements, |
9 | syntax_node::SyntaxElementChildren, | 9 | AstChildTokens, AstChildren, AstNode, AstToken, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | pub trait TypeAscriptionOwner: AstNode { | 12 | pub trait TypeAscriptionOwner: AstNode { |
@@ -31,6 +31,10 @@ pub trait LoopBodyOwner: AstNode { | |||
31 | fn loop_body(&self) -> Option<ast::BlockExpr> { | 31 | fn loop_body(&self) -> Option<ast::BlockExpr> { |
32 | child_opt(self) | 32 | child_opt(self) |
33 | } | 33 | } |
34 | |||
35 | fn label(&self) -> Option<ast::Label> { | ||
36 | child_opt(self) | ||
37 | } | ||
34 | } | 38 | } |
35 | 39 | ||
36 | pub trait ArgListOwner: AstNode { | 40 | pub trait ArgListOwner: AstNode { |
@@ -65,6 +69,10 @@ pub trait TypeBoundsOwner: AstNode { | |||
65 | fn type_bound_list(&self) -> Option<ast::TypeBoundList> { | 69 | fn type_bound_list(&self) -> Option<ast::TypeBoundList> { |
66 | child_opt(self) | 70 | child_opt(self) |
67 | } | 71 | } |
72 | |||
73 | fn colon(&self) -> Option<ast::Colon> { | ||
74 | child_token_opt(self) | ||
75 | } | ||
68 | } | 76 | } |
69 | 77 | ||
70 | pub trait AttrsOwner: AstNode { | 78 | pub trait AttrsOwner: AstNode { |
@@ -74,11 +82,14 @@ pub trait AttrsOwner: AstNode { | |||
74 | fn has_atom_attr(&self, atom: &str) -> bool { | 82 | fn has_atom_attr(&self, atom: &str) -> bool { |
75 | self.attrs().filter_map(|x| x.as_simple_atom()).any(|x| x == atom) | 83 | self.attrs().filter_map(|x| x.as_simple_atom()).any(|x| x == atom) |
76 | } | 84 | } |
85 | fn attr_or_comments(&self) -> AstChildElements<ast::AttrOrComment> { | ||
86 | child_elements(self) | ||
87 | } | ||
77 | } | 88 | } |
78 | 89 | ||
79 | pub trait DocCommentsOwner: AstNode { | 90 | pub trait DocCommentsOwner: AstNode { |
80 | fn doc_comments(&self) -> CommentIter { | 91 | fn doc_comments(&self) -> AstChildTokens<ast::Comment> { |
81 | CommentIter { iter: self.syntax().children_with_tokens() } | 92 | child_tokens(self) |
82 | } | 93 | } |
83 | 94 | ||
84 | /// Returns the textual content of a doc comment block as a single string. | 95 | /// Returns the textual content of a doc comment block as a single string. |
@@ -123,14 +134,3 @@ pub trait DocCommentsOwner: AstNode { | |||
123 | } | 134 | } |
124 | } | 135 | } |
125 | } | 136 | } |
126 | |||
127 | pub struct CommentIter { | ||
128 | iter: SyntaxElementChildren, | ||
129 | } | ||
130 | |||
131 | impl Iterator for CommentIter { | ||
132 | type Item = ast::Comment; | ||
133 | fn next(&mut self) -> Option<ast::Comment> { | ||
134 | self.iter.by_ref().find_map(|el| el.into_token().and_then(ast::Comment::cast)) | ||
135 | } | ||
136 | } | ||