aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src')
-rw-r--r--crates/hir_def/src/body/tests.rs149
-rw-r--r--crates/hir_def/src/nameres/tests.rs1
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs118
-rw-r--r--crates/hir_def/src/test_db.rs152
4 files changed, 9 insertions, 411 deletions
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index d4fae05a6..27d837d47 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -3,7 +3,7 @@ mod block;
3use base_db::{fixture::WithFixture, SourceDatabase}; 3use base_db::{fixture::WithFixture, SourceDatabase};
4use expect_test::Expect; 4use expect_test::Expect;
5 5
6use crate::{test_db::TestDB, ModuleDefId}; 6use crate::ModuleDefId;
7 7
8use super::*; 8use super::*;
9 9
@@ -28,11 +28,6 @@ fn lower(ra_fixture: &str) -> Arc<Body> {
28 db.body(fn_def.unwrap().into()) 28 db.body(fn_def.unwrap().into())
29} 29}
30 30
31fn check_diagnostics(ra_fixture: &str) {
32 let db: TestDB = TestDB::with_files(ra_fixture);
33 db.check_diagnostics();
34}
35
36fn block_def_map_at(ra_fixture: &str) -> String { 31fn block_def_map_at(ra_fixture: &str) -> String {
37 let (db, position) = crate::test_db::TestDB::with_position(ra_fixture); 32 let (db, position) = crate::test_db::TestDB::with_position(ra_fixture);
38 33
@@ -57,7 +52,7 @@ fn check_at(ra_fixture: &str, expect: Expect) {
57fn your_stack_belongs_to_me() { 52fn your_stack_belongs_to_me() {
58 cov_mark::check!(your_stack_belongs_to_me); 53 cov_mark::check!(your_stack_belongs_to_me);
59 lower( 54 lower(
60 " 55 r#"
61macro_rules! n_nuple { 56macro_rules! n_nuple {
62 ($e:tt) => (); 57 ($e:tt) => ();
63 ($($rest:tt)*) => {{ 58 ($($rest:tt)*) => {{
@@ -65,7 +60,7 @@ macro_rules! n_nuple {
65 }}; 60 }};
66} 61}
67fn main() { n_nuple!(1,2,3); } 62fn main() { n_nuple!(1,2,3); }
68", 63"#,
69 ); 64 );
70} 65}
71 66
@@ -73,7 +68,7 @@ fn main() { n_nuple!(1,2,3); }
73fn macro_resolve() { 68fn macro_resolve() {
74 // Regression test for a path resolution bug introduced with inner item handling. 69 // Regression test for a path resolution bug introduced with inner item handling.
75 lower( 70 lower(
76 r" 71 r#"
77macro_rules! vec { 72macro_rules! vec {
78 () => { () }; 73 () => { () };
79 ($elem:expr; $n:expr) => { () }; 74 ($elem:expr; $n:expr) => { () };
@@ -84,140 +79,6 @@ mod m {
84 let _ = vec![FileSet::default(); self.len()]; 79 let _ = vec![FileSet::default(); self.len()];
85 } 80 }
86} 81}
87 ", 82"#,
88 );
89}
90
91#[test]
92fn cfg_diagnostics() {
93 check_diagnostics(
94 r"
95fn f() {
96 // The three g̶e̶n̶d̶e̶r̶s̶ statements:
97
98 #[cfg(a)] fn f() {} // Item statement
99 //^^^^^^^^^^^^^^^^^^^ InactiveCode
100 #[cfg(a)] {} // Expression statement
101 //^^^^^^^^^^^^ InactiveCode
102 #[cfg(a)] let x = 0; // let statement
103 //^^^^^^^^^^^^^^^^^^^^ InactiveCode
104
105 abc(#[cfg(a)] 0);
106 //^^^^^^^^^^^ InactiveCode
107 let x = Struct {
108 #[cfg(a)] f: 0,
109 //^^^^^^^^^^^^^^ InactiveCode
110 };
111 match () {
112 () => (),
113 #[cfg(a)] () => (),
114 //^^^^^^^^^^^^^^^^^^ InactiveCode
115 }
116
117 #[cfg(a)] 0 // Trailing expression of block
118 //^^^^^^^^^^^ InactiveCode
119}
120 ",
121 );
122}
123
124#[test]
125fn macro_diag_builtin() {
126 check_diagnostics(
127 r#"
128#[rustc_builtin_macro]
129macro_rules! env {}
130
131#[rustc_builtin_macro]
132macro_rules! include {}
133
134#[rustc_builtin_macro]
135macro_rules! compile_error {}
136
137#[rustc_builtin_macro]
138macro_rules! format_args {
139 () => {}
140}
141
142fn f() {
143 // Test a handful of built-in (eager) macros:
144
145 include!(invalid);
146 //^^^^^^^^^^^^^^^^^ could not convert tokens
147 include!("does not exist");
148 //^^^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `does not exist`
149
150 env!(invalid);
151 //^^^^^^^^^^^^^ could not convert tokens
152
153 env!("OUT_DIR");
154 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
155
156 compile_error!("compile_error works");
157 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works
158
159 // Lazy:
160
161 format_args!();
162 //^^^^^^^^^^^^^^ no rule matches input tokens
163}
164 "#,
165 );
166}
167
168#[test]
169fn macro_rules_diag() {
170 check_diagnostics(
171 r#"
172macro_rules! m {
173 () => {};
174}
175fn f() {
176 m!();
177
178 m!(hi);
179 //^^^^^^ leftover tokens
180}
181 "#,
182 ); 83 );
183} 84}
184
185#[test]
186fn unresolved_macro_diag() {
187 check_diagnostics(
188 r#"
189fn f() {
190 m!();
191 //^^^^ UnresolvedMacroCall
192}
193 "#,
194 );
195}
196
197#[test]
198fn dollar_crate_in_builtin_macro() {
199 check_diagnostics(
200 r#"
201#[macro_export]
202#[rustc_builtin_macro]
203macro_rules! format_args {}
204
205#[macro_export]
206macro_rules! arg {
207 () => {}
208}
209
210#[macro_export]
211macro_rules! outer {
212 () => {
213 $crate::format_args!( "", $crate::arg!(1) )
214 };
215}
216
217fn f() {
218 outer!();
219 //^^^^^^^^ leftover tokens
220}
221 "#,
222 )
223}
diff --git a/crates/hir_def/src/nameres/tests.rs b/crates/hir_def/src/nameres/tests.rs
index 58c01354a..cf43f2a96 100644
--- a/crates/hir_def/src/nameres/tests.rs
+++ b/crates/hir_def/src/nameres/tests.rs
@@ -2,7 +2,6 @@ mod globs;
2mod incremental; 2mod incremental;
3mod macros; 3mod macros;
4mod mod_resolution; 4mod mod_resolution;
5mod diagnostics;
6mod primitives; 5mod primitives;
7 6
8use std::sync::Arc; 7use std::sync::Arc;
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
deleted file mode 100644
index 5a088b6e5..000000000
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ /dev/null
@@ -1,118 +0,0 @@
1use base_db::fixture::WithFixture;
2
3use crate::test_db::TestDB;
4
5fn check_diagnostics(ra_fixture: &str) {
6 let db: TestDB = TestDB::with_files(ra_fixture);
7 db.check_diagnostics();
8}
9
10fn check_no_diagnostics(ra_fixture: &str) {
11 let db: TestDB = TestDB::with_files(ra_fixture);
12 db.check_no_diagnostics();
13}
14
15#[test]
16fn inactive_item() {
17 // Additional tests in `cfg` crate. This only tests disabled cfgs.
18
19 check_diagnostics(
20 r#"
21 //- /lib.rs
22 #[cfg(no)] pub fn f() {}
23 //^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
24
25 #[cfg(no)] #[cfg(no2)] mod m;
26 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
27
28 #[cfg(all(not(a), b))] enum E {}
29 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
30
31 #[cfg(feature = "std")] use std;
32 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
33 "#,
34 );
35}
36
37/// Tests that `cfg` attributes behind `cfg_attr` is handled properly.
38#[test]
39fn inactive_via_cfg_attr() {
40 cov_mark::check!(cfg_attr_active);
41 check_diagnostics(
42 r#"
43 //- /lib.rs
44 #[cfg_attr(not(never), cfg(no))] fn f() {}
45 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
46
47 #[cfg_attr(not(never), cfg(not(no)))] fn f() {}
48
49 #[cfg_attr(never, cfg(no))] fn g() {}
50
51 #[cfg_attr(not(never), inline, cfg(no))] fn h() {}
52 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UnconfiguredCode
53 "#,
54 );
55}
56
57#[test]
58fn builtin_macro_fails_expansion() {
59 check_diagnostics(
60 r#"
61 //- /lib.rs
62 #[rustc_builtin_macro]
63 macro_rules! include { () => {} }
64
65 include!("doesntexist");
66 //^^^^^^^^^^^^^^^^^^^^^^^^ failed to load file `doesntexist`
67 "#,
68 );
69}
70
71#[test]
72fn include_macro_should_allow_empty_content() {
73 check_no_diagnostics(
74 r#"
75 //- /lib.rs
76 #[rustc_builtin_macro]
77 macro_rules! include { () => {} }
78
79 include!("bar.rs");
80 //- /bar.rs
81 // empty
82 "#,
83 );
84}
85
86#[test]
87fn good_out_dir_diagnostic() {
88 check_diagnostics(
89 r#"
90 #[rustc_builtin_macro]
91 macro_rules! include { () => {} }
92 #[rustc_builtin_macro]
93 macro_rules! env { () => {} }
94 #[rustc_builtin_macro]
95 macro_rules! concat { () => {} }
96
97 include!(concat!(env!("OUT_DIR"), "/out.rs"));
98 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
99 "#,
100 );
101}
102
103#[test]
104fn register_attr_and_tool() {
105 cov_mark::check!(register_attr);
106 cov_mark::check!(register_tool);
107 check_no_diagnostics(
108 r#"
109#![register_tool(tool)]
110#![register_attr(attr)]
111
112#[tool::path]
113#[attr]
114struct S;
115 "#,
116 );
117 // NB: we don't currently emit diagnostics here
118}
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs
index a16203fdb..2635b556e 100644
--- a/crates/hir_def/src/test_db.rs
+++ b/crates/hir_def/src/test_db.rs
@@ -6,19 +6,16 @@ use std::{
6}; 6};
7 7
8use base_db::{ 8use base_db::{
9 salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition, FileRange, Upcast, 9 salsa, AnchoredPath, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition,
10 SourceDatabase, Upcast,
10}; 11};
11use base_db::{AnchoredPath, SourceDatabase};
12use hir_expand::{db::AstDatabase, InFile}; 12use hir_expand::{db::AstDatabase, InFile};
13use rustc_hash::FxHashMap;
14use rustc_hash::FxHashSet; 13use rustc_hash::FxHashSet;
15use syntax::{algo, ast, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize}; 14use syntax::{algo, ast, AstNode};
16use test_utils::extract_annotations;
17 15
18use crate::{ 16use crate::{
19 body::BodyDiagnostic,
20 db::DefDatabase, 17 db::DefDatabase,
21 nameres::{diagnostics::DefDiagnosticKind, DefMap, ModuleSource}, 18 nameres::{DefMap, ModuleSource},
22 src::HasSource, 19 src::HasSource,
23 LocalModuleId, Lookup, ModuleDefId, ModuleId, 20 LocalModuleId, Lookup, ModuleDefId, ModuleId,
24}; 21};
@@ -245,145 +242,4 @@ impl TestDB {
245 }) 242 })
246 .collect() 243 .collect()
247 } 244 }
248
249 pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
250 let mut files = Vec::new();
251 let crate_graph = self.crate_graph();
252 for krate in crate_graph.iter() {
253 let crate_def_map = self.crate_def_map(krate);
254 for (module_id, _) in crate_def_map.modules() {
255 let file_id = crate_def_map[module_id].origin.file_id();
256 files.extend(file_id)
257 }
258 }
259 assert!(!files.is_empty());
260 files
261 .into_iter()
262 .filter_map(|file_id| {
263 let text = self.file_text(file_id);
264 let annotations = extract_annotations(&text);
265 if annotations.is_empty() {
266 return None;
267 }
268 Some((file_id, annotations))
269 })
270 .collect()
271 }
272
273 pub(crate) fn diagnostics(&self, cb: &mut dyn FnMut(FileRange, String)) {
274 let crate_graph = self.crate_graph();
275 for krate in crate_graph.iter() {
276 let crate_def_map = self.crate_def_map(krate);
277
278 for diag in crate_def_map.diagnostics() {
279 let (node, message): (InFile<SyntaxNode>, &str) = match &diag.kind {
280 DefDiagnosticKind::UnresolvedModule { ast, .. } => {
281 let node = ast.to_node(self.upcast());
282 (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedModule")
283 }
284 DefDiagnosticKind::UnresolvedExternCrate { ast, .. } => {
285 let node = ast.to_node(self.upcast());
286 (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedExternCrate")
287 }
288 DefDiagnosticKind::UnresolvedImport { id, .. } => {
289 let item_tree = id.item_tree(self.upcast());
290 let import = &item_tree[id.value];
291 let node = InFile::new(id.file_id(), import.ast_id).to_node(self.upcast());
292 (InFile::new(id.file_id(), node.syntax().clone()), "UnresolvedImport")
293 }
294 DefDiagnosticKind::UnconfiguredCode { ast, .. } => {
295 let node = ast.to_node(self.upcast());
296 (InFile::new(ast.file_id, node.syntax().clone()), "UnconfiguredCode")
297 }
298 DefDiagnosticKind::UnresolvedProcMacro { ast, .. } => {
299 (ast.to_node(self.upcast()), "UnresolvedProcMacro")
300 }
301 DefDiagnosticKind::UnresolvedMacroCall { ast, .. } => {
302 let node = ast.to_node(self.upcast());
303 (InFile::new(ast.file_id, node.syntax().clone()), "UnresolvedMacroCall")
304 }
305 DefDiagnosticKind::MacroError { ast, message } => {
306 (ast.to_node(self.upcast()), message.as_str())
307 }
308 DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
309 let node = ast.to_node(self.upcast());
310 (
311 InFile::new(ast.file_id, node.syntax().clone()),
312 "UnimplementedBuiltinMacro",
313 )
314 }
315 };
316
317 let frange = node.as_ref().original_file_range(self);
318 cb(frange, message.to_string())
319 }
320
321 for (_module_id, module) in crate_def_map.modules() {
322 for decl in module.scope.declarations() {
323 if let ModuleDefId::FunctionId(it) = decl {
324 let source_map = self.body_with_source_map(it.into()).1;
325 for diag in source_map.diagnostics() {
326 let (ptr, message): (InFile<SyntaxNodePtr>, &str) = match diag {
327 BodyDiagnostic::InactiveCode { node, .. } => {
328 (node.clone().map(|it| it), "InactiveCode")
329 }
330 BodyDiagnostic::MacroError { node, message } => {
331 (node.clone().map(|it| it.into()), message.as_str())
332 }
333 BodyDiagnostic::UnresolvedProcMacro { node } => {
334 (node.clone().map(|it| it.into()), "UnresolvedProcMacro")
335 }
336 BodyDiagnostic::UnresolvedMacroCall { node, .. } => {
337 (node.clone().map(|it| it.into()), "UnresolvedMacroCall")
338 }
339 };
340
341 let root = self.parse_or_expand(ptr.file_id).unwrap();
342 let node = ptr.map(|ptr| ptr.to_node(&root));
343 let frange = node.as_ref().original_file_range(self);
344 cb(frange, message.to_string())
345 }
346 }
347 }
348 }
349 }
350 }
351
352 pub(crate) fn check_diagnostics(&self) {
353 let db: &TestDB = self;
354 let annotations = db.extract_annotations();
355 assert!(!annotations.is_empty());
356
357 let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
358 db.diagnostics(&mut |frange, message| {
359 actual.entry(frange.file_id).or_default().push((frange.range, message));
360 });
361
362 for (file_id, diags) in actual.iter_mut() {
363 diags.sort_by_key(|it| it.0.start());
364 let text = db.file_text(*file_id);
365 // For multiline spans, place them on line start
366 for (range, content) in diags {
367 if text[*range].contains('\n') {
368 *range = TextRange::new(range.start(), range.start() + TextSize::from(1));
369 *content = format!("... {}", content);
370 }
371 }
372 }
373
374 assert_eq!(annotations, actual);
375 }
376
377 pub(crate) fn check_no_diagnostics(&self) {
378 let db: &TestDB = self;
379 let annotations = db.extract_annotations();
380 assert!(annotations.is_empty());
381
382 let mut has_diagnostics = false;
383 db.diagnostics(&mut |_, _| {
384 has_diagnostics = true;
385 });
386
387 assert!(!has_diagnostics);
388 }
389} 245}