aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/nameres
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/nameres')
-rw-r--r--crates/hir_def/src/nameres/collector.rs57
-rw-r--r--crates/hir_def/src/nameres/diagnostics.rs9
-rw-r--r--crates/hir_def/src/nameres/proc_macro.rs10
-rw-r--r--crates/hir_def/src/nameres/tests/incremental.rs74
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
21impl 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
21impl Attrs { 31impl 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 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use base_db::SourceDatabaseExt; 3use base_db::{salsa::SweepStrategy, SourceDatabaseExt};
4
5use crate::{AdtId, ModuleDefId};
4 6
5use super::*; 7use 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]
170fn 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#"
177pub struct S;
178pub union U {}
179pub enum E {
180 Variant,
181}
182pub fn f(_: S) { $0 }
183pub trait Tr {}
184impl Tr for () {}
185pub const C: u8 = 0;
186pub static ST: u8 = 0;
187pub 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}