aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r--crates/hir_def/src/adt.rs47
-rw-r--r--crates/hir_def/src/attr.rs290
-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.rs24
-rw-r--r--crates/hir_def/src/item_tree/lower.rs24
-rw-r--r--crates/hir_def/src/lib.rs30
-rw-r--r--crates/hir_def/src/nameres/collector.rs107
-rw-r--r--crates/hir_def/src/nameres/tests.rs4
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs18
-rw-r--r--crates/hir_def/src/nameres/tests/macros.rs8
-rw-r--r--crates/hir_def/src/path.rs12
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 @@
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 c64b78445..042e119b1 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -2,22 +2,24 @@
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, name::AsName, AstId, InFile};
8use itertools::Itertools; 9use itertools::Itertools;
9use mbe::ast_to_token_tree; 10use mbe::ast_to_token_tree;
10use syntax::{ 11use 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};
15use test_utils::mark;
14use tt::Subtree; 16use tt::Subtree;
15 17
16use crate::{ 18use 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)]
42pub struct Attrs { 45pub(crate) struct RawAttrs {
43 entries: Option<Arc<[Attr]>>, 46 entries: Option<Arc<[Attr]>>,
44} 47}
45 48
46impl ops::Deref for Attrs { 49#[derive(Default, Debug, Clone, PartialEq, Eq)]
50pub struct Attrs(RawAttrs);
51
52impl 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
63impl 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
74impl 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
57impl Attrs { 191impl 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)]
230pub struct Attr { 317pub 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
294fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> Attrs 434fn attrs_from_ast<N>(src: AstId<N>, db: &dyn DefDatabase) -> RawAttrs
295where 435where
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
302fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> Attrs { 442fn 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
448fn 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;
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..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
14use arena::{Arena, Idx, RawId}; 14use arena::{Arena, Idx, RawId};
15use ast::{AstNode, AttrsOwner, NameOwner, StructKind}; 15use ast::{AstNode, 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.
@@ -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
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 })
@@ -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
428impl 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
428impl HasModule for DefWithBodyId { 438impl 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
478impl 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
469pub trait AsMacroCall { 499pub 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
138impl Import { 138impl 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
906impl ModCollector<'_, '_> { 921impl 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
14use crate::{db::DefDatabase, nameres::*, test_db::TestDB}; 14use crate::{db::DefDatabase, nameres::*, test_db::TestDB};
15 15
16fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> { 16fn 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 @@
1use base_db::fixture::WithFixture; 1use base_db::fixture::WithFixture;
2use test_utils::mark;
2 3
3use crate::test_db::TestDB; 4use 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]
126fn 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]
633fn expand_derive() { 633fn 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
10use crate::{body::LowerCtx, type_ref::LifetimeRef}; 10use crate::{body::LowerCtx, type_ref::LifetimeRef};
11use base_db::CrateId; 11use base_db::CrateId;
12use hir_expand::{ 12use hir_expand::{hygiene::Hygiene, name::Name};
13 hygiene::Hygiene, 13use syntax::ast;
14 name::{AsName, Name},
15};
16use syntax::ast::{self};
17 14
18use crate::{ 15use 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>,