aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/attr.rs42
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
189fn inner_attributes(syntax: &SyntaxNode) -> Option<impl Iterator<Item = ast::Attr>> { 194fn 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)]