diff options
Diffstat (limited to 'crates/hir_def/src/nameres')
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 136 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/diagnostics.rs | 105 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/proc_macro.rs | 10 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/diagnostics.rs | 57 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/incremental.rs | 74 |
5 files changed, 286 insertions, 96 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index 014ea4de4..7f9fdb379 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -17,6 +17,7 @@ use hir_expand::{ | |||
17 | }; | 17 | }; |
18 | use hir_expand::{InFile, MacroCallLoc}; | 18 | use hir_expand::{InFile, MacroCallLoc}; |
19 | use itertools::Itertools; | 19 | use itertools::Itertools; |
20 | use la_arena::Idx; | ||
20 | use rustc_hash::{FxHashMap, FxHashSet}; | 21 | use rustc_hash::{FxHashMap, FxHashSet}; |
21 | use syntax::ast; | 22 | use syntax::ast; |
22 | 23 | ||
@@ -33,7 +34,10 @@ use crate::{ | |||
33 | }, | 34 | }, |
34 | macro_call_as_call_id, | 35 | macro_call_as_call_id, |
35 | nameres::{ | 36 | nameres::{ |
36 | diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, | 37 | diagnostics::DefDiagnostic, |
38 | mod_resolution::ModDir, | ||
39 | path_resolution::ReachedFixedPoint, | ||
40 | proc_macro::{ProcMacroDef, ProcMacroKind}, | ||
37 | BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode, | 41 | BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode, |
38 | }, | 42 | }, |
39 | path::{ImportAlias, ModPath, PathKind}, | 43 | path::{ImportAlias, ModPath, PathKind}, |
@@ -44,8 +48,6 @@ use crate::{ | |||
44 | UnresolvedMacro, | 48 | UnresolvedMacro, |
45 | }; | 49 | }; |
46 | 50 | ||
47 | use super::proc_macro::{ProcMacroDef, ProcMacroKind}; | ||
48 | |||
49 | const GLOB_RECURSION_LIMIT: usize = 100; | 51 | const GLOB_RECURSION_LIMIT: usize = 100; |
50 | const EXPANSION_DEPTH_LIMIT: usize = 128; | 52 | const EXPANSION_DEPTH_LIMIT: usize = 128; |
51 | const FIXED_POINT_LIMIT: usize = 8192; | 53 | const FIXED_POINT_LIMIT: usize = 8192; |
@@ -142,7 +144,7 @@ impl PartialResolvedImport { | |||
142 | 144 | ||
143 | #[derive(Clone, Debug, Eq, PartialEq)] | 145 | #[derive(Clone, Debug, Eq, PartialEq)] |
144 | enum ImportSource { | 146 | enum ImportSource { |
145 | Import(ItemTreeId<item_tree::Import>), | 147 | Import { id: ItemTreeId<item_tree::Import>, use_tree: Idx<ast::UseTree> }, |
146 | ExternCrate(ItemTreeId<item_tree::ExternCrate>), | 148 | ExternCrate(ItemTreeId<item_tree::ExternCrate>), |
147 | } | 149 | } |
148 | 150 | ||
@@ -164,20 +166,26 @@ impl Import { | |||
164 | krate: CrateId, | 166 | krate: CrateId, |
165 | tree: &ItemTree, | 167 | tree: &ItemTree, |
166 | id: ItemTreeId<item_tree::Import>, | 168 | id: ItemTreeId<item_tree::Import>, |
167 | ) -> Self { | 169 | ) -> Vec<Self> { |
168 | let it = &tree[id.value]; | 170 | let it = &tree[id.value]; |
169 | let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into()); | 171 | let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into()); |
170 | let visibility = &tree[it.visibility]; | 172 | let visibility = &tree[it.visibility]; |
171 | Self { | 173 | let is_prelude = attrs.by_key("prelude_import").exists(); |
172 | path: it.path.clone(), | 174 | |
173 | alias: it.alias.clone(), | 175 | let mut res = Vec::new(); |
174 | visibility: visibility.clone(), | 176 | it.use_tree.expand(|idx, path, is_glob, alias| { |
175 | is_glob: it.is_glob, | 177 | res.push(Self { |
176 | is_prelude: attrs.by_key("prelude_import").exists(), | 178 | path: Interned::new(path), // FIXME this makes little sense |
177 | is_extern_crate: false, | 179 | alias, |
178 | is_macro_use: false, | 180 | visibility: visibility.clone(), |
179 | source: ImportSource::Import(id), | 181 | is_glob, |
180 | } | 182 | is_prelude, |
183 | is_extern_crate: false, | ||
184 | is_macro_use: false, | ||
185 | source: ImportSource::Import { id, use_tree: idx }, | ||
186 | }); | ||
187 | }); | ||
188 | res | ||
181 | } | 189 | } |
182 | 190 | ||
183 | fn from_extern_crate( | 191 | fn from_extern_crate( |
@@ -285,7 +293,7 @@ impl DefCollector<'_> { | |||
285 | let registered_name = if *attr_name == hir_expand::name![register_attr] | 293 | let registered_name = if *attr_name == hir_expand::name![register_attr] |
286 | || *attr_name == hir_expand::name![register_tool] | 294 | || *attr_name == hir_expand::name![register_tool] |
287 | { | 295 | { |
288 | match &attr.input { | 296 | match attr.input.as_deref() { |
289 | Some(AttrInput::TokenTree(subtree)) => match &*subtree.token_trees { | 297 | Some(AttrInput::TokenTree(subtree)) => match &*subtree.token_trees { |
290 | [tt::TokenTree::Leaf(tt::Leaf::Ident(name))] => name.as_name(), | 298 | [tt::TokenTree::Leaf(tt::Leaf::Ident(name))] => name.as_name(), |
291 | _ => continue, | 299 | _ => continue, |
@@ -343,7 +351,7 @@ impl DefCollector<'_> { | |||
343 | let mut i = 0; | 351 | let mut i = 0; |
344 | 'outer: loop { | 352 | 'outer: loop { |
345 | loop { | 353 | loop { |
346 | self.db.check_canceled(); | 354 | self.db.unwind_if_cancelled(); |
347 | loop { | 355 | loop { |
348 | if self.resolve_imports() == ReachedFixedPoint::Yes { | 356 | if self.resolve_imports() == ReachedFixedPoint::Yes { |
349 | break; | 357 | break; |
@@ -469,16 +477,21 @@ impl DefCollector<'_> { | |||
469 | /// 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 |
470 | /// 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. |
471 | 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(); | ||
472 | self.exports_proc_macros = true; | 481 | self.exports_proc_macros = true; |
473 | 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) { |
474 | Some((_, expander)) => MacroDefId { | 483 | Some((_, expander)) => MacroDefId { |
475 | krate: self.def_map.krate, | 484 | krate: self.def_map.krate, |
476 | kind: MacroDefKind::ProcMacro(*expander, ast_id), | 485 | kind: MacroDefKind::ProcMacro(*expander, kind, ast_id), |
477 | local_inner: false, | 486 | local_inner: false, |
478 | }, | 487 | }, |
479 | None => MacroDefId { | 488 | None => MacroDefId { |
480 | krate: self.def_map.krate, | 489 | krate: self.def_map.krate, |
481 | 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 | ), | ||
482 | local_inner: false, | 495 | local_inner: false, |
483 | }, | 496 | }, |
484 | }; | 497 | }; |
@@ -823,7 +836,7 @@ impl DefCollector<'_> { | |||
823 | vis: Visibility, | 836 | vis: Visibility, |
824 | import_type: ImportType, | 837 | import_type: ImportType, |
825 | ) { | 838 | ) { |
826 | self.db.check_canceled(); | 839 | self.db.unwind_if_cancelled(); |
827 | self.update_recursive(module_id, resolutions, vis, import_type, 0) | 840 | self.update_recursive(module_id, resolutions, vis, import_type, 0) |
828 | } | 841 | } |
829 | 842 | ||
@@ -1129,11 +1142,8 @@ impl DefCollector<'_> { | |||
1129 | } | 1142 | } |
1130 | 1143 | ||
1131 | for directive in &self.unresolved_imports { | 1144 | for directive in &self.unresolved_imports { |
1132 | if let ImportSource::Import(import) = &directive.import.source { | 1145 | if let ImportSource::Import { id: import, use_tree } = &directive.import.source { |
1133 | let item_tree = import.item_tree(self.db); | 1146 | match (directive.import.path.segments().first(), &directive.import.path.kind) { |
1134 | let import_data = &item_tree[import.value]; | ||
1135 | |||
1136 | match (import_data.path.segments().first(), &import_data.path.kind) { | ||
1137 | (Some(krate), PathKind::Plain) | (Some(krate), PathKind::Abs) => { | 1147 | (Some(krate), PathKind::Plain) | (Some(krate), PathKind::Abs) => { |
1138 | if diagnosed_extern_crates.contains(krate) { | 1148 | if diagnosed_extern_crates.contains(krate) { |
1139 | continue; | 1149 | continue; |
@@ -1144,8 +1154,8 @@ impl DefCollector<'_> { | |||
1144 | 1154 | ||
1145 | self.def_map.diagnostics.push(DefDiagnostic::unresolved_import( | 1155 | self.def_map.diagnostics.push(DefDiagnostic::unresolved_import( |
1146 | directive.module_id, | 1156 | directive.module_id, |
1147 | InFile::new(import.file_id(), import_data.ast_id), | 1157 | *import, |
1148 | import_data.index, | 1158 | *use_tree, |
1149 | )); | 1159 | )); |
1150 | } | 1160 | } |
1151 | } | 1161 | } |
@@ -1221,16 +1231,20 @@ impl ModCollector<'_, '_> { | |||
1221 | match item { | 1231 | match item { |
1222 | ModItem::Mod(m) => self.collect_module(&self.item_tree[m], &attrs), | 1232 | ModItem::Mod(m) => self.collect_module(&self.item_tree[m], &attrs), |
1223 | ModItem::Import(import_id) => { | 1233 | ModItem::Import(import_id) => { |
1224 | self.def_collector.unresolved_imports.push(ImportDirective { | 1234 | let module_id = self.module_id; |
1225 | module_id: self.module_id, | 1235 | let imports = Import::from_use( |
1226 | import: Import::from_use( | 1236 | self.def_collector.db, |
1227 | self.def_collector.db, | 1237 | krate, |
1228 | krate, | 1238 | &self.item_tree, |
1229 | &self.item_tree, | 1239 | ItemTreeId::new(self.file_id, import_id), |
1230 | ItemTreeId::new(self.file_id, import_id), | 1240 | ); |
1231 | ), | 1241 | self.def_collector.unresolved_imports.extend(imports.into_iter().map( |
1232 | status: PartialResolvedImport::Unresolved, | 1242 | |import| ImportDirective { |
1233 | }) | 1243 | module_id, |
1244 | import, | ||
1245 | status: PartialResolvedImport::Unresolved, | ||
1246 | }, | ||
1247 | )); | ||
1234 | } | 1248 | } |
1235 | ModItem::ExternCrate(import_id) => { | 1249 | ModItem::ExternCrate(import_id) => { |
1236 | self.def_collector.unresolved_imports.push(ImportDirective { | 1250 | self.def_collector.unresolved_imports.push(ImportDirective { |
@@ -1665,14 +1679,22 @@ impl ModCollector<'_, '_> { | |||
1665 | None => &mac.name, | 1679 | None => &mac.name, |
1666 | }; | 1680 | }; |
1667 | let krate = self.def_collector.def_map.krate; | 1681 | let krate = self.def_collector.def_map.krate; |
1668 | if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) { | 1682 | match find_builtin_macro(name, krate, ast_id) { |
1669 | self.def_collector.define_macro_rules( | 1683 | Some(macro_id) => { |
1670 | self.module_id, | 1684 | self.def_collector.define_macro_rules( |
1671 | mac.name.clone(), | 1685 | self.module_id, |
1672 | macro_id, | 1686 | mac.name.clone(), |
1673 | is_export, | 1687 | macro_id, |
1674 | ); | 1688 | is_export, |
1675 | 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 | } | ||
1676 | } | 1698 | } |
1677 | } | 1699 | } |
1678 | 1700 | ||
@@ -1701,15 +1723,23 @@ impl ModCollector<'_, '_> { | |||
1701 | let macro_id = find_builtin_macro(&mac.name, krate, ast_id) | 1723 | let macro_id = find_builtin_macro(&mac.name, krate, ast_id) |
1702 | .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)); | 1724 | .or_else(|| find_builtin_derive(&mac.name, krate, ast_id)); |
1703 | 1725 | ||
1704 | if let Some(macro_id) = macro_id { | 1726 | match macro_id { |
1705 | self.def_collector.define_macro_def( | 1727 | Some(macro_id) => { |
1706 | self.module_id, | 1728 | self.def_collector.define_macro_def( |
1707 | mac.name.clone(), | 1729 | self.module_id, |
1708 | macro_id, | 1730 | mac.name.clone(), |
1709 | &self.item_tree[mac.visibility], | 1731 | macro_id, |
1710 | ); | 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 | } | ||
1711 | } | 1742 | } |
1712 | return; | ||
1713 | } | 1743 | } |
1714 | 1744 | ||
1715 | // 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 new file mode 100644 index 000000000..95061f601 --- /dev/null +++ b/crates/hir_def/src/nameres/diagnostics.rs | |||
@@ -0,0 +1,105 @@ | |||
1 | //! Diagnostics emitted during DefMap construction. | ||
2 | |||
3 | use cfg::{CfgExpr, CfgOptions}; | ||
4 | use hir_expand::MacroCallKind; | ||
5 | use la_arena::Idx; | ||
6 | use syntax::ast; | ||
7 | |||
8 | use crate::{ | ||
9 | item_tree::{self, ItemTreeId}, | ||
10 | nameres::LocalModuleId, | ||
11 | path::ModPath, | ||
12 | AstId, | ||
13 | }; | ||
14 | |||
15 | #[derive(Debug, PartialEq, Eq)] | ||
16 | pub enum DefDiagnosticKind { | ||
17 | UnresolvedModule { ast: AstId<ast::Module>, candidate: String }, | ||
18 | |||
19 | UnresolvedExternCrate { ast: AstId<ast::ExternCrate> }, | ||
20 | |||
21 | UnresolvedImport { id: ItemTreeId<item_tree::Import>, index: Idx<ast::UseTree> }, | ||
22 | |||
23 | UnconfiguredCode { ast: AstId<ast::Item>, cfg: CfgExpr, opts: CfgOptions }, | ||
24 | |||
25 | UnresolvedProcMacro { ast: MacroCallKind }, | ||
26 | |||
27 | UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath }, | ||
28 | |||
29 | MacroError { ast: MacroCallKind, message: String }, | ||
30 | |||
31 | UnimplementedBuiltinMacro { ast: AstId<ast::Macro> }, | ||
32 | } | ||
33 | |||
34 | #[derive(Debug, PartialEq, Eq)] | ||
35 | pub struct DefDiagnostic { | ||
36 | pub in_module: LocalModuleId, | ||
37 | pub kind: DefDiagnosticKind, | ||
38 | } | ||
39 | |||
40 | impl DefDiagnostic { | ||
41 | pub(super) fn unresolved_module( | ||
42 | container: LocalModuleId, | ||
43 | declaration: AstId<ast::Module>, | ||
44 | candidate: String, | ||
45 | ) -> Self { | ||
46 | Self { | ||
47 | in_module: container, | ||
48 | kind: DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate }, | ||
49 | } | ||
50 | } | ||
51 | |||
52 | pub(super) fn unresolved_extern_crate( | ||
53 | container: LocalModuleId, | ||
54 | declaration: AstId<ast::ExternCrate>, | ||
55 | ) -> Self { | ||
56 | Self { | ||
57 | in_module: container, | ||
58 | kind: DefDiagnosticKind::UnresolvedExternCrate { ast: declaration }, | ||
59 | } | ||
60 | } | ||
61 | |||
62 | pub(super) fn unresolved_import( | ||
63 | container: LocalModuleId, | ||
64 | id: ItemTreeId<item_tree::Import>, | ||
65 | index: Idx<ast::UseTree>, | ||
66 | ) -> Self { | ||
67 | Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } } | ||
68 | } | ||
69 | |||
70 | pub(super) fn unconfigured_code( | ||
71 | container: LocalModuleId, | ||
72 | ast: AstId<ast::Item>, | ||
73 | cfg: CfgExpr, | ||
74 | opts: CfgOptions, | ||
75 | ) -> Self { | ||
76 | Self { in_module: container, kind: DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } } | ||
77 | } | ||
78 | |||
79 | pub(super) fn unresolved_proc_macro(container: LocalModuleId, ast: MacroCallKind) -> Self { | ||
80 | Self { in_module: container, kind: DefDiagnosticKind::UnresolvedProcMacro { ast } } | ||
81 | } | ||
82 | |||
83 | pub(super) fn macro_error( | ||
84 | container: LocalModuleId, | ||
85 | ast: MacroCallKind, | ||
86 | message: String, | ||
87 | ) -> Self { | ||
88 | Self { in_module: container, kind: DefDiagnosticKind::MacroError { ast, message } } | ||
89 | } | ||
90 | |||
91 | pub(super) fn unresolved_macro_call( | ||
92 | container: LocalModuleId, | ||
93 | ast: AstId<ast::MacroCall>, | ||
94 | path: ModPath, | ||
95 | ) -> Self { | ||
96 | Self { in_module: container, kind: DefDiagnosticKind::UnresolvedMacroCall { ast, path } } | ||
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 | } | ||
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/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs index 75147d973..ec6670952 100644 --- a/crates/hir_def/src/nameres/tests/diagnostics.rs +++ b/crates/hir_def/src/nameres/tests/diagnostics.rs | |||
@@ -18,7 +18,7 @@ fn unresolved_import() { | |||
18 | r" | 18 | r" |
19 | use does_exist; | 19 | use does_exist; |
20 | use does_not_exist; | 20 | use does_not_exist; |
21 | //^^^^^^^^^^^^^^ unresolved import | 21 | //^^^^^^^^^^^^^^^^^^^ UnresolvedImport |
22 | 22 | ||
23 | mod does_exist {} | 23 | mod does_exist {} |
24 | ", | 24 | ", |
@@ -26,40 +26,13 @@ fn unresolved_import() { | |||
26 | } | 26 | } |
27 | 27 | ||
28 | #[test] | 28 | #[test] |
29 | fn unresolved_import_in_use_tree() { | ||
30 | // Only the relevant part of a nested `use` item should be highlighted. | ||
31 | check_diagnostics( | ||
32 | r" | ||
33 | use does_exist::{Exists, DoesntExist}; | ||
34 | //^^^^^^^^^^^ unresolved import | ||
35 | |||
36 | use {does_not_exist::*, does_exist}; | ||
37 | //^^^^^^^^^^^^^^^^^ unresolved import | ||
38 | |||
39 | use does_not_exist::{ | ||
40 | a, | ||
41 | //^ unresolved import | ||
42 | b, | ||
43 | //^ unresolved import | ||
44 | c, | ||
45 | //^ unresolved import | ||
46 | }; | ||
47 | |||
48 | mod does_exist { | ||
49 | pub struct Exists; | ||
50 | } | ||
51 | ", | ||
52 | ); | ||
53 | } | ||
54 | |||
55 | #[test] | ||
56 | fn unresolved_extern_crate() { | 29 | fn unresolved_extern_crate() { |
57 | check_diagnostics( | 30 | check_diagnostics( |
58 | r" | 31 | r" |
59 | //- /main.rs crate:main deps:core | 32 | //- /main.rs crate:main deps:core |
60 | extern crate core; | 33 | extern crate core; |
61 | extern crate doesnotexist; | 34 | extern crate doesnotexist; |
62 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate | 35 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedExternCrate |
63 | //- /lib.rs crate:core | 36 | //- /lib.rs crate:core |
64 | ", | 37 | ", |
65 | ); | 38 | ); |
@@ -72,7 +45,7 @@ fn extern_crate_self_as() { | |||
72 | r" | 45 | r" |
73 | //- /lib.rs | 46 | //- /lib.rs |
74 | extern crate doesnotexist; | 47 | extern crate doesnotexist; |
75 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate | 48 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedExternCrate |
76 | // Should not error. | 49 | // Should not error. |
77 | extern crate self as foo; | 50 | extern crate self as foo; |
78 | struct Foo; | 51 | struct Foo; |
@@ -88,18 +61,18 @@ fn dedup_unresolved_import_from_unresolved_crate() { | |||
88 | //- /main.rs crate:main | 61 | //- /main.rs crate:main |
89 | mod a { | 62 | mod a { |
90 | extern crate doesnotexist; | 63 | extern crate doesnotexist; |
91 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate | 64 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedExternCrate |
92 | 65 | ||
93 | // Should not error, since we already errored for the missing crate. | 66 | // Should not error, since we already errored for the missing crate. |
94 | use doesnotexist::{self, bla, *}; | 67 | use doesnotexist::{self, bla, *}; |
95 | 68 | ||
96 | use crate::doesnotexist; | 69 | use crate::doesnotexist; |
97 | //^^^^^^^^^^^^^^^^^^^ unresolved import | 70 | //^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedImport |
98 | } | 71 | } |
99 | 72 | ||
100 | mod m { | 73 | mod m { |
101 | use super::doesnotexist; | 74 | use super::doesnotexist; |
102 | //^^^^^^^^^^^^^^^^^^^ unresolved import | 75 | //^^^^^^^^^^^^^^^^^^^^^^^^ UnresolvedImport |
103 | } | 76 | } |
104 | ", | 77 | ", |
105 | ); | 78 | ); |
@@ -112,7 +85,7 @@ fn unresolved_module() { | |||
112 | //- /lib.rs | 85 | //- /lib.rs |
113 | mod foo; | 86 | mod foo; |
114 | mod bar; | 87 | mod bar; |
115 | //^^^^^^^^ unresolved module | 88 | //^^^^^^^^ UnresolvedModule |
116 | mod baz {} | 89 | mod baz {} |
117 | //- /foo.rs | 90 | //- /foo.rs |
118 | ", | 91 | ", |
@@ -127,16 +100,16 @@ fn inactive_item() { | |||
127 | r#" | 100 | r#" |
128 | //- /lib.rs | 101 | //- /lib.rs |
129 | #[cfg(no)] pub fn f() {} | 102 | #[cfg(no)] pub fn f() {} |
130 | //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | 103 | //^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode |
131 | 104 | ||
132 | #[cfg(no)] #[cfg(no2)] mod m; | 105 | #[cfg(no)] #[cfg(no2)] mod m; |
133 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no and no2 are disabled | 106 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode |
134 | 107 | ||
135 | #[cfg(all(not(a), b))] enum E {} | 108 | #[cfg(all(not(a), b))] enum E {} |
136 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: b is disabled | 109 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode |
137 | 110 | ||
138 | #[cfg(feature = "std")] use std; | 111 | #[cfg(feature = "std")] use std; |
139 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled | 112 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode |
140 | "#, | 113 | "#, |
141 | ); | 114 | ); |
142 | } | 115 | } |
@@ -149,14 +122,14 @@ fn inactive_via_cfg_attr() { | |||
149 | r#" | 122 | r#" |
150 | //- /lib.rs | 123 | //- /lib.rs |
151 | #[cfg_attr(not(never), cfg(no))] fn f() {} | 124 | #[cfg_attr(not(never), cfg(no))] fn f() {} |
152 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | 125 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode |
153 | 126 | ||
154 | #[cfg_attr(not(never), cfg(not(no)))] fn f() {} | 127 | #[cfg_attr(not(never), cfg(not(no)))] fn f() {} |
155 | 128 | ||
156 | #[cfg_attr(never, cfg(no))] fn g() {} | 129 | #[cfg_attr(never, cfg(no))] fn g() {} |
157 | 130 | ||
158 | #[cfg_attr(not(never), inline, cfg(no))] fn h() {} | 131 | #[cfg_attr(not(never), inline, cfg(no))] fn h() {} |
159 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | 132 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode |
160 | "#, | 133 | "#, |
161 | ); | 134 | ); |
162 | } | 135 | } |
@@ -170,7 +143,7 @@ fn unresolved_legacy_scope_macro() { | |||
170 | 143 | ||
171 | m!(); | 144 | m!(); |
172 | m2!(); | 145 | m2!(); |
173 | //^^^^^^ unresolved macro `self::m2!` | 146 | //^^^^^^ UnresolvedMacroCall |
174 | "#, | 147 | "#, |
175 | ); | 148 | ); |
176 | } | 149 | } |
@@ -187,7 +160,7 @@ fn unresolved_module_scope_macro() { | |||
187 | 160 | ||
188 | self::m!(); | 161 | self::m!(); |
189 | self::m2!(); | 162 | self::m2!(); |
190 | //^^^^^^^^^^^^ unresolved macro `self::m2!` | 163 | //^^^^^^^^^^^^ UnresolvedMacroCall |
191 | "#, | 164 | "#, |
192 | ); | 165 | ); |
193 | } | 166 | } |
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 | } | ||