]> git.lizzy.rs Git - rust.git/blob - crates/ra_syntax/src/ast/extensions.rs
Merge #1683
[rust.git] / crates / ra_syntax / src / ast / extensions.rs
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.
3
4 use itertools::Itertools;
5
6 use crate::{
7     ast::{self, child_opt, children, AstNode, SyntaxNode},
8     SmolStr, SyntaxElement,
9     SyntaxKind::*,
10     SyntaxToken, T,
11 };
12 use ra_parser::SyntaxKind;
13
14 impl ast::Name {
15     pub fn text(&self) -> &SmolStr {
16         text_of_first_token(self.syntax())
17     }
18 }
19
20 impl ast::NameRef {
21     pub fn text(&self) -> &SmolStr {
22         text_of_first_token(self.syntax())
23     }
24 }
25
26 fn text_of_first_token(node: &SyntaxNode) -> &SmolStr {
27     node.green().children().first().and_then(|it| it.as_token()).unwrap().text()
28 }
29
30 impl ast::Attr {
31     pub fn is_inner(&self) -> bool {
32         let tt = match self.value() {
33             None => return false,
34             Some(tt) => tt,
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         }
53     }
54
55     pub fn as_call(&self) -> Option<(SmolStr, ast::TokenTree)> {
56         let tt = self.value()?;
57         let (_bra, attr, args, _ket) = tt.syntax().children_with_tokens().collect_tuple()?;
58         let args = ast::TokenTree::cast(args.as_node()?.clone())?;
59         if attr.kind() == IDENT {
60             Some((attr.as_token()?.text().clone(), args))
61         } else {
62             None
63         }
64     }
65
66     pub fn as_named(&self) -> Option<SmolStr> {
67         let tt = self.value()?;
68         let attr = tt.syntax().children_with_tokens().nth(1)?;
69         if attr.kind() == IDENT {
70             Some(attr.as_token()?.text().clone())
71         } else {
72             None
73         }
74     }
75
76     pub fn as_key_value(&self) -> Option<(SmolStr, SmolStr)> {
77         let tt = self.value()?;
78         let tt_node = tt.syntax();
79         let attr = tt_node.children_with_tokens().nth(1)?;
80         if attr.kind() == IDENT {
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         }
88     }
89 }
90
91 #[derive(Debug, Clone, PartialEq, Eq)]
92 pub enum PathSegmentKind {
93     Name(ast::NameRef),
94     SelfKw,
95     SuperKw,
96     CrateKw,
97 }
98
99 impl ast::PathSegment {
100     pub fn parent_path(&self) -> ast::Path {
101         self.syntax()
102             .parent()
103             .and_then(ast::Path::cast)
104             .expect("segments are always nested in paths")
105     }
106
107     pub fn kind(&self) -> Option<PathSegmentKind> {
108         let res = if let Some(name_ref) = self.name_ref() {
109             PathSegmentKind::Name(name_ref)
110         } else {
111             match self.syntax().first_child_or_token()?.kind() {
112                 T![self] => PathSegmentKind::SelfKw,
113                 T![super] => PathSegmentKind::SuperKw,
114                 T![crate] => PathSegmentKind::CrateKw,
115                 _ => return None,
116             }
117         };
118         Some(res)
119     }
120
121     pub fn has_colon_colon(&self) -> bool {
122         match self.syntax.first_child_or_token().map(|s| s.kind()) {
123             Some(T![::]) => true,
124             _ => false,
125         }
126     }
127 }
128
129 impl ast::Path {
130     pub fn parent_path(&self) -> Option<ast::Path> {
131         self.syntax().parent().and_then(ast::Path::cast)
132     }
133 }
134
135 impl ast::Module {
136     pub fn has_semi(&self) -> bool {
137         match self.syntax().last_child_or_token() {
138             None => false,
139             Some(node) => node.kind() == T![;],
140         }
141     }
142 }
143
144 impl ast::UseTree {
145     pub fn has_star(&self) -> bool {
146         self.syntax().children_with_tokens().any(|it| it.kind() == T![*])
147     }
148 }
149
150 impl ast::UseTreeList {
151     pub fn parent_use_tree(&self) -> ast::UseTree {
152         self.syntax()
153             .parent()
154             .and_then(ast::UseTree::cast)
155             .expect("UseTreeLists are always nested in UseTrees")
156     }
157 }
158
159 impl ast::ImplBlock {
160     pub fn target_type(&self) -> Option<ast::TypeRef> {
161         match self.target() {
162             (Some(t), None) | (_, Some(t)) => Some(t),
163             _ => None,
164         }
165     }
166
167     pub fn target_trait(&self) -> Option<ast::TypeRef> {
168         match self.target() {
169             (Some(t), Some(_)) => Some(t),
170             _ => None,
171         }
172     }
173
174     fn target(&self) -> (Option<ast::TypeRef>, Option<ast::TypeRef>) {
175         let mut types = children(self);
176         let first = types.next();
177         let second = types.next();
178         (first, second)
179     }
180
181     pub fn is_negative(&self) -> bool {
182         self.syntax().children_with_tokens().any(|t| t.kind() == T![!])
183     }
184 }
185
186 #[derive(Debug, Clone, PartialEq, Eq)]
187 pub enum StructKind {
188     Tuple(ast::PosFieldDefList),
189     Named(ast::NamedFieldDefList),
190     Unit,
191 }
192
193 impl StructKind {
194     fn from_node<N: AstNode>(node: &N) -> StructKind {
195         if let Some(nfdl) = child_opt::<_, ast::NamedFieldDefList>(node) {
196             StructKind::Named(nfdl)
197         } else if let Some(pfl) = child_opt::<_, ast::PosFieldDefList>(node) {
198             StructKind::Tuple(pfl)
199         } else {
200             StructKind::Unit
201         }
202     }
203 }
204
205 impl ast::StructDef {
206     pub fn is_union(&self) -> bool {
207         for child in self.syntax().children_with_tokens() {
208             match child.kind() {
209                 T![struct] => return false,
210                 T![union] => return true,
211                 _ => (),
212             }
213         }
214         false
215     }
216
217     pub fn kind(&self) -> StructKind {
218         StructKind::from_node(self)
219     }
220 }
221
222 impl ast::EnumVariant {
223     pub fn parent_enum(&self) -> ast::EnumDef {
224         self.syntax()
225             .parent()
226             .and_then(|it| it.parent())
227             .and_then(ast::EnumDef::cast)
228             .expect("EnumVariants are always nested in Enums")
229     }
230     pub fn kind(&self) -> StructKind {
231         StructKind::from_node(self)
232     }
233 }
234
235 impl ast::FnDef {
236     pub fn semicolon_token(&self) -> Option<SyntaxToken> {
237         self.syntax()
238             .last_child_or_token()
239             .and_then(|it| it.into_token())
240             .filter(|it| it.kind() == T![;])
241     }
242 }
243
244 impl ast::LetStmt {
245     pub fn has_semi(&self) -> bool {
246         match self.syntax().last_child_or_token() {
247             None => false,
248             Some(node) => node.kind() == T![;],
249         }
250     }
251 }
252
253 impl ast::ExprStmt {
254     pub fn has_semi(&self) -> bool {
255         match self.syntax().last_child_or_token() {
256             None => false,
257             Some(node) => node.kind() == T![;],
258         }
259     }
260 }
261
262 #[derive(Debug, Clone, PartialEq, Eq)]
263 pub enum FieldKind {
264     Name(ast::NameRef),
265     Index(SyntaxToken),
266 }
267
268 impl ast::FieldExpr {
269     pub fn index_token(&self) -> Option<SyntaxToken> {
270         self.syntax
271             .children_with_tokens()
272             // FIXME: Accepting floats here to reject them in validation later
273             .find(|c| c.kind() == SyntaxKind::INT_NUMBER || c.kind() == SyntaxKind::FLOAT_NUMBER)
274             .as_ref()
275             .and_then(SyntaxElement::as_token)
276             .cloned()
277     }
278
279     pub fn field_access(&self) -> Option<FieldKind> {
280         if let Some(nr) = self.name_ref() {
281             Some(FieldKind::Name(nr))
282         } else if let Some(tok) = self.index_token() {
283             Some(FieldKind::Index(tok))
284         } else {
285             None
286         }
287     }
288 }
289
290 impl ast::RefPat {
291     pub fn is_mut(&self) -> bool {
292         self.syntax().children_with_tokens().any(|n| n.kind() == T![mut])
293     }
294 }
295
296 impl ast::BindPat {
297     pub fn is_mutable(&self) -> bool {
298         self.syntax().children_with_tokens().any(|n| n.kind() == T![mut])
299     }
300
301     pub fn is_ref(&self) -> bool {
302         self.syntax().children_with_tokens().any(|n| n.kind() == T![ref])
303     }
304 }
305
306 impl ast::PointerType {
307     pub fn is_mut(&self) -> bool {
308         self.syntax().children_with_tokens().any(|n| n.kind() == T![mut])
309     }
310 }
311
312 impl ast::ReferenceType {
313     pub fn is_mut(&self) -> bool {
314         self.syntax().children_with_tokens().any(|n| n.kind() == T![mut])
315     }
316 }
317
318 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
319 pub enum SelfParamKind {
320     /// self
321     Owned,
322     /// &self
323     Ref,
324     /// &mut self
325     MutRef,
326 }
327
328 impl ast::SelfParam {
329     pub fn self_kw_token(&self) -> SyntaxToken {
330         self.syntax()
331             .children_with_tokens()
332             .filter_map(|it| it.into_token())
333             .find(|it| it.kind() == T![self])
334             .expect("invalid tree: self param must have self")
335     }
336
337     pub fn kind(&self) -> SelfParamKind {
338         let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == T![&]);
339         if borrowed {
340             // check for a `mut` coming after the & -- `mut &self` != `&mut self`
341             if self
342                 .syntax()
343                 .children_with_tokens()
344                 .skip_while(|n| n.kind() != T![&])
345                 .any(|n| n.kind() == T![mut])
346             {
347                 SelfParamKind::MutRef
348             } else {
349                 SelfParamKind::Ref
350             }
351         } else {
352             SelfParamKind::Owned
353         }
354     }
355 }
356
357 impl ast::LifetimeParam {
358     pub fn lifetime_token(&self) -> Option<SyntaxToken> {
359         self.syntax()
360             .children_with_tokens()
361             .filter_map(|it| it.into_token())
362             .find(|it| it.kind() == LIFETIME)
363     }
364 }
365
366 impl ast::WherePred {
367     pub fn lifetime_token(&self) -> Option<SyntaxToken> {
368         self.syntax()
369             .children_with_tokens()
370             .filter_map(|it| it.into_token())
371             .find(|it| it.kind() == LIFETIME)
372     }
373 }
374
375 impl ast::TraitDef {
376     pub fn is_auto(&self) -> bool {
377         self.syntax().children_with_tokens().any(|t| t.kind() == T![auto])
378     }
379 }