• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Various traits that are implemented by ast nodes.
2 //!
3 //! The implementations are usually trivial, and live in generated.rs
4 use either::Either;
5 
6 use crate::{
7     ast::{self, support, AstChildren, AstNode, AstToken},
8     syntax_node::SyntaxElementChildren,
9     SyntaxElement, SyntaxToken, T,
10 };
11 
12 pub trait HasName: AstNode {
name(&self) -> Option<ast::Name>13     fn name(&self) -> Option<ast::Name> {
14         support::child(self.syntax())
15     }
16 }
17 
18 pub trait HasVisibility: AstNode {
visibility(&self) -> Option<ast::Visibility>19     fn visibility(&self) -> Option<ast::Visibility> {
20         support::child(self.syntax())
21     }
22 }
23 
24 pub trait HasLoopBody: AstNode {
loop_body(&self) -> Option<ast::BlockExpr>25     fn loop_body(&self) -> Option<ast::BlockExpr> {
26         support::child(self.syntax())
27     }
28 
label(&self) -> Option<ast::Label>29     fn label(&self) -> Option<ast::Label> {
30         support::child(self.syntax())
31     }
32 }
33 
34 pub trait HasArgList: AstNode {
arg_list(&self) -> Option<ast::ArgList>35     fn arg_list(&self) -> Option<ast::ArgList> {
36         support::child(self.syntax())
37     }
38 }
39 
40 pub trait HasModuleItem: AstNode {
items(&self) -> AstChildren<ast::Item>41     fn items(&self) -> AstChildren<ast::Item> {
42         support::children(self.syntax())
43     }
44 }
45 
46 pub trait HasGenericParams: AstNode {
generic_param_list(&self) -> Option<ast::GenericParamList>47     fn generic_param_list(&self) -> Option<ast::GenericParamList> {
48         support::child(self.syntax())
49     }
50 
where_clause(&self) -> Option<ast::WhereClause>51     fn where_clause(&self) -> Option<ast::WhereClause> {
52         support::child(self.syntax())
53     }
54 }
55 
56 pub trait HasTypeBounds: AstNode {
type_bound_list(&self) -> Option<ast::TypeBoundList>57     fn type_bound_list(&self) -> Option<ast::TypeBoundList> {
58         support::child(self.syntax())
59     }
60 
colon_token(&self) -> Option<SyntaxToken>61     fn colon_token(&self) -> Option<SyntaxToken> {
62         support::token(self.syntax(), T![:])
63     }
64 }
65 
66 pub trait HasAttrs: AstNode {
attrs(&self) -> AstChildren<ast::Attr>67     fn attrs(&self) -> AstChildren<ast::Attr> {
68         support::children(self.syntax())
69     }
has_atom_attr(&self, atom: &str) -> bool70     fn has_atom_attr(&self, atom: &str) -> bool {
71         self.attrs().filter_map(|x| x.as_simple_atom()).any(|x| x == atom)
72     }
73 }
74 
75 pub trait HasDocComments: HasAttrs {
doc_comments(&self) -> DocCommentIter76     fn doc_comments(&self) -> DocCommentIter {
77         DocCommentIter { iter: self.syntax().children_with_tokens() }
78     }
doc_comments_and_attrs(&self) -> AttrDocCommentIter79     fn doc_comments_and_attrs(&self) -> AttrDocCommentIter {
80         AttrDocCommentIter { iter: self.syntax().children_with_tokens() }
81     }
82 }
83 
84 impl DocCommentIter {
from_syntax_node(syntax_node: &ast::SyntaxNode) -> DocCommentIter85     pub fn from_syntax_node(syntax_node: &ast::SyntaxNode) -> DocCommentIter {
86         DocCommentIter { iter: syntax_node.children_with_tokens() }
87     }
88 
89     #[cfg(test)]
doc_comment_text(self) -> Option<String>90     pub fn doc_comment_text(self) -> Option<String> {
91         let docs = itertools::Itertools::join(
92             &mut self.filter_map(|comment| comment.doc_comment().map(ToOwned::to_owned)),
93             "\n",
94         );
95         if docs.is_empty() {
96             None
97         } else {
98             Some(docs)
99         }
100     }
101 }
102 
103 pub struct DocCommentIter {
104     iter: SyntaxElementChildren,
105 }
106 
107 impl Iterator for DocCommentIter {
108     type Item = ast::Comment;
next(&mut self) -> Option<ast::Comment>109     fn next(&mut self) -> Option<ast::Comment> {
110         self.iter.by_ref().find_map(|el| {
111             el.into_token().and_then(ast::Comment::cast).filter(ast::Comment::is_doc)
112         })
113     }
114 }
115 
116 pub struct AttrDocCommentIter {
117     iter: SyntaxElementChildren,
118 }
119 
120 impl AttrDocCommentIter {
from_syntax_node(syntax_node: &ast::SyntaxNode) -> AttrDocCommentIter121     pub fn from_syntax_node(syntax_node: &ast::SyntaxNode) -> AttrDocCommentIter {
122         AttrDocCommentIter { iter: syntax_node.children_with_tokens() }
123     }
124 }
125 
126 impl Iterator for AttrDocCommentIter {
127     type Item = Either<ast::Attr, ast::Comment>;
next(&mut self) -> Option<Self::Item>128     fn next(&mut self) -> Option<Self::Item> {
129         self.iter.by_ref().find_map(|el| match el {
130             SyntaxElement::Node(node) => ast::Attr::cast(node).map(Either::Left),
131             SyntaxElement::Token(tok) => {
132                 ast::Comment::cast(tok).filter(ast::Comment::is_doc).map(Either::Right)
133             }
134         })
135     }
136 }
137 
138 impl<A: HasName, B: HasName> HasName for Either<A, B> {}
139