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.rs93
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
4use itertools::Itertools;
5
6use crate::{ 4use 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
26fn text_of_first_token(node: &SyntaxNode) -> &SmolStr { 34fn text_of_first_token(node: &SyntaxNode) -> &SmolStr {
@@ -28,62 +36,37 @@ fn text_of_first_token(node: &SyntaxNode) -> &SmolStr {
28} 36}
29 37
30impl ast::Attr { 38impl 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
179impl 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)]
197pub enum StructKind { 190pub enum StructKind {
198 Tuple(ast::TupleFieldDefList), 191 Tuple(ast::TupleFieldDefList),