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