diff options
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r-- | crates/hir_def/src/attr.rs | 44 |
1 files changed, 39 insertions, 5 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 12f4b02e2..e9192528a 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -9,7 +9,7 @@ use itertools::Itertools; | |||
9 | use mbe::ast_to_token_tree; | 9 | use mbe::ast_to_token_tree; |
10 | use syntax::{ | 10 | use syntax::{ |
11 | ast::{self, AstNode, AttrsOwner}, | 11 | ast::{self, AstNode, AttrsOwner}, |
12 | AstToken, SmolStr, | 12 | match_ast, AstToken, SmolStr, SyntaxNode, |
13 | }; | 13 | }; |
14 | use tt::Subtree; | 14 | use tt::Subtree; |
15 | 15 | ||
@@ -110,7 +110,7 @@ impl Attrs { | |||
110 | } | 110 | } |
111 | 111 | ||
112 | pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs { | 112 | pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs { |
113 | let docs = ast::CommentIter::from_syntax_node(owner.syntax()).map(|docs_text| { | 113 | let outer_docs = ast::CommentIter::from_syntax_node(owner.syntax()).map(|docs_text| { |
114 | ( | 114 | ( |
115 | docs_text.syntax().text_range().start(), | 115 | docs_text.syntax().text_range().start(), |
116 | docs_text.doc_comment().map(|doc| Attr { | 116 | docs_text.doc_comment().map(|doc| Attr { |
@@ -119,11 +119,13 @@ impl Attrs { | |||
119 | }), | 119 | }), |
120 | ) | 120 | ) |
121 | }); | 121 | }); |
122 | let attrs = owner | 122 | let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none()); |
123 | .attrs() | 123 | let inner_attrs = inner_attributes(owner.syntax()).into_iter().flatten(); |
124 | let attrs = outer_attrs | ||
125 | .chain(inner_attrs) | ||
124 | .map(|attr| (attr.syntax().text_range().start(), Attr::from_src(attr, hygiene))); | 126 | .map(|attr| (attr.syntax().text_range().start(), Attr::from_src(attr, hygiene))); |
125 | // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved | 127 | // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved |
126 | let attrs: Vec<_> = docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).collect(); | 128 | let attrs: Vec<_> = outer_docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).collect(); |
127 | let entries = if attrs.is_empty() { | 129 | let entries = if attrs.is_empty() { |
128 | // Avoid heap allocation | 130 | // Avoid heap allocation |
129 | None | 131 | None |
@@ -184,6 +186,38 @@ impl Attrs { | |||
184 | } | 186 | } |
185 | } | 187 | } |
186 | 188 | ||
189 | fn inner_attributes(syntax: &SyntaxNode) -> Option<impl Iterator<Item = ast::Attr>> { | ||
190 | let (attrs, _docs) = match_ast! { | ||
191 | match syntax { | ||
192 | ast::SourceFile(it) => (it.attrs(), None::<ast::Comment>), | ||
193 | ast::ExternBlock(it) => { | ||
194 | let extern_item_list = it.extern_item_list()?; | ||
195 | (extern_item_list.attrs(), None) | ||
196 | }, | ||
197 | ast::Fn(it) => { | ||
198 | let body = it.body()?; | ||
199 | (body.attrs(), None) | ||
200 | }, | ||
201 | ast::Impl(it) => { | ||
202 | let assoc_item_list = it.assoc_item_list()?; | ||
203 | (assoc_item_list.attrs(), None) | ||
204 | }, | ||
205 | ast::Module(it) => { | ||
206 | let item_list = it.item_list()?; | ||
207 | (item_list.attrs(), None) | ||
208 | }, | ||
209 | // FIXME: BlockExpr's only accept inner attributes in specific cases | ||
210 | // Excerpt from the reference: | ||
211 | // Block expressions accept outer and inner attributes, but only when they are the outer | ||
212 | // expression of an expression statement or the final expression of another block expression. | ||
213 | ast::BlockExpr(it) => return None, | ||
214 | _ => return None, | ||
215 | } | ||
216 | }; | ||
217 | let attrs = attrs.filter(|attr| attr.excl_token().is_some()); | ||
218 | Some(attrs) | ||
219 | } | ||
220 | |||
187 | #[derive(Debug, Clone, PartialEq, Eq)] | 221 | #[derive(Debug, Clone, PartialEq, Eq)] |
188 | pub struct Attr { | 222 | pub struct Attr { |
189 | pub(crate) path: ModPath, | 223 | pub(crate) path: ModPath, |