diff options
Diffstat (limited to 'crates/hir_def/src/nameres')
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 57 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/diagnostics.rs | 9 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/proc_macro.rs | 10 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/incremental.rs | 74 |
4 files changed, 131 insertions, 19 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 716dcf1f7..7f9fdb379 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -477,16 +477,21 @@ impl DefCollector<'_> { | |||
477 | /// going out of sync with what the build system sees (since we resolve using VFS state, but | 477 | /// going out of sync with what the build system sees (since we resolve using VFS state, but |
478 | /// Cargo builds only on-disk files). We could and probably should add diagnostics for that. | 478 | /// Cargo builds only on-disk files). We could and probably should add diagnostics for that. |
479 | fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>) { | 479 | fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>) { |
480 | let kind = def.kind.to_basedb_kind(); | ||
480 | self.exports_proc_macros = true; | 481 | self.exports_proc_macros = true; |
481 | let macro_def = match self.proc_macros.iter().find(|(n, _)| n == &def.name) { | 482 | let macro_def = match self.proc_macros.iter().find(|(n, _)| n == &def.name) { |
482 | Some((_, expander)) => MacroDefId { | 483 | Some((_, expander)) => MacroDefId { |
483 | krate: self.def_map.krate, | 484 | krate: self.def_map.krate, |
484 | kind: MacroDefKind::ProcMacro(*expander, ast_id), | 485 | kind: MacroDefKind::ProcMacro(*expander, kind, ast_id), |
485 | local_inner: false, | 486 | local_inner: false, |
486 | }, | 487 | }, |
487 | None => MacroDefId { | 488 | None => MacroDefId { |
488 | krate: self.def_map.krate, | 489 | krate: self.def_map.krate, |
489 | kind: MacroDefKind::ProcMacro(ProcMacroExpander::dummy(self.def_map.krate), ast_id), | 490 | kind: MacroDefKind::ProcMacro( |
491 | ProcMacroExpander::dummy(self.def_map.krate), | ||
492 | kind, | ||
493 | ast_id, | ||
494 | ), | ||
490 | local_inner: false, | 495 | local_inner: false, |
491 | }, | 496 | }, |
492 | }; | 497 | }; |
@@ -1674,14 +1679,22 @@ impl ModCollector<'_, '_> { | |||
1674 | None => &mac.name, | 1679 | None => &mac.name, |
1675 | }; | 1680 | }; |
1676 | let krate = self.def_collector.def_map.krate; | 1681 | let krate = self.def_collector.def_map.krate; |
1677 | if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) { | 1682 | match find_builtin_macro(name, krate, ast_id) { |
1678 | self.def_collector.define_macro_rules( | 1683 | Some(macro_id) => { |
1679 | self.module_id, | 1684 | self.def_collector.define_macro_rules( |
1680 | mac.name.clone(), | 1685 | self.module_id, |
1681 | macro_id, | 1686 | mac.name.clone(), |
1682 | is_export, | 1687 | macro_id, |
1683 | ); | 1688 | is_export, |
1684 | return; | 1689 | ); |
1690 | return; | ||
1691 | } | ||
1692 | None => { | ||
1693 | self.def_collector | ||
1694 | .def_map | ||
1695 | .diagnostics | ||
1696 | .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id)); | ||
1697 | } | ||
1685 | } | 1698 | } |
1686 | } | 1699 | } |
1687 | 1700 | ||
@@ -1710,15 +1723,23 @@ impl ModCollector<'_, '_> { | |||
1710 | let macro_id = find_builtin_macro(&mac.name, krate, ast_id) | 1723 | let macro_id = find_builtin_macro(&mac.name, krate, ast_id) |
1711 | .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)); | 1724 | .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)); |
1712 | 1725 | ||
1713 | if let Some(macro_id) = macro_id { | 1726 | match macro_id { |
1714 | self.def_collector.define_macro_def( | 1727 | Some(macro_id) => { |
1715 | self.module_id, | 1728 | self.def_collector.define_macro_def( |
1716 | mac.name.clone(), | 1729 | self.module_id, |
1717 | macro_id, | 1730 | mac.name.clone(), |
1718 | &self.item_tree[mac.visibility], | 1731 | macro_id, |
1719 | ); | 1732 | &self.item_tree[mac.visibility], |
1733 | ); | ||
1734 | return; | ||
1735 | } | ||
1736 | None => { | ||
1737 | self.def_collector | ||
1738 | .def_map | ||
1739 | .diagnostics | ||
1740 | .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id)); | ||
1741 | } | ||
1720 | } | 1742 | } |
1721 | return; | ||
1722 | } | 1743 | } |
1723 | 1744 | ||
1724 | // Case 2: normal `macro` | 1745 | // Case 2: normal `macro` |
diff --git a/crates/hir_def/src/nameres/diagnostics.rs b/crates/hir_def/src/nameres/diagnostics.rs index 57c36c3c6..95061f601 100644 --- a/crates/hir_def/src/nameres/diagnostics.rs +++ b/crates/hir_def/src/nameres/diagnostics.rs | |||
@@ -27,6 +27,8 @@ pub enum DefDiagnosticKind { | |||
27 | UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath }, | 27 | UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath }, |
28 | 28 | ||
29 | MacroError { ast: MacroCallKind, message: String }, | 29 | MacroError { ast: MacroCallKind, message: String }, |
30 | |||
31 | UnimplementedBuiltinMacro { ast: AstId<ast::Macro> }, | ||
30 | } | 32 | } |
31 | 33 | ||
32 | #[derive(Debug, PartialEq, Eq)] | 34 | #[derive(Debug, PartialEq, Eq)] |
@@ -93,4 +95,11 @@ impl DefDiagnostic { | |||
93 | ) -> Self { | 95 | ) -> Self { |
94 | Self { in_module: container, kind: DefDiagnosticKind::UnresolvedMacroCall { ast, path } } | 96 | Self { in_module: container, kind: DefDiagnosticKind::UnresolvedMacroCall { ast, path } } |
95 | } | 97 | } |
98 | |||
99 | pub(super) fn unimplemented_builtin_macro( | ||
100 | container: LocalModuleId, | ||
101 | ast: AstId<ast::Macro>, | ||
102 | ) -> Self { | ||
103 | Self { in_module: container, kind: DefDiagnosticKind::UnimplementedBuiltinMacro { ast } } | ||
104 | } | ||
96 | } | 105 | } |
diff --git a/crates/hir_def/src/nameres/proc_macro.rs b/crates/hir_def/src/nameres/proc_macro.rs index 156598f19..3f095d623 100644 --- a/crates/hir_def/src/nameres/proc_macro.rs +++ b/crates/hir_def/src/nameres/proc_macro.rs | |||
@@ -18,6 +18,16 @@ pub(super) enum ProcMacroKind { | |||
18 | Attr, | 18 | Attr, |
19 | } | 19 | } |
20 | 20 | ||
21 | impl ProcMacroKind { | ||
22 | pub(super) fn to_basedb_kind(&self) -> base_db::ProcMacroKind { | ||
23 | match self { | ||
24 | ProcMacroKind::CustomDerive { .. } => base_db::ProcMacroKind::CustomDerive, | ||
25 | ProcMacroKind::FnLike => base_db::ProcMacroKind::FuncLike, | ||
26 | ProcMacroKind::Attr => base_db::ProcMacroKind::Attr, | ||
27 | } | ||
28 | } | ||
29 | } | ||
30 | |||
21 | impl Attrs { | 31 | impl Attrs { |
22 | #[rustfmt::skip] | 32 | #[rustfmt::skip] |
23 | pub(super) fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> { | 33 | pub(super) fn parse_proc_macro_decl(&self, func_name: &Name) -> Option<ProcMacroDef> { |
diff --git a/crates/hir_def/src/nameres/tests/incremental.rs b/crates/hir_def/src/nameres/tests/incremental.rs index d884a6eb4..7bf152e26 100644 --- a/crates/hir_def/src/nameres/tests/incremental.rs +++ b/crates/hir_def/src/nameres/tests/incremental.rs | |||
@@ -1,6 +1,8 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use base_db::SourceDatabaseExt; | 3 | use base_db::{salsa::SweepStrategy, SourceDatabaseExt}; |
4 | |||
5 | use crate::{AdtId, ModuleDefId}; | ||
4 | 6 | ||
5 | use super::*; | 7 | use super::*; |
6 | 8 | ||
@@ -163,3 +165,73 @@ m!(Z); | |||
163 | assert_eq!(n_reparsed_macros, 0); | 165 | assert_eq!(n_reparsed_macros, 0); |
164 | } | 166 | } |
165 | } | 167 | } |
168 | |||
169 | #[test] | ||
170 | fn item_tree_prevents_reparsing() { | ||
171 | // The `ItemTree` is used by both name resolution and the various queries in `adt.rs` and | ||
172 | // `data.rs`. After computing the `ItemTree` and deleting the parse tree, we should be able to | ||
173 | // run those other queries without triggering a reparse. | ||
174 | |||
175 | let (db, pos) = TestDB::with_position( | ||
176 | r#" | ||
177 | pub struct S; | ||
178 | pub union U {} | ||
179 | pub enum E { | ||
180 | Variant, | ||
181 | } | ||
182 | pub fn f(_: S) { $0 } | ||
183 | pub trait Tr {} | ||
184 | impl Tr for () {} | ||
185 | pub const C: u8 = 0; | ||
186 | pub static ST: u8 = 0; | ||
187 | pub type Ty = (); | ||
188 | "#, | ||
189 | ); | ||
190 | let krate = db.test_crate(); | ||
191 | { | ||
192 | let events = db.log_executed(|| { | ||
193 | db.file_item_tree(pos.file_id.into()); | ||
194 | }); | ||
195 | let n_calculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); | ||
196 | assert_eq!(n_calculated_item_trees, 1); | ||
197 | let n_parsed_files = events.iter().filter(|it| it.contains("parse(")).count(); | ||
198 | assert_eq!(n_parsed_files, 1); | ||
199 | } | ||
200 | |||
201 | // Delete the parse tree. | ||
202 | let sweep = SweepStrategy::default().discard_values().sweep_all_revisions(); | ||
203 | base_db::ParseQuery.in_db(&db).sweep(sweep); | ||
204 | |||
205 | { | ||
206 | let events = db.log_executed(|| { | ||
207 | let crate_def_map = db.crate_def_map(krate); | ||
208 | let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); | ||
209 | assert_eq!(module_data.scope.resolutions().count(), 8); | ||
210 | assert_eq!(module_data.scope.impls().count(), 1); | ||
211 | |||
212 | for imp in module_data.scope.impls() { | ||
213 | db.impl_data(imp); | ||
214 | } | ||
215 | |||
216 | for (_, res) in module_data.scope.resolutions() { | ||
217 | match res.values.or(res.types).unwrap().0 { | ||
218 | ModuleDefId::FunctionId(f) => drop(db.function_data(f)), | ||
219 | ModuleDefId::AdtId(adt) => match adt { | ||
220 | AdtId::StructId(it) => drop(db.struct_data(it)), | ||
221 | AdtId::UnionId(it) => drop(db.union_data(it)), | ||
222 | AdtId::EnumId(it) => drop(db.enum_data(it)), | ||
223 | }, | ||
224 | ModuleDefId::ConstId(it) => drop(db.const_data(it)), | ||
225 | ModuleDefId::StaticId(it) => drop(db.static_data(it)), | ||
226 | ModuleDefId::TraitId(it) => drop(db.trait_data(it)), | ||
227 | ModuleDefId::TypeAliasId(it) => drop(db.type_alias_data(it)), | ||
228 | ModuleDefId::EnumVariantId(_) | ||
229 | | ModuleDefId::ModuleId(_) | ||
230 | | ModuleDefId::BuiltinType(_) => unreachable!(), | ||
231 | } | ||
232 | } | ||
233 | }); | ||
234 | let n_reparsed_files = events.iter().filter(|it| it.contains("parse(")).count(); | ||
235 | assert_eq!(n_reparsed_files, 0); | ||
236 | } | ||
237 | } | ||