aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2020-12-17 23:23:46 +0000
committerJonas Schievink <[email protected]>2020-12-18 01:24:14 +0000
commit4f07d8dd587c24bca8622ee8c39e5a1e156825b4 (patch)
treed60fc981c2dcc2fe5b78d73ac419c65a5574d027 /crates/hir_def
parenta4e17a5a96d3a8c15c91e90adce9d9b8cdc48a46 (diff)
Refactor attributes API to allow handling cfg_attr
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/adt.rs47
-rw-r--r--crates/hir_def/src/attr.rs146
-rw-r--r--crates/hir_def/src/body.rs17
-rw-r--r--crates/hir_def/src/body/lower.rs2
-rw-r--r--crates/hir_def/src/data.rs5
-rw-r--r--crates/hir_def/src/item_tree.rs19
-rw-r--r--crates/hir_def/src/item_tree/lower.rs17
-rw-r--r--crates/hir_def/src/nameres/collector.rs48
8 files changed, 187 insertions, 114 deletions
diff --git a/crates/hir_def/src/adt.rs b/crates/hir_def/src/adt.rs
index eafa3abb6..236d6f1b7 100644
--- a/crates/hir_def/src/adt.rs
+++ b/crates/hir_def/src/adt.rs
@@ -3,6 +3,7 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use arena::{map::ArenaMap, Arena}; 5use arena::{map::ArenaMap, Arena};
6use base_db::CrateId;
6use either::Either; 7use either::Either;
7use hir_expand::{ 8use hir_expand::{
8 name::{AsName, Name}, 9 name::{AsName, Name},
@@ -66,8 +67,13 @@ pub enum ReprKind {
66 Other, 67 Other,
67} 68}
68 69
69fn repr_from_value(item_tree: &ItemTree, of: AttrOwner) -> Option<ReprKind> { 70fn repr_from_value(
70 item_tree.attrs(of).by_key("repr").tt_values().find_map(parse_repr_tt) 71 db: &dyn DefDatabase,
72 krate: CrateId,
73 item_tree: &ItemTree,
74 of: AttrOwner,
75) -> Option<ReprKind> {
76 item_tree.attrs(db, krate, of).by_key("repr").tt_values().find_map(parse_repr_tt)
71} 77}
72 78
73fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> { 79fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> {
@@ -86,12 +92,13 @@ fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> {
86impl StructData { 92impl StructData {
87 pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> { 93 pub(crate) fn struct_data_query(db: &dyn DefDatabase, id: StructId) -> Arc<StructData> {
88 let loc = id.lookup(db); 94 let loc = id.lookup(db);
95 let krate = loc.container.module(db).krate;
89 let item_tree = db.item_tree(loc.id.file_id); 96 let item_tree = db.item_tree(loc.id.file_id);
90 let repr = repr_from_value(&item_tree, ModItem::from(loc.id.value).into()); 97 let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
91 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); 98 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
92 99
93 let strukt = &item_tree[loc.id.value]; 100 let strukt = &item_tree[loc.id.value];
94 let variant_data = lower_fields(&item_tree, &cfg_options, &strukt.fields, None); 101 let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &strukt.fields, None);
95 Arc::new(StructData { 102 Arc::new(StructData {
96 name: strukt.name.clone(), 103 name: strukt.name.clone(),
97 variant_data: Arc::new(variant_data), 104 variant_data: Arc::new(variant_data),
@@ -100,12 +107,13 @@ impl StructData {
100 } 107 }
101 pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> { 108 pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
102 let loc = id.lookup(db); 109 let loc = id.lookup(db);
110 let krate = loc.container.module(db).krate;
103 let item_tree = db.item_tree(loc.id.file_id); 111 let item_tree = db.item_tree(loc.id.file_id);
104 let repr = repr_from_value(&item_tree, ModItem::from(loc.id.value).into()); 112 let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
105 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); 113 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone();
106 114
107 let union = &item_tree[loc.id.value]; 115 let union = &item_tree[loc.id.value];
108 let variant_data = lower_fields(&item_tree, &cfg_options, &union.fields, None); 116 let variant_data = lower_fields(db, krate, &item_tree, &cfg_options, &union.fields, None);
109 117
110 Arc::new(StructData { 118 Arc::new(StructData {
111 name: union.name.clone(), 119 name: union.name.clone(),
@@ -118,16 +126,23 @@ impl StructData {
118impl EnumData { 126impl EnumData {
119 pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> { 127 pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
120 let loc = e.lookup(db); 128 let loc = e.lookup(db);
129 let krate = loc.container.module(db).krate;
121 let item_tree = db.item_tree(loc.id.file_id); 130 let item_tree = db.item_tree(loc.id.file_id);
122 let cfg_options = db.crate_graph()[loc.container.module(db).krate].cfg_options.clone(); 131 let cfg_options = db.crate_graph()[krate].cfg_options.clone();
123 132
124 let enum_ = &item_tree[loc.id.value]; 133 let enum_ = &item_tree[loc.id.value];
125 let mut variants = Arena::new(); 134 let mut variants = Arena::new();
126 for var_id in enum_.variants.clone() { 135 for var_id in enum_.variants.clone() {
127 if item_tree.attrs(var_id.into()).is_cfg_enabled(&cfg_options) { 136 if item_tree.attrs(db, krate, var_id.into()).is_cfg_enabled(&cfg_options) {
128 let var = &item_tree[var_id]; 137 let var = &item_tree[var_id];
129 let var_data = 138 let var_data = lower_fields(
130 lower_fields(&item_tree, &cfg_options, &var.fields, Some(enum_.visibility)); 139 db,
140 krate,
141 &item_tree,
142 &cfg_options,
143 &var.fields,
144 Some(enum_.visibility),
145 );
131 146
132 variants.alloc(EnumVariantData { 147 variants.alloc(EnumVariantData {
133 name: var.name.clone(), 148 name: var.name.clone(),
@@ -170,7 +185,7 @@ fn lower_enum(
170 .variant_list() 185 .variant_list()
171 .into_iter() 186 .into_iter()
172 .flat_map(|it| it.variants()) 187 .flat_map(|it| it.variants())
173 .filter(|var| expander.is_cfg_enabled(var)); 188 .filter(|var| expander.is_cfg_enabled(db, var));
174 for var in variants { 189 for var in variants {
175 trace.alloc( 190 trace.alloc(
176 || var.clone(), 191 || var.clone(),
@@ -262,7 +277,7 @@ fn lower_struct(
262 match &ast.value { 277 match &ast.value {
263 ast::StructKind::Tuple(fl) => { 278 ast::StructKind::Tuple(fl) => {
264 for (i, fd) in fl.fields().enumerate() { 279 for (i, fd) in fl.fields().enumerate() {
265 if !expander.is_cfg_enabled(&fd) { 280 if !expander.is_cfg_enabled(db, &fd) {
266 continue; 281 continue;
267 } 282 }
268 283
@@ -279,7 +294,7 @@ fn lower_struct(
279 } 294 }
280 ast::StructKind::Record(fl) => { 295 ast::StructKind::Record(fl) => {
281 for fd in fl.fields() { 296 for fd in fl.fields() {
282 if !expander.is_cfg_enabled(&fd) { 297 if !expander.is_cfg_enabled(db, &fd) {
283 continue; 298 continue;
284 } 299 }
285 300
@@ -299,6 +314,8 @@ fn lower_struct(
299} 314}
300 315
301fn lower_fields( 316fn lower_fields(
317 db: &dyn DefDatabase,
318 krate: CrateId,
302 item_tree: &ItemTree, 319 item_tree: &ItemTree,
303 cfg_options: &CfgOptions, 320 cfg_options: &CfgOptions,
304 fields: &Fields, 321 fields: &Fields,
@@ -308,7 +325,7 @@ fn lower_fields(
308 Fields::Record(flds) => { 325 Fields::Record(flds) => {
309 let mut arena = Arena::new(); 326 let mut arena = Arena::new();
310 for field_id in flds.clone() { 327 for field_id in flds.clone() {
311 if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) { 328 if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) {
312 arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility)); 329 arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
313 } 330 }
314 } 331 }
@@ -317,7 +334,7 @@ fn lower_fields(
317 Fields::Tuple(flds) => { 334 Fields::Tuple(flds) => {
318 let mut arena = Arena::new(); 335 let mut arena = Arena::new();
319 for field_id in flds.clone() { 336 for field_id in flds.clone() {
320 if item_tree.attrs(field_id.into()).is_cfg_enabled(cfg_options) { 337 if item_tree.attrs(db, krate, field_id.into()).is_cfg_enabled(cfg_options) {
321 arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility)); 338 arena.alloc(lower_field(item_tree, &item_tree[field_id], override_visibility));
322 } 339 }
323 } 340 }
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 45313f335..9cd0b72aa 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -2,6 +2,7 @@
2 2
3use std::{ops, sync::Arc}; 3use std::{ops, sync::Arc};
4 4
5use base_db::CrateId;
5use cfg::{CfgExpr, CfgOptions}; 6use cfg::{CfgExpr, CfgOptions};
6use either::Either; 7use either::Either;
7use hir_expand::{hygiene::Hygiene, AstId, InFile}; 8use hir_expand::{hygiene::Hygiene, AstId, InFile};
@@ -38,12 +39,16 @@ impl From<Documentation> for String {
38 } 39 }
39} 40}
40 41
42/// Syntactical attributes, without filtering of `cfg_attr`s.
41#[derive(Default, Debug, Clone, PartialEq, Eq)] 43#[derive(Default, Debug, Clone, PartialEq, Eq)]
42pub struct Attrs { 44pub struct RawAttrs {
43 entries: Option<Arc<[Attr]>>, 45 entries: Option<Arc<[Attr]>>,
44} 46}
45 47
46impl ops::Deref for Attrs { 48#[derive(Default, Debug, Clone, PartialEq, Eq)]
49pub struct Attrs(RawAttrs);
50
51impl ops::Deref for RawAttrs {
47 type Target = [Attr]; 52 type Target = [Attr];
48 53
49 fn deref(&self) -> &[Attr] { 54 fn deref(&self) -> &[Attr] {
@@ -54,19 +59,88 @@ impl ops::Deref for Attrs {
54 } 59 }
55} 60}
56 61
62impl ops::Deref for Attrs {
63 type Target = [Attr];
64
65 fn deref(&self) -> &[Attr] {
66 match &self.0.entries {
67 Some(it) => &*it,
68 None => &[],
69 }
70 }
71}
72
73impl RawAttrs {
74 pub const EMPTY: Self = Self { entries: None };
75
76 pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Self {
77 let (inner_attrs, inner_docs) = inner_attributes(owner.syntax())
78 .map_or((None, None), |(attrs, docs)| ((Some(attrs), Some(docs))));
79
80 let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none());
81 let attrs = outer_attrs
82 .chain(inner_attrs.into_iter().flatten())
83 .map(|attr| (attr.syntax().text_range().start(), Attr::from_src(attr, hygiene)));
84
85 let outer_docs =
86 ast::CommentIter::from_syntax_node(owner.syntax()).filter(ast::Comment::is_outer);
87 let docs = outer_docs.chain(inner_docs.into_iter().flatten()).map(|docs_text| {
88 (
89 docs_text.syntax().text_range().start(),
90 docs_text.doc_comment().map(|doc| Attr {
91 input: Some(AttrInput::Literal(SmolStr::new(doc))),
92 path: ModPath::from(hir_expand::name!(doc)),
93 }),
94 )
95 });
96 // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved
97 let attrs: Vec<_> = docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).collect();
98 let entries = if attrs.is_empty() {
99 // Avoid heap allocation
100 None
101 } else {
102 Some(attrs.into_iter().flat_map(|(_, attr)| attr).collect())
103 };
104 Self { entries }
105 }
106
107 fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Self {
108 let hygiene = Hygiene::new(db.upcast(), owner.file_id);
109 Self::new(owner.value, &hygiene)
110 }
111
112 pub(crate) fn merge(&self, other: Self) -> Self {
113 match (&self.entries, &other.entries) {
114 (None, None) => Self::EMPTY,
115 (Some(entries), None) | (None, Some(entries)) => {
116 Self { entries: Some(entries.clone()) }
117 }
118 (Some(a), Some(b)) => {
119 Self { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }
120 }
121 }
122 }
123
124 /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`.
125 pub(crate) fn filter(self, _db: &dyn DefDatabase, _krate: CrateId) -> Attrs {
126 // FIXME actually implement this
127 Attrs(self)
128 }
129}
130
57impl Attrs { 131impl Attrs {
58 pub const EMPTY: Attrs = Attrs { entries: None }; 132 pub const EMPTY: Self = Self(RawAttrs::EMPTY);
59 133
60 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { 134 pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
61 match def { 135 let raw_attrs = match def {
62 AttrDefId::ModuleId(module) => { 136 AttrDefId::ModuleId(module) => {
63 let def_map = db.crate_def_map(module.krate); 137 let def_map = db.crate_def_map(module.krate);
64 let mod_data = &def_map[module.local_id]; 138 let mod_data = &def_map[module.local_id];
65 match mod_data.declaration_source(db) { 139 match mod_data.declaration_source(db) {
66 Some(it) => { 140 Some(it) => {
67 Attrs::from_attrs_owner(db, it.as_ref().map(|it| it as &dyn AttrsOwner)) 141 RawAttrs::from_attrs_owner(db, it.as_ref().map(|it| it as &dyn AttrsOwner))
68 } 142 }
69 None => Attrs::from_attrs_owner( 143 None => RawAttrs::from_attrs_owner(
70 db, 144 db,
71 mod_data.definition_source(db).as_ref().map(|src| match src { 145 mod_data.definition_source(db).as_ref().map(|src| match src {
72 ModuleSource::SourceFile(file) => file as &dyn AttrsOwner, 146 ModuleSource::SourceFile(file) => file as &dyn AttrsOwner,
@@ -78,14 +152,14 @@ impl Attrs {
78 AttrDefId::FieldId(it) => { 152 AttrDefId::FieldId(it) => {
79 let src = it.parent.child_source(db); 153 let src = it.parent.child_source(db);
80 match &src.value[it.local_id] { 154 match &src.value[it.local_id] {
81 Either::Left(_tuple) => Attrs::default(), 155 Either::Left(_tuple) => RawAttrs::default(),
82 Either::Right(record) => Attrs::from_attrs_owner(db, src.with_value(record)), 156 Either::Right(record) => RawAttrs::from_attrs_owner(db, src.with_value(record)),
83 } 157 }
84 } 158 }
85 AttrDefId::EnumVariantId(var_id) => { 159 AttrDefId::EnumVariantId(var_id) => {
86 let src = var_id.parent.child_source(db); 160 let src = var_id.parent.child_source(db);
87 let src = src.as_ref().map(|it| &it[var_id.local_id]); 161 let src = src.as_ref().map(|it| &it[var_id.local_id]);
88 Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) 162 RawAttrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
89 } 163 }
90 AttrDefId::AdtId(it) => match it { 164 AttrDefId::AdtId(it) => match it {
91 AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db), 165 AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
@@ -101,53 +175,19 @@ impl Attrs {
101 AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), 175 AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
102 AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db), 176 AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
103 AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), 177 AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
104 }
105 }
106
107 fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs {
108 let hygiene = Hygiene::new(db.upcast(), owner.file_id);
109 Attrs::new(owner.value, &hygiene)
110 }
111
112 pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs {
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| {
124 (
125 docs_text.syntax().text_range().start(),
126 docs_text.doc_comment().map(|doc| Attr {
127 input: Some(AttrInput::Literal(SmolStr::new(doc))),
128 path: ModPath::from(hir_expand::name!(doc)),
129 }),
130 )
131 });
132 // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved
133 let attrs: Vec<_> = docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).collect();
134 let entries = if attrs.is_empty() {
135 // Avoid heap allocation
136 None
137 } else {
138 Some(attrs.into_iter().flat_map(|(_, attr)| attr).collect())
139 }; 178 };
140 Attrs { entries } 179
180 raw_attrs.filter(db, def.krate(db))
141 } 181 }
142 182
143 pub fn merge(&self, other: Attrs) -> Attrs { 183 pub fn merge(&self, other: Attrs) -> Attrs {
144 match (&self.entries, &other.entries) { 184 match (&self.0.entries, &other.0.entries) {
145 (None, None) => Attrs { entries: None }, 185 (None, None) => Attrs::EMPTY,
146 (Some(entries), None) | (None, Some(entries)) => { 186 (Some(entries), None) | (None, Some(entries)) => {
147 Attrs { entries: Some(entries.clone()) } 187 Attrs(RawAttrs { entries: Some(entries.clone()) })
148 } 188 }
149 (Some(a), Some(b)) => { 189 (Some(a), Some(b)) => {
150 Attrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) } 190 Attrs(RawAttrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) })
151 } 191 }
152 } 192 }
153 } 193 }
@@ -291,16 +331,16 @@ impl<'a> AttrQuery<'a> {
291 } 331 }
292} 332}
293 333
294fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> Attrs 334fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> RawAttrs
295where 335where
296 N: ast::AttrsOwner, 336 N: ast::AttrsOwner,
297{ 337{
298 let src = InFile::new(src.file_id, src.to_node(db.upcast())); 338 let src = InFile::new(src.file_id, src.to_node(db.upcast()));
299 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) 339 RawAttrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
300} 340}
301 341
302fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> Attrs { 342fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> RawAttrs {
303 let tree = db.item_tree(id.file_id); 343 let tree = db.item_tree(id.file_id);
304 let mod_item = N::id_to_mod_item(id.value); 344 let mod_item = N::id_to_mod_item(id.value);
305 tree.attrs(mod_item.into()).clone() 345 tree.raw_attrs(mod_item.into()).clone()
306} 346}
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index c5d6f5fb0..998b82601 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -24,7 +24,7 @@ use test_utils::mark;
24pub(crate) use lower::LowerCtx; 24pub(crate) use lower::LowerCtx;
25 25
26use crate::{ 26use crate::{
27 attr::Attrs, 27 attr::{Attrs, RawAttrs},
28 db::DefDatabase, 28 db::DefDatabase,
29 expr::{Expr, ExprId, Pat, PatId}, 29 expr::{Expr, ExprId, Pat, PatId},
30 item_scope::BuiltinShadowMode, 30 item_scope::BuiltinShadowMode,
@@ -40,6 +40,7 @@ use crate::{
40pub(crate) struct CfgExpander { 40pub(crate) struct CfgExpander {
41 cfg_options: CfgOptions, 41 cfg_options: CfgOptions,
42 hygiene: Hygiene, 42 hygiene: Hygiene,
43 krate: CrateId,
43} 44}
44 45
45pub(crate) struct Expander { 46pub(crate) struct Expander {
@@ -65,15 +66,15 @@ impl CfgExpander {
65 ) -> CfgExpander { 66 ) -> CfgExpander {
66 let hygiene = Hygiene::new(db.upcast(), current_file_id); 67 let hygiene = Hygiene::new(db.upcast(), current_file_id);
67 let cfg_options = db.crate_graph()[krate].cfg_options.clone(); 68 let cfg_options = db.crate_graph()[krate].cfg_options.clone();
68 CfgExpander { cfg_options, hygiene } 69 CfgExpander { cfg_options, hygiene, krate }
69 } 70 }
70 71
71 pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs { 72 pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> Attrs {
72 Attrs::new(owner, &self.hygiene) 73 RawAttrs::new(owner, &self.hygiene).filter(db, self.krate)
73 } 74 }
74 75
75 pub(crate) fn is_cfg_enabled(&self, owner: &dyn ast::AttrsOwner) -> bool { 76 pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> bool {
76 let attrs = self.parse_attrs(owner); 77 let attrs = self.parse_attrs(db, owner);
77 attrs.is_cfg_enabled(&self.cfg_options) 78 attrs.is_cfg_enabled(&self.cfg_options)
78 } 79 }
79} 80}
@@ -189,8 +190,8 @@ impl Expander {
189 InFile { file_id: self.current_file_id, value } 190 InFile { file_id: self.current_file_id, value }
190 } 191 }
191 192
192 pub(crate) fn parse_attrs(&self, owner: &dyn ast::AttrsOwner) -> Attrs { 193 pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> Attrs {
193 self.cfg_expander.parse_attrs(owner) 194 self.cfg_expander.parse_attrs(db, owner)
194 } 195 }
195 196
196 pub(crate) fn cfg_options(&self) -> &CfgOptions { 197 pub(crate) fn cfg_options(&self) -> &CfgOptions {
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 3b3d74987..0f404be1b 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -963,7 +963,7 @@ impl ExprCollector<'_> {
963 /// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when 963 /// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when
964 /// not. 964 /// not.
965 fn check_cfg(&mut self, owner: &dyn ast::AttrsOwner) -> Option<()> { 965 fn check_cfg(&mut self, owner: &dyn ast::AttrsOwner) -> Option<()> {
966 match self.expander.parse_attrs(owner).cfg() { 966 match self.expander.parse_attrs(self.db, owner).cfg() {
967 Some(cfg) => { 967 Some(cfg) => {
968 if self.expander.cfg_options().check(&cfg) != Some(false) { 968 if self.expander.cfg_options().check(&cfg) != Some(false) {
969 return Some(()); 969 return Some(());
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index dd3a906af..e7b7724f7 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -35,6 +35,7 @@ pub struct FunctionData {
35impl FunctionData { 35impl FunctionData {
36 pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> { 36 pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
37 let loc = func.lookup(db); 37 let loc = func.lookup(db);
38 let krate = loc.container.module(db).krate;
38 let item_tree = db.item_tree(loc.id.file_id); 39 let item_tree = db.item_tree(loc.id.file_id);
39 let func = &item_tree[loc.id.value]; 40 let func = &item_tree[loc.id.value];
40 41
@@ -42,7 +43,7 @@ impl FunctionData {
42 name: func.name.clone(), 43 name: func.name.clone(),
43 params: func.params.to_vec(), 44 params: func.params.to_vec(),
44 ret_type: func.ret_type.clone(), 45 ret_type: func.ret_type.clone(),
45 attrs: item_tree.attrs(ModItem::from(loc.id.value).into()).clone(), 46 attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()).clone(),
46 has_self_param: func.has_self_param, 47 has_self_param: func.has_self_param,
47 has_body: func.has_body, 48 has_body: func.has_body,
48 is_unsafe: func.is_unsafe, 49 is_unsafe: func.is_unsafe,
@@ -233,7 +234,7 @@ fn collect_items(
233 match item { 234 match item {
234 AssocItem::Function(id) => { 235 AssocItem::Function(id) => {
235 let item = &item_tree[id]; 236 let item = &item_tree[id];
236 let attrs = item_tree.attrs(ModItem::from(id).into()); 237 let attrs = item_tree.attrs(db, module.krate, ModItem::from(id).into());
237 if !attrs.is_cfg_enabled(&cfg_options) { 238 if !attrs.is_cfg_enabled(&cfg_options) {
238 continue; 239 continue;
239 } 240 }
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index b8e09e3af..5eb7cae7f 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -13,6 +13,7 @@ use std::{
13 13
14use arena::{Arena, Idx, RawId}; 14use arena::{Arena, Idx, RawId};
15use ast::{AstNode, AttrsOwner, NameOwner, StructKind}; 15use ast::{AstNode, AttrsOwner, NameOwner, StructKind};
16use base_db::CrateId;
16use either::Either; 17use either::Either;
17use hir_expand::{ 18use hir_expand::{
18 ast_id_map::FileAstId, 19 ast_id_map::FileAstId,
@@ -26,7 +27,7 @@ use syntax::{ast, match_ast};
26use test_utils::mark; 27use test_utils::mark;
27 28
28use crate::{ 29use crate::{
29 attr::Attrs, 30 attr::{Attrs, RawAttrs},
30 db::DefDatabase, 31 db::DefDatabase,
31 generics::GenericParams, 32 generics::GenericParams,
32 path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, 33 path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
@@ -67,7 +68,7 @@ impl GenericParamsId {
67#[derive(Debug, Eq, PartialEq)] 68#[derive(Debug, Eq, PartialEq)]
68pub struct ItemTree { 69pub struct ItemTree {
69 top_level: SmallVec<[ModItem; 1]>, 70 top_level: SmallVec<[ModItem; 1]>,
70 attrs: FxHashMap<AttrOwner, Attrs>, 71 attrs: FxHashMap<AttrOwner, RawAttrs>,
71 inner_items: FxHashMap<FileAstId<ast::Item>, SmallVec<[ModItem; 1]>>, 72 inner_items: FxHashMap<FileAstId<ast::Item>, SmallVec<[ModItem; 1]>>,
72 73
73 data: Option<Box<ItemTreeData>>, 74 data: Option<Box<ItemTreeData>>,
@@ -88,7 +89,7 @@ impl ItemTree {
88 let mut item_tree = match_ast! { 89 let mut item_tree = match_ast! {
89 match syntax { 90 match syntax {
90 ast::SourceFile(file) => { 91 ast::SourceFile(file) => {
91 top_attrs = Some(Attrs::new(&file, &hygiene)); 92 top_attrs = Some(RawAttrs::new(&file, &hygiene));
92 ctx.lower_module_items(&file) 93 ctx.lower_module_items(&file)
93 }, 94 },
94 ast::MacroItems(items) => { 95 ast::MacroItems(items) => {
@@ -180,12 +181,16 @@ impl ItemTree {
180 } 181 }
181 182
182 /// Returns the inner attributes of the source file. 183 /// Returns the inner attributes of the source file.
183 pub fn top_level_attrs(&self) -> &Attrs { 184 pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: CrateId) -> Attrs {
184 self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&Attrs::EMPTY) 185 self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&RawAttrs::EMPTY).clone().filter(db, krate)
185 } 186 }
186 187
187 pub fn attrs(&self, of: AttrOwner) -> &Attrs { 188 pub(crate) fn raw_attrs(&self, of: AttrOwner) -> &RawAttrs {
188 self.attrs.get(&of).unwrap_or(&Attrs::EMPTY) 189 self.attrs.get(&of).unwrap_or(&RawAttrs::EMPTY)
190 }
191
192 pub fn attrs(&self, db: &dyn DefDatabase, krate: CrateId, of: AttrOwner) -> Attrs {
193 self.raw_attrs(of).clone().filter(db, krate)
189 } 194 }
190 195
191 /// Returns the lowered inner items that `ast` corresponds to. 196 /// Returns the lowered inner items that `ast` corresponds to.
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 7de385ee8..c8f090c22 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -10,7 +10,6 @@ use syntax::{
10}; 10};
11 11
12use crate::{ 12use crate::{
13 attr::Attrs,
14 generics::{GenericParams, TypeParamData, TypeParamProvenance}, 13 generics::{GenericParams, TypeParamData, TypeParamProvenance},
15 type_ref::LifetimeRef, 14 type_ref::LifetimeRef,
16}; 15};
@@ -105,7 +104,7 @@ impl Ctx {
105 | ast::Item::MacroDef(_) => {} 104 | ast::Item::MacroDef(_) => {}
106 }; 105 };
107 106
108 let attrs = Attrs::new(item, &self.hygiene); 107 let attrs = RawAttrs::new(item, &self.hygiene);
109 let items = match item { 108 let items = match item {
110 ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into), 109 ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into),
111 ast::Item::Union(ast) => self.lower_union(ast).map(Into::into), 110 ast::Item::Union(ast) => self.lower_union(ast).map(Into::into),
@@ -138,7 +137,7 @@ impl Ctx {
138 items 137 items
139 } 138 }
140 139
141 fn add_attrs(&mut self, item: AttrOwner, attrs: Attrs) { 140 fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
142 match self.tree.attrs.entry(item) { 141 match self.tree.attrs.entry(item) {
143 Entry::Occupied(mut entry) => { 142 Entry::Occupied(mut entry) => {
144 *entry.get_mut() = entry.get().merge(attrs); 143 *entry.get_mut() = entry.get().merge(attrs);
@@ -205,7 +204,7 @@ impl Ctx {
205 for field in fields.fields() { 204 for field in fields.fields() {
206 if let Some(data) = self.lower_record_field(&field) { 205 if let Some(data) = self.lower_record_field(&field) {
207 let idx = self.data().fields.alloc(data); 206 let idx = self.data().fields.alloc(data);
208 self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene)); 207 self.add_attrs(idx.into(), RawAttrs::new(&field, &self.hygiene));
209 } 208 }
210 } 209 }
211 let end = self.next_field_idx(); 210 let end = self.next_field_idx();
@@ -225,7 +224,7 @@ impl Ctx {
225 for (i, field) in fields.fields().enumerate() { 224 for (i, field) in fields.fields().enumerate() {
226 let data = self.lower_tuple_field(i, &field); 225 let data = self.lower_tuple_field(i, &field);
227 let idx = self.data().fields.alloc(data); 226 let idx = self.data().fields.alloc(data);
228 self.add_attrs(idx.into(), Attrs::new(&field, &self.hygiene)); 227 self.add_attrs(idx.into(), RawAttrs::new(&field, &self.hygiene));
229 } 228 }
230 let end = self.next_field_idx(); 229 let end = self.next_field_idx();
231 IdRange::new(start..end) 230 IdRange::new(start..end)
@@ -270,7 +269,7 @@ impl Ctx {
270 for variant in variants.variants() { 269 for variant in variants.variants() {
271 if let Some(data) = self.lower_variant(&variant) { 270 if let Some(data) = self.lower_variant(&variant) {
272 let idx = self.data().variants.alloc(data); 271 let idx = self.data().variants.alloc(data);
273 self.add_attrs(idx.into(), Attrs::new(&variant, &self.hygiene)); 272 self.add_attrs(idx.into(), RawAttrs::new(&variant, &self.hygiene));
274 } 273 }
275 } 274 }
276 let end = self.next_variant_idx(); 275 let end = self.next_variant_idx();
@@ -438,7 +437,7 @@ impl Ctx {
438 self.with_inherited_visibility(visibility, |this| { 437 self.with_inherited_visibility(visibility, |this| {
439 list.assoc_items() 438 list.assoc_items()
440 .filter_map(|item| { 439 .filter_map(|item| {
441 let attrs = Attrs::new(&item, &this.hygiene); 440 let attrs = RawAttrs::new(&item, &this.hygiene);
442 this.collect_inner_items(item.syntax()); 441 this.collect_inner_items(item.syntax());
443 this.lower_assoc_item(&item).map(|item| { 442 this.lower_assoc_item(&item).map(|item| {
444 this.add_attrs(ModItem::from(item).into(), attrs); 443 this.add_attrs(ModItem::from(item).into(), attrs);
@@ -475,7 +474,7 @@ impl Ctx {
475 .filter_map(|item| { 474 .filter_map(|item| {
476 self.collect_inner_items(item.syntax()); 475 self.collect_inner_items(item.syntax());
477 let assoc = self.lower_assoc_item(&item)?; 476 let assoc = self.lower_assoc_item(&item)?;
478 let attrs = Attrs::new(&item, &self.hygiene); 477 let attrs = RawAttrs::new(&item, &self.hygiene);
479 self.add_attrs(ModItem::from(assoc).into(), attrs); 478 self.add_attrs(ModItem::from(assoc).into(), attrs);
480 Some(assoc) 479 Some(assoc)
481 }) 480 })
@@ -560,7 +559,7 @@ impl Ctx {
560 list.extern_items() 559 list.extern_items()
561 .filter_map(|item| { 560 .filter_map(|item| {
562 self.collect_inner_items(item.syntax()); 561 self.collect_inner_items(item.syntax());
563 let attrs = Attrs::new(&item, &self.hygiene); 562 let attrs = RawAttrs::new(&item, &self.hygiene);
564 let id: ModItem = match item { 563 let id: ModItem = match item {
565 ast::ExternItem::Fn(ast) => { 564 ast::ExternItem::Fn(ast) => {
566 let func_id = self.lower_function(&ast)?; 565 let func_id = self.lower_function(&ast)?;
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 1936348fb..b114a6fe4 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -221,17 +221,20 @@ impl DefCollector<'_> {
221 let item_tree = self.db.item_tree(file_id.into()); 221 let item_tree = self.db.item_tree(file_id.into());
222 let module_id = self.def_map.root; 222 let module_id = self.def_map.root;
223 self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; 223 self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id };
224 let mut root_collector = ModCollector { 224 if item_tree
225 def_collector: &mut *self, 225 .top_level_attrs(self.db, self.def_map.krate)
226 macro_depth: 0, 226 .cfg()
227 module_id, 227 .map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false))
228 file_id: file_id.into(),
229 item_tree: &item_tree,
230 mod_dir: ModDir::root(),
231 };
232 if item_tree.top_level_attrs().cfg().map_or(true, |cfg| root_collector.is_cfg_enabled(&cfg))
233 { 228 {
234 root_collector.collect(item_tree.top_level_items()); 229 ModCollector {
230 def_collector: &mut *self,
231 macro_depth: 0,
232 module_id,
233 file_id: file_id.into(),
234 item_tree: &item_tree,
235 mod_dir: ModDir::root(),
236 }
237 .collect(item_tree.top_level_items());
235 } 238 }
236 239
237 // main name resolution fixed-point loop. 240 // main name resolution fixed-point loop.
@@ -905,6 +908,8 @@ struct ModCollector<'a, 'b> {
905 908
906impl ModCollector<'_, '_> { 909impl ModCollector<'_, '_> {
907 fn collect(&mut self, items: &[ModItem]) { 910 fn collect(&mut self, items: &[ModItem]) {
911 let krate = self.def_collector.def_map.krate;
912
908 // Note: don't assert that inserted value is fresh: it's simply not true 913 // Note: don't assert that inserted value is fresh: it's simply not true
909 // for macros. 914 // for macros.
910 self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone()); 915 self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
@@ -921,7 +926,7 @@ impl ModCollector<'_, '_> {
921 // `#[macro_use] extern crate` is hoisted to imports macros before collecting 926 // `#[macro_use] extern crate` is hoisted to imports macros before collecting
922 // any other items. 927 // any other items.
923 for item in items { 928 for item in items {
924 let attrs = self.item_tree.attrs((*item).into()); 929 let attrs = self.item_tree.attrs(self.def_collector.db, krate, (*item).into());
925 if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) { 930 if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) {
926 if let ModItem::ExternCrate(id) = item { 931 if let ModItem::ExternCrate(id) = item {
927 let import = self.item_tree[*id].clone(); 932 let import = self.item_tree[*id].clone();
@@ -933,7 +938,7 @@ impl ModCollector<'_, '_> {
933 } 938 }
934 939
935 for &item in items { 940 for &item in items {
936 let attrs = self.item_tree.attrs(item.into()); 941 let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
937 if let Some(cfg) = attrs.cfg() { 942 if let Some(cfg) = attrs.cfg() {
938 if !self.is_cfg_enabled(&cfg) { 943 if !self.is_cfg_enabled(&cfg) {
939 self.emit_unconfigured_diagnostic(item, &cfg); 944 self.emit_unconfigured_diagnostic(item, &cfg);
@@ -946,7 +951,7 @@ impl ModCollector<'_, '_> {
946 951
947 let mut def = None; 952 let mut def = None;
948 match item { 953 match item {
949 ModItem::Mod(m) => self.collect_module(&self.item_tree[m], attrs), 954 ModItem::Mod(m) => self.collect_module(&self.item_tree[m], &attrs),
950 ModItem::Import(import_id) => { 955 ModItem::Import(import_id) => {
951 self.def_collector.unresolved_imports.push(ImportDirective { 956 self.def_collector.unresolved_imports.push(ImportDirective {
952 module_id: self.module_id, 957 module_id: self.module_id,
@@ -975,7 +980,11 @@ impl ModCollector<'_, '_> {
975 980
976 // "Macro 2.0" is not currently supported by rust-analyzer, but libcore uses it 981 // "Macro 2.0" is not currently supported by rust-analyzer, but libcore uses it
977 // to define builtin macros, so we support at least that part. 982 // to define builtin macros, so we support at least that part.
978 let attrs = self.item_tree.attrs(ModItem::from(id).into()); 983 let attrs = self.item_tree.attrs(
984 self.def_collector.db,
985 krate,
986 ModItem::from(id).into(),
987 );
979 if attrs.by_key("rustc_builtin_macro").exists() { 988 if attrs.by_key("rustc_builtin_macro").exists() {
980 let krate = self.def_collector.def_map.krate; 989 let krate = self.def_collector.def_map.krate;
981 let macro_id = find_builtin_macro(&mac.name, krate, ast_id) 990 let macro_id = find_builtin_macro(&mac.name, krate, ast_id)
@@ -1012,7 +1021,7 @@ impl ModCollector<'_, '_> {
1012 ModItem::Function(id) => { 1021 ModItem::Function(id) => {
1013 let func = &self.item_tree[id]; 1022 let func = &self.item_tree[id];
1014 1023
1015 self.collect_proc_macro_def(&func.name, attrs); 1024 self.collect_proc_macro_def(&func.name, &attrs);
1016 1025
1017 def = Some(DefData { 1026 def = Some(DefData {
1018 id: FunctionLoc { 1027 id: FunctionLoc {
@@ -1032,7 +1041,7 @@ impl ModCollector<'_, '_> {
1032 // FIXME: check attrs to see if this is an attribute macro invocation; 1041 // FIXME: check attrs to see if this is an attribute macro invocation;
1033 // in which case we don't add the invocation, just a single attribute 1042 // in which case we don't add the invocation, just a single attribute
1034 // macro invocation 1043 // macro invocation
1035 self.collect_derives(attrs, it.ast_id.upcast()); 1044 self.collect_derives(&attrs, it.ast_id.upcast());
1036 1045
1037 def = Some(DefData { 1046 def = Some(DefData {
1038 id: StructLoc { container, id: ItemTreeId::new(self.file_id, id) } 1047 id: StructLoc { container, id: ItemTreeId::new(self.file_id, id) }
@@ -1049,7 +1058,7 @@ impl ModCollector<'_, '_> {
1049 // FIXME: check attrs to see if this is an attribute macro invocation; 1058 // FIXME: check attrs to see if this is an attribute macro invocation;
1050 // in which case we don't add the invocation, just a single attribute 1059 // in which case we don't add the invocation, just a single attribute
1051 // macro invocation 1060 // macro invocation
1052 self.collect_derives(attrs, it.ast_id.upcast()); 1061 self.collect_derives(&attrs, it.ast_id.upcast());
1053 1062
1054 def = Some(DefData { 1063 def = Some(DefData {
1055 id: UnionLoc { container, id: ItemTreeId::new(self.file_id, id) } 1064 id: UnionLoc { container, id: ItemTreeId::new(self.file_id, id) }
@@ -1066,7 +1075,7 @@ impl ModCollector<'_, '_> {
1066 // FIXME: check attrs to see if this is an attribute macro invocation; 1075 // FIXME: check attrs to see if this is an attribute macro invocation;
1067 // in which case we don't add the invocation, just a single attribute 1076 // in which case we don't add the invocation, just a single attribute
1068 // macro invocation 1077 // macro invocation
1069 self.collect_derives(attrs, it.ast_id.upcast()); 1078 self.collect_derives(&attrs, it.ast_id.upcast());
1070 1079
1071 def = Some(DefData { 1080 def = Some(DefData {
1072 id: EnumLoc { container, id: ItemTreeId::new(self.file_id, id) } 1081 id: EnumLoc { container, id: ItemTreeId::new(self.file_id, id) }
@@ -1303,8 +1312,9 @@ impl ModCollector<'_, '_> {
1303 } 1312 }
1304 1313
1305 fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) { 1314 fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) {
1315 let krate = self.def_collector.def_map.krate;
1306 let mac = &self.item_tree[id]; 1316 let mac = &self.item_tree[id];
1307 let attrs = self.item_tree.attrs(ModItem::from(id).into()); 1317 let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
1308 let ast_id = InFile::new(self.file_id, mac.ast_id.upcast()); 1318 let ast_id = InFile::new(self.file_id, mac.ast_id.upcast());
1309 1319
1310 let export_attr = attrs.by_key("macro_export"); 1320 let export_attr = attrs.by_key("macro_export");