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.rs136
-rw-r--r--crates/hir_def/src/nameres/diagnostics.rs105
-rw-r--r--crates/hir_def/src/nameres/proc_macro.rs10
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs57
-rw-r--r--crates/hir_def/src/nameres/tests/incremental.rs74
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};
18use hir_expand::{InFile, MacroCallLoc}; 18use hir_expand::{InFile, MacroCallLoc};
19use itertools::Itertools; 19use itertools::Itertools;
20use la_arena::Idx;
20use rustc_hash::{FxHashMap, FxHashSet}; 21use rustc_hash::{FxHashMap, FxHashSet};
21use syntax::ast; 22use 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
47use super::proc_macro::{ProcMacroDef, ProcMacroKind};
48
49const GLOB_RECURSION_LIMIT: usize = 100; 51const GLOB_RECURSION_LIMIT: usize = 100;
50const EXPANSION_DEPTH_LIMIT: usize = 128; 52const EXPANSION_DEPTH_LIMIT: usize = 128;
51const FIXED_POINT_LIMIT: usize = 8192; 53const 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)]
144enum ImportSource { 146enum 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
3use cfg::{CfgExpr, CfgOptions};
4use hir_expand::MacroCallKind;
5use la_arena::Idx;
6use syntax::ast;
7
8use crate::{
9 item_tree::{self, ItemTreeId},
10 nameres::LocalModuleId,
11 path::ModPath,
12 AstId,
13};
14
15#[derive(Debug, PartialEq, Eq)]
16pub 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)]
35pub struct DefDiagnostic {
36 pub in_module: LocalModuleId,
37 pub kind: DefDiagnosticKind,
38}
39
40impl 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
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/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]
29fn 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]
56fn unresolved_extern_crate() { 29fn 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 @@
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}