aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r--crates/hir_def/src/attr.rs44
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;
9use mbe::ast_to_token_tree; 9use mbe::ast_to_token_tree;
10use syntax::{ 10use syntax::{
11 ast::{self, AstNode, AttrsOwner}, 11 ast::{self, AstNode, AttrsOwner},
12 AstToken, SmolStr, 12 match_ast, AstToken, SmolStr, SyntaxNode,
13}; 13};
14use tt::Subtree; 14use 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
189fn 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)]
188pub struct Attr { 222pub struct Attr {
189 pub(crate) path: ModPath, 223 pub(crate) path: ModPath,