diff options
Diffstat (limited to 'crates/hir_def')
-rw-r--r-- | crates/hir_def/src/adt.rs | 47 | ||||
-rw-r--r-- | crates/hir_def/src/attr.rs | 290 | ||||
-rw-r--r-- | crates/hir_def/src/body.rs | 17 | ||||
-rw-r--r-- | crates/hir_def/src/body/lower.rs | 2 | ||||
-rw-r--r-- | crates/hir_def/src/data.rs | 5 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree.rs | 24 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree/lower.rs | 24 | ||||
-rw-r--r-- | crates/hir_def/src/lib.rs | 30 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 107 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests.rs | 4 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/diagnostics.rs | 18 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/macros.rs | 8 | ||||
-rw-r--r-- | crates/hir_def/src/path.rs | 12 |
13 files changed, 417 insertions, 171 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 @@ | |||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use arena::{map::ArenaMap, Arena}; | 5 | use arena::{map::ArenaMap, Arena}; |
6 | use base_db::CrateId; | ||
6 | use either::Either; | 7 | use either::Either; |
7 | use hir_expand::{ | 8 | use 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 | ||
69 | fn repr_from_value(item_tree: &ItemTree, of: AttrOwner) -> Option<ReprKind> { | 70 | fn 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 | ||
73 | fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> { | 79 | fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> { |
@@ -86,12 +92,13 @@ fn parse_repr_tt(tt: &Subtree) -> Option<ReprKind> { | |||
86 | impl StructData { | 92 | impl 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 { | |||
118 | impl EnumData { | 126 | impl 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 | ||
301 | fn lower_fields( | 316 | fn 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 c64b78445..042e119b1 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -2,22 +2,24 @@ | |||
2 | 2 | ||
3 | use std::{ops, sync::Arc}; | 3 | use std::{ops, sync::Arc}; |
4 | 4 | ||
5 | use base_db::CrateId; | ||
5 | use cfg::{CfgExpr, CfgOptions}; | 6 | use cfg::{CfgExpr, CfgOptions}; |
6 | use either::Either; | 7 | use either::Either; |
7 | use hir_expand::{hygiene::Hygiene, AstId, InFile}; | 8 | use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile}; |
8 | use itertools::Itertools; | 9 | use itertools::Itertools; |
9 | use mbe::ast_to_token_tree; | 10 | use mbe::ast_to_token_tree; |
10 | use syntax::{ | 11 | use syntax::{ |
11 | ast::{self, AstNode, AttrsOwner}, | 12 | ast::{self, AstNode, AttrsOwner}, |
12 | match_ast, AstToken, SmolStr, SyntaxNode, | 13 | match_ast, AstToken, SmolStr, SyntaxNode, |
13 | }; | 14 | }; |
15 | use test_utils::mark; | ||
14 | use tt::Subtree; | 16 | use tt::Subtree; |
15 | 17 | ||
16 | use crate::{ | 18 | use crate::{ |
17 | db::DefDatabase, | 19 | db::DefDatabase, |
18 | item_tree::{ItemTreeId, ItemTreeNode}, | 20 | item_tree::{ItemTreeId, ItemTreeNode}, |
19 | nameres::ModuleSource, | 21 | nameres::ModuleSource, |
20 | path::ModPath, | 22 | path::{ModPath, PathKind}, |
21 | src::HasChildSource, | 23 | src::HasChildSource, |
22 | AdtId, AttrDefId, Lookup, | 24 | AdtId, AttrDefId, Lookup, |
23 | }; | 25 | }; |
@@ -38,12 +40,16 @@ impl From<Documentation> for String { | |||
38 | } | 40 | } |
39 | } | 41 | } |
40 | 42 | ||
43 | /// Syntactical attributes, without filtering of `cfg_attr`s. | ||
41 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | 44 | #[derive(Default, Debug, Clone, PartialEq, Eq)] |
42 | pub struct Attrs { | 45 | pub(crate) struct RawAttrs { |
43 | entries: Option<Arc<[Attr]>>, | 46 | entries: Option<Arc<[Attr]>>, |
44 | } | 47 | } |
45 | 48 | ||
46 | impl ops::Deref for Attrs { | 49 | #[derive(Default, Debug, Clone, PartialEq, Eq)] |
50 | pub struct Attrs(RawAttrs); | ||
51 | |||
52 | impl ops::Deref for RawAttrs { | ||
47 | type Target = [Attr]; | 53 | type Target = [Attr]; |
48 | 54 | ||
49 | fn deref(&self) -> &[Attr] { | 55 | fn deref(&self) -> &[Attr] { |
@@ -54,19 +60,147 @@ impl ops::Deref for Attrs { | |||
54 | } | 60 | } |
55 | } | 61 | } |
56 | 62 | ||
63 | impl ops::Deref for Attrs { | ||
64 | type Target = [Attr]; | ||
65 | |||
66 | fn deref(&self) -> &[Attr] { | ||
67 | match &self.0.entries { | ||
68 | Some(it) => &*it, | ||
69 | None => &[], | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
74 | impl RawAttrs { | ||
75 | pub(crate) const EMPTY: Self = Self { entries: None }; | ||
76 | |||
77 | pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Self { | ||
78 | let attrs: Vec<_> = collect_attrs(owner).collect(); | ||
79 | let entries = if attrs.is_empty() { | ||
80 | // Avoid heap allocation | ||
81 | None | ||
82 | } else { | ||
83 | Some( | ||
84 | attrs | ||
85 | .into_iter() | ||
86 | .enumerate() | ||
87 | .flat_map(|(i, attr)| match attr { | ||
88 | Either::Left(attr) => Attr::from_src(attr, hygiene).map(|attr| (i, attr)), | ||
89 | Either::Right(comment) => comment.doc_comment().map(|doc| { | ||
90 | ( | ||
91 | i, | ||
92 | Attr { | ||
93 | index: 0, | ||
94 | input: Some(AttrInput::Literal(SmolStr::new(doc))), | ||
95 | path: ModPath::from(hir_expand::name!(doc)), | ||
96 | }, | ||
97 | ) | ||
98 | }), | ||
99 | }) | ||
100 | .map(|(i, attr)| Attr { index: i as u32, ..attr }) | ||
101 | .collect(), | ||
102 | ) | ||
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 | let has_cfg_attrs = self.iter().any(|attr| { | ||
127 | attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr]) | ||
128 | }); | ||
129 | if !has_cfg_attrs { | ||
130 | return Attrs(self); | ||
131 | } | ||
132 | |||
133 | let crate_graph = db.crate_graph(); | ||
134 | let new_attrs = self | ||
135 | .iter() | ||
136 | .filter_map(|attr| { | ||
137 | let attr = attr.clone(); | ||
138 | let is_cfg_attr = | ||
139 | attr.path.as_ident().map_or(false, |name| *name == hir_expand::name![cfg_attr]); | ||
140 | if !is_cfg_attr { | ||
141 | return Some(attr); | ||
142 | } | ||
143 | |||
144 | let subtree = match &attr.input { | ||
145 | Some(AttrInput::TokenTree(it)) => it, | ||
146 | _ => return Some(attr), | ||
147 | }; | ||
148 | |||
149 | // Input subtree is: `(cfg, attr)` | ||
150 | // Split it up into a `cfg` and an `attr` subtree. | ||
151 | // FIXME: There should be a common API for this. | ||
152 | let mut saw_comma = false; | ||
153 | let (mut cfg, attr): (Vec<_>, Vec<_>) = | ||
154 | subtree.clone().token_trees.into_iter().partition(|tree| { | ||
155 | if saw_comma { | ||
156 | return false; | ||
157 | } | ||
158 | |||
159 | match tree { | ||
160 | tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => { | ||
161 | saw_comma = true; | ||
162 | } | ||
163 | _ => {} | ||
164 | } | ||
165 | |||
166 | true | ||
167 | }); | ||
168 | cfg.pop(); // `,` ends up in here | ||
169 | |||
170 | let attr = Subtree { delimiter: None, token_trees: attr }; | ||
171 | let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg }; | ||
172 | let cfg = CfgExpr::parse(&cfg); | ||
173 | |||
174 | let cfg_options = &crate_graph[krate].cfg_options; | ||
175 | if cfg_options.check(&cfg) == Some(false) { | ||
176 | None | ||
177 | } else { | ||
178 | mark::hit!(cfg_attr_active); | ||
179 | |||
180 | let attr = ast::Attr::parse(&format!("#[{}]", attr)).ok()?; | ||
181 | let hygiene = Hygiene::new_unhygienic(); // FIXME | ||
182 | Attr::from_src(attr, &hygiene) | ||
183 | } | ||
184 | }) | ||
185 | .collect(); | ||
186 | |||
187 | Attrs(RawAttrs { entries: Some(new_attrs) }) | ||
188 | } | ||
189 | } | ||
190 | |||
57 | impl Attrs { | 191 | impl Attrs { |
58 | pub const EMPTY: Attrs = Attrs { entries: None }; | 192 | pub const EMPTY: Self = Self(RawAttrs::EMPTY); |
59 | 193 | ||
60 | pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { | 194 | pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { |
61 | match def { | 195 | let raw_attrs = match def { |
62 | AttrDefId::ModuleId(module) => { | 196 | AttrDefId::ModuleId(module) => { |
63 | let def_map = db.crate_def_map(module.krate); | 197 | let def_map = db.crate_def_map(module.krate); |
64 | let mod_data = &def_map[module.local_id]; | 198 | let mod_data = &def_map[module.local_id]; |
65 | match mod_data.declaration_source(db) { | 199 | match mod_data.declaration_source(db) { |
66 | Some(it) => { | 200 | Some(it) => { |
67 | Attrs::from_attrs_owner(db, it.as_ref().map(|it| it as &dyn AttrsOwner)) | 201 | RawAttrs::from_attrs_owner(db, it.as_ref().map(|it| it as &dyn AttrsOwner)) |
68 | } | 202 | } |
69 | None => Attrs::from_attrs_owner( | 203 | None => RawAttrs::from_attrs_owner( |
70 | db, | 204 | db, |
71 | mod_data.definition_source(db).as_ref().map(|src| match src { | 205 | mod_data.definition_source(db).as_ref().map(|src| match src { |
72 | ModuleSource::SourceFile(file) => file as &dyn AttrsOwner, | 206 | ModuleSource::SourceFile(file) => file as &dyn AttrsOwner, |
@@ -78,14 +212,14 @@ impl Attrs { | |||
78 | AttrDefId::FieldId(it) => { | 212 | AttrDefId::FieldId(it) => { |
79 | let src = it.parent.child_source(db); | 213 | let src = it.parent.child_source(db); |
80 | match &src.value[it.local_id] { | 214 | match &src.value[it.local_id] { |
81 | Either::Left(_tuple) => Attrs::default(), | 215 | Either::Left(_tuple) => RawAttrs::default(), |
82 | Either::Right(record) => Attrs::from_attrs_owner(db, src.with_value(record)), | 216 | Either::Right(record) => RawAttrs::from_attrs_owner(db, src.with_value(record)), |
83 | } | 217 | } |
84 | } | 218 | } |
85 | AttrDefId::EnumVariantId(var_id) => { | 219 | AttrDefId::EnumVariantId(var_id) => { |
86 | let src = var_id.parent.child_source(db); | 220 | let src = var_id.parent.child_source(db); |
87 | let src = src.as_ref().map(|it| &it[var_id.local_id]); | 221 | 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)) | 222 | RawAttrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) |
89 | } | 223 | } |
90 | AttrDefId::AdtId(it) => match it { | 224 | AttrDefId::AdtId(it) => match it { |
91 | AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 225 | AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
@@ -101,55 +235,9 @@ impl Attrs { | |||
101 | AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 235 | 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), | 236 | 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), | 237 | AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
104 | } | ||
105 | } | ||
106 | |||
107 | pub 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 | }; | 238 | }; |
140 | Attrs { entries } | ||
141 | } | ||
142 | 239 | ||
143 | pub fn merge(&self, other: Attrs) -> Attrs { | 240 | raw_attrs.filter(db, def.krate(db)) |
144 | match (&self.entries, &other.entries) { | ||
145 | (None, None) => Attrs { entries: None }, | ||
146 | (Some(entries), None) | (None, Some(entries)) => { | ||
147 | Attrs { entries: Some(entries.clone()) } | ||
148 | } | ||
149 | (Some(a), Some(b)) => { | ||
150 | Attrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) } | ||
151 | } | ||
152 | } | ||
153 | } | 241 | } |
154 | 242 | ||
155 | pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { | 243 | pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { |
@@ -157,7 +245,6 @@ impl Attrs { | |||
157 | } | 245 | } |
158 | 246 | ||
159 | pub fn cfg(&self) -> Option<CfgExpr> { | 247 | pub fn cfg(&self) -> Option<CfgExpr> { |
160 | // FIXME: handle cfg_attr :-) | ||
161 | let mut cfgs = self.by_key("cfg").tt_values().map(CfgExpr::parse).collect::<Vec<_>>(); | 248 | let mut cfgs = self.by_key("cfg").tt_values().map(CfgExpr::parse).collect::<Vec<_>>(); |
162 | match cfgs.len() { | 249 | match cfgs.len() { |
163 | 0 => None, | 250 | 0 => None, |
@@ -228,6 +315,7 @@ fn inner_attributes( | |||
228 | 315 | ||
229 | #[derive(Debug, Clone, PartialEq, Eq)] | 316 | #[derive(Debug, Clone, PartialEq, Eq)] |
230 | pub struct Attr { | 317 | pub struct Attr { |
318 | index: u32, | ||
231 | pub(crate) path: ModPath, | 319 | pub(crate) path: ModPath, |
232 | pub(crate) input: Option<AttrInput>, | 320 | pub(crate) input: Option<AttrInput>, |
233 | } | 321 | } |
@@ -254,7 +342,59 @@ impl Attr { | |||
254 | } else { | 342 | } else { |
255 | None | 343 | None |
256 | }; | 344 | }; |
257 | Some(Attr { path, input }) | 345 | Some(Attr { index: 0, path, input }) |
346 | } | ||
347 | |||
348 | /// Maps this lowered `Attr` back to its original syntax node. | ||
349 | /// | ||
350 | /// `owner` must be the original owner of the attribute. | ||
351 | /// | ||
352 | /// Note that the returned syntax node might be a `#[cfg_attr]`, or a doc comment, instead of | ||
353 | /// the attribute represented by `Attr`. | ||
354 | pub fn to_src(&self, owner: &dyn AttrsOwner) -> Either<ast::Attr, ast::Comment> { | ||
355 | collect_attrs(owner).nth(self.index as usize).unwrap_or_else(|| { | ||
356 | panic!("cannot find `Attr` at index {} in {}", self.index, owner.syntax()) | ||
357 | }) | ||
358 | } | ||
359 | |||
360 | /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths | ||
361 | /// to derive macros. | ||
362 | /// | ||
363 | /// Returns `None` when the attribute is not a well-formed `#[derive]` attribute. | ||
364 | pub(crate) fn parse_derive(&self) -> Option<impl Iterator<Item = ModPath>> { | ||
365 | if self.path.as_ident() != Some(&hir_expand::name![derive]) { | ||
366 | return None; | ||
367 | } | ||
368 | |||
369 | match &self.input { | ||
370 | Some(AttrInput::TokenTree(args)) => { | ||
371 | let mut counter = 0; | ||
372 | let paths = args | ||
373 | .token_trees | ||
374 | .iter() | ||
375 | .group_by(move |tt| { | ||
376 | match tt { | ||
377 | tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => { | ||
378 | counter += 1; | ||
379 | } | ||
380 | _ => {} | ||
381 | } | ||
382 | counter | ||
383 | }) | ||
384 | .into_iter() | ||
385 | .map(|(_, tts)| { | ||
386 | let segments = tts.filter_map(|tt| match tt { | ||
387 | tt::TokenTree::Leaf(tt::Leaf::Ident(id)) => Some(id.as_name()), | ||
388 | _ => None, | ||
389 | }); | ||
390 | ModPath::from_segments(PathKind::Plain, segments) | ||
391 | }) | ||
392 | .collect::<Vec<_>>(); | ||
393 | |||
394 | Some(paths.into_iter()) | ||
395 | } | ||
396 | _ => None, | ||
397 | } | ||
258 | } | 398 | } |
259 | } | 399 | } |
260 | 400 | ||
@@ -283,7 +423,7 @@ impl<'a> AttrQuery<'a> { | |||
283 | self.attrs().next().is_some() | 423 | self.attrs().next().is_some() |
284 | } | 424 | } |
285 | 425 | ||
286 | fn attrs(self) -> impl Iterator<Item = &'a Attr> { | 426 | pub(crate) fn attrs(self) -> impl Iterator<Item = &'a Attr> { |
287 | let key = self.key; | 427 | let key = self.key; |
288 | self.attrs | 428 | self.attrs |
289 | .iter() | 429 | .iter() |
@@ -291,16 +431,36 @@ impl<'a> AttrQuery<'a> { | |||
291 | } | 431 | } |
292 | } | 432 | } |
293 | 433 | ||
294 | fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> Attrs | 434 | fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> RawAttrs |
295 | where | 435 | where |
296 | N: ast::AttrsOwner, | 436 | N: ast::AttrsOwner, |
297 | { | 437 | { |
298 | let src = InFile::new(src.file_id, src.to_node(db.upcast())); | 438 | 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)) | 439 | RawAttrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) |
300 | } | 440 | } |
301 | 441 | ||
302 | fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> Attrs { | 442 | fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> RawAttrs { |
303 | let tree = db.item_tree(id.file_id); | 443 | let tree = db.item_tree(id.file_id); |
304 | let mod_item = N::id_to_mod_item(id.value); | 444 | let mod_item = N::id_to_mod_item(id.value); |
305 | tree.attrs(mod_item.into()).clone() | 445 | tree.raw_attrs(mod_item.into()).clone() |
446 | } | ||
447 | |||
448 | fn collect_attrs(owner: &dyn AttrsOwner) -> impl Iterator<Item = Either<ast::Attr, ast::Comment>> { | ||
449 | let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) | ||
450 | .map_or((None, None), |(attrs, docs)| ((Some(attrs), Some(docs)))); | ||
451 | |||
452 | let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none()); | ||
453 | let attrs = outer_attrs | ||
454 | .chain(inner_attrs.into_iter().flatten()) | ||
455 | .map(|attr| (attr.syntax().text_range().start(), Either::Left(attr))); | ||
456 | |||
457 | let outer_docs = | ||
458 | ast::CommentIter::from_syntax_node(owner.syntax()).filter(ast::Comment::is_outer); | ||
459 | let docs = outer_docs | ||
460 | .chain(inner_docs.into_iter().flatten()) | ||
461 | .map(|docs_text| (docs_text.syntax().text_range().start(), Either::Right(docs_text))); | ||
462 | // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved | ||
463 | let attrs: Vec<_> = docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).collect(); | ||
464 | |||
465 | attrs.into_iter().map(|(_, attr)| attr) | ||
306 | } | 466 | } |
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; | |||
24 | pub(crate) use lower::LowerCtx; | 24 | pub(crate) use lower::LowerCtx; |
25 | 25 | ||
26 | use crate::{ | 26 | use 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::{ | |||
40 | pub(crate) struct CfgExpander { | 40 | pub(crate) struct CfgExpander { |
41 | cfg_options: CfgOptions, | 41 | cfg_options: CfgOptions, |
42 | hygiene: Hygiene, | 42 | hygiene: Hygiene, |
43 | krate: CrateId, | ||
43 | } | 44 | } |
44 | 45 | ||
45 | pub(crate) struct Expander { | 46 | pub(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 { | |||
35 | impl FunctionData { | 35 | impl 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..100dbf5d6 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -12,7 +12,8 @@ use std::{ | |||
12 | }; | 12 | }; |
13 | 13 | ||
14 | use arena::{Arena, Idx, RawId}; | 14 | use arena::{Arena, Idx, RawId}; |
15 | use ast::{AstNode, AttrsOwner, NameOwner, StructKind}; | 15 | use ast::{AstNode, NameOwner, StructKind}; |
16 | use base_db::CrateId; | ||
16 | use either::Either; | 17 | use either::Either; |
17 | use hir_expand::{ | 18 | use hir_expand::{ |
18 | ast_id_map::FileAstId, | 19 | ast_id_map::FileAstId, |
@@ -26,7 +27,7 @@ use syntax::{ast, match_ast}; | |||
26 | use test_utils::mark; | 27 | use test_utils::mark; |
27 | 28 | ||
28 | use crate::{ | 29 | use 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)] |
68 | pub struct ItemTree { | 69 | pub 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. |
@@ -490,7 +495,6 @@ pub struct Import { | |||
490 | pub alias: Option<ImportAlias>, | 495 | pub alias: Option<ImportAlias>, |
491 | pub visibility: RawVisibilityId, | 496 | pub visibility: RawVisibilityId, |
492 | pub is_glob: bool, | 497 | pub is_glob: bool, |
493 | pub is_prelude: bool, | ||
494 | /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many | 498 | /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many |
495 | /// `Import`s can map to the same `use` item. | 499 | /// `Import`s can map to the same `use` item. |
496 | pub ast_id: FileAstId<ast::Use>, | 500 | pub ast_id: FileAstId<ast::Use>, |
@@ -506,8 +510,6 @@ pub struct ExternCrate { | |||
506 | pub name: Name, | 510 | pub name: Name, |
507 | pub alias: Option<ImportAlias>, | 511 | pub alias: Option<ImportAlias>, |
508 | pub visibility: RawVisibilityId, | 512 | pub visibility: RawVisibilityId, |
509 | /// Whether this is a `#[macro_use] extern crate ...`. | ||
510 | pub is_macro_use: bool, | ||
511 | pub ast_id: FileAstId<ast::ExternCrate>, | 513 | pub ast_id: FileAstId<ast::ExternCrate>, |
512 | } | 514 | } |
513 | 515 | ||
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 7de385ee8..3b206ef85 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 | ||
12 | use crate::{ | 12 | use 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 | }) |
@@ -486,8 +485,6 @@ impl Ctx { | |||
486 | } | 485 | } |
487 | 486 | ||
488 | fn lower_use(&mut self, use_item: &ast::Use) -> Vec<FileItemTreeId<Import>> { | 487 | fn lower_use(&mut self, use_item: &ast::Use) -> Vec<FileItemTreeId<Import>> { |
489 | // FIXME: cfg_attr | ||
490 | let is_prelude = use_item.has_atom_attr("prelude_import"); | ||
491 | let visibility = self.lower_visibility(use_item); | 488 | let visibility = self.lower_visibility(use_item); |
492 | let ast_id = self.source_ast_id_map.ast_id(use_item); | 489 | let ast_id = self.source_ast_id_map.ast_id(use_item); |
493 | 490 | ||
@@ -503,7 +500,6 @@ impl Ctx { | |||
503 | alias, | 500 | alias, |
504 | visibility, | 501 | visibility, |
505 | is_glob, | 502 | is_glob, |
506 | is_prelude, | ||
507 | ast_id, | 503 | ast_id, |
508 | index: imports.len(), | 504 | index: imports.len(), |
509 | }))); | 505 | }))); |
@@ -523,10 +519,8 @@ impl Ctx { | |||
523 | }); | 519 | }); |
524 | let visibility = self.lower_visibility(extern_crate); | 520 | let visibility = self.lower_visibility(extern_crate); |
525 | let ast_id = self.source_ast_id_map.ast_id(extern_crate); | 521 | let ast_id = self.source_ast_id_map.ast_id(extern_crate); |
526 | // FIXME: cfg_attr | ||
527 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); | ||
528 | 522 | ||
529 | let res = ExternCrate { name, alias, visibility, is_macro_use, ast_id }; | 523 | let res = ExternCrate { name, alias, visibility, ast_id }; |
530 | Some(id(self.data().extern_crates.alloc(res))) | 524 | Some(id(self.data().extern_crates.alloc(res))) |
531 | } | 525 | } |
532 | 526 | ||
@@ -560,7 +554,7 @@ impl Ctx { | |||
560 | list.extern_items() | 554 | list.extern_items() |
561 | .filter_map(|item| { | 555 | .filter_map(|item| { |
562 | self.collect_inner_items(item.syntax()); | 556 | self.collect_inner_items(item.syntax()); |
563 | let attrs = Attrs::new(&item, &self.hygiene); | 557 | let attrs = RawAttrs::new(&item, &self.hygiene); |
564 | let id: ModItem = match item { | 558 | let id: ModItem = match item { |
565 | ast::ExternItem::Fn(ast) => { | 559 | ast::ExternItem::Fn(ast) => { |
566 | let func_id = self.lower_function(&ast)?; | 560 | let func_id = self.lower_function(&ast)?; |
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index 7e2199a9c..ba09a9126 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -425,6 +425,16 @@ impl HasModule for AdtId { | |||
425 | } | 425 | } |
426 | } | 426 | } |
427 | 427 | ||
428 | impl HasModule for VariantId { | ||
429 | fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { | ||
430 | match self { | ||
431 | VariantId::EnumVariantId(it) => it.parent.lookup(db).container.module(db), | ||
432 | VariantId::StructId(it) => it.lookup(db).container.module(db), | ||
433 | VariantId::UnionId(it) => it.lookup(db).container.module(db), | ||
434 | } | ||
435 | } | ||
436 | } | ||
437 | |||
428 | impl HasModule for DefWithBodyId { | 438 | impl HasModule for DefWithBodyId { |
429 | fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { | 439 | fn module(&self, db: &dyn db::DefDatabase) -> ModuleId { |
430 | match self { | 440 | match self { |
@@ -465,6 +475,26 @@ impl HasModule for StaticLoc { | |||
465 | } | 475 | } |
466 | } | 476 | } |
467 | 477 | ||
478 | impl AttrDefId { | ||
479 | pub fn krate(&self, db: &dyn db::DefDatabase) -> CrateId { | ||
480 | match self { | ||
481 | AttrDefId::ModuleId(it) => it.krate, | ||
482 | AttrDefId::FieldId(it) => it.parent.module(db).krate, | ||
483 | AttrDefId::AdtId(it) => it.module(db).krate, | ||
484 | AttrDefId::FunctionId(it) => it.lookup(db).module(db).krate, | ||
485 | AttrDefId::EnumVariantId(it) => it.parent.lookup(db).container.module(db).krate, | ||
486 | AttrDefId::StaticId(it) => it.lookup(db).module(db).krate, | ||
487 | AttrDefId::ConstId(it) => it.lookup(db).module(db).krate, | ||
488 | AttrDefId::TraitId(it) => it.lookup(db).container.module(db).krate, | ||
489 | AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate, | ||
490 | AttrDefId::ImplId(it) => it.lookup(db).container.module(db).krate, | ||
491 | // FIXME: `MacroDefId` should store the defining module, then this can implement | ||
492 | // `HasModule` | ||
493 | AttrDefId::MacroDefId(it) => it.krate, | ||
494 | } | ||
495 | } | ||
496 | } | ||
497 | |||
468 | /// A helper trait for converting to MacroCallId | 498 | /// A helper trait for converting to MacroCallId |
469 | pub trait AsMacroCall { | 499 | pub trait AsMacroCall { |
470 | fn as_call_id( | 500 | fn as_call_id( |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 1936348fb..a636ec77d 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -136,23 +136,35 @@ struct Import { | |||
136 | } | 136 | } |
137 | 137 | ||
138 | impl Import { | 138 | impl Import { |
139 | fn from_use(tree: &ItemTree, id: ItemTreeId<item_tree::Import>) -> Self { | 139 | fn from_use( |
140 | db: &dyn DefDatabase, | ||
141 | krate: CrateId, | ||
142 | tree: &ItemTree, | ||
143 | id: ItemTreeId<item_tree::Import>, | ||
144 | ) -> Self { | ||
140 | let it = &tree[id.value]; | 145 | let it = &tree[id.value]; |
146 | let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into()); | ||
141 | let visibility = &tree[it.visibility]; | 147 | let visibility = &tree[it.visibility]; |
142 | Self { | 148 | Self { |
143 | path: it.path.clone(), | 149 | path: it.path.clone(), |
144 | alias: it.alias.clone(), | 150 | alias: it.alias.clone(), |
145 | visibility: visibility.clone(), | 151 | visibility: visibility.clone(), |
146 | is_glob: it.is_glob, | 152 | is_glob: it.is_glob, |
147 | is_prelude: it.is_prelude, | 153 | is_prelude: attrs.by_key("prelude_import").exists(), |
148 | is_extern_crate: false, | 154 | is_extern_crate: false, |
149 | is_macro_use: false, | 155 | is_macro_use: false, |
150 | source: ImportSource::Import(id), | 156 | source: ImportSource::Import(id), |
151 | } | 157 | } |
152 | } | 158 | } |
153 | 159 | ||
154 | fn from_extern_crate(tree: &ItemTree, id: ItemTreeId<item_tree::ExternCrate>) -> Self { | 160 | fn from_extern_crate( |
161 | db: &dyn DefDatabase, | ||
162 | krate: CrateId, | ||
163 | tree: &ItemTree, | ||
164 | id: ItemTreeId<item_tree::ExternCrate>, | ||
165 | ) -> Self { | ||
155 | let it = &tree[id.value]; | 166 | let it = &tree[id.value]; |
167 | let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into()); | ||
156 | let visibility = &tree[it.visibility]; | 168 | let visibility = &tree[it.visibility]; |
157 | Self { | 169 | Self { |
158 | path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())), | 170 | path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())), |
@@ -161,7 +173,7 @@ impl Import { | |||
161 | is_glob: false, | 173 | is_glob: false, |
162 | is_prelude: false, | 174 | is_prelude: false, |
163 | is_extern_crate: true, | 175 | is_extern_crate: true, |
164 | is_macro_use: it.is_macro_use, | 176 | is_macro_use: attrs.by_key("macro_use").exists(), |
165 | source: ImportSource::ExternCrate(id), | 177 | source: ImportSource::ExternCrate(id), |
166 | } | 178 | } |
167 | } | 179 | } |
@@ -221,17 +233,20 @@ impl DefCollector<'_> { | |||
221 | let item_tree = self.db.item_tree(file_id.into()); | 233 | let item_tree = self.db.item_tree(file_id.into()); |
222 | let module_id = self.def_map.root; | 234 | let module_id = self.def_map.root; |
223 | self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; | 235 | self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; |
224 | let mut root_collector = ModCollector { | 236 | if item_tree |
225 | def_collector: &mut *self, | 237 | .top_level_attrs(self.db, self.def_map.krate) |
226 | macro_depth: 0, | 238 | .cfg() |
227 | module_id, | 239 | .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 | { | 240 | { |
234 | root_collector.collect(item_tree.top_level_items()); | 241 | ModCollector { |
242 | def_collector: &mut *self, | ||
243 | macro_depth: 0, | ||
244 | module_id, | ||
245 | file_id: file_id.into(), | ||
246 | item_tree: &item_tree, | ||
247 | mod_dir: ModDir::root(), | ||
248 | } | ||
249 | .collect(item_tree.top_level_items()); | ||
235 | } | 250 | } |
236 | 251 | ||
237 | // main name resolution fixed-point loop. | 252 | // main name resolution fixed-point loop. |
@@ -905,6 +920,8 @@ struct ModCollector<'a, 'b> { | |||
905 | 920 | ||
906 | impl ModCollector<'_, '_> { | 921 | impl ModCollector<'_, '_> { |
907 | fn collect(&mut self, items: &[ModItem]) { | 922 | fn collect(&mut self, items: &[ModItem]) { |
923 | let krate = self.def_collector.def_map.krate; | ||
924 | |||
908 | // Note: don't assert that inserted value is fresh: it's simply not true | 925 | // Note: don't assert that inserted value is fresh: it's simply not true |
909 | // for macros. | 926 | // for macros. |
910 | self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone()); | 927 | self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone()); |
@@ -921,11 +938,16 @@ impl ModCollector<'_, '_> { | |||
921 | // `#[macro_use] extern crate` is hoisted to imports macros before collecting | 938 | // `#[macro_use] extern crate` is hoisted to imports macros before collecting |
922 | // any other items. | 939 | // any other items. |
923 | for item in items { | 940 | for item in items { |
924 | let attrs = self.item_tree.attrs((*item).into()); | 941 | 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)) { | 942 | if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) { |
926 | if let ModItem::ExternCrate(id) = item { | 943 | if let ModItem::ExternCrate(id) = item { |
927 | let import = self.item_tree[*id].clone(); | 944 | let import = self.item_tree[*id].clone(); |
928 | if import.is_macro_use { | 945 | let attrs = self.item_tree.attrs( |
946 | self.def_collector.db, | ||
947 | krate, | ||
948 | ModItem::from(*id).into(), | ||
949 | ); | ||
950 | if attrs.by_key("macro_use").exists() { | ||
929 | self.def_collector.import_macros_from_extern_crate(self.module_id, &import); | 951 | self.def_collector.import_macros_from_extern_crate(self.module_id, &import); |
930 | } | 952 | } |
931 | } | 953 | } |
@@ -933,7 +955,7 @@ impl ModCollector<'_, '_> { | |||
933 | } | 955 | } |
934 | 956 | ||
935 | for &item in items { | 957 | for &item in items { |
936 | let attrs = self.item_tree.attrs(item.into()); | 958 | let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into()); |
937 | if let Some(cfg) = attrs.cfg() { | 959 | if let Some(cfg) = attrs.cfg() { |
938 | if !self.is_cfg_enabled(&cfg) { | 960 | if !self.is_cfg_enabled(&cfg) { |
939 | self.emit_unconfigured_diagnostic(item, &cfg); | 961 | self.emit_unconfigured_diagnostic(item, &cfg); |
@@ -946,11 +968,13 @@ impl ModCollector<'_, '_> { | |||
946 | 968 | ||
947 | let mut def = None; | 969 | let mut def = None; |
948 | match item { | 970 | match item { |
949 | ModItem::Mod(m) => self.collect_module(&self.item_tree[m], attrs), | 971 | ModItem::Mod(m) => self.collect_module(&self.item_tree[m], &attrs), |
950 | ModItem::Import(import_id) => { | 972 | ModItem::Import(import_id) => { |
951 | self.def_collector.unresolved_imports.push(ImportDirective { | 973 | self.def_collector.unresolved_imports.push(ImportDirective { |
952 | module_id: self.module_id, | 974 | module_id: self.module_id, |
953 | import: Import::from_use( | 975 | import: Import::from_use( |
976 | self.def_collector.db, | ||
977 | krate, | ||
954 | &self.item_tree, | 978 | &self.item_tree, |
955 | InFile::new(self.file_id, import_id), | 979 | InFile::new(self.file_id, import_id), |
956 | ), | 980 | ), |
@@ -961,6 +985,8 @@ impl ModCollector<'_, '_> { | |||
961 | self.def_collector.unresolved_imports.push(ImportDirective { | 985 | self.def_collector.unresolved_imports.push(ImportDirective { |
962 | module_id: self.module_id, | 986 | module_id: self.module_id, |
963 | import: Import::from_extern_crate( | 987 | import: Import::from_extern_crate( |
988 | self.def_collector.db, | ||
989 | krate, | ||
964 | &self.item_tree, | 990 | &self.item_tree, |
965 | InFile::new(self.file_id, import_id), | 991 | InFile::new(self.file_id, import_id), |
966 | ), | 992 | ), |
@@ -975,7 +1001,11 @@ impl ModCollector<'_, '_> { | |||
975 | 1001 | ||
976 | // "Macro 2.0" is not currently supported by rust-analyzer, but libcore uses it | 1002 | // "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. | 1003 | // to define builtin macros, so we support at least that part. |
978 | let attrs = self.item_tree.attrs(ModItem::from(id).into()); | 1004 | let attrs = self.item_tree.attrs( |
1005 | self.def_collector.db, | ||
1006 | krate, | ||
1007 | ModItem::from(id).into(), | ||
1008 | ); | ||
979 | if attrs.by_key("rustc_builtin_macro").exists() { | 1009 | if attrs.by_key("rustc_builtin_macro").exists() { |
980 | let krate = self.def_collector.def_map.krate; | 1010 | let krate = self.def_collector.def_map.krate; |
981 | let macro_id = find_builtin_macro(&mac.name, krate, ast_id) | 1011 | let macro_id = find_builtin_macro(&mac.name, krate, ast_id) |
@@ -1012,7 +1042,7 @@ impl ModCollector<'_, '_> { | |||
1012 | ModItem::Function(id) => { | 1042 | ModItem::Function(id) => { |
1013 | let func = &self.item_tree[id]; | 1043 | let func = &self.item_tree[id]; |
1014 | 1044 | ||
1015 | self.collect_proc_macro_def(&func.name, attrs); | 1045 | self.collect_proc_macro_def(&func.name, &attrs); |
1016 | 1046 | ||
1017 | def = Some(DefData { | 1047 | def = Some(DefData { |
1018 | id: FunctionLoc { | 1048 | id: FunctionLoc { |
@@ -1032,7 +1062,7 @@ impl ModCollector<'_, '_> { | |||
1032 | // FIXME: check attrs to see if this is an attribute macro invocation; | 1062 | // 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 | 1063 | // in which case we don't add the invocation, just a single attribute |
1034 | // macro invocation | 1064 | // macro invocation |
1035 | self.collect_derives(attrs, it.ast_id.upcast()); | 1065 | self.collect_derives(&attrs, it.ast_id.upcast()); |
1036 | 1066 | ||
1037 | def = Some(DefData { | 1067 | def = Some(DefData { |
1038 | id: StructLoc { container, id: ItemTreeId::new(self.file_id, id) } | 1068 | id: StructLoc { container, id: ItemTreeId::new(self.file_id, id) } |
@@ -1049,7 +1079,7 @@ impl ModCollector<'_, '_> { | |||
1049 | // FIXME: check attrs to see if this is an attribute macro invocation; | 1079 | // 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 | 1080 | // in which case we don't add the invocation, just a single attribute |
1051 | // macro invocation | 1081 | // macro invocation |
1052 | self.collect_derives(attrs, it.ast_id.upcast()); | 1082 | self.collect_derives(&attrs, it.ast_id.upcast()); |
1053 | 1083 | ||
1054 | def = Some(DefData { | 1084 | def = Some(DefData { |
1055 | id: UnionLoc { container, id: ItemTreeId::new(self.file_id, id) } | 1085 | id: UnionLoc { container, id: ItemTreeId::new(self.file_id, id) } |
@@ -1066,7 +1096,7 @@ impl ModCollector<'_, '_> { | |||
1066 | // FIXME: check attrs to see if this is an attribute macro invocation; | 1096 | // 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 | 1097 | // in which case we don't add the invocation, just a single attribute |
1068 | // macro invocation | 1098 | // macro invocation |
1069 | self.collect_derives(attrs, it.ast_id.upcast()); | 1099 | self.collect_derives(&attrs, it.ast_id.upcast()); |
1070 | 1100 | ||
1071 | def = Some(DefData { | 1101 | def = Some(DefData { |
1072 | id: EnumLoc { container, id: ItemTreeId::new(self.file_id, id) } | 1102 | id: EnumLoc { container, id: ItemTreeId::new(self.file_id, id) } |
@@ -1259,20 +1289,20 @@ impl ModCollector<'_, '_> { | |||
1259 | } | 1289 | } |
1260 | 1290 | ||
1261 | fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) { | 1291 | fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) { |
1262 | for derive_subtree in attrs.by_key("derive").tt_values() { | 1292 | for derive in attrs.by_key("derive").attrs() { |
1263 | // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree | 1293 | match derive.parse_derive() { |
1264 | for tt in &derive_subtree.token_trees { | 1294 | Some(derive_macros) => { |
1265 | let ident = match &tt { | 1295 | for path in derive_macros { |
1266 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident, | 1296 | let ast_id = AstIdWithPath::new(self.file_id, ast_id, path); |
1267 | tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok | 1297 | self.def_collector |
1268 | _ => continue, // anything else would be an error (which we currently ignore) | 1298 | .unexpanded_attribute_macros |
1269 | }; | 1299 | .push(DeriveDirective { module_id: self.module_id, ast_id }); |
1270 | let path = ModPath::from_tt_ident(ident); | 1300 | } |
1271 | 1301 | } | |
1272 | let ast_id = AstIdWithPath::new(self.file_id, ast_id, path); | 1302 | None => { |
1273 | self.def_collector | 1303 | // FIXME: diagnose |
1274 | .unexpanded_attribute_macros | 1304 | log::debug!("malformed derive: {:?}", derive); |
1275 | .push(DeriveDirective { module_id: self.module_id, ast_id }); | 1305 | } |
1276 | } | 1306 | } |
1277 | } | 1307 | } |
1278 | } | 1308 | } |
@@ -1303,8 +1333,9 @@ impl ModCollector<'_, '_> { | |||
1303 | } | 1333 | } |
1304 | 1334 | ||
1305 | fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) { | 1335 | fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>) { |
1336 | let krate = self.def_collector.def_map.krate; | ||
1306 | let mac = &self.item_tree[id]; | 1337 | let mac = &self.item_tree[id]; |
1307 | let attrs = self.item_tree.attrs(ModItem::from(id).into()); | 1338 | 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()); | 1339 | let ast_id = InFile::new(self.file_id, mac.ast_id.upcast()); |
1309 | 1340 | ||
1310 | let export_attr = attrs.by_key("macro_export"); | 1341 | let export_attr = attrs.by_key("macro_export"); |
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs index a4d1fb8f3..c459fa66d 100644 --- a/crates/hir_def/src/nameres/tests.rs +++ b/crates/hir_def/src/nameres/tests.rs | |||
@@ -13,8 +13,8 @@ use test_utils::mark; | |||
13 | 13 | ||
14 | use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; | 14 | use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; |
15 | 15 | ||
16 | fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> { | 16 | fn compute_crate_def_map(ra_fixture: &str) -> Arc<CrateDefMap> { |
17 | let db = TestDB::with_files(fixture); | 17 | let db = TestDB::with_files(ra_fixture); |
18 | let krate = db.crate_graph().iter().next().unwrap(); | 18 | let krate = db.crate_graph().iter().next().unwrap(); |
19 | db.crate_def_map(krate) | 19 | db.crate_def_map(krate) |
20 | } | 20 | } |
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs index 1a7b98831..58d69d3c6 100644 --- a/crates/hir_def/src/nameres/tests/diagnostics.rs +++ b/crates/hir_def/src/nameres/tests/diagnostics.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | use base_db::fixture::WithFixture; | 1 | use base_db::fixture::WithFixture; |
2 | use test_utils::mark; | ||
2 | 3 | ||
3 | use crate::test_db::TestDB; | 4 | use crate::test_db::TestDB; |
4 | 5 | ||
@@ -119,3 +120,20 @@ fn inactive_item() { | |||
119 | "#, | 120 | "#, |
120 | ); | 121 | ); |
121 | } | 122 | } |
123 | |||
124 | /// Tests that `cfg` attributes behind `cfg_attr` is handled properly. | ||
125 | #[test] | ||
126 | fn inactive_via_cfg_attr() { | ||
127 | mark::check!(cfg_attr_active); | ||
128 | check_diagnostics( | ||
129 | r#" | ||
130 | //- /lib.rs | ||
131 | #[cfg_attr(not(never), cfg(no))] fn f() {} | ||
132 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | ||
133 | |||
134 | #[cfg_attr(not(never), cfg(not(no)))] fn f() {} | ||
135 | |||
136 | #[cfg_attr(never, cfg(no))] fn g() {} | ||
137 | "#, | ||
138 | ); | ||
139 | } | ||
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs index 6fe2ee78a..f9bf5bc72 100644 --- a/crates/hir_def/src/nameres/tests/macros.rs +++ b/crates/hir_def/src/nameres/tests/macros.rs | |||
@@ -632,11 +632,11 @@ pub struct bar; | |||
632 | #[test] | 632 | #[test] |
633 | fn expand_derive() { | 633 | fn expand_derive() { |
634 | let map = compute_crate_def_map( | 634 | let map = compute_crate_def_map( |
635 | " | 635 | r#" |
636 | //- /main.rs crate:main deps:core | 636 | //- /main.rs crate:main deps:core |
637 | use core::*; | 637 | use core::Copy; |
638 | 638 | ||
639 | #[derive(Copy, Clone)] | 639 | #[derive(Copy, core::Clone)] |
640 | struct Foo; | 640 | struct Foo; |
641 | 641 | ||
642 | //- /core.rs crate:core | 642 | //- /core.rs crate:core |
@@ -645,7 +645,7 @@ fn expand_derive() { | |||
645 | 645 | ||
646 | #[rustc_builtin_macro] | 646 | #[rustc_builtin_macro] |
647 | pub macro Clone {} | 647 | pub macro Clone {} |
648 | ", | 648 | "#, |
649 | ); | 649 | ); |
650 | assert_eq!(map.modules[map.root].scope.impls().len(), 2); | 650 | assert_eq!(map.modules[map.root].scope.impls().len(), 2); |
651 | } | 651 | } |
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index 00a69a8a6..e2bf85bbc 100644 --- a/crates/hir_def/src/path.rs +++ b/crates/hir_def/src/path.rs | |||
@@ -9,11 +9,8 @@ use std::{ | |||
9 | 9 | ||
10 | use crate::{body::LowerCtx, type_ref::LifetimeRef}; | 10 | use crate::{body::LowerCtx, type_ref::LifetimeRef}; |
11 | use base_db::CrateId; | 11 | use base_db::CrateId; |
12 | use hir_expand::{ | 12 | use hir_expand::{hygiene::Hygiene, name::Name}; |
13 | hygiene::Hygiene, | 13 | use syntax::ast; |
14 | name::{AsName, Name}, | ||
15 | }; | ||
16 | use syntax::ast::{self}; | ||
17 | 14 | ||
18 | use crate::{ | 15 | use crate::{ |
19 | type_ref::{TypeBound, TypeRef}, | 16 | type_ref::{TypeBound, TypeRef}, |
@@ -56,11 +53,6 @@ impl ModPath { | |||
56 | ModPath { kind, segments } | 53 | ModPath { kind, segments } |
57 | } | 54 | } |
58 | 55 | ||
59 | /// Converts an `tt::Ident` into a single-identifier `Path`. | ||
60 | pub(crate) fn from_tt_ident(ident: &tt::Ident) -> ModPath { | ||
61 | ident.as_name().into() | ||
62 | } | ||
63 | |||
64 | /// Calls `cb` with all paths, represented by this use item. | 56 | /// Calls `cb` with all paths, represented by this use item. |
65 | pub(crate) fn expand_use_item( | 57 | pub(crate) fn expand_use_item( |
66 | item_src: InFile<ast::Use>, | 58 | item_src: InFile<ast::Use>, |