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.rs37
-rw-r--r--crates/hir_def/src/nameres/tests.rs17
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs56
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 @@
6use std::iter; 6use std::iter;
7 7
8use base_db::{CrateId, FileId, ProcMacroId}; 8use base_db::{CrateId, FileId, ProcMacroId};
9use cfg::CfgOptions; 9use cfg::{CfgExpr, CfgOptions};
10use hir_expand::InFile; 10use hir_expand::InFile;
11use hir_expand::{ 11use 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]
696fn cfg_the_entire_crate() {
697 check(
698 r#"
699//- /main.rs
700#![cfg(never)]
701
702pub struct S;
703pub enum E {}
704pub 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 @@
1use base_db::fixture::WithFixture; 1use base_db::fixture::WithFixture;
2use base_db::FileId;
3use base_db::SourceDatabaseExt;
4use hir_expand::db::AstDatabase;
5use rustc_hash::FxHashMap;
6use syntax::TextRange;
7use syntax::TextSize;
8 2
9use crate::test_db::TestDB; 3use crate::test_db::TestDB;
10 4
11fn check_diagnostics(ra_fixture: &str) { 5fn 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]
102fn 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}