1 //! Various traits that are implemented by ast nodes.
3 //! The implementations are usually trivial, and live in generated.rs
5 use itertools::Itertools;
8 ast::{self, child_opt, children, AstChildren, AstNode, AstToken},
9 syntax_node::{SyntaxElementChildren, SyntaxNodeChildren},
12 pub trait TypeAscriptionOwner: AstNode {
13 fn ascribed_type(&self) -> Option<ast::TypeRef> {
18 pub trait NameOwner: AstNode {
19 fn name(&self) -> Option<ast::Name> {
24 pub trait VisibilityOwner: AstNode {
25 fn visibility(&self) -> Option<ast::Visibility> {
30 pub trait LoopBodyOwner: AstNode {
31 fn loop_body(&self) -> Option<ast::BlockExpr> {
36 pub trait ArgListOwner: AstNode {
37 fn arg_list(&self) -> Option<ast::ArgList> {
42 pub trait FnDefOwner: AstNode {
43 fn functions(&self) -> AstChildren<ast::FnDef> {
48 #[derive(Debug, Clone, PartialEq, Eq)]
49 pub enum ItemOrMacro {
50 Item(ast::ModuleItem),
51 Macro(ast::MacroCall),
54 pub trait ModuleItemOwner: AstNode {
55 fn items(&self) -> AstChildren<ast::ModuleItem> {
58 fn items_with_macros(&self) -> ItemOrMacroIter {
59 ItemOrMacroIter(self.syntax().children())
64 pub struct ItemOrMacroIter(SyntaxNodeChildren);
66 impl Iterator for ItemOrMacroIter {
67 type Item = ItemOrMacro;
68 fn next(&mut self) -> Option<ItemOrMacro> {
70 let n = self.0.next()?;
71 if let Some(item) = ast::ModuleItem::cast(n.clone()) {
72 return Some(ItemOrMacro::Item(item));
74 if let Some(call) = ast::MacroCall::cast(n) {
75 return Some(ItemOrMacro::Macro(call));
81 pub trait TypeParamsOwner: AstNode {
82 fn type_param_list(&self) -> Option<ast::TypeParamList> {
86 fn where_clause(&self) -> Option<ast::WhereClause> {
91 pub trait TypeBoundsOwner: AstNode {
92 fn type_bound_list(&self) -> Option<ast::TypeBoundList> {
97 pub trait AttrsOwner: AstNode {
98 fn attrs(&self) -> AstChildren<ast::Attr> {
101 fn has_atom_attr(&self, atom: &str) -> bool {
102 self.attrs().filter_map(|x| x.as_simple_atom()).any(|x| x == atom)
106 pub trait DocCommentsOwner: AstNode {
107 fn doc_comments(&self) -> CommentIter {
108 CommentIter { iter: self.syntax().children_with_tokens() }
111 /// Returns the textual content of a doc comment block as a single string.
112 /// That is, strips leading `///` (+ optional 1 character of whitespace),
113 /// trailing `*/`, trailing whitespace and then joins the lines.
114 fn doc_comment_text(&self) -> Option<String> {
115 let mut has_comments = false;
118 .filter(|comment| comment.kind().doc.is_some())
121 let prefix_len = comment.prefix().len();
123 let line = comment.text().as_str();
125 // Determine if the prefix or prefix + 1 char is stripped
127 if line.chars().nth(prefix_len).map(|c| c.is_whitespace()).unwrap_or(false) {
133 let end = if comment.kind().shape.is_block() && line.ends_with("*/") {
139 line[pos..end].trim_end().to_owned()
151 pub struct CommentIter {
152 iter: SyntaxElementChildren,
155 impl Iterator for CommentIter {
156 type Item = ast::Comment;
157 fn next(&mut self) -> Option<ast::Comment> {
158 self.iter.by_ref().find_map(|el| el.into_token().and_then(ast::Comment::cast))
162 pub trait DefaultTypeParamOwner: AstNode {
163 fn default_type(&self) -> Option<ast::PathType> {