Skip to content

Commit 8b16af5

Browse files
Merge #8112
8112: Revamp `hir_def` attribute API r=Veykril a=jonas-schievink This adds `AttrsWithOwner`, which can construct an accurate `AttrSourceMap` without requiring additional information from the caller. r? @Veykril Co-authored-by: Jonas Schievink <[email protected]>
2 parents fc21640 + 636de3c commit 8b16af5

File tree

7 files changed

+248
-187
lines changed

7 files changed

+248
-187
lines changed

crates/hir/src/attrs.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Attributes & documentation for hir types.
22
use hir_def::{
3-
attr::{Attrs, Documentation},
3+
attr::{AttrsWithOwner, Documentation},
44
path::ModPath,
55
per_ns::PerNs,
66
resolver::HasResolver,
@@ -16,7 +16,7 @@ use crate::{
1616
};
1717

1818
pub trait HasAttrs {
19-
fn attrs(self, db: &dyn HirDatabase) -> Attrs;
19+
fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner;
2020
fn docs(self, db: &dyn HirDatabase) -> Option<Documentation>;
2121
fn resolve_doc_path(
2222
self,
@@ -36,7 +36,7 @@ pub enum Namespace {
3636
macro_rules! impl_has_attrs {
3737
($(($def:ident, $def_id:ident),)*) => {$(
3838
impl HasAttrs for $def {
39-
fn attrs(self, db: &dyn HirDatabase) -> Attrs {
39+
fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
4040
let def = AttrDefId::$def_id(self.into());
4141
db.attrs(def)
4242
}
@@ -70,7 +70,7 @@ impl_has_attrs![
7070
macro_rules! impl_has_attrs_enum {
7171
($($variant:ident),* for $enum:ident) => {$(
7272
impl HasAttrs for $variant {
73-
fn attrs(self, db: &dyn HirDatabase) -> Attrs {
73+
fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
7474
$enum::$variant(self).attrs(db)
7575
}
7676
fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {

crates/hir/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ pub use crate::{
8989
pub use {
9090
hir_def::{
9191
adt::StructKind,
92-
attr::{Attr, Attrs, Documentation},
92+
attr::{Attr, Attrs, AttrsWithOwner, Documentation},
9393
body::scope::ExprScopes,
9494
find_path::PrefixKind,
9595
import_map,

crates/hir_def/src/attr.rs

Lines changed: 189 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use crate::{
2121
item_tree::{ItemTreeId, ItemTreeNode},
2222
nameres::ModuleSource,
2323
path::{ModPath, PathKind},
24-
src::HasChildSource,
24+
src::{HasChildSource, HasSource},
2525
AdtId, AttrDefId, EnumId, GenericParamId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup,
2626
VariantId,
2727
};
@@ -51,6 +51,12 @@ pub(crate) struct RawAttrs {
5151
#[derive(Default, Debug, Clone, PartialEq, Eq)]
5252
pub struct Attrs(RawAttrs);
5353

54+
#[derive(Debug, Clone, PartialEq, Eq)]
55+
pub struct AttrsWithOwner {
56+
attrs: Attrs,
57+
owner: AttrDefId,
58+
}
59+
5460
impl ops::Deref for RawAttrs {
5561
type Target = [Attr];
5662

@@ -73,6 +79,14 @@ impl ops::Deref for Attrs {
7379
}
7480
}
7581

82+
impl ops::Deref for AttrsWithOwner {
83+
type Target = Attrs;
84+
85+
fn deref(&self) -> &Attrs {
86+
&self.attrs
87+
}
88+
}
89+
7690
impl RawAttrs {
7791
pub(crate) const EMPTY: Self = Self { entries: None };
7892

@@ -169,78 +183,6 @@ impl RawAttrs {
169183
impl Attrs {
170184
pub const EMPTY: Self = Self(RawAttrs::EMPTY);
171185

172-
pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
173-
let raw_attrs = match def {
174-
AttrDefId::ModuleId(module) => {
175-
let def_map = module.def_map(db);
176-
let mod_data = &def_map[module.local_id];
177-
match mod_data.declaration_source(db) {
178-
Some(it) => {
179-
let raw_attrs = RawAttrs::from_attrs_owner(
180-
db,
181-
it.as_ref().map(|it| it as &dyn ast::AttrsOwner),
182-
);
183-
match mod_data.definition_source(db) {
184-
InFile { file_id, value: ModuleSource::SourceFile(file) } => raw_attrs
185-
.merge(RawAttrs::from_attrs_owner(db, InFile::new(file_id, &file))),
186-
_ => raw_attrs,
187-
}
188-
}
189-
None => RawAttrs::from_attrs_owner(
190-
db,
191-
mod_data.definition_source(db).as_ref().map(|src| match src {
192-
ModuleSource::SourceFile(file) => file as &dyn ast::AttrsOwner,
193-
ModuleSource::Module(module) => module as &dyn ast::AttrsOwner,
194-
ModuleSource::BlockExpr(block) => block as &dyn ast::AttrsOwner,
195-
}),
196-
),
197-
}
198-
}
199-
AttrDefId::FieldId(it) => {
200-
return db.fields_attrs(it.parent)[it.local_id].clone();
201-
}
202-
AttrDefId::EnumVariantId(it) => {
203-
return db.variants_attrs(it.parent)[it.local_id].clone();
204-
}
205-
AttrDefId::AdtId(it) => match it {
206-
AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
207-
AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db),
208-
AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
209-
},
210-
AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
211-
AttrDefId::MacroDefId(it) => it
212-
.ast_id()
213-
.left()
214-
.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)),
215-
AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
216-
AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
217-
AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
218-
AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
219-
AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
220-
AttrDefId::GenericParamId(it) => match it {
221-
GenericParamId::TypeParamId(it) => {
222-
let src = it.parent.child_source(db);
223-
RawAttrs::from_attrs_owner(
224-
db,
225-
src.with_value(
226-
src.value[it.local_id].as_ref().either(|it| it as _, |it| it as _),
227-
),
228-
)
229-
}
230-
GenericParamId::LifetimeParamId(it) => {
231-
let src = it.parent.child_source(db);
232-
RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
233-
}
234-
GenericParamId::ConstParamId(it) => {
235-
let src = it.parent.child_source(db);
236-
RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
237-
}
238-
},
239-
};
240-
241-
raw_attrs.filter(db, def.krate(db))
242-
}
243-
244186
pub(crate) fn variants_attrs_query(
245187
db: &dyn DefDatabase,
246188
e: EnumId,
@@ -281,56 +223,6 @@ impl Attrs {
281223
Arc::new(res)
282224
}
283225

284-
/// Constructs a map that maps the lowered `Attr`s in this `Attrs` back to its original syntax nodes.
285-
///
286-
/// `owner` must be the original owner of the attributes.
287-
// FIXME: figure out a better api that doesnt require the for_module hack
288-
pub fn source_map(&self, owner: InFile<&dyn ast::AttrsOwner>) -> AttrSourceMap {
289-
// FIXME: This doesn't work correctly for modules, as the attributes there can have up to
290-
// two different owners
291-
AttrSourceMap {
292-
attrs: collect_attrs(owner.value)
293-
.map(|attr| InFile::new(owner.file_id, attr))
294-
.collect(),
295-
}
296-
}
297-
298-
pub fn source_map_for_module(
299-
&self,
300-
db: &dyn DefDatabase,
301-
module: crate::ModuleId,
302-
) -> AttrSourceMap {
303-
let def_map = module.def_map(db);
304-
let mod_data = &def_map[module.local_id];
305-
let attrs = match mod_data.declaration_source(db) {
306-
Some(it) => {
307-
let mut attrs: Vec<_> = collect_attrs(&it.value as &dyn ast::AttrsOwner)
308-
.map(|attr| InFile::new(it.file_id, attr))
309-
.collect();
310-
if let InFile { file_id, value: ModuleSource::SourceFile(file) } =
311-
mod_data.definition_source(db)
312-
{
313-
attrs.extend(
314-
collect_attrs(&file as &dyn ast::AttrsOwner)
315-
.map(|attr| InFile::new(file_id, attr)),
316-
)
317-
}
318-
attrs
319-
}
320-
None => {
321-
let InFile { file_id, value } = mod_data.definition_source(db);
322-
match &value {
323-
ModuleSource::SourceFile(file) => collect_attrs(file as &dyn ast::AttrsOwner),
324-
ModuleSource::Module(module) => collect_attrs(module as &dyn ast::AttrsOwner),
325-
ModuleSource::BlockExpr(block) => collect_attrs(block as &dyn ast::AttrsOwner),
326-
}
327-
.map(|attr| InFile::new(file_id, attr))
328-
.collect()
329-
}
330-
};
331-
AttrSourceMap { attrs }
332-
}
333-
334226
pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
335227
AttrQuery { attrs: self, key }
336228
}
@@ -387,6 +279,180 @@ impl Attrs {
387279
}
388280
}
389281

282+
impl AttrsWithOwner {
283+
pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Self {
284+
// FIXME: this should use `Trace` to avoid duplication in `source_map` below
285+
let raw_attrs = match def {
286+
AttrDefId::ModuleId(module) => {
287+
let def_map = module.def_map(db);
288+
let mod_data = &def_map[module.local_id];
289+
match mod_data.declaration_source(db) {
290+
Some(it) => {
291+
let raw_attrs = RawAttrs::from_attrs_owner(
292+
db,
293+
it.as_ref().map(|it| it as &dyn ast::AttrsOwner),
294+
);
295+
match mod_data.definition_source(db) {
296+
InFile { file_id, value: ModuleSource::SourceFile(file) } => raw_attrs
297+
.merge(RawAttrs::from_attrs_owner(db, InFile::new(file_id, &file))),
298+
_ => raw_attrs,
299+
}
300+
}
301+
None => RawAttrs::from_attrs_owner(
302+
db,
303+
mod_data.definition_source(db).as_ref().map(|src| match src {
304+
ModuleSource::SourceFile(file) => file as &dyn ast::AttrsOwner,
305+
ModuleSource::Module(module) => module as &dyn ast::AttrsOwner,
306+
ModuleSource::BlockExpr(block) => block as &dyn ast::AttrsOwner,
307+
}),
308+
),
309+
}
310+
}
311+
AttrDefId::FieldId(it) => {
312+
return Self { attrs: db.fields_attrs(it.parent)[it.local_id].clone(), owner: def };
313+
}
314+
AttrDefId::EnumVariantId(it) => {
315+
return Self {
316+
attrs: db.variants_attrs(it.parent)[it.local_id].clone(),
317+
owner: def,
318+
};
319+
}
320+
AttrDefId::AdtId(it) => match it {
321+
AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
322+
AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db),
323+
AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
324+
},
325+
AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
326+
AttrDefId::MacroDefId(it) => it
327+
.ast_id()
328+
.left()
329+
.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db)),
330+
AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
331+
AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
332+
AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
333+
AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
334+
AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
335+
AttrDefId::GenericParamId(it) => match it {
336+
GenericParamId::TypeParamId(it) => {
337+
let src = it.parent.child_source(db);
338+
RawAttrs::from_attrs_owner(
339+
db,
340+
src.with_value(
341+
src.value[it.local_id].as_ref().either(|it| it as _, |it| it as _),
342+
),
343+
)
344+
}
345+
GenericParamId::LifetimeParamId(it) => {
346+
let src = it.parent.child_source(db);
347+
RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
348+
}
349+
GenericParamId::ConstParamId(it) => {
350+
let src = it.parent.child_source(db);
351+
RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
352+
}
353+
},
354+
};
355+
356+
let attrs = raw_attrs.filter(db, def.krate(db));
357+
Self { attrs, owner: def }
358+
}
359+
360+
pub fn source_map(&self, db: &dyn DefDatabase) -> AttrSourceMap {
361+
let owner = match self.owner {
362+
AttrDefId::ModuleId(module) => {
363+
// Modules can have 2 attribute owners (the `mod x;` item, and the module file itself).
364+
365+
let def_map = module.def_map(db);
366+
let mod_data = &def_map[module.local_id];
367+
let attrs = match mod_data.declaration_source(db) {
368+
Some(it) => {
369+
let mut attrs: Vec<_> = collect_attrs(&it.value as &dyn ast::AttrsOwner)
370+
.map(|attr| InFile::new(it.file_id, attr))
371+
.collect();
372+
if let InFile { file_id, value: ModuleSource::SourceFile(file) } =
373+
mod_data.definition_source(db)
374+
{
375+
attrs.extend(
376+
collect_attrs(&file as &dyn ast::AttrsOwner)
377+
.map(|attr| InFile::new(file_id, attr)),
378+
)
379+
}
380+
attrs
381+
}
382+
None => {
383+
let InFile { file_id, value } = mod_data.definition_source(db);
384+
match &value {
385+
ModuleSource::SourceFile(file) => {
386+
collect_attrs(file as &dyn ast::AttrsOwner)
387+
}
388+
ModuleSource::Module(module) => {
389+
collect_attrs(module as &dyn ast::AttrsOwner)
390+
}
391+
ModuleSource::BlockExpr(block) => {
392+
collect_attrs(block as &dyn ast::AttrsOwner)
393+
}
394+
}
395+
.map(|attr| InFile::new(file_id, attr))
396+
.collect()
397+
}
398+
};
399+
return AttrSourceMap { attrs };
400+
}
401+
AttrDefId::FieldId(id) => {
402+
id.parent.child_source(db).map(|source| match &source[id.local_id] {
403+
Either::Left(field) => ast::AttrsOwnerNode::new(field.clone()),
404+
Either::Right(field) => ast::AttrsOwnerNode::new(field.clone()),
405+
})
406+
}
407+
AttrDefId::AdtId(adt) => match adt {
408+
AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
409+
AdtId::UnionId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
410+
AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
411+
},
412+
AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
413+
AttrDefId::EnumVariantId(id) => id
414+
.parent
415+
.child_source(db)
416+
.map(|source| ast::AttrsOwnerNode::new(source[id.local_id].clone())),
417+
AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
418+
AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
419+
AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
420+
AttrDefId::TypeAliasId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
421+
AttrDefId::MacroDefId(id) => match id.ast_id() {
422+
Either::Left(it) => {
423+
it.with_value(ast::AttrsOwnerNode::new(it.to_node(db.upcast())))
424+
}
425+
Either::Right(it) => {
426+
it.with_value(ast::AttrsOwnerNode::new(it.to_node(db.upcast())))
427+
}
428+
},
429+
AttrDefId::ImplId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
430+
AttrDefId::GenericParamId(id) => match id {
431+
GenericParamId::TypeParamId(id) => {
432+
id.parent.child_source(db).map(|source| match &source[id.local_id] {
433+
Either::Left(id) => ast::AttrsOwnerNode::new(id.clone()),
434+
Either::Right(id) => ast::AttrsOwnerNode::new(id.clone()),
435+
})
436+
}
437+
GenericParamId::LifetimeParamId(id) => id
438+
.parent
439+
.child_source(db)
440+
.map(|source| ast::AttrsOwnerNode::new(source[id.local_id].clone())),
441+
GenericParamId::ConstParamId(id) => id
442+
.parent
443+
.child_source(db)
444+
.map(|source| ast::AttrsOwnerNode::new(source[id.local_id].clone())),
445+
},
446+
};
447+
448+
AttrSourceMap {
449+
attrs: collect_attrs(&owner.value)
450+
.map(|attr| InFile::new(owner.file_id, attr))
451+
.collect(),
452+
}
453+
}
454+
}
455+
390456
fn inner_attributes(
391457
syntax: &SyntaxNode,
392458
) -> Option<(impl Iterator<Item = ast::Attr>, impl Iterator<Item = ast::Comment>)> {

0 commit comments

Comments
 (0)