1mod generated;
2
3use std::marker::PhantomData;
4
5use itertools::Itertools;
6
7pub use self::generated::*;
8use crate::{
9 yellow::{RefRoot, SyntaxNodeChildren},
10 SmolStr,
11 SyntaxKind::*,
12 SyntaxNodeRef,
13};
14
15pub trait AstNode<'a>: Clone + Copy + 'a {
16 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self>
17 where
18 Self: Sized;
19 fn syntax(self) -> SyntaxNodeRef<'a>;
20}
21
22pub trait NameOwner<'a>: AstNode<'a> {
23 fn name(self) -> Option<Name<'a>> {
24 child_opt(self)
25 }
26}
27
28pub trait LoopBodyOwner<'a>: AstNode<'a> {
29 fn loop_body(self) -> Option<Block<'a>> {
30 child_opt(self)
31 }
32}
33
34pub trait ArgListOwner<'a>: AstNode<'a> {
35 fn arg_list(self) -> Option<ArgList<'a>> {
36 child_opt(self)
37 }
38}
39
40pub trait FnDefOwner<'a>: AstNode<'a> {
41 fn functions(self) -> AstChildren<'a, FnDef<'a>> {
42 children(self)
43 }
44}
45
46pub trait ModuleItemOwner<'a>: AstNode<'a> {
47 fn items(self) -> AstChildren<'a, ModuleItem<'a>> {
48 children(self)
49 }
50}
51
52pub trait TypeParamsOwner<'a>: AstNode<'a> {
53 fn type_param_list(self) -> Option<TypeParamList<'a>> {
54 child_opt(self)
55 }
56
57 fn where_clause(self) -> Option<WhereClause<'a>> {
58 child_opt(self)
59 }
60}
61
62pub trait AttrsOwner<'a>: AstNode<'a> {
63 fn attrs(self) -> AstChildren<'a, Attr<'a>> {
64 children(self)
65 }
66}
67
68pub trait DocCommentsOwner<'a>: AstNode<'a> {
69 fn doc_comments(self) -> AstChildren<'a, Comment<'a>> {
70 children(self)
71 }
72
73 fn doc_comment_text(self) -> String {
76 self.doc_comments()
77 .map(|comment| {
78 let prefix = comment.prefix();
79 let trimmed = comment
80 .text()
81 .as_str()
82 .trim()
83 .trim_start_matches(prefix)
84 .trim_start();
85 trimmed.to_owned()
86 })
87 .join("\n")
88 }
89}
90
91impl<'a> FnDef<'a> {
92 pub fn has_atom_attr(&self, atom: &str) -> bool {
93 self.attrs().filter_map(|x| x.as_atom()).any(|x| x == atom)
94 }
95}
96
97impl<'a> Attr<'a> {
98 pub fn as_atom(&self) -> Option<SmolStr> {
99 let tt = self.value()?;
100 let (_bra, attr, _ket) = tt.syntax().children().collect_tuple()?;
101 if attr.kind() == IDENT {
102 Some(attr.leaf_text().unwrap().clone())
103 } else {
104 None
105 }
106 }
107
108 pub fn as_call(&self) -> Option<(SmolStr, TokenTree<'a>)> {
109 let tt = self.value()?;
110 let (_bra, attr, args, _ket) = tt.syntax().children().collect_tuple()?;
111 let args = TokenTree::cast(args)?;
112 if attr.kind() == IDENT {
113 Some((attr.leaf_text().unwrap().clone(), args))
114 } else {
115 None
116 }
117 }
118}
119
120impl<'a> Lifetime<'a> {
121 pub fn text(&self) -> SmolStr {
122 self.syntax().leaf_text().unwrap().clone()
123 }
124}
125
126impl<'a> Char<'a> {
127 pub fn text(&self) -> &SmolStr {
128 &self.syntax().leaf_text().unwrap()
129 }
130}
131
132impl<'a> Comment<'a> {
133 pub fn text(&self) -> &SmolStr {
134 self.syntax().leaf_text().unwrap()
135 }
136
137 pub fn flavor(&self) -> CommentFlavor {
138 let text = self.text();
139 if text.starts_with("///") {
140 CommentFlavor::Doc
141 } else if text.starts_with("//!") {
142 CommentFlavor::ModuleDoc
143 } else if text.starts_with("//") {
144 CommentFlavor::Line
145 } else {
146 CommentFlavor::Multiline
147 }
148 }
149
150 pub fn prefix(&self) -> &'static str {
151 self.flavor().prefix()
152 }
153
154 pub fn count_newlines_lazy(&self) -> impl Iterator<Item = &()> {
155 self.text().chars().filter(|&c| c == '\n').map(|_| &())
156 }
157
158 pub fn has_newlines(&self) -> bool {
159 self.count_newlines_lazy().count() > 0
160 }
161}
162
163#[derive(Debug, PartialEq, Eq)]
164pub enum CommentFlavor {
165 Line,
166 Doc,
167 ModuleDoc,
168 Multiline,
169}
170
171impl CommentFlavor {
172 pub fn prefix(&self) -> &'static str {
173 use self::CommentFlavor::*;
174 match *self {
175 Line => "//",
176 Doc => "///",
177 ModuleDoc => "//!",
178 Multiline => "/*",
179 }
180 }
181}
182
183impl<'a> Whitespace<'a> {
184 pub fn text(&self) -> &SmolStr {
185 &self.syntax().leaf_text().unwrap()
186 }
187
188 pub fn count_newlines_lazy(&self) -> impl Iterator<Item = &()> {
189 self.text().chars().filter(|&c| c == '\n').map(|_| &())
190 }
191
192 pub fn has_newlines(&self) -> bool {
193 self.count_newlines_lazy().count() > 0
194 }
195}
196
197impl<'a> Name<'a> {
198 pub fn text(&self) -> SmolStr {
199 let ident = self.syntax().first_child().unwrap();
200 ident.leaf_text().unwrap().clone()
201 }
202}
203
204impl<'a> NameRef<'a> {
205 pub fn text(&self) -> SmolStr {
206 let ident = self.syntax().first_child().unwrap();
207 ident.leaf_text().unwrap().clone()
208 }
209}
210
211impl<'a> ImplItem<'a> {
212 pub fn target_type(self) -> Option<TypeRef<'a>> {
213 match self.target() {
214 (Some(t), None) | (_, Some(t)) => Some(t),
215 _ => None,
216 }
217 }
218
219 pub fn target_trait(self) -> Option<TypeRef<'a>> {
220 match self.target() {
221 (Some(t), Some(_)) => Some(t),
222 _ => None,
223 }
224 }
225
226 fn target(self) -> (Option<TypeRef<'a>>, Option<TypeRef<'a>>) {
227 let mut types = children(self);
228 let first = types.next();
229 let second = types.next();
230 (first, second)
231 }
232}
233
234impl<'a> Module<'a> {
235 pub fn has_semi(self) -> bool {
236 match self.syntax().last_child() {
237 None => false,
238 Some(node) => node.kind() == SEMI,
239 }
240 }
241}
242
243impl<'a> LetStmt<'a> {
244 pub fn has_semi(self) -> bool {
245 match self.syntax().last_child() {
246 None => false,
247 Some(node) => node.kind() == SEMI,
248 }
249 }
250}
251
252impl<'a> IfExpr<'a> {
253 pub fn then_branch(self) -> Option<Block<'a>> {
254 self.blocks().nth(0)
255 }
256 pub fn else_branch(self) -> Option<Block<'a>> {
257 self.blocks().nth(1)
258 }
259 fn blocks(self) -> AstChildren<'a, Block<'a>> {
260 children(self)
261 }
262}
263
264#[derive(Debug, Clone, Copy)]
265pub enum PathSegmentKind<'a> {
266 Name(NameRef<'a>),
267 SelfKw,
268 SuperKw,
269 CrateKw,
270}
271
272impl<'a> PathSegment<'a> {
273 pub fn parent_path(self) -> Path<'a> {
274 self.syntax()
275 .parent()
276 .and_then(Path::cast)
277 .expect("segments are always nested in paths")
278 }
279
280 pub fn kind(self) -> Option<PathSegmentKind<'a>> {
281 let res = if let Some(name_ref) = self.name_ref() {
282 PathSegmentKind::Name(name_ref)
283 } else {
284 match self.syntax().first_child()?.kind() {
285 SELF_KW => PathSegmentKind::SelfKw,
286 SUPER_KW => PathSegmentKind::SuperKw,
287 CRATE_KW => PathSegmentKind::CrateKw,
288 _ => return None,
289 }
290 };
291 Some(res)
292 }
293}
294
295fn child_opt<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> Option<C> {
296 children(parent).next()
297}
298
299fn children<'a, P: AstNode<'a>, C: AstNode<'a>>(parent: P) -> AstChildren<'a, C> {
300 AstChildren::new(parent.syntax())
301}
302
303#[derive(Debug)]
304pub struct AstChildren<'a, N> {
305 inner: SyntaxNodeChildren<RefRoot<'a>>,
306 ph: PhantomData<N>,
307}
308
309impl<'a, N> AstChildren<'a, N> {
310 fn new(parent: SyntaxNodeRef<'a>) -> Self {
311 AstChildren {
312 inner: parent.children(),
313 ph: PhantomData,
314 }
315 }
316}
317
318impl<'a, N: AstNode<'a>> Iterator for AstChildren<'a, N> {
319 type Item = N;
320 fn next(&mut self) -> Option<N> {
321 loop {
322 if let Some(n) = N::cast(self.inner.next()?) {
323 return Some(n);
324 }
325 }
326 }
327}