1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
use base_db::fixture::WithFixture;
use base_db::FileId;
use base_db::SourceDatabaseExt;
use hir_expand::db::AstDatabase;
use rustc_hash::FxHashMap;
use syntax::TextRange;
use syntax::TextSize;
use crate::test_db::TestDB;
fn check_diagnostics(ra_fixture: &str) {
let db: TestDB = TestDB::with_files(ra_fixture);
let annotations = db.extract_annotations();
assert!(!annotations.is_empty());
let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
db.diagnostics(|d| {
let src = d.display_source();
let root = db.parse_or_expand(src.file_id).unwrap();
// FIXME: macros...
let file_id = src.file_id.original_file(&db);
let range = src.value.to_node(&root).text_range();
let message = d.message().to_owned();
actual.entry(file_id).or_default().push((range, message));
});
for (file_id, diags) in actual.iter_mut() {
diags.sort_by_key(|it| it.0.start());
let text = db.file_text(*file_id);
// For multiline spans, place them on line start
for (range, content) in diags {
if text[*range].contains('\n') {
*range = TextRange::new(range.start(), range.start() + TextSize::from(1));
*content = format!("... {}", content);
}
}
}
assert_eq!(annotations, actual);
}
#[test]
fn unresolved_import() {
check_diagnostics(
r"
use does_exist;
use does_not_exist;
//^^^^^^^^^^^^^^ unresolved import
mod does_exist {}
",
);
}
#[test]
fn unresolved_import_in_use_tree() {
// Only the relevant part of a nested `use` item should be highlighted.
check_diagnostics(
r"
use does_exist::{Exists, DoesntExist};
//^^^^^^^^^^^ unresolved import
use {does_not_exist::*, does_exist};
//^^^^^^^^^^^^^^^^^ unresolved import
use does_not_exist::{
a,
//^ unresolved import
b,
//^ unresolved import
c,
//^ unresolved import
};
mod does_exist {
pub struct Exists;
}
",
);
}
#[test]
fn unresolved_extern_crate() {
check_diagnostics(
r"
//- /main.rs crate:main deps:core
extern crate core;
extern crate doesnotexist;
//^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate
//- /lib.rs crate:core
",
);
}
#[test]
fn dedup_unresolved_import_from_unresolved_crate() {
check_diagnostics(
r"
//- /main.rs crate:main
mod a {
extern crate doesnotexist;
//^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate
// Should not error, since we already errored for the missing crate.
use doesnotexist::{self, bla, *};
use crate::doesnotexist;
//^^^^^^^^^^^^^^^^^^^ unresolved import
}
mod m {
use super::doesnotexist;
//^^^^^^^^^^^^^^^^^^^ unresolved import
}
",
);
}
#[test]
fn unresolved_module() {
check_diagnostics(
r"
//- /lib.rs
mod foo;
mod bar;
//^^^^^^^^ unresolved module
mod baz {}
//- /foo.rs
",
);
}
|