2019-04-02 10:02:23 +00:00
|
|
|
//! Various traits that are implemented by ast nodes.
|
|
|
|
//!
|
|
|
|
//! The implementations are usually trivial, and live in generated.rs
|
|
|
|
|
2019-04-02 07:03:19 +00:00
|
|
|
use itertools::Itertools;
|
|
|
|
|
2020-04-09 11:00:09 +00:00
|
|
|
use crate::{
|
|
|
|
ast::{self, child_opt, children, support, AstChildren, AstNode, AstToken},
|
|
|
|
syntax_node::SyntaxElementChildren,
|
2019-04-02 07:03:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
pub trait TypeAscriptionOwner: AstNode {
|
2019-07-18 16:23:05 +00:00
|
|
|
fn ascribed_type(&self) -> Option<ast::TypeRef> {
|
2019-04-02 07:03:19 +00:00
|
|
|
child_opt(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait NameOwner: AstNode {
|
2019-07-18 16:23:05 +00:00
|
|
|
fn name(&self) -> Option<ast::Name> {
|
2019-04-02 07:03:19 +00:00
|
|
|
child_opt(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait VisibilityOwner: AstNode {
|
2019-07-18 16:23:05 +00:00
|
|
|
fn visibility(&self) -> Option<ast::Visibility> {
|
2019-04-02 07:03:19 +00:00
|
|
|
child_opt(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait LoopBodyOwner: AstNode {
|
2019-09-02 18:23:19 +00:00
|
|
|
fn loop_body(&self) -> Option<ast::BlockExpr> {
|
2019-04-02 07:03:19 +00:00
|
|
|
child_opt(self)
|
|
|
|
}
|
2020-04-03 19:12:09 +00:00
|
|
|
|
|
|
|
fn label(&self) -> Option<ast::Label> {
|
|
|
|
child_opt(self)
|
|
|
|
}
|
2019-04-02 07:03:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub trait ArgListOwner: AstNode {
|
2019-07-18 16:23:05 +00:00
|
|
|
fn arg_list(&self) -> Option<ast::ArgList> {
|
2019-04-02 07:03:19 +00:00
|
|
|
child_opt(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait FnDefOwner: AstNode {
|
|
|
|
fn functions(&self) -> AstChildren<ast::FnDef> {
|
|
|
|
children(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait ModuleItemOwner: AstNode {
|
|
|
|
fn items(&self) -> AstChildren<ast::ModuleItem> {
|
|
|
|
children(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait TypeParamsOwner: AstNode {
|
2019-07-18 16:23:05 +00:00
|
|
|
fn type_param_list(&self) -> Option<ast::TypeParamList> {
|
2019-04-02 07:03:19 +00:00
|
|
|
child_opt(self)
|
|
|
|
}
|
|
|
|
|
2019-07-18 16:23:05 +00:00
|
|
|
fn where_clause(&self) -> Option<ast::WhereClause> {
|
2019-04-02 07:03:19 +00:00
|
|
|
child_opt(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait TypeBoundsOwner: AstNode {
|
2019-07-18 16:23:05 +00:00
|
|
|
fn type_bound_list(&self) -> Option<ast::TypeBoundList> {
|
2019-04-02 07:03:19 +00:00
|
|
|
child_opt(self)
|
|
|
|
}
|
2020-04-03 19:12:09 +00:00
|
|
|
|
|
|
|
fn colon(&self) -> Option<ast::Colon> {
|
2020-04-09 11:00:09 +00:00
|
|
|
support::token(self.syntax())
|
2020-04-03 19:12:09 +00:00
|
|
|
}
|
2019-04-02 07:03:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub trait AttrsOwner: AstNode {
|
|
|
|
fn attrs(&self) -> AstChildren<ast::Attr> {
|
|
|
|
children(self)
|
|
|
|
}
|
|
|
|
fn has_atom_attr(&self, atom: &str) -> bool {
|
2019-09-29 21:15:03 +00:00
|
|
|
self.attrs().filter_map(|x| x.as_simple_atom()).any(|x| x == atom)
|
2019-04-02 07:03:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait DocCommentsOwner: AstNode {
|
2020-04-09 11:00:09 +00:00
|
|
|
fn doc_comments(&self) -> CommentIter {
|
|
|
|
CommentIter { iter: self.syntax().children_with_tokens() }
|
2019-04-02 07:03:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the textual content of a doc comment block as a single string.
|
2019-07-31 17:59:14 +00:00
|
|
|
/// That is, strips leading `///` (+ optional 1 character of whitespace),
|
|
|
|
/// trailing `*/`, trailing whitespace and then joins the lines.
|
2019-04-02 07:34:34 +00:00
|
|
|
fn doc_comment_text(&self) -> Option<String> {
|
|
|
|
let mut has_comments = false;
|
2019-04-02 07:03:19 +00:00
|
|
|
let docs = self
|
|
|
|
.doc_comments()
|
2019-04-02 09:18:52 +00:00
|
|
|
.filter(|comment| comment.kind().doc.is_some())
|
2019-04-02 07:03:19 +00:00
|
|
|
.map(|comment| {
|
2019-04-02 07:34:34 +00:00
|
|
|
has_comments = true;
|
2019-04-02 07:03:19 +00:00
|
|
|
let prefix_len = comment.prefix().len();
|
|
|
|
|
2019-10-27 20:56:25 +00:00
|
|
|
let line: &str = comment.text().as_str();
|
2019-04-02 07:03:19 +00:00
|
|
|
|
|
|
|
// Determine if the prefix or prefix + 1 char is stripped
|
|
|
|
let pos =
|
2020-02-19 04:13:29 +00:00
|
|
|
if let Some(ws) = line.chars().nth(prefix_len).filter(|c| c.is_whitespace()) {
|
|
|
|
prefix_len + ws.len_utf8()
|
2019-04-02 07:03:19 +00:00
|
|
|
} else {
|
|
|
|
prefix_len
|
|
|
|
};
|
|
|
|
|
2019-07-31 15:43:00 +00:00
|
|
|
let end = if comment.kind().shape.is_block() && line.ends_with("*/") {
|
2019-07-31 17:59:14 +00:00
|
|
|
line.len() - 2
|
2019-07-31 15:43:00 +00:00
|
|
|
} else {
|
|
|
|
line.len()
|
|
|
|
};
|
|
|
|
|
2019-10-27 20:56:25 +00:00
|
|
|
// Note that we do not trim the end of the line here
|
|
|
|
// since whitespace can have special meaning at the end
|
|
|
|
// of a line in markdown.
|
|
|
|
line[pos..end].to_owned()
|
2019-04-02 07:03:19 +00:00
|
|
|
})
|
|
|
|
.join("\n");
|
|
|
|
|
2019-04-02 07:34:34 +00:00
|
|
|
if has_comments {
|
2019-04-02 07:03:19 +00:00
|
|
|
Some(docs)
|
2019-04-02 07:34:34 +00:00
|
|
|
} else {
|
|
|
|
None
|
2019-04-02 07:03:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-09 11:00:09 +00:00
|
|
|
|
|
|
|
pub struct CommentIter {
|
|
|
|
iter: SyntaxElementChildren,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Iterator for CommentIter {
|
|
|
|
type Item = ast::Comment;
|
|
|
|
fn next(&mut self) -> Option<ast::Comment> {
|
|
|
|
self.iter.by_ref().find_map(|el| el.into_token().and_then(ast::Comment::cast))
|
|
|
|
}
|
|
|
|
}
|