Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/syntax/src/ast/traits.rs')
| -rw-r--r-- | crates/syntax/src/ast/traits.rs | 67 |
1 files changed, 28 insertions, 39 deletions
diff --git a/crates/syntax/src/ast/traits.rs b/crates/syntax/src/ast/traits.rs index 2f4109a2c9..5290f32dd2 100644 --- a/crates/syntax/src/ast/traits.rs +++ b/crates/syntax/src/ast/traits.rs @@ -4,9 +4,8 @@ use either::Either; use crate::{ - SyntaxElement, SyntaxNode, SyntaxToken, T, + SyntaxElement, SyntaxToken, T, ast::{self, AstChildren, AstNode, AstToken, support}, - match_ast, syntax_node::SyntaxElementChildren, }; @@ -77,44 +76,34 @@ pub trait HasAttrs: AstNode { self.attrs().filter_map(|x| x.as_simple_atom()).any(|x| x == atom) } - /// This may return the same node as called with (with `SourceFile`). The caller has the responsibility - /// to avoid duplicate attributes. - fn inner_attributes_node(&self) -> Option<SyntaxNode> { - let syntax = self.syntax(); - Some(match_ast! { - match syntax { - // A `SourceFile` contains the inner attributes of itself. - ast::SourceFile(_) => syntax.clone(), - ast::ExternBlock(it) => it.extern_item_list()?.syntax().clone(), - ast::Fn(it) => it.body()?.stmt_list()?.syntax().clone(), - ast::MatchExpr(it) => it.match_arm_list()?.syntax().clone(), - ast::Impl(it) => it.assoc_item_list()?.syntax().clone(), - ast::Trait(it) => it.assoc_item_list()?.syntax().clone(), - ast::Module(it) => it.item_list()?.syntax().clone(), - ast::BlockExpr(it) => { - if !it.may_carry_attributes() { - return None; - } - syntax.clone() - }, - _ => return None, - } - }) + /// Returns all attributes of this node, including inner attributes that may not be directly under this node + /// but under a child. + fn attrs_including_inner(self) -> impl Iterator<Item = ast::Attr> + where + Self: Sized, + { + let inner_attrs_node = if let Some(it) = + support::child::<ast::BlockExpr>(self.syntax()).and_then(|it| it.stmt_list()) + { + Some(it.syntax) + } else if let Some(it) = support::child::<ast::MatchArmList>(self.syntax()) { + Some(it.syntax) + } else if let Some(it) = support::child::<ast::AssocItemList>(self.syntax()) { + Some(it.syntax) + } else if let Some(it) = support::child::<ast::ItemList>(self.syntax()) { + Some(it.syntax) + } else if let Some(it) = support::child::<ast::ExternItemList>(self.syntax()) { + Some(it.syntax) + } else if let Some(it) = support::child::<ast::MacroItems>(self.syntax()) { + Some(it.syntax) + } else { + None + }; + + self.attrs().chain(inner_attrs_node.into_iter().flat_map(|it| support::children(&it))) } } -/// Returns all attributes of this node, including inner attributes that may not be directly under this node -/// but under a child. -pub fn attrs_including_inner(owner: &dyn HasAttrs) -> impl Iterator<Item = ast::Attr> + Clone { - owner.attrs().filter(|attr| attr.kind().is_outer()).chain( - owner - .inner_attributes_node() - .into_iter() - .flat_map(|node| support::children::<ast::Attr>(&node)) - .filter(|attr| attr.kind().is_inner()), - ) -} - pub trait HasDocComments: HasAttrs { fn doc_comments(&self) -> DocCommentIter { DocCommentIter { iter: self.syntax().children_with_tokens() } @@ -129,7 +118,7 @@ impl DocCommentIter { #[cfg(test)] pub fn doc_comment_text(self) -> Option<String> { let docs = itertools::Itertools::join( - &mut self.filter_map(|comment| comment.doc_comment().map(|it| it.0.to_owned())), + &mut self.filter_map(|comment| comment.doc_comment().map(ToOwned::to_owned)), "\n", ); if docs.is_empty() { None } else { Some(docs) } @@ -162,7 +151,7 @@ impl AttrDocCommentIter { impl Iterator for AttrDocCommentIter { type Item = Either<ast::Attr, ast::Comment>; fn next(&mut self) -> Option<Self::Item> { - self.iter.find_map(|el| match el { + self.iter.by_ref().find_map(|el| match el { SyntaxElement::Node(node) => ast::Attr::cast(node).map(Either::Left), SyntaxElement::Token(tok) => { ast::Comment::cast(tok).filter(ast::Comment::is_doc).map(Either::Right) |