Skip to content

Commit eac7799

Browse files
committed
Properly fetch inner and outer attributes on hir-level
1 parent e2e6b70 commit eac7799

File tree

1 file changed

+39
-5
lines changed

1 file changed

+39
-5
lines changed

crates/hir_def/src/attr.rs

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use itertools::Itertools;
99
use mbe::ast_to_token_tree;
1010
use syntax::{
1111
ast::{self, AstNode, AttrsOwner},
12-
AstToken, SmolStr,
12+
match_ast, AstToken, SmolStr, SyntaxNode,
1313
};
1414
use tt::Subtree;
1515

@@ -110,7 +110,7 @@ impl Attrs {
110110
}
111111

112112
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| {
114114
(
115115
docs_text.syntax().text_range().start(),
116116
docs_text.doc_comment().map(|doc| Attr {
@@ -119,11 +119,13 @@ impl Attrs {
119119
}),
120120
)
121121
});
122-
let attrs = owner
123-
.attrs()
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)
124126
.map(|attr| (attr.syntax().text_range().start(), Attr::from_src(attr, hygiene)));
125127
// 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();
127129
let entries = if attrs.is_empty() {
128130
// Avoid heap allocation
129131
None
@@ -184,6 +186,38 @@ impl Attrs {
184186
}
185187
}
186188

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+
187221
#[derive(Debug, Clone, PartialEq, Eq)]
188222
pub struct Attr {
189223
pub(crate) path: ModPath,

0 commit comments

Comments
 (0)