diff options
Diffstat (limited to 'crates/hir_def')
-rw-r--r-- | crates/hir_def/src/attr.rs | 42 |
1 files changed, 25 insertions, 17 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index e9192528a..228d706db 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -110,7 +110,17 @@ 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 outer_docs = ast::CommentIter::from_syntax_node(owner.syntax()).map(|docs_text| { | 113 | let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) |
114 | .map_or((None, None), |(attrs, docs)| ((Some(attrs), Some(docs)))); | ||
115 | |||
116 | let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none()); | ||
117 | let attrs = outer_attrs | ||
118 | .chain(inner_attrs.into_iter().flatten()) | ||
119 | .map(|attr| (attr.syntax().text_range().start(), Attr::from_src(attr, hygiene))); | ||
120 | |||
121 | let outer_docs = | ||
122 | ast::CommentIter::from_syntax_node(owner.syntax()).filter(ast::Comment::is_outer); | ||
123 | let docs = outer_docs.chain(inner_docs.into_iter().flatten()).map(|docs_text| { | ||
114 | ( | 124 | ( |
115 | docs_text.syntax().text_range().start(), | 125 | docs_text.syntax().text_range().start(), |
116 | docs_text.doc_comment().map(|doc| Attr { | 126 | docs_text.doc_comment().map(|doc| Attr { |
@@ -119,13 +129,8 @@ impl Attrs { | |||
119 | }), | 129 | }), |
120 | ) | 130 | ) |
121 | }); | 131 | }); |
122 | let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none()); | ||
123 | let inner_attrs = inner_attributes(owner.syntax()).into_iter().flatten(); | ||
124 | let attrs = outer_attrs | ||
125 | .chain(inner_attrs) | ||
126 | .map(|attr| (attr.syntax().text_range().start(), Attr::from_src(attr, hygiene))); | ||
127 | // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved | 132 | // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved |
128 | let attrs: Vec<_> = outer_docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).collect(); | 133 | let attrs: Vec<_> = docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).collect(); |
129 | let entries = if attrs.is_empty() { | 134 | let entries = if attrs.is_empty() { |
130 | // Avoid heap allocation | 135 | // Avoid heap allocation |
131 | None | 136 | None |
@@ -186,36 +191,39 @@ impl Attrs { | |||
186 | } | 191 | } |
187 | } | 192 | } |
188 | 193 | ||
189 | fn inner_attributes(syntax: &SyntaxNode) -> Option<impl Iterator<Item = ast::Attr>> { | 194 | fn inner_attributes( |
190 | let (attrs, _docs) = match_ast! { | 195 | syntax: &SyntaxNode, |
196 | ) -> Option<(impl Iterator<Item = ast::Attr>, impl Iterator<Item = ast::Comment>)> { | ||
197 | let (attrs, docs) = match_ast! { | ||
191 | match syntax { | 198 | match syntax { |
192 | ast::SourceFile(it) => (it.attrs(), None::<ast::Comment>), | 199 | ast::SourceFile(it) => (it.attrs(), ast::CommentIter::from_syntax_node(it.syntax())), |
193 | ast::ExternBlock(it) => { | 200 | ast::ExternBlock(it) => { |
194 | let extern_item_list = it.extern_item_list()?; | 201 | let extern_item_list = it.extern_item_list()?; |
195 | (extern_item_list.attrs(), None) | 202 | (extern_item_list.attrs(), ast::CommentIter::from_syntax_node(extern_item_list.syntax())) |
196 | }, | 203 | }, |
197 | ast::Fn(it) => { | 204 | ast::Fn(it) => { |
198 | let body = it.body()?; | 205 | let body = it.body()?; |
199 | (body.attrs(), None) | 206 | (body.attrs(), ast::CommentIter::from_syntax_node(body.syntax())) |
200 | }, | 207 | }, |
201 | ast::Impl(it) => { | 208 | ast::Impl(it) => { |
202 | let assoc_item_list = it.assoc_item_list()?; | 209 | let assoc_item_list = it.assoc_item_list()?; |
203 | (assoc_item_list.attrs(), None) | 210 | (assoc_item_list.attrs(), ast::CommentIter::from_syntax_node(assoc_item_list.syntax())) |
204 | }, | 211 | }, |
205 | ast::Module(it) => { | 212 | ast::Module(it) => { |
206 | let item_list = it.item_list()?; | 213 | let item_list = it.item_list()?; |
207 | (item_list.attrs(), None) | 214 | (item_list.attrs(), ast::CommentIter::from_syntax_node(item_list.syntax())) |
208 | }, | 215 | }, |
209 | // FIXME: BlockExpr's only accept inner attributes in specific cases | 216 | // FIXME: BlockExpr's only accept inner attributes in specific cases |
210 | // Excerpt from the reference: | 217 | // Excerpt from the reference: |
211 | // Block expressions accept outer and inner attributes, but only when they are the outer | 218 | // 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. | 219 | // expression of an expression statement or the final expression of another block expression. |
213 | ast::BlockExpr(it) => return None, | 220 | ast::BlockExpr(it) => return None, |
214 | _ => return None, | 221 | _ => return None, |
215 | } | 222 | } |
216 | }; | 223 | }; |
217 | let attrs = attrs.filter(|attr| attr.excl_token().is_some()); | 224 | let attrs = attrs.filter(|attr| attr.excl_token().is_some()); |
218 | Some(attrs) | 225 | let docs = docs.filter(|doc| doc.is_inner()); |
226 | Some((attrs, docs)) | ||
219 | } | 227 | } |
220 | 228 | ||
221 | #[derive(Debug, Clone, PartialEq, Eq)] | 229 | #[derive(Debug, Clone, PartialEq, Eq)] |