diff options
Diffstat (limited to 'crates/hir_def/src/nameres')
-rw-r--r-- | crates/hir_def/src/nameres/collector.rs | 37 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests.rs | 17 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/diagnostics.rs | 56 |
3 files changed, 69 insertions, 41 deletions
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index c8cd04264..1ff45d244 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -6,7 +6,7 @@ | |||
6 | use std::iter; | 6 | use std::iter; |
7 | 7 | ||
8 | use base_db::{CrateId, FileId, ProcMacroId}; | 8 | use base_db::{CrateId, FileId, ProcMacroId}; |
9 | use cfg::CfgOptions; | 9 | use cfg::{CfgExpr, CfgOptions}; |
10 | use hir_expand::InFile; | 10 | use hir_expand::InFile; |
11 | use hir_expand::{ | 11 | use hir_expand::{ |
12 | ast_id_map::FileAstId, | 12 | ast_id_map::FileAstId, |
@@ -218,15 +218,18 @@ impl DefCollector<'_> { | |||
218 | let item_tree = self.db.item_tree(file_id.into()); | 218 | let item_tree = self.db.item_tree(file_id.into()); |
219 | let module_id = self.def_map.root; | 219 | let module_id = self.def_map.root; |
220 | self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; | 220 | self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; |
221 | ModCollector { | 221 | let mut root_collector = ModCollector { |
222 | def_collector: &mut *self, | 222 | def_collector: &mut *self, |
223 | macro_depth: 0, | 223 | macro_depth: 0, |
224 | module_id, | 224 | module_id, |
225 | file_id: file_id.into(), | 225 | file_id: file_id.into(), |
226 | item_tree: &item_tree, | 226 | item_tree: &item_tree, |
227 | mod_dir: ModDir::root(), | 227 | mod_dir: ModDir::root(), |
228 | }; | ||
229 | if item_tree.top_level_attrs().cfg().map_or(true, |cfg| root_collector.is_cfg_enabled(&cfg)) | ||
230 | { | ||
231 | root_collector.collect(item_tree.top_level_items()); | ||
228 | } | 232 | } |
229 | .collect(item_tree.top_level_items()); | ||
230 | 233 | ||
231 | // main name resolution fixed-point loop. | 234 | // main name resolution fixed-point loop. |
232 | let mut i = 0; | 235 | let mut i = 0; |
@@ -900,7 +903,8 @@ impl ModCollector<'_, '_> { | |||
900 | // `#[macro_use] extern crate` is hoisted to imports macros before collecting | 903 | // `#[macro_use] extern crate` is hoisted to imports macros before collecting |
901 | // any other items. | 904 | // any other items. |
902 | for item in items { | 905 | for item in items { |
903 | if self.is_cfg_enabled(self.item_tree.attrs((*item).into())) { | 906 | let attrs = self.item_tree.attrs((*item).into()); |
907 | if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) { | ||
904 | if let ModItem::ExternCrate(id) = item { | 908 | if let ModItem::ExternCrate(id) = item { |
905 | let import = self.item_tree[*id].clone(); | 909 | let import = self.item_tree[*id].clone(); |
906 | if import.is_macro_use { | 910 | if import.is_macro_use { |
@@ -912,8 +916,11 @@ impl ModCollector<'_, '_> { | |||
912 | 916 | ||
913 | for &item in items { | 917 | for &item in items { |
914 | let attrs = self.item_tree.attrs(item.into()); | 918 | let attrs = self.item_tree.attrs(item.into()); |
915 | if !self.is_cfg_enabled(attrs) { | 919 | if let Some(cfg) = attrs.cfg() { |
916 | continue; | 920 | if !self.is_cfg_enabled(&cfg) { |
921 | self.emit_unconfigured_diagnostic(item, &cfg); | ||
922 | continue; | ||
923 | } | ||
917 | } | 924 | } |
918 | let module = | 925 | let module = |
919 | ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; | 926 | ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; |
@@ -1320,8 +1327,22 @@ impl ModCollector<'_, '_> { | |||
1320 | } | 1327 | } |
1321 | } | 1328 | } |
1322 | 1329 | ||
1323 | fn is_cfg_enabled(&self, attrs: &Attrs) -> bool { | 1330 | fn is_cfg_enabled(&self, cfg: &CfgExpr) -> bool { |
1324 | attrs.is_cfg_enabled(self.def_collector.cfg_options) | 1331 | self.def_collector.cfg_options.check(cfg) != Some(false) |
1332 | } | ||
1333 | |||
1334 | fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) { | ||
1335 | let ast_id = item.ast_id(self.item_tree); | ||
1336 | let id_map = self.def_collector.db.ast_id_map(self.file_id); | ||
1337 | let syntax_ptr = id_map.get(ast_id).syntax_node_ptr(); | ||
1338 | |||
1339 | let ast_node = InFile::new(self.file_id, syntax_ptr); | ||
1340 | self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code( | ||
1341 | self.module_id, | ||
1342 | ast_node, | ||
1343 | cfg.clone(), | ||
1344 | self.def_collector.cfg_options.clone(), | ||
1345 | )); | ||
1325 | } | 1346 | } |
1326 | } | 1347 | } |
1327 | 1348 | ||
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs index 11d84f808..9c19bf572 100644 --- a/crates/hir_def/src/nameres/tests.rs +++ b/crates/hir_def/src/nameres/tests.rs | |||
@@ -691,3 +691,20 @@ mod tr { | |||
691 | "#]], | 691 | "#]], |
692 | ); | 692 | ); |
693 | } | 693 | } |
694 | |||
695 | #[test] | ||
696 | fn cfg_the_entire_crate() { | ||
697 | check( | ||
698 | r#" | ||
699 | //- /main.rs | ||
700 | #![cfg(never)] | ||
701 | |||
702 | pub struct S; | ||
703 | pub enum E {} | ||
704 | pub fn f() {} | ||
705 | "#, | ||
706 | expect![[r#" | ||
707 | crate | ||
708 | "#]], | ||
709 | ); | ||
710 | } | ||
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs index 576b813d2..1a7b98831 100644 --- a/crates/hir_def/src/nameres/tests/diagnostics.rs +++ b/crates/hir_def/src/nameres/tests/diagnostics.rs | |||
@@ -1,42 +1,10 @@ | |||
1 | use base_db::fixture::WithFixture; | 1 | use base_db::fixture::WithFixture; |
2 | use base_db::FileId; | ||
3 | use base_db::SourceDatabaseExt; | ||
4 | use hir_expand::db::AstDatabase; | ||
5 | use rustc_hash::FxHashMap; | ||
6 | use syntax::TextRange; | ||
7 | use syntax::TextSize; | ||
8 | 2 | ||
9 | use crate::test_db::TestDB; | 3 | use crate::test_db::TestDB; |
10 | 4 | ||
11 | fn check_diagnostics(ra_fixture: &str) { | 5 | fn check_diagnostics(ra_fixture: &str) { |
12 | let db: TestDB = TestDB::with_files(ra_fixture); | 6 | let db: TestDB = TestDB::with_files(ra_fixture); |
13 | let annotations = db.extract_annotations(); | 7 | db.check_diagnostics(); |
14 | assert!(!annotations.is_empty()); | ||
15 | |||
16 | let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default(); | ||
17 | db.diagnostics(|d| { | ||
18 | let src = d.display_source(); | ||
19 | let root = db.parse_or_expand(src.file_id).unwrap(); | ||
20 | // FIXME: macros... | ||
21 | let file_id = src.file_id.original_file(&db); | ||
22 | let range = src.value.to_node(&root).text_range(); | ||
23 | let message = d.message().to_owned(); | ||
24 | actual.entry(file_id).or_default().push((range, message)); | ||
25 | }); | ||
26 | |||
27 | for (file_id, diags) in actual.iter_mut() { | ||
28 | diags.sort_by_key(|it| it.0.start()); | ||
29 | let text = db.file_text(*file_id); | ||
30 | // For multiline spans, place them on line start | ||
31 | for (range, content) in diags { | ||
32 | if text[*range].contains('\n') { | ||
33 | *range = TextRange::new(range.start(), range.start() + TextSize::from(1)); | ||
34 | *content = format!("... {}", content); | ||
35 | } | ||
36 | } | ||
37 | } | ||
38 | |||
39 | assert_eq!(annotations, actual); | ||
40 | } | 8 | } |
41 | 9 | ||
42 | #[test] | 10 | #[test] |
@@ -129,3 +97,25 @@ fn unresolved_module() { | |||
129 | ", | 97 | ", |
130 | ); | 98 | ); |
131 | } | 99 | } |
100 | |||
101 | #[test] | ||
102 | fn inactive_item() { | ||
103 | // Additional tests in `cfg` crate. This only tests disabled cfgs. | ||
104 | |||
105 | check_diagnostics( | ||
106 | r#" | ||
107 | //- /lib.rs | ||
108 | #[cfg(no)] pub fn f() {} | ||
109 | //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled | ||
110 | |||
111 | #[cfg(no)] #[cfg(no2)] mod m; | ||
112 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no and no2 are disabled | ||
113 | |||
114 | #[cfg(all(not(a), b))] enum E {} | ||
115 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: b is disabled | ||
116 | |||
117 | #[cfg(feature = "std")] use std; | ||
118 | //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled | ||
119 | "#, | ||
120 | ); | ||
121 | } | ||