diff options
author | Jonas Schievink <[email protected]> | 2020-09-16 16:26:16 +0100 |
---|---|---|
committer | Jonas Schievink <[email protected]> | 2020-09-16 16:26:51 +0100 |
commit | f792bc7ddd2616c0bb1fcdffda204151fc40b3d6 (patch) | |
tree | 247c78b6b4792a55fa638edafdc97d262fab6124 /crates/hir_def | |
parent | 603613a3028d7d385195f03f626ce00e1968191e (diff) |
Add annotation-based nameres diagnostic tests
Diffstat (limited to 'crates/hir_def')
-rw-r--r-- | crates/hir_def/src/nameres/tests.rs | 1 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/diagnostics.rs | 107 | ||||
-rw-r--r-- | crates/hir_def/src/nameres/tests/mod_resolution.rs | 38 | ||||
-rw-r--r-- | crates/hir_def/src/test_db.rs | 42 |
4 files changed, 150 insertions, 38 deletions
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs index 5ca30dac9..11d84f808 100644 --- a/crates/hir_def/src/nameres/tests.rs +++ b/crates/hir_def/src/nameres/tests.rs | |||
@@ -2,6 +2,7 @@ mod globs; | |||
2 | mod incremental; | 2 | mod incremental; |
3 | mod macros; | 3 | mod macros; |
4 | mod mod_resolution; | 4 | mod mod_resolution; |
5 | mod diagnostics; | ||
5 | mod primitives; | 6 | mod primitives; |
6 | 7 | ||
7 | use std::sync::Arc; | 8 | use std::sync::Arc; |
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs new file mode 100644 index 000000000..cd0eb1a4b --- /dev/null +++ b/crates/hir_def/src/nameres/tests/diagnostics.rs | |||
@@ -0,0 +1,107 @@ | |||
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 | |||
9 | use crate::test_db::TestDB; | ||
10 | |||
11 | fn check_diagnostics(ra_fixture: &str) { | ||
12 | let db: TestDB = TestDB::with_files(ra_fixture); | ||
13 | let annotations = db.extract_annotations(); | ||
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 | } | ||
41 | |||
42 | #[test] | ||
43 | fn unresolved_import() { | ||
44 | check_diagnostics( | ||
45 | r" | ||
46 | use does_exist; | ||
47 | use does_not_exist; | ||
48 | //^^^^^^^^^^^^^^ unresolved import | ||
49 | |||
50 | mod does_exist {} | ||
51 | ", | ||
52 | ); | ||
53 | } | ||
54 | |||
55 | #[test] | ||
56 | fn unresolved_import_in_use_tree() { | ||
57 | // Only the relevant part of a nested `use` item should be highlighted. | ||
58 | check_diagnostics( | ||
59 | r" | ||
60 | use does_exist::{Exists, DoesntExist}; | ||
61 | //^^^^^^^^^^^ unresolved import | ||
62 | |||
63 | use {does_not_exist::*, does_exist}; | ||
64 | //^^^^^^^^^^^^^^^^^ unresolved import | ||
65 | |||
66 | use does_not_exist::{ | ||
67 | a, | ||
68 | //^ unresolved import | ||
69 | b, | ||
70 | //^ unresolved import | ||
71 | c, | ||
72 | //^ unresolved import | ||
73 | }; | ||
74 | |||
75 | mod does_exist { | ||
76 | pub struct Exists; | ||
77 | } | ||
78 | ", | ||
79 | ); | ||
80 | } | ||
81 | |||
82 | #[test] | ||
83 | fn unresolved_extern_crate() { | ||
84 | check_diagnostics( | ||
85 | r" | ||
86 | //- /main.rs crate:main deps:core | ||
87 | extern crate core; | ||
88 | extern crate doesnotexist; | ||
89 | //^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate | ||
90 | //- /lib.rs crate:core | ||
91 | ", | ||
92 | ); | ||
93 | } | ||
94 | |||
95 | #[test] | ||
96 | fn unresolved_module() { | ||
97 | check_diagnostics( | ||
98 | r" | ||
99 | //- /lib.rs | ||
100 | mod foo; | ||
101 | mod bar; | ||
102 | //^^^^^^^^ unresolved module | ||
103 | mod baz {} | ||
104 | //- /foo.rs | ||
105 | ", | ||
106 | ); | ||
107 | } | ||
diff --git a/crates/hir_def/src/nameres/tests/mod_resolution.rs b/crates/hir_def/src/nameres/tests/mod_resolution.rs index 3b9f79544..f93337a6e 100644 --- a/crates/hir_def/src/nameres/tests/mod_resolution.rs +++ b/crates/hir_def/src/nameres/tests/mod_resolution.rs | |||
@@ -672,44 +672,6 @@ pub struct Baz; | |||
672 | } | 672 | } |
673 | 673 | ||
674 | #[test] | 674 | #[test] |
675 | fn unresolved_module_diagnostics() { | ||
676 | let db = TestDB::with_files( | ||
677 | r" | ||
678 | //- /lib.rs | ||
679 | mod foo; | ||
680 | mod bar; | ||
681 | mod baz {} | ||
682 | //- /foo.rs | ||
683 | ", | ||
684 | ); | ||
685 | let krate = db.test_crate(); | ||
686 | |||
687 | let crate_def_map = db.crate_def_map(krate); | ||
688 | |||
689 | expect![[r#" | ||
690 | [ | ||
691 | DefDiagnostic { | ||
692 | in_module: Idx::<ModuleData>(0), | ||
693 | kind: UnresolvedModule { | ||
694 | declaration: InFile { | ||
695 | file_id: HirFileId( | ||
696 | FileId( | ||
697 | FileId( | ||
698 | 0, | ||
699 | ), | ||
700 | ), | ||
701 | ), | ||
702 | value: FileAstId::<syntax::ast::generated::nodes::Module>(1), | ||
703 | }, | ||
704 | candidate: "bar.rs", | ||
705 | }, | ||
706 | }, | ||
707 | ] | ||
708 | "#]] | ||
709 | .assert_debug_eq(&crate_def_map.diagnostics); | ||
710 | } | ||
711 | |||
712 | #[test] | ||
713 | fn module_resolution_decl_inside_module_in_non_crate_root_2() { | 675 | fn module_resolution_decl_inside_module_in_non_crate_root_2() { |
714 | check( | 676 | check( |
715 | r#" | 677 | r#" |
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs index 42a762936..fb1d3c974 100644 --- a/crates/hir_def/src/test_db.rs +++ b/crates/hir_def/src/test_db.rs | |||
@@ -5,9 +5,15 @@ use std::{ | |||
5 | sync::{Arc, Mutex}, | 5 | sync::{Arc, Mutex}, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use base_db::SourceDatabase; | ||
8 | use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast}; | 9 | use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast}; |
9 | use hir_expand::db::AstDatabase; | 10 | use hir_expand::db::AstDatabase; |
11 | use hir_expand::diagnostics::Diagnostic; | ||
12 | use hir_expand::diagnostics::DiagnosticSinkBuilder; | ||
13 | use rustc_hash::FxHashMap; | ||
10 | use rustc_hash::FxHashSet; | 14 | use rustc_hash::FxHashSet; |
15 | use syntax::TextRange; | ||
16 | use test_utils::extract_annotations; | ||
11 | 17 | ||
12 | use crate::db::DefDatabase; | 18 | use crate::db::DefDatabase; |
13 | 19 | ||
@@ -98,4 +104,40 @@ impl TestDB { | |||
98 | }) | 104 | }) |
99 | .collect() | 105 | .collect() |
100 | } | 106 | } |
107 | |||
108 | pub fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> { | ||
109 | let mut files = Vec::new(); | ||
110 | let crate_graph = self.crate_graph(); | ||
111 | for krate in crate_graph.iter() { | ||
112 | let crate_def_map = self.crate_def_map(krate); | ||
113 | for (module_id, _) in crate_def_map.modules.iter() { | ||
114 | let file_id = crate_def_map[module_id].origin.file_id(); | ||
115 | files.extend(file_id) | ||
116 | } | ||
117 | } | ||
118 | assert!(!files.is_empty()); | ||
119 | files | ||
120 | .into_iter() | ||
121 | .filter_map(|file_id| { | ||
122 | let text = self.file_text(file_id); | ||
123 | let annotations = extract_annotations(&text); | ||
124 | if annotations.is_empty() { | ||
125 | return None; | ||
126 | } | ||
127 | Some((file_id, annotations)) | ||
128 | }) | ||
129 | .collect() | ||
130 | } | ||
131 | |||
132 | pub fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) { | ||
133 | let crate_graph = self.crate_graph(); | ||
134 | for krate in crate_graph.iter() { | ||
135 | let crate_def_map = self.crate_def_map(krate); | ||
136 | |||
137 | let mut sink = DiagnosticSinkBuilder::new().build(&mut cb); | ||
138 | for (module_id, _) in crate_def_map.modules.iter() { | ||
139 | crate_def_map.add_diagnostics(self, module_id, &mut sink); | ||
140 | } | ||
141 | } | ||
142 | } | ||
101 | } | 143 | } |