diff options
author | Aleksey Kladov <[email protected]> | 2019-04-02 10:47:39 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-04-02 10:47:39 +0100 |
commit | cb5001c0a5ddadccd18fe787d89de3d6c3c8147f (patch) | |
tree | 1acf66538292bb3fc9e789ab1e55f61ee46b997e | |
parent | f3a82c372ccaa079842f151b749fbe9b8b9eb004 (diff) |
move extensions to submodules
-rw-r--r-- | crates/ra_syntax/src/ast.rs | 565 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/expr_extensions.rs | 250 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 300 |
3 files changed, 566 insertions, 549 deletions
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index b0e0f8bf9..74a415bdd 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs | |||
@@ -2,21 +2,22 @@ | |||
2 | mod generated; | 2 | mod generated; |
3 | mod traits; | 3 | mod traits; |
4 | mod tokens; | 4 | mod tokens; |
5 | mod extensions; | ||
6 | mod expr_extensions; | ||
5 | 7 | ||
6 | use std::marker::PhantomData; | 8 | use std::marker::PhantomData; |
7 | 9 | ||
8 | use itertools::Itertools; | ||
9 | |||
10 | use crate::{ | 10 | use crate::{ |
11 | syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken, SyntaxElement}, | 11 | syntax_node::{SyntaxNode, SyntaxNodeChildren, TreeArc, RaTypes, SyntaxToken}, |
12 | SmolStr, | 12 | SmolStr, |
13 | SyntaxKind::*, | ||
14 | }; | 13 | }; |
15 | 14 | ||
16 | pub use self::{ | 15 | pub use self::{ |
17 | generated::*, | 16 | generated::*, |
18 | traits::*, | 17 | traits::*, |
19 | tokens::*, | 18 | tokens::*, |
19 | extensions::{PathSegmentKind, StructFlavor, SelfParamFlavor}, | ||
20 | expr_extensions::{ElseBranch, PrefixOp, BinOp, LiteralFlavor}, | ||
20 | }; | 21 | }; |
21 | 22 | ||
22 | /// The main trait to go from untyped `SyntaxNode` to a typed ast. The | 23 | /// The main trait to go from untyped `SyntaxNode` to a typed ast. The |
@@ -32,6 +33,17 @@ pub trait AstNode: | |||
32 | fn syntax(&self) -> &SyntaxNode; | 33 | fn syntax(&self) -> &SyntaxNode; |
33 | } | 34 | } |
34 | 35 | ||
36 | /// Like `AstNode`, but wraps tokens rather than interior nodes. | ||
37 | pub trait AstToken<'a> { | ||
38 | fn cast(token: SyntaxToken<'a>) -> Option<Self> | ||
39 | where | ||
40 | Self: Sized; | ||
41 | fn syntax(&self) -> SyntaxToken<'a>; | ||
42 | fn text(&self) -> &'a SmolStr { | ||
43 | self.syntax().text() | ||
44 | } | ||
45 | } | ||
46 | |||
35 | #[derive(Debug)] | 47 | #[derive(Debug)] |
36 | pub struct AstChildren<'a, N> { | 48 | pub struct AstChildren<'a, N> { |
37 | inner: SyntaxNodeChildren<'a>, | 49 | inner: SyntaxNodeChildren<'a>, |
@@ -51,215 +63,6 @@ impl<'a, N: AstNode + 'a> Iterator for AstChildren<'a, N> { | |||
51 | } | 63 | } |
52 | } | 64 | } |
53 | 65 | ||
54 | pub trait AstToken<'a> { | ||
55 | fn cast(token: SyntaxToken<'a>) -> Option<Self> | ||
56 | where | ||
57 | Self: Sized; | ||
58 | fn syntax(&self) -> SyntaxToken<'a>; | ||
59 | fn text(&self) -> &'a SmolStr { | ||
60 | self.syntax().text() | ||
61 | } | ||
62 | } | ||
63 | |||
64 | impl Attr { | ||
65 | pub fn is_inner(&self) -> bool { | ||
66 | let tt = match self.value() { | ||
67 | None => return false, | ||
68 | Some(tt) => tt, | ||
69 | }; | ||
70 | |||
71 | let prev = match tt.syntax().prev_sibling() { | ||
72 | None => return false, | ||
73 | Some(prev) => prev, | ||
74 | }; | ||
75 | |||
76 | prev.kind() == EXCL | ||
77 | } | ||
78 | |||
79 | pub fn as_atom(&self) -> Option<SmolStr> { | ||
80 | let tt = self.value()?; | ||
81 | let (_bra, attr, _ket) = tt.syntax().children_with_tokens().collect_tuple()?; | ||
82 | if attr.kind() == IDENT { | ||
83 | Some(attr.as_token()?.text().clone()) | ||
84 | } else { | ||
85 | None | ||
86 | } | ||
87 | } | ||
88 | |||
89 | pub fn as_call(&self) -> Option<(SmolStr, &TokenTree)> { | ||
90 | let tt = self.value()?; | ||
91 | let (_bra, attr, args, _ket) = tt.syntax().children_with_tokens().collect_tuple()?; | ||
92 | let args = TokenTree::cast(args.as_node()?)?; | ||
93 | if attr.kind() == IDENT { | ||
94 | Some((attr.as_token()?.text().clone(), args)) | ||
95 | } else { | ||
96 | None | ||
97 | } | ||
98 | } | ||
99 | |||
100 | pub fn as_named(&self) -> Option<SmolStr> { | ||
101 | let tt = self.value()?; | ||
102 | let attr = tt.syntax().children_with_tokens().nth(1)?; | ||
103 | if attr.kind() == IDENT { | ||
104 | Some(attr.as_token()?.text().clone()) | ||
105 | } else { | ||
106 | None | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | |||
111 | impl Name { | ||
112 | pub fn text(&self) -> &SmolStr { | ||
113 | let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap(); | ||
114 | ident.text() | ||
115 | } | ||
116 | } | ||
117 | |||
118 | impl NameRef { | ||
119 | pub fn text(&self) -> &SmolStr { | ||
120 | let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap(); | ||
121 | ident.text() | ||
122 | } | ||
123 | } | ||
124 | |||
125 | impl ImplBlock { | ||
126 | pub fn target_type(&self) -> Option<&TypeRef> { | ||
127 | match self.target() { | ||
128 | (Some(t), None) | (_, Some(t)) => Some(t), | ||
129 | _ => None, | ||
130 | } | ||
131 | } | ||
132 | |||
133 | pub fn target_trait(&self) -> Option<&TypeRef> { | ||
134 | match self.target() { | ||
135 | (Some(t), Some(_)) => Some(t), | ||
136 | _ => None, | ||
137 | } | ||
138 | } | ||
139 | |||
140 | fn target(&self) -> (Option<&TypeRef>, Option<&TypeRef>) { | ||
141 | let mut types = children(self); | ||
142 | let first = types.next(); | ||
143 | let second = types.next(); | ||
144 | (first, second) | ||
145 | } | ||
146 | } | ||
147 | |||
148 | impl Module { | ||
149 | pub fn has_semi(&self) -> bool { | ||
150 | match self.syntax().last_child_or_token() { | ||
151 | None => false, | ||
152 | Some(node) => node.kind() == SEMI, | ||
153 | } | ||
154 | } | ||
155 | } | ||
156 | |||
157 | impl LetStmt { | ||
158 | pub fn has_semi(&self) -> bool { | ||
159 | match self.syntax().last_child_or_token() { | ||
160 | None => false, | ||
161 | Some(node) => node.kind() == SEMI, | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | |||
166 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
167 | pub enum ElseBranch<'a> { | ||
168 | Block(&'a Block), | ||
169 | IfExpr(&'a IfExpr), | ||
170 | } | ||
171 | |||
172 | impl IfExpr { | ||
173 | pub fn then_branch(&self) -> Option<&Block> { | ||
174 | self.blocks().nth(0) | ||
175 | } | ||
176 | pub fn else_branch(&self) -> Option<ElseBranch> { | ||
177 | let res = match self.blocks().nth(1) { | ||
178 | Some(block) => ElseBranch::Block(block), | ||
179 | None => { | ||
180 | let elif: &IfExpr = child_opt(self)?; | ||
181 | ElseBranch::IfExpr(elif) | ||
182 | } | ||
183 | }; | ||
184 | Some(res) | ||
185 | } | ||
186 | |||
187 | fn blocks(&self) -> AstChildren<Block> { | ||
188 | children(self) | ||
189 | } | ||
190 | } | ||
191 | |||
192 | impl ExprStmt { | ||
193 | pub fn has_semi(&self) -> bool { | ||
194 | match self.syntax().last_child_or_token() { | ||
195 | None => false, | ||
196 | Some(node) => node.kind() == SEMI, | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
202 | pub enum PathSegmentKind<'a> { | ||
203 | Name(&'a NameRef), | ||
204 | SelfKw, | ||
205 | SuperKw, | ||
206 | CrateKw, | ||
207 | } | ||
208 | |||
209 | impl PathSegment { | ||
210 | pub fn parent_path(&self) -> &Path { | ||
211 | self.syntax().parent().and_then(Path::cast).expect("segments are always nested in paths") | ||
212 | } | ||
213 | |||
214 | pub fn kind(&self) -> Option<PathSegmentKind> { | ||
215 | let res = if let Some(name_ref) = self.name_ref() { | ||
216 | PathSegmentKind::Name(name_ref) | ||
217 | } else { | ||
218 | match self.syntax().first_child_or_token()?.kind() { | ||
219 | SELF_KW => PathSegmentKind::SelfKw, | ||
220 | SUPER_KW => PathSegmentKind::SuperKw, | ||
221 | CRATE_KW => PathSegmentKind::CrateKw, | ||
222 | _ => return None, | ||
223 | } | ||
224 | }; | ||
225 | Some(res) | ||
226 | } | ||
227 | |||
228 | pub fn has_colon_colon(&self) -> bool { | ||
229 | match self.syntax.first_child_or_token().map(|s| s.kind()) { | ||
230 | Some(COLONCOLON) => true, | ||
231 | _ => false, | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | |||
236 | impl Path { | ||
237 | pub fn parent_path(&self) -> Option<&Path> { | ||
238 | self.syntax().parent().and_then(Path::cast) | ||
239 | } | ||
240 | } | ||
241 | |||
242 | impl UseTree { | ||
243 | pub fn has_star(&self) -> bool { | ||
244 | self.syntax().children_with_tokens().any(|it| it.kind() == STAR) | ||
245 | } | ||
246 | } | ||
247 | |||
248 | impl UseTreeList { | ||
249 | pub fn parent_use_tree(&self) -> &UseTree { | ||
250 | self.syntax() | ||
251 | .parent() | ||
252 | .and_then(UseTree::cast) | ||
253 | .expect("UseTreeLists are always nested in UseTrees") | ||
254 | } | ||
255 | } | ||
256 | |||
257 | impl RefPat { | ||
258 | pub fn is_mut(&self) -> bool { | ||
259 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
260 | } | ||
261 | } | ||
262 | |||
263 | fn child_opt<P: AstNode, C: AstNode>(parent: &P) -> Option<&C> { | 66 | fn child_opt<P: AstNode, C: AstNode>(parent: &P) -> Option<&C> { |
264 | children(parent).next() | 67 | children(parent).next() |
265 | } | 68 | } |
@@ -268,342 +71,6 @@ fn children<P: AstNode, C: AstNode>(parent: &P) -> AstChildren<C> { | |||
268 | AstChildren::new(parent.syntax()) | 71 | AstChildren::new(parent.syntax()) |
269 | } | 72 | } |
270 | 73 | ||
271 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
272 | pub enum StructFlavor<'a> { | ||
273 | Tuple(&'a PosFieldDefList), | ||
274 | Named(&'a NamedFieldDefList), | ||
275 | Unit, | ||
276 | } | ||
277 | |||
278 | impl StructFlavor<'_> { | ||
279 | fn from_node<N: AstNode>(node: &N) -> StructFlavor { | ||
280 | if let Some(nfdl) = child_opt::<_, NamedFieldDefList>(node) { | ||
281 | StructFlavor::Named(nfdl) | ||
282 | } else if let Some(pfl) = child_opt::<_, PosFieldDefList>(node) { | ||
283 | StructFlavor::Tuple(pfl) | ||
284 | } else { | ||
285 | StructFlavor::Unit | ||
286 | } | ||
287 | } | ||
288 | } | ||
289 | |||
290 | impl StructDef { | ||
291 | pub fn flavor(&self) -> StructFlavor { | ||
292 | StructFlavor::from_node(self) | ||
293 | } | ||
294 | } | ||
295 | |||
296 | impl EnumVariant { | ||
297 | pub fn parent_enum(&self) -> &EnumDef { | ||
298 | self.syntax() | ||
299 | .parent() | ||
300 | .and_then(|it| it.parent()) | ||
301 | .and_then(EnumDef::cast) | ||
302 | .expect("EnumVariants are always nested in Enums") | ||
303 | } | ||
304 | pub fn flavor(&self) -> StructFlavor { | ||
305 | StructFlavor::from_node(self) | ||
306 | } | ||
307 | } | ||
308 | |||
309 | impl PointerType { | ||
310 | pub fn is_mut(&self) -> bool { | ||
311 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
312 | } | ||
313 | } | ||
314 | |||
315 | impl ReferenceType { | ||
316 | pub fn is_mut(&self) -> bool { | ||
317 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
318 | } | ||
319 | } | ||
320 | |||
321 | impl RefExpr { | ||
322 | pub fn is_mut(&self) -> bool { | ||
323 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
324 | } | ||
325 | } | ||
326 | |||
327 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
328 | pub enum PrefixOp { | ||
329 | /// The `*` operator for dereferencing | ||
330 | Deref, | ||
331 | /// The `!` operator for logical inversion | ||
332 | Not, | ||
333 | /// The `-` operator for negation | ||
334 | Neg, | ||
335 | } | ||
336 | |||
337 | impl PrefixExpr { | ||
338 | pub fn op_kind(&self) -> Option<PrefixOp> { | ||
339 | match self.op_token()?.kind() { | ||
340 | STAR => Some(PrefixOp::Deref), | ||
341 | EXCL => Some(PrefixOp::Not), | ||
342 | MINUS => Some(PrefixOp::Neg), | ||
343 | _ => None, | ||
344 | } | ||
345 | } | ||
346 | |||
347 | pub fn op_token(&self) -> Option<SyntaxToken> { | ||
348 | self.syntax().first_child_or_token()?.as_token() | ||
349 | } | ||
350 | } | ||
351 | |||
352 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
353 | pub enum BinOp { | ||
354 | /// The `||` operator for boolean OR | ||
355 | BooleanOr, | ||
356 | /// The `&&` operator for boolean AND | ||
357 | BooleanAnd, | ||
358 | /// The `==` operator for equality testing | ||
359 | EqualityTest, | ||
360 | /// The `!=` operator for equality testing | ||
361 | NegatedEqualityTest, | ||
362 | /// The `<=` operator for lesser-equal testing | ||
363 | LesserEqualTest, | ||
364 | /// The `>=` operator for greater-equal testing | ||
365 | GreaterEqualTest, | ||
366 | /// The `<` operator for comparison | ||
367 | LesserTest, | ||
368 | /// The `>` operator for comparison | ||
369 | GreaterTest, | ||
370 | /// The `+` operator for addition | ||
371 | Addition, | ||
372 | /// The `*` operator for multiplication | ||
373 | Multiplication, | ||
374 | /// The `-` operator for subtraction | ||
375 | Subtraction, | ||
376 | /// The `/` operator for division | ||
377 | Division, | ||
378 | /// The `%` operator for remainder after division | ||
379 | Remainder, | ||
380 | /// The `<<` operator for left shift | ||
381 | LeftShift, | ||
382 | /// The `>>` operator for right shift | ||
383 | RightShift, | ||
384 | /// The `^` operator for bitwise XOR | ||
385 | BitwiseXor, | ||
386 | /// The `|` operator for bitwise OR | ||
387 | BitwiseOr, | ||
388 | /// The `&` operator for bitwise AND | ||
389 | BitwiseAnd, | ||
390 | /// The `..` operator for right-open ranges | ||
391 | RangeRightOpen, | ||
392 | /// The `..=` operator for right-closed ranges | ||
393 | RangeRightClosed, | ||
394 | /// The `=` operator for assignment | ||
395 | Assignment, | ||
396 | /// The `+=` operator for assignment after addition | ||
397 | AddAssign, | ||
398 | /// The `/=` operator for assignment after division | ||
399 | DivAssign, | ||
400 | /// The `*=` operator for assignment after multiplication | ||
401 | MulAssign, | ||
402 | /// The `%=` operator for assignment after remainders | ||
403 | RemAssign, | ||
404 | /// The `>>=` operator for assignment after shifting right | ||
405 | ShrAssign, | ||
406 | /// The `<<=` operator for assignment after shifting left | ||
407 | ShlAssign, | ||
408 | /// The `-=` operator for assignment after subtraction | ||
409 | SubAssign, | ||
410 | /// The `|=` operator for assignment after bitwise OR | ||
411 | BitOrAssign, | ||
412 | /// The `&=` operator for assignment after bitwise AND | ||
413 | BitAndAssign, | ||
414 | /// The `^=` operator for assignment after bitwise XOR | ||
415 | BitXorAssign, | ||
416 | } | ||
417 | |||
418 | impl BinExpr { | ||
419 | fn op_details(&self) -> Option<(SyntaxToken, BinOp)> { | ||
420 | self.syntax().children_with_tokens().filter_map(|it| it.as_token()).find_map(|c| { | ||
421 | match c.kind() { | ||
422 | PIPEPIPE => Some((c, BinOp::BooleanOr)), | ||
423 | AMPAMP => Some((c, BinOp::BooleanAnd)), | ||
424 | EQEQ => Some((c, BinOp::EqualityTest)), | ||
425 | NEQ => Some((c, BinOp::NegatedEqualityTest)), | ||
426 | LTEQ => Some((c, BinOp::LesserEqualTest)), | ||
427 | GTEQ => Some((c, BinOp::GreaterEqualTest)), | ||
428 | L_ANGLE => Some((c, BinOp::LesserTest)), | ||
429 | R_ANGLE => Some((c, BinOp::GreaterTest)), | ||
430 | PLUS => Some((c, BinOp::Addition)), | ||
431 | STAR => Some((c, BinOp::Multiplication)), | ||
432 | MINUS => Some((c, BinOp::Subtraction)), | ||
433 | SLASH => Some((c, BinOp::Division)), | ||
434 | PERCENT => Some((c, BinOp::Remainder)), | ||
435 | SHL => Some((c, BinOp::LeftShift)), | ||
436 | SHR => Some((c, BinOp::RightShift)), | ||
437 | CARET => Some((c, BinOp::BitwiseXor)), | ||
438 | PIPE => Some((c, BinOp::BitwiseOr)), | ||
439 | AMP => Some((c, BinOp::BitwiseAnd)), | ||
440 | DOTDOT => Some((c, BinOp::RangeRightOpen)), | ||
441 | DOTDOTEQ => Some((c, BinOp::RangeRightClosed)), | ||
442 | EQ => Some((c, BinOp::Assignment)), | ||
443 | PLUSEQ => Some((c, BinOp::AddAssign)), | ||
444 | SLASHEQ => Some((c, BinOp::DivAssign)), | ||
445 | STAREQ => Some((c, BinOp::MulAssign)), | ||
446 | PERCENTEQ => Some((c, BinOp::RemAssign)), | ||
447 | SHREQ => Some((c, BinOp::ShrAssign)), | ||
448 | SHLEQ => Some((c, BinOp::ShlAssign)), | ||
449 | MINUSEQ => Some((c, BinOp::SubAssign)), | ||
450 | PIPEEQ => Some((c, BinOp::BitOrAssign)), | ||
451 | AMPEQ => Some((c, BinOp::BitAndAssign)), | ||
452 | CARETEQ => Some((c, BinOp::BitXorAssign)), | ||
453 | _ => None, | ||
454 | } | ||
455 | }) | ||
456 | } | ||
457 | |||
458 | pub fn op_kind(&self) -> Option<BinOp> { | ||
459 | self.op_details().map(|t| t.1) | ||
460 | } | ||
461 | |||
462 | pub fn op_token(&self) -> Option<SyntaxToken> { | ||
463 | self.op_details().map(|t| t.0) | ||
464 | } | ||
465 | |||
466 | pub fn lhs(&self) -> Option<&Expr> { | ||
467 | children(self).nth(0) | ||
468 | } | ||
469 | |||
470 | pub fn rhs(&self) -> Option<&Expr> { | ||
471 | children(self).nth(1) | ||
472 | } | ||
473 | |||
474 | pub fn sub_exprs(&self) -> (Option<&Expr>, Option<&Expr>) { | ||
475 | let mut children = children(self); | ||
476 | let first = children.next(); | ||
477 | let second = children.next(); | ||
478 | (first, second) | ||
479 | } | ||
480 | } | ||
481 | |||
482 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
483 | pub enum SelfParamFlavor { | ||
484 | /// self | ||
485 | Owned, | ||
486 | /// &self | ||
487 | Ref, | ||
488 | /// &mut self | ||
489 | MutRef, | ||
490 | } | ||
491 | |||
492 | impl SelfParam { | ||
493 | pub fn self_kw_token(&self) -> SyntaxToken { | ||
494 | self.syntax() | ||
495 | .children_with_tokens() | ||
496 | .filter_map(|it| it.as_token()) | ||
497 | .find(|it| it.kind() == SELF_KW) | ||
498 | .expect("invalid tree: self param must have self") | ||
499 | } | ||
500 | |||
501 | pub fn flavor(&self) -> SelfParamFlavor { | ||
502 | let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == AMP); | ||
503 | if borrowed { | ||
504 | // check for a `mut` coming after the & -- `mut &self` != `&mut self` | ||
505 | if self | ||
506 | .syntax() | ||
507 | .children_with_tokens() | ||
508 | .skip_while(|n| n.kind() != AMP) | ||
509 | .any(|n| n.kind() == MUT_KW) | ||
510 | { | ||
511 | SelfParamFlavor::MutRef | ||
512 | } else { | ||
513 | SelfParamFlavor::Ref | ||
514 | } | ||
515 | } else { | ||
516 | SelfParamFlavor::Owned | ||
517 | } | ||
518 | } | ||
519 | } | ||
520 | |||
521 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
522 | pub enum LiteralFlavor { | ||
523 | String, | ||
524 | ByteString, | ||
525 | Char, | ||
526 | Byte, | ||
527 | IntNumber { suffix: Option<SmolStr> }, | ||
528 | FloatNumber { suffix: Option<SmolStr> }, | ||
529 | Bool, | ||
530 | } | ||
531 | |||
532 | impl Literal { | ||
533 | pub fn token(&self) -> SyntaxToken { | ||
534 | match self.syntax().first_child_or_token().unwrap() { | ||
535 | SyntaxElement::Token(token) => token, | ||
536 | _ => unreachable!(), | ||
537 | } | ||
538 | } | ||
539 | |||
540 | pub fn flavor(&self) -> LiteralFlavor { | ||
541 | match self.token().kind() { | ||
542 | INT_NUMBER => { | ||
543 | let allowed_suffix_list = [ | ||
544 | "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32", | ||
545 | "u16", "u8", | ||
546 | ]; | ||
547 | let text = self.token().text().to_string(); | ||
548 | let suffix = allowed_suffix_list | ||
549 | .iter() | ||
550 | .find(|&s| text.ends_with(s)) | ||
551 | .map(|&suf| SmolStr::new(suf)); | ||
552 | LiteralFlavor::IntNumber { suffix } | ||
553 | } | ||
554 | FLOAT_NUMBER => { | ||
555 | let allowed_suffix_list = ["f64", "f32"]; | ||
556 | let text = self.token().text().to_string(); | ||
557 | let suffix = allowed_suffix_list | ||
558 | .iter() | ||
559 | .find(|&s| text.ends_with(s)) | ||
560 | .map(|&suf| SmolStr::new(suf)); | ||
561 | LiteralFlavor::FloatNumber { suffix: suffix } | ||
562 | } | ||
563 | STRING | RAW_STRING => LiteralFlavor::String, | ||
564 | TRUE_KW | FALSE_KW => LiteralFlavor::Bool, | ||
565 | BYTE_STRING | RAW_BYTE_STRING => LiteralFlavor::ByteString, | ||
566 | CHAR => LiteralFlavor::Char, | ||
567 | BYTE => LiteralFlavor::Byte, | ||
568 | _ => unreachable!(), | ||
569 | } | ||
570 | } | ||
571 | } | ||
572 | |||
573 | impl NamedField { | ||
574 | pub fn parent_struct_lit(&self) -> &StructLit { | ||
575 | self.syntax().ancestors().find_map(StructLit::cast).unwrap() | ||
576 | } | ||
577 | } | ||
578 | |||
579 | impl BindPat { | ||
580 | pub fn is_mutable(&self) -> bool { | ||
581 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
582 | } | ||
583 | |||
584 | pub fn is_ref(&self) -> bool { | ||
585 | self.syntax().children_with_tokens().any(|n| n.kind() == REF_KW) | ||
586 | } | ||
587 | } | ||
588 | |||
589 | impl LifetimeParam { | ||
590 | pub fn lifetime_token(&self) -> Option<SyntaxToken> { | ||
591 | self.syntax() | ||
592 | .children_with_tokens() | ||
593 | .filter_map(|it| it.as_token()) | ||
594 | .find(|it| it.kind() == LIFETIME) | ||
595 | } | ||
596 | } | ||
597 | |||
598 | impl WherePred { | ||
599 | pub fn lifetime_token(&self) -> Option<SyntaxToken> { | ||
600 | self.syntax() | ||
601 | .children_with_tokens() | ||
602 | .filter_map(|it| it.as_token()) | ||
603 | .find(|it| it.kind() == LIFETIME) | ||
604 | } | ||
605 | } | ||
606 | |||
607 | #[test] | 74 | #[test] |
608 | fn test_doc_comment_none() { | 75 | fn test_doc_comment_none() { |
609 | let file = SourceFile::parse( | 76 | let file = SourceFile::parse( |
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs new file mode 100644 index 000000000..ddc26206f --- /dev/null +++ b/crates/ra_syntax/src/ast/expr_extensions.rs | |||
@@ -0,0 +1,250 @@ | |||
1 | use crate::{ | ||
2 | SyntaxToken, SyntaxElement, SmolStr, | ||
3 | ast::{self, AstNode, AstChildren, children, child_opt}, | ||
4 | SyntaxKind::* | ||
5 | }; | ||
6 | |||
7 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
8 | pub enum ElseBranch<'a> { | ||
9 | Block(&'a ast::Block), | ||
10 | IfExpr(&'a ast::IfExpr), | ||
11 | } | ||
12 | |||
13 | impl ast::IfExpr { | ||
14 | pub fn then_branch(&self) -> Option<&ast::Block> { | ||
15 | self.blocks().nth(0) | ||
16 | } | ||
17 | pub fn else_branch(&self) -> Option<ElseBranch> { | ||
18 | let res = match self.blocks().nth(1) { | ||
19 | Some(block) => ElseBranch::Block(block), | ||
20 | None => { | ||
21 | let elif: &ast::IfExpr = child_opt(self)?; | ||
22 | ElseBranch::IfExpr(elif) | ||
23 | } | ||
24 | }; | ||
25 | Some(res) | ||
26 | } | ||
27 | |||
28 | fn blocks(&self) -> AstChildren<ast::Block> { | ||
29 | children(self) | ||
30 | } | ||
31 | } | ||
32 | |||
33 | impl ast::RefExpr { | ||
34 | pub fn is_mut(&self) -> bool { | ||
35 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
36 | } | ||
37 | } | ||
38 | |||
39 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
40 | pub enum PrefixOp { | ||
41 | /// The `*` operator for dereferencing | ||
42 | Deref, | ||
43 | /// The `!` operator for logical inversion | ||
44 | Not, | ||
45 | /// The `-` operator for negation | ||
46 | Neg, | ||
47 | } | ||
48 | |||
49 | impl ast::PrefixExpr { | ||
50 | pub fn op_kind(&self) -> Option<PrefixOp> { | ||
51 | match self.op_token()?.kind() { | ||
52 | STAR => Some(PrefixOp::Deref), | ||
53 | EXCL => Some(PrefixOp::Not), | ||
54 | MINUS => Some(PrefixOp::Neg), | ||
55 | _ => None, | ||
56 | } | ||
57 | } | ||
58 | |||
59 | pub fn op_token(&self) -> Option<SyntaxToken> { | ||
60 | self.syntax().first_child_or_token()?.as_token() | ||
61 | } | ||
62 | } | ||
63 | |||
64 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
65 | pub enum BinOp { | ||
66 | /// The `||` operator for boolean OR | ||
67 | BooleanOr, | ||
68 | /// The `&&` operator for boolean AND | ||
69 | BooleanAnd, | ||
70 | /// The `==` operator for equality testing | ||
71 | EqualityTest, | ||
72 | /// The `!=` operator for equality testing | ||
73 | NegatedEqualityTest, | ||
74 | /// The `<=` operator for lesser-equal testing | ||
75 | LesserEqualTest, | ||
76 | /// The `>=` operator for greater-equal testing | ||
77 | GreaterEqualTest, | ||
78 | /// The `<` operator for comparison | ||
79 | LesserTest, | ||
80 | /// The `>` operator for comparison | ||
81 | GreaterTest, | ||
82 | /// The `+` operator for addition | ||
83 | Addition, | ||
84 | /// The `*` operator for multiplication | ||
85 | Multiplication, | ||
86 | /// The `-` operator for subtraction | ||
87 | Subtraction, | ||
88 | /// The `/` operator for division | ||
89 | Division, | ||
90 | /// The `%` operator for remainder after division | ||
91 | Remainder, | ||
92 | /// The `<<` operator for left shift | ||
93 | LeftShift, | ||
94 | /// The `>>` operator for right shift | ||
95 | RightShift, | ||
96 | /// The `^` operator for bitwise XOR | ||
97 | BitwiseXor, | ||
98 | /// The `|` operator for bitwise OR | ||
99 | BitwiseOr, | ||
100 | /// The `&` operator for bitwise AND | ||
101 | BitwiseAnd, | ||
102 | /// The `..` operator for right-open ranges | ||
103 | RangeRightOpen, | ||
104 | /// The `..=` operator for right-closed ranges | ||
105 | RangeRightClosed, | ||
106 | /// The `=` operator for assignment | ||
107 | Assignment, | ||
108 | /// The `+=` operator for assignment after addition | ||
109 | AddAssign, | ||
110 | /// The `/=` operator for assignment after division | ||
111 | DivAssign, | ||
112 | /// The `*=` operator for assignment after multiplication | ||
113 | MulAssign, | ||
114 | /// The `%=` operator for assignment after remainders | ||
115 | RemAssign, | ||
116 | /// The `>>=` operator for assignment after shifting right | ||
117 | ShrAssign, | ||
118 | /// The `<<=` operator for assignment after shifting left | ||
119 | ShlAssign, | ||
120 | /// The `-=` operator for assignment after subtraction | ||
121 | SubAssign, | ||
122 | /// The `|=` operator for assignment after bitwise OR | ||
123 | BitOrAssign, | ||
124 | /// The `&=` operator for assignment after bitwise AND | ||
125 | BitAndAssign, | ||
126 | /// The `^=` operator for assignment after bitwise XOR | ||
127 | BitXorAssign, | ||
128 | } | ||
129 | |||
130 | impl ast::BinExpr { | ||
131 | fn op_details(&self) -> Option<(SyntaxToken, BinOp)> { | ||
132 | self.syntax().children_with_tokens().filter_map(|it| it.as_token()).find_map(|c| { | ||
133 | match c.kind() { | ||
134 | PIPEPIPE => Some((c, BinOp::BooleanOr)), | ||
135 | AMPAMP => Some((c, BinOp::BooleanAnd)), | ||
136 | EQEQ => Some((c, BinOp::EqualityTest)), | ||
137 | NEQ => Some((c, BinOp::NegatedEqualityTest)), | ||
138 | LTEQ => Some((c, BinOp::LesserEqualTest)), | ||
139 | GTEQ => Some((c, BinOp::GreaterEqualTest)), | ||
140 | L_ANGLE => Some((c, BinOp::LesserTest)), | ||
141 | R_ANGLE => Some((c, BinOp::GreaterTest)), | ||
142 | PLUS => Some((c, BinOp::Addition)), | ||
143 | STAR => Some((c, BinOp::Multiplication)), | ||
144 | MINUS => Some((c, BinOp::Subtraction)), | ||
145 | SLASH => Some((c, BinOp::Division)), | ||
146 | PERCENT => Some((c, BinOp::Remainder)), | ||
147 | SHL => Some((c, BinOp::LeftShift)), | ||
148 | SHR => Some((c, BinOp::RightShift)), | ||
149 | CARET => Some((c, BinOp::BitwiseXor)), | ||
150 | PIPE => Some((c, BinOp::BitwiseOr)), | ||
151 | AMP => Some((c, BinOp::BitwiseAnd)), | ||
152 | DOTDOT => Some((c, BinOp::RangeRightOpen)), | ||
153 | DOTDOTEQ => Some((c, BinOp::RangeRightClosed)), | ||
154 | EQ => Some((c, BinOp::Assignment)), | ||
155 | PLUSEQ => Some((c, BinOp::AddAssign)), | ||
156 | SLASHEQ => Some((c, BinOp::DivAssign)), | ||
157 | STAREQ => Some((c, BinOp::MulAssign)), | ||
158 | PERCENTEQ => Some((c, BinOp::RemAssign)), | ||
159 | SHREQ => Some((c, BinOp::ShrAssign)), | ||
160 | SHLEQ => Some((c, BinOp::ShlAssign)), | ||
161 | MINUSEQ => Some((c, BinOp::SubAssign)), | ||
162 | PIPEEQ => Some((c, BinOp::BitOrAssign)), | ||
163 | AMPEQ => Some((c, BinOp::BitAndAssign)), | ||
164 | CARETEQ => Some((c, BinOp::BitXorAssign)), | ||
165 | _ => None, | ||
166 | } | ||
167 | }) | ||
168 | } | ||
169 | |||
170 | pub fn op_kind(&self) -> Option<BinOp> { | ||
171 | self.op_details().map(|t| t.1) | ||
172 | } | ||
173 | |||
174 | pub fn op_token(&self) -> Option<SyntaxToken> { | ||
175 | self.op_details().map(|t| t.0) | ||
176 | } | ||
177 | |||
178 | pub fn lhs(&self) -> Option<&ast::Expr> { | ||
179 | children(self).nth(0) | ||
180 | } | ||
181 | |||
182 | pub fn rhs(&self) -> Option<&ast::Expr> { | ||
183 | children(self).nth(1) | ||
184 | } | ||
185 | |||
186 | pub fn sub_exprs(&self) -> (Option<&ast::Expr>, Option<&ast::Expr>) { | ||
187 | let mut children = children(self); | ||
188 | let first = children.next(); | ||
189 | let second = children.next(); | ||
190 | (first, second) | ||
191 | } | ||
192 | } | ||
193 | |||
194 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
195 | pub enum LiteralFlavor { | ||
196 | String, | ||
197 | ByteString, | ||
198 | Char, | ||
199 | Byte, | ||
200 | IntNumber { suffix: Option<SmolStr> }, | ||
201 | FloatNumber { suffix: Option<SmolStr> }, | ||
202 | Bool, | ||
203 | } | ||
204 | |||
205 | impl ast::Literal { | ||
206 | pub fn token(&self) -> SyntaxToken { | ||
207 | match self.syntax().first_child_or_token().unwrap() { | ||
208 | SyntaxElement::Token(token) => token, | ||
209 | _ => unreachable!(), | ||
210 | } | ||
211 | } | ||
212 | |||
213 | pub fn flavor(&self) -> LiteralFlavor { | ||
214 | match self.token().kind() { | ||
215 | INT_NUMBER => { | ||
216 | let allowed_suffix_list = [ | ||
217 | "isize", "i128", "i64", "i32", "i16", "i8", "usize", "u128", "u64", "u32", | ||
218 | "u16", "u8", | ||
219 | ]; | ||
220 | let text = self.token().text().to_string(); | ||
221 | let suffix = allowed_suffix_list | ||
222 | .iter() | ||
223 | .find(|&s| text.ends_with(s)) | ||
224 | .map(|&suf| SmolStr::new(suf)); | ||
225 | LiteralFlavor::IntNumber { suffix } | ||
226 | } | ||
227 | FLOAT_NUMBER => { | ||
228 | let allowed_suffix_list = ["f64", "f32"]; | ||
229 | let text = self.token().text().to_string(); | ||
230 | let suffix = allowed_suffix_list | ||
231 | .iter() | ||
232 | .find(|&s| text.ends_with(s)) | ||
233 | .map(|&suf| SmolStr::new(suf)); | ||
234 | LiteralFlavor::FloatNumber { suffix: suffix } | ||
235 | } | ||
236 | STRING | RAW_STRING => LiteralFlavor::String, | ||
237 | TRUE_KW | FALSE_KW => LiteralFlavor::Bool, | ||
238 | BYTE_STRING | RAW_BYTE_STRING => LiteralFlavor::ByteString, | ||
239 | CHAR => LiteralFlavor::Char, | ||
240 | BYTE => LiteralFlavor::Byte, | ||
241 | _ => unreachable!(), | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | |||
246 | impl ast::NamedField { | ||
247 | pub fn parent_struct_lit(&self) -> &ast::StructLit { | ||
248 | self.syntax().ancestors().find_map(ast::StructLit::cast).unwrap() | ||
249 | } | ||
250 | } | ||
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs new file mode 100644 index 000000000..87592bfd8 --- /dev/null +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -0,0 +1,300 @@ | |||
1 | use itertools::Itertools; | ||
2 | |||
3 | use crate::{ | ||
4 | SmolStr, SyntaxToken, | ||
5 | ast::{self, AstNode, children, child_opt}, | ||
6 | SyntaxKind::*, | ||
7 | }; | ||
8 | |||
9 | impl ast::Name { | ||
10 | pub fn text(&self) -> &SmolStr { | ||
11 | let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap(); | ||
12 | ident.text() | ||
13 | } | ||
14 | } | ||
15 | |||
16 | impl ast::NameRef { | ||
17 | pub fn text(&self) -> &SmolStr { | ||
18 | let ident = self.syntax().first_child_or_token().unwrap().as_token().unwrap(); | ||
19 | ident.text() | ||
20 | } | ||
21 | } | ||
22 | |||
23 | impl ast::Attr { | ||
24 | pub fn is_inner(&self) -> bool { | ||
25 | let tt = match self.value() { | ||
26 | None => return false, | ||
27 | Some(tt) => tt, | ||
28 | }; | ||
29 | |||
30 | let prev = match tt.syntax().prev_sibling() { | ||
31 | None => return false, | ||
32 | Some(prev) => prev, | ||
33 | }; | ||
34 | |||
35 | prev.kind() == EXCL | ||
36 | } | ||
37 | |||
38 | pub fn as_atom(&self) -> Option<SmolStr> { | ||
39 | let tt = self.value()?; | ||
40 | let (_bra, attr, _ket) = tt.syntax().children_with_tokens().collect_tuple()?; | ||
41 | if attr.kind() == IDENT { | ||
42 | Some(attr.as_token()?.text().clone()) | ||
43 | } else { | ||
44 | None | ||
45 | } | ||
46 | } | ||
47 | |||
48 | pub fn as_call(&self) -> Option<(SmolStr, &ast::TokenTree)> { | ||
49 | let tt = self.value()?; | ||
50 | let (_bra, attr, args, _ket) = tt.syntax().children_with_tokens().collect_tuple()?; | ||
51 | let args = ast::TokenTree::cast(args.as_node()?)?; | ||
52 | if attr.kind() == IDENT { | ||
53 | Some((attr.as_token()?.text().clone(), args)) | ||
54 | } else { | ||
55 | None | ||
56 | } | ||
57 | } | ||
58 | |||
59 | pub fn as_named(&self) -> Option<SmolStr> { | ||
60 | let tt = self.value()?; | ||
61 | let attr = tt.syntax().children_with_tokens().nth(1)?; | ||
62 | if attr.kind() == IDENT { | ||
63 | Some(attr.as_token()?.text().clone()) | ||
64 | } else { | ||
65 | None | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
70 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
71 | pub enum PathSegmentKind<'a> { | ||
72 | Name(&'a ast::NameRef), | ||
73 | SelfKw, | ||
74 | SuperKw, | ||
75 | CrateKw, | ||
76 | } | ||
77 | |||
78 | impl ast::PathSegment { | ||
79 | pub fn parent_path(&self) -> &ast::Path { | ||
80 | self.syntax() | ||
81 | .parent() | ||
82 | .and_then(ast::Path::cast) | ||
83 | .expect("segments are always nested in paths") | ||
84 | } | ||
85 | |||
86 | pub fn kind(&self) -> Option<PathSegmentKind> { | ||
87 | let res = if let Some(name_ref) = self.name_ref() { | ||
88 | PathSegmentKind::Name(name_ref) | ||
89 | } else { | ||
90 | match self.syntax().first_child_or_token()?.kind() { | ||
91 | SELF_KW => PathSegmentKind::SelfKw, | ||
92 | SUPER_KW => PathSegmentKind::SuperKw, | ||
93 | CRATE_KW => PathSegmentKind::CrateKw, | ||
94 | _ => return None, | ||
95 | } | ||
96 | }; | ||
97 | Some(res) | ||
98 | } | ||
99 | |||
100 | pub fn has_colon_colon(&self) -> bool { | ||
101 | match self.syntax.first_child_or_token().map(|s| s.kind()) { | ||
102 | Some(COLONCOLON) => true, | ||
103 | _ => false, | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
108 | impl ast::Path { | ||
109 | pub fn parent_path(&self) -> Option<&ast::Path> { | ||
110 | self.syntax().parent().and_then(ast::Path::cast) | ||
111 | } | ||
112 | } | ||
113 | |||
114 | impl ast::Module { | ||
115 | pub fn has_semi(&self) -> bool { | ||
116 | match self.syntax().last_child_or_token() { | ||
117 | None => false, | ||
118 | Some(node) => node.kind() == SEMI, | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | |||
123 | impl ast::UseTree { | ||
124 | pub fn has_star(&self) -> bool { | ||
125 | self.syntax().children_with_tokens().any(|it| it.kind() == STAR) | ||
126 | } | ||
127 | } | ||
128 | |||
129 | impl ast::UseTreeList { | ||
130 | pub fn parent_use_tree(&self) -> &ast::UseTree { | ||
131 | self.syntax() | ||
132 | .parent() | ||
133 | .and_then(ast::UseTree::cast) | ||
134 | .expect("UseTreeLists are always nested in UseTrees") | ||
135 | } | ||
136 | } | ||
137 | |||
138 | impl ast::ImplBlock { | ||
139 | pub fn target_type(&self) -> Option<&ast::TypeRef> { | ||
140 | match self.target() { | ||
141 | (Some(t), None) | (_, Some(t)) => Some(t), | ||
142 | _ => None, | ||
143 | } | ||
144 | } | ||
145 | |||
146 | pub fn target_trait(&self) -> Option<&ast::TypeRef> { | ||
147 | match self.target() { | ||
148 | (Some(t), Some(_)) => Some(t), | ||
149 | _ => None, | ||
150 | } | ||
151 | } | ||
152 | |||
153 | fn target(&self) -> (Option<&ast::TypeRef>, Option<&ast::TypeRef>) { | ||
154 | let mut types = children(self); | ||
155 | let first = types.next(); | ||
156 | let second = types.next(); | ||
157 | (first, second) | ||
158 | } | ||
159 | } | ||
160 | |||
161 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
162 | pub enum StructFlavor<'a> { | ||
163 | Tuple(&'a ast::PosFieldDefList), | ||
164 | Named(&'a ast::NamedFieldDefList), | ||
165 | Unit, | ||
166 | } | ||
167 | |||
168 | impl StructFlavor<'_> { | ||
169 | fn from_node<N: AstNode>(node: &N) -> StructFlavor { | ||
170 | if let Some(nfdl) = child_opt::<_, ast::NamedFieldDefList>(node) { | ||
171 | StructFlavor::Named(nfdl) | ||
172 | } else if let Some(pfl) = child_opt::<_, ast::PosFieldDefList>(node) { | ||
173 | StructFlavor::Tuple(pfl) | ||
174 | } else { | ||
175 | StructFlavor::Unit | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | impl ast::StructDef { | ||
181 | pub fn flavor(&self) -> StructFlavor { | ||
182 | StructFlavor::from_node(self) | ||
183 | } | ||
184 | } | ||
185 | |||
186 | impl ast::EnumVariant { | ||
187 | pub fn parent_enum(&self) -> &ast::EnumDef { | ||
188 | self.syntax() | ||
189 | .parent() | ||
190 | .and_then(|it| it.parent()) | ||
191 | .and_then(ast::EnumDef::cast) | ||
192 | .expect("EnumVariants are always nested in Enums") | ||
193 | } | ||
194 | pub fn flavor(&self) -> StructFlavor { | ||
195 | StructFlavor::from_node(self) | ||
196 | } | ||
197 | } | ||
198 | |||
199 | impl ast::LetStmt { | ||
200 | pub fn has_semi(&self) -> bool { | ||
201 | match self.syntax().last_child_or_token() { | ||
202 | None => false, | ||
203 | Some(node) => node.kind() == SEMI, | ||
204 | } | ||
205 | } | ||
206 | } | ||
207 | |||
208 | impl ast::ExprStmt { | ||
209 | pub fn has_semi(&self) -> bool { | ||
210 | match self.syntax().last_child_or_token() { | ||
211 | None => false, | ||
212 | Some(node) => node.kind() == SEMI, | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | |||
217 | impl ast::RefPat { | ||
218 | pub fn is_mut(&self) -> bool { | ||
219 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
220 | } | ||
221 | } | ||
222 | |||
223 | impl ast::BindPat { | ||
224 | pub fn is_mutable(&self) -> bool { | ||
225 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
226 | } | ||
227 | |||
228 | pub fn is_ref(&self) -> bool { | ||
229 | self.syntax().children_with_tokens().any(|n| n.kind() == REF_KW) | ||
230 | } | ||
231 | } | ||
232 | |||
233 | impl ast::PointerType { | ||
234 | pub fn is_mut(&self) -> bool { | ||
235 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
236 | } | ||
237 | } | ||
238 | |||
239 | impl ast::ReferenceType { | ||
240 | pub fn is_mut(&self) -> bool { | ||
241 | self.syntax().children_with_tokens().any(|n| n.kind() == MUT_KW) | ||
242 | } | ||
243 | } | ||
244 | |||
245 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||
246 | pub enum SelfParamFlavor { | ||
247 | /// self | ||
248 | Owned, | ||
249 | /// &self | ||
250 | Ref, | ||
251 | /// &mut self | ||
252 | MutRef, | ||
253 | } | ||
254 | |||
255 | impl ast::SelfParam { | ||
256 | pub fn self_kw_token(&self) -> SyntaxToken { | ||
257 | self.syntax() | ||
258 | .children_with_tokens() | ||
259 | .filter_map(|it| it.as_token()) | ||
260 | .find(|it| it.kind() == SELF_KW) | ||
261 | .expect("invalid tree: self param must have self") | ||
262 | } | ||
263 | |||
264 | pub fn flavor(&self) -> SelfParamFlavor { | ||
265 | let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == AMP); | ||
266 | if borrowed { | ||
267 | // check for a `mut` coming after the & -- `mut &self` != `&mut self` | ||
268 | if self | ||
269 | .syntax() | ||
270 | .children_with_tokens() | ||
271 | .skip_while(|n| n.kind() != AMP) | ||
272 | .any(|n| n.kind() == MUT_KW) | ||
273 | { | ||
274 | SelfParamFlavor::MutRef | ||
275 | } else { | ||
276 | SelfParamFlavor::Ref | ||
277 | } | ||
278 | } else { | ||
279 | SelfParamFlavor::Owned | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | |||
284 | impl ast::LifetimeParam { | ||
285 | pub fn lifetime_token(&self) -> Option<SyntaxToken> { | ||
286 | self.syntax() | ||
287 | .children_with_tokens() | ||
288 | .filter_map(|it| it.as_token()) | ||
289 | .find(|it| it.kind() == LIFETIME) | ||
290 | } | ||
291 | } | ||
292 | |||
293 | impl ast::WherePred { | ||
294 | pub fn lifetime_token(&self) -> Option<SyntaxToken> { | ||
295 | self.syntax() | ||
296 | .children_with_tokens() | ||
297 | .filter_map(|it| it.as_token()) | ||
298 | .find(|it| it.kind() == LIFETIME) | ||
299 | } | ||
300 | } | ||