diff options
Diffstat (limited to 'crates/ra_syntax/src/ast/extensions.rs')
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 93 |
1 files changed, 43 insertions, 50 deletions
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index 5f7e9f5b1..cefc00402 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -1,10 +1,8 @@ | |||
1 | //! Various extension methods to ast Nodes, which are hard to code-generate. | 1 | //! Various extension methods to ast Nodes, which are hard to code-generate. |
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; | ||
5 | |||
6 | use crate::{ | 4 | use crate::{ |
7 | ast::{self, child_opt, children, AstNode, SyntaxNode}, | 5 | ast::{self, child_opt, children, AstChildren, AstNode, AttrInput, SyntaxNode}, |
8 | SmolStr, SyntaxElement, | 6 | SmolStr, SyntaxElement, |
9 | SyntaxKind::*, | 7 | SyntaxKind::*, |
10 | SyntaxToken, T, | 8 | SyntaxToken, T, |
@@ -21,6 +19,16 @@ impl ast::NameRef { | |||
21 | pub fn text(&self) -> &SmolStr { | 19 | pub fn text(&self) -> &SmolStr { |
22 | text_of_first_token(self.syntax()) | 20 | text_of_first_token(self.syntax()) |
23 | } | 21 | } |
22 | |||
23 | pub fn as_tuple_field(&self) -> Option<usize> { | ||
24 | self.syntax().children_with_tokens().find_map(|c| { | ||
25 | if c.kind() == SyntaxKind::INT_NUMBER { | ||
26 | c.as_token().and_then(|tok| tok.text().as_str().parse().ok()) | ||
27 | } else { | ||
28 | None | ||
29 | } | ||
30 | }) | ||
31 | } | ||
24 | } | 32 | } |
25 | 33 | ||
26 | fn text_of_first_token(node: &SyntaxNode) -> &SmolStr { | 34 | fn text_of_first_token(node: &SyntaxNode) -> &SmolStr { |
@@ -28,62 +36,37 @@ fn text_of_first_token(node: &SyntaxNode) -> &SmolStr { | |||
28 | } | 36 | } |
29 | 37 | ||
30 | impl ast::Attr { | 38 | impl ast::Attr { |
31 | pub fn is_inner(&self) -> bool { | 39 | pub fn as_simple_atom(&self) -> Option<SmolStr> { |
32 | let tt = match self.value() { | 40 | match self.input() { |
33 | None => return false, | 41 | None => self.simple_name(), |
34 | Some(tt) => tt, | 42 | Some(_) => None, |
35 | }; | ||
36 | |||
37 | let prev = match tt.syntax().prev_sibling() { | ||
38 | None => return false, | ||
39 | Some(prev) => prev, | ||
40 | }; | ||
41 | |||
42 | prev.kind() == T![!] | ||
43 | } | ||
44 | |||
45 | pub fn as_atom(&self) -> Option<SmolStr> { | ||
46 | let tt = self.value()?; | ||
47 | let (_bra, attr, _ket) = tt.syntax().children_with_tokens().collect_tuple()?; | ||
48 | if attr.kind() == IDENT { | ||
49 | Some(attr.as_token()?.text().clone()) | ||
50 | } else { | ||
51 | None | ||
52 | } | 43 | } |
53 | } | 44 | } |
54 | 45 | ||
55 | pub fn as_call(&self) -> Option<(SmolStr, ast::TokenTree)> { | 46 | pub fn as_simple_call(&self) -> Option<(SmolStr, ast::TokenTree)> { |
56 | let tt = self.value()?; | 47 | match self.input() { |
57 | let (_bra, attr, args, _ket) = tt.syntax().children_with_tokens().collect_tuple()?; | 48 | Some(AttrInput::TokenTree(tt)) => Some((self.simple_name()?, tt)), |
58 | let args = ast::TokenTree::cast(args.as_node()?.clone())?; | 49 | _ => None, |
59 | if attr.kind() == IDENT { | ||
60 | Some((attr.as_token()?.text().clone(), args)) | ||
61 | } else { | ||
62 | None | ||
63 | } | 50 | } |
64 | } | 51 | } |
65 | 52 | ||
66 | pub fn as_named(&self) -> Option<SmolStr> { | 53 | pub fn as_simple_key_value(&self) -> Option<(SmolStr, SmolStr)> { |
67 | let tt = self.value()?; | 54 | match self.input() { |
68 | let attr = tt.syntax().children_with_tokens().nth(1)?; | 55 | Some(AttrInput::Literal(lit)) => { |
69 | if attr.kind() == IDENT { | 56 | let key = self.simple_name()?; |
70 | Some(attr.as_token()?.text().clone()) | 57 | // FIXME: escape? raw string? |
71 | } else { | 58 | let value = lit.syntax().first_token()?.text().trim_matches('"').into(); |
72 | None | 59 | Some((key, value)) |
60 | } | ||
61 | _ => None, | ||
73 | } | 62 | } |
74 | } | 63 | } |
75 | 64 | ||
76 | pub fn as_key_value(&self) -> Option<(SmolStr, SmolStr)> { | 65 | pub fn simple_name(&self) -> Option<SmolStr> { |
77 | let tt = self.value()?; | 66 | let path = self.path()?; |
78 | let tt_node = tt.syntax(); | 67 | match (path.segment(), path.qualifier()) { |
79 | let attr = tt_node.children_with_tokens().nth(1)?; | 68 | (Some(segment), None) => Some(segment.syntax().first_token()?.text().clone()), |
80 | if attr.kind() == IDENT { | 69 | _ => None, |
81 | let key = attr.as_token()?.text().clone(); | ||
82 | let val_node = tt_node.children_with_tokens().find(|t| t.kind() == STRING)?; | ||
83 | let val = val_node.as_token()?.text().trim_start_matches('"').trim_end_matches('"'); | ||
84 | Some((key, SmolStr::new(val))) | ||
85 | } else { | ||
86 | None | ||
87 | } | 70 | } |
88 | } | 71 | } |
89 | } | 72 | } |
@@ -193,6 +176,16 @@ impl ast::ImplBlock { | |||
193 | } | 176 | } |
194 | } | 177 | } |
195 | 178 | ||
179 | impl ast::AttrsOwner for ast::ImplItem { | ||
180 | fn attrs(&self) -> AstChildren<ast::Attr> { | ||
181 | match self { | ||
182 | ast::ImplItem::FnDef(it) => it.attrs(), | ||
183 | ast::ImplItem::TypeAliasDef(it) => it.attrs(), | ||
184 | ast::ImplItem::ConstDef(it) => it.attrs(), | ||
185 | } | ||
186 | } | ||
187 | } | ||
188 | |||
196 | #[derive(Debug, Clone, PartialEq, Eq)] | 189 | #[derive(Debug, Clone, PartialEq, Eq)] |
197 | pub enum StructKind { | 190 | pub enum StructKind { |
198 | Tuple(ast::TupleFieldDefList), | 191 | Tuple(ast::TupleFieldDefList), |