diff options
Diffstat (limited to 'crates/hir_def')
-rw-r--r-- | crates/hir_def/src/attr.rs | 208 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree.rs | 5 | ||||
-rw-r--r-- | crates/hir_def/src/item_tree/lower.rs | 7 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 59 | ||||
-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 |
8 files changed, 232 insertions, 89 deletions
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 9cd0b72aa..042e119b1 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -5,20 +5,21 @@ use std::{ops, sync::Arc}; | |||
5 | use base_db::CrateId; | 5 | use base_db::CrateId; |
6 | use cfg::{CfgExpr, CfgOptions}; | 6 | use cfg::{CfgExpr, CfgOptions}; |
7 | use either::Either; | 7 | use either::Either; |
8 | use hir_expand::{hygiene::Hygiene, AstId, InFile}; | 8 | use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile}; |
9 | use itertools::Itertools; | 9 | use itertools::Itertools; |
10 | use mbe::ast_to_token_tree; | 10 | use mbe::ast_to_token_tree; |
11 | use syntax::{ | 11 | use syntax::{ |
12 | ast::{self, AstNode, AttrsOwner}, | 12 | ast::{self, AstNode, AttrsOwner}, |
13 | match_ast, AstToken, SmolStr, SyntaxNode, | 13 | match_ast, AstToken, SmolStr, SyntaxNode, |
14 | }; | 14 | }; |
15 | use test_utils::mark; | ||
15 | use tt::Subtree; | 16 | use tt::Subtree; |
16 | 17 | ||
17 | use crate::{ | 18 | use crate::{ |
18 | db::DefDatabase, | 19 | db::DefDatabase, |
19 | item_tree::{ItemTreeId, ItemTreeNode}, | 20 | item_tree::{ItemTreeId, ItemTreeNode}, |
20 | nameres::ModuleSource, | 21 | nameres::ModuleSource, |
21 | path::ModPath, | 22 | path::{ModPath, PathKind}, |
22 | src::HasChildSource, | 23 | src::HasChildSource, |
23 | AdtId, AttrDefId, Lookup, | 24 | AdtId, AttrDefId, Lookup, |
24 | }; | 25 | }; |
@@ -41,7 +42,7 @@ impl From<Documentation> for String { | |||
41 | 42 | ||
42 | /// Syntactical attributes, without filtering of `cfg_attr`s. | 43 | /// Syntactical attributes, without filtering of `cfg_attr`s. |
43 | #[derive(Default, Debug, Clone, PartialEq, Eq)] | 44 | #[derive(Default, Debug, Clone, PartialEq, Eq)] |
44 | pub struct RawAttrs { | 45 | pub(crate) struct RawAttrs { |
45 | entries: Option<Arc<[Attr]>>, | 46 | entries: Option<Arc<[Attr]>>, |
46 | } | 47 | } |
47 | 48 | ||
@@ -71,35 +72,34 @@ impl ops::Deref for Attrs { | |||
71 | } | 72 | } |
72 | 73 | ||
73 | impl RawAttrs { | 74 | impl RawAttrs { |
74 | pub const EMPTY: Self = Self { entries: None }; | 75 | pub(crate) const EMPTY: Self = Self { entries: None }; |
75 | 76 | ||
76 | pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Self { | 77 | pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Self { |
77 | let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) | 78 | let attrs: Vec<_> = collect_attrs(owner).collect(); |
78 | .map_or((None, None), |(attrs, docs)| ((Some(attrs), Some(docs)))); | ||
79 | |||
80 | let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none()); | ||
81 | let attrs = outer_attrs | ||
82 | .chain(inner_attrs.into_iter().flatten()) | ||
83 | .map(|attr| (attr.syntax().text_range().start(), Attr::from_src(attr, hygiene))); | ||
84 | |||
85 | let outer_docs = | ||
86 | ast::CommentIter::from_syntax_node(owner.syntax()).filter(ast::Comment::is_outer); | ||
87 | let docs = outer_docs.chain(inner_docs.into_iter().flatten()).map(|docs_text| { | ||
88 | ( | ||
89 | docs_text.syntax().text_range().start(), | ||
90 | docs_text.doc_comment().map(|doc| Attr { | ||
91 | input: Some(AttrInput::Literal(SmolStr::new(doc))), | ||
92 | path: ModPath::from(hir_expand::name!(doc)), | ||
93 | }), | ||
94 | ) | ||
95 | }); | ||
96 | // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved | ||
97 | let attrs: Vec<_> = docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).collect(); | ||
98 | let entries = if attrs.is_empty() { | 79 | let entries = if attrs.is_empty() { |
99 | // Avoid heap allocation | 80 | // Avoid heap allocation |
100 | None | 81 | None |
101 | } else { | 82 | } else { |
102 | Some(attrs.into_iter().flat_map(|(_, attr)| attr).collect()) | 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 | }; | 103 | }; |
104 | Self { entries } | 104 | Self { entries } |
105 | } | 105 | } |
@@ -122,9 +122,69 @@ impl RawAttrs { | |||
122 | } | 122 | } |
123 | 123 | ||
124 | /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`. | 124 | /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`. |
125 | pub(crate) fn filter(self, _db: &dyn DefDatabase, _krate: CrateId) -> Attrs { | 125 | pub(crate) fn filter(self, db: &dyn DefDatabase, krate: CrateId) -> Attrs { |
126 | // FIXME actually implement this | 126 | let has_cfg_attrs = self.iter().any(|attr| { |
127 | Attrs(self) | 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) }) | ||
128 | } | 188 | } |
129 | } | 189 | } |
130 | 190 | ||
@@ -180,24 +240,11 @@ impl Attrs { | |||
180 | raw_attrs.filter(db, def.krate(db)) | 240 | raw_attrs.filter(db, def.krate(db)) |
181 | } | 241 | } |
182 | 242 | ||
183 | pub fn merge(&self, other: Attrs) -> Attrs { | ||
184 | match (&self.0.entries, &other.0.entries) { | ||
185 | (None, None) => Attrs::EMPTY, | ||
186 | (Some(entries), None) | (None, Some(entries)) => { | ||
187 | Attrs(RawAttrs { entries: Some(entries.clone()) }) | ||
188 | } | ||
189 | (Some(a), Some(b)) => { | ||
190 | Attrs(RawAttrs { entries: Some(a.iter().chain(b.iter()).cloned().collect()) }) | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | |||
195 | pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { | 243 | pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { |
196 | AttrQuery { attrs: self, key } | 244 | AttrQuery { attrs: self, key } |
197 | } | 245 | } |
198 | 246 | ||
199 | pub fn cfg(&self) -> Option<CfgExpr> { | 247 | pub fn cfg(&self) -> Option<CfgExpr> { |
200 | // FIXME: handle cfg_attr :-) | ||
201 | 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<_>>(); |
202 | match cfgs.len() { | 249 | match cfgs.len() { |
203 | 0 => None, | 250 | 0 => None, |
@@ -268,6 +315,7 @@ fn inner_attributes( | |||
268 | 315 | ||
269 | #[derive(Debug, Clone, PartialEq, Eq)] | 316 | #[derive(Debug, Clone, PartialEq, Eq)] |
270 | pub struct Attr { | 317 | pub struct Attr { |
318 | index: u32, | ||
271 | pub(crate) path: ModPath, | 319 | pub(crate) path: ModPath, |
272 | pub(crate) input: Option<AttrInput>, | 320 | pub(crate) input: Option<AttrInput>, |
273 | } | 321 | } |
@@ -294,7 +342,59 @@ impl Attr { | |||
294 | } else { | 342 | } else { |
295 | None | 343 | None |
296 | }; | 344 | }; |
297 | 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 | } | ||
298 | } | 398 | } |
299 | } | 399 | } |
300 | 400 | ||
@@ -323,7 +423,7 @@ impl<'a> AttrQuery<'a> { | |||
323 | self.attrs().next().is_some() | 423 | self.attrs().next().is_some() |
324 | } | 424 | } |
325 | 425 | ||
326 | fn attrs(self) -> impl Iterator<Item = &'a Attr> { | 426 | pub(crate) fn attrs(self) -> impl Iterator<Item = &'a Attr> { |
327 | let key = self.key; | 427 | let key = self.key; |
328 | self.attrs | 428 | self.attrs |
329 | .iter() | 429 | .iter() |
@@ -344,3 +444,23 @@ fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase | |||
344 | let mod_item = N::id_to_mod_item(id.value); | 444 | let mod_item = N::id_to_mod_item(id.value); |
345 | tree.raw_attrs(mod_item.into()).clone() | 445 | tree.raw_attrs(mod_item.into()).clone() |
346 | } | 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) | ||
466 | } | ||
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 5eb7cae7f..100dbf5d6 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs | |||
@@ -12,7 +12,7 @@ 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 base_db::CrateId; |
17 | use either::Either; | 17 | use either::Either; |
18 | use hir_expand::{ | 18 | use hir_expand::{ |
@@ -495,7 +495,6 @@ pub struct Import { | |||
495 | pub alias: Option<ImportAlias>, | 495 | pub alias: Option<ImportAlias>, |
496 | pub visibility: RawVisibilityId, | 496 | pub visibility: RawVisibilityId, |
497 | pub is_glob: bool, | 497 | pub is_glob: bool, |
498 | pub is_prelude: bool, | ||
499 | /// 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 |
500 | /// `Import`s can map to the same `use` item. | 499 | /// `Import`s can map to the same `use` item. |
501 | pub ast_id: FileAstId<ast::Use>, | 500 | pub ast_id: FileAstId<ast::Use>, |
@@ -511,8 +510,6 @@ pub struct ExternCrate { | |||
511 | pub name: Name, | 510 | pub name: Name, |
512 | pub alias: Option<ImportAlias>, | 511 | pub alias: Option<ImportAlias>, |
513 | pub visibility: RawVisibilityId, | 512 | pub visibility: RawVisibilityId, |
514 | /// Whether this is a `#[macro_use] extern crate ...`. | ||
515 | pub is_macro_use: bool, | ||
516 | pub ast_id: FileAstId<ast::ExternCrate>, | 513 | pub ast_id: FileAstId<ast::ExternCrate>, |
517 | } | 514 | } |
518 | 515 | ||
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index c8f090c22..3b206ef85 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs | |||
@@ -485,8 +485,6 @@ impl Ctx { | |||
485 | } | 485 | } |
486 | 486 | ||
487 | 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>> { |
488 | // FIXME: cfg_attr | ||
489 | let is_prelude = use_item.has_atom_attr("prelude_import"); | ||
490 | let visibility = self.lower_visibility(use_item); | 488 | let visibility = self.lower_visibility(use_item); |
491 | 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); |
492 | 490 | ||
@@ -502,7 +500,6 @@ impl Ctx { | |||
502 | alias, | 500 | alias, |
503 | visibility, | 501 | visibility, |
504 | is_glob, | 502 | is_glob, |
505 | is_prelude, | ||
506 | ast_id, | 503 | ast_id, |
507 | index: imports.len(), | 504 | index: imports.len(), |
508 | }))); | 505 | }))); |
@@ -522,10 +519,8 @@ impl Ctx { | |||
522 | }); | 519 | }); |
523 | let visibility = self.lower_visibility(extern_crate); | 520 | let visibility = self.lower_visibility(extern_crate); |
524 | 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); |
525 | // FIXME: cfg_attr | ||
526 | let is_macro_use = extern_crate.has_atom_attr("macro_use"); | ||
527 | 522 | ||
528 | let res = ExternCrate { name, alias, visibility, is_macro_use, ast_id }; | 523 | let res = ExternCrate { name, alias, visibility, ast_id }; |
529 | Some(id(self.data().extern_crates.alloc(res))) | 524 | Some(id(self.data().extern_crates.alloc(res))) |
530 | } | 525 | } |
531 | 526 | ||
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index b114a6fe4..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 | } |
@@ -930,7 +942,12 @@ impl ModCollector<'_, '_> { | |||
930 | 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)) { |
931 | if let ModItem::ExternCrate(id) = item { | 943 | if let ModItem::ExternCrate(id) = item { |
932 | let import = self.item_tree[*id].clone(); | 944 | let import = self.item_tree[*id].clone(); |
933 | 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() { | ||
934 | 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); |
935 | } | 952 | } |
936 | } | 953 | } |
@@ -956,6 +973,8 @@ impl ModCollector<'_, '_> { | |||
956 | self.def_collector.unresolved_imports.push(ImportDirective { | 973 | self.def_collector.unresolved_imports.push(ImportDirective { |
957 | module_id: self.module_id, | 974 | module_id: self.module_id, |
958 | import: Import::from_use( | 975 | import: Import::from_use( |
976 | self.def_collector.db, | ||
977 | krate, | ||
959 | &self.item_tree, | 978 | &self.item_tree, |
960 | InFile::new(self.file_id, import_id), | 979 | InFile::new(self.file_id, import_id), |
961 | ), | 980 | ), |
@@ -966,6 +985,8 @@ impl ModCollector<'_, '_> { | |||
966 | self.def_collector.unresolved_imports.push(ImportDirective { | 985 | self.def_collector.unresolved_imports.push(ImportDirective { |
967 | module_id: self.module_id, | 986 | module_id: self.module_id, |
968 | import: Import::from_extern_crate( | 987 | import: Import::from_extern_crate( |
988 | self.def_collector.db, | ||
989 | krate, | ||
969 | &self.item_tree, | 990 | &self.item_tree, |
970 | InFile::new(self.file_id, import_id), | 991 | InFile::new(self.file_id, import_id), |
971 | ), | 992 | ), |
@@ -1268,20 +1289,20 @@ impl ModCollector<'_, '_> { | |||
1268 | } | 1289 | } |
1269 | 1290 | ||
1270 | 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>) { |
1271 | for derive_subtree in attrs.by_key("derive").tt_values() { | 1292 | for derive in attrs.by_key("derive").attrs() { |
1272 | // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree | 1293 | match derive.parse_derive() { |
1273 | for tt in &derive_subtree.token_trees { | 1294 | Some(derive_macros) => { |
1274 | let ident = match &tt { | 1295 | for path in derive_macros { |
1275 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident, | 1296 | let ast_id = AstIdWithPath::new(self.file_id, ast_id, path); |
1276 | tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok | 1297 | self.def_collector |
1277 | _ => continue, // anything else would be an error (which we currently ignore) | 1298 | .unexpanded_attribute_macros |
1278 | }; | 1299 | .push(DeriveDirective { module_id: self.module_id, ast_id }); |
1279 | let path = ModPath::from_tt_ident(ident); | 1300 | } |
1280 | 1301 | } | |
1281 | let ast_id = AstIdWithPath::new(self.file_id, ast_id, path); | 1302 | None => { |
1282 | self.def_collector | 1303 | // FIXME: diagnose |
1283 | .unexpanded_attribute_macros | 1304 | log::debug!("malformed derive: {:?}", derive); |
1284 | .push(DeriveDirective { module_id: self.module_id, ast_id }); | 1305 | } |
1285 | } | 1306 | } |
1286 | } | 1307 | } |
1287 | } | 1308 | } |
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>, |