aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2021-06-13 17:23:37 +0100
committerAleksey Kladov <[email protected]>2021-06-13 17:23:37 +0100
commita1940d8c75bee8c319e7e7f19607bdc4b01c28d4 (patch)
tree9286c07c119c3d7bbf95a9b4aa7047944cbb1990
parent7bff76d8ae1e8c3fbada1ade9ccf5111a1c0547e (diff)
internal: check diagnostics in all files and not just the first one
-rw-r--r--crates/ide/src/diagnostics.rs31
-rw-r--r--crates/ide/src/diagnostics/inactive_code.rs16
-rw-r--r--crates/ide/src/diagnostics/macro_error.rs16
-rw-r--r--crates/ide/src/fixture.rs12
-rw-r--r--crates/ide/src/goto_definition.rs12
-rw-r--r--crates/test_utils/src/lib.rs47
6 files changed, 84 insertions, 50 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index c257ea8e7..fb956d5ee 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -341,7 +341,6 @@ fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
341#[cfg(test)] 341#[cfg(test)]
342mod tests { 342mod tests {
343 use expect_test::Expect; 343 use expect_test::Expect;
344 use hir::diagnostics::DiagnosticCode;
345 use ide_assists::AssistResolveStrategy; 344 use ide_assists::AssistResolveStrategy;
346 use stdx::trim_indent; 345 use stdx::trim_indent;
347 use test_utils::{assert_eq_text, extract_annotations}; 346 use test_utils::{assert_eq_text, extract_annotations};
@@ -442,24 +441,24 @@ mod tests {
442 441
443 #[track_caller] 442 #[track_caller]
444 pub(crate) fn check_diagnostics(ra_fixture: &str) { 443 pub(crate) fn check_diagnostics(ra_fixture: &str) {
445 check_diagnostics_with_inactive_code(ra_fixture, false) 444 let mut config = DiagnosticsConfig::default();
445 config.disabled.insert("inactive-code".to_string());
446 check_diagnostics_with_config(config, ra_fixture)
446 } 447 }
447 448
448 #[track_caller] 449 #[track_caller]
449 pub(crate) fn check_diagnostics_with_inactive_code(ra_fixture: &str, with_inactive_code: bool) { 450 pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixture: &str) {
450 let (analysis, file_id) = fixture::file(ra_fixture); 451 let (analysis, files) = fixture::files(ra_fixture);
451 let diagnostics = analysis 452 for file_id in files {
452 .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id) 453 let diagnostics =
453 .unwrap(); 454 analysis.diagnostics(&config, AssistResolveStrategy::All, file_id).unwrap();
454 455
455 let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); 456 let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
456 let mut actual = diagnostics 457 let mut actual =
457 .into_iter() 458 diagnostics.into_iter().map(|d| (d.range, d.message)).collect::<Vec<_>>();
458 .filter(|d| d.code != Some(DiagnosticCode("inactive-code")) || with_inactive_code) 459 actual.sort_by_key(|(range, _)| range.start());
459 .map(|d| (d.range, d.message)) 460 assert_eq!(expected, actual);
460 .collect::<Vec<_>>(); 461 }
461 actual.sort_by_key(|(range, _)| range.start());
462 assert_eq!(expected, actual);
463 } 462 }
464 463
465 #[test] 464 #[test]
diff --git a/crates/ide/src/diagnostics/inactive_code.rs b/crates/ide/src/diagnostics/inactive_code.rs
index afe333204..d9d3e88c1 100644
--- a/crates/ide/src/diagnostics/inactive_code.rs
+++ b/crates/ide/src/diagnostics/inactive_code.rs
@@ -37,11 +37,16 @@ pub(super) fn inactive_code(
37 37
38#[cfg(test)] 38#[cfg(test)]
39mod tests { 39mod tests {
40 use crate::diagnostics::tests::check_diagnostics_with_inactive_code; 40 use crate::{diagnostics::tests::check_diagnostics_with_config, DiagnosticsConfig};
41
42 pub(crate) fn check(ra_fixture: &str) {
43 let config = DiagnosticsConfig::default();
44 check_diagnostics_with_config(config, ra_fixture)
45 }
41 46
42 #[test] 47 #[test]
43 fn cfg_diagnostics() { 48 fn cfg_diagnostics() {
44 check_diagnostics_with_inactive_code( 49 check(
45 r#" 50 r#"
46fn f() { 51fn f() {
47 // The three g̶e̶n̶d̶e̶r̶s̶ statements: 52 // The three g̶e̶n̶d̶e̶r̶s̶ statements:
@@ -69,7 +74,6 @@ fn f() {
69 //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled 74 //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled
70} 75}
71 "#, 76 "#,
72 true,
73 ); 77 );
74 } 78 }
75 79
@@ -77,7 +81,7 @@ fn f() {
77 fn inactive_item() { 81 fn inactive_item() {
78 // Additional tests in `cfg` crate. This only tests disabled cfgs. 82 // Additional tests in `cfg` crate. This only tests disabled cfgs.
79 83
80 check_diagnostics_with_inactive_code( 84 check(
81 r#" 85 r#"
82 #[cfg(no)] pub fn f() {} 86 #[cfg(no)] pub fn f() {}
83 //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled 87 //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled
@@ -91,7 +95,6 @@ fn f() {
91 #[cfg(feature = "std")] use std; 95 #[cfg(feature = "std")] use std;
92 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled 96 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled
93"#, 97"#,
94 true,
95 ); 98 );
96 } 99 }
97 100
@@ -99,7 +102,7 @@ fn f() {
99 #[test] 102 #[test]
100 fn inactive_via_cfg_attr() { 103 fn inactive_via_cfg_attr() {
101 cov_mark::check!(cfg_attr_active); 104 cov_mark::check!(cfg_attr_active);
102 check_diagnostics_with_inactive_code( 105 check(
103 r#" 106 r#"
104 #[cfg_attr(not(never), cfg(no))] fn f() {} 107 #[cfg_attr(not(never), cfg(no))] fn f() {}
105 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled 108 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled
@@ -111,7 +114,6 @@ fn f() {
111 #[cfg_attr(not(never), inline, cfg(no))] fn h() {} 114 #[cfg_attr(not(never), inline, cfg(no))] fn h() {}
112 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled 115 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled
113"#, 116"#,
114 true,
115 ); 117 );
116 } 118 }
117} 119}
diff --git a/crates/ide/src/diagnostics/macro_error.rs b/crates/ide/src/diagnostics/macro_error.rs
index 8cc8cfb48..d76a3a094 100644
--- a/crates/ide/src/diagnostics/macro_error.rs
+++ b/crates/ide/src/diagnostics/macro_error.rs
@@ -14,7 +14,12 @@ pub(super) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) ->
14 14
15#[cfg(test)] 15#[cfg(test)]
16mod tests { 16mod tests {
17 use crate::diagnostics::tests::{check_diagnostics, check_no_diagnostics}; 17 use crate::{
18 diagnostics::tests::{
19 check_diagnostics, check_diagnostics_with_config, check_no_diagnostics,
20 },
21 DiagnosticsConfig,
22 };
18 23
19 #[test] 24 #[test]
20 fn builtin_macro_fails_expansion() { 25 fn builtin_macro_fails_expansion() {
@@ -31,7 +36,14 @@ macro_rules! include { () => {} }
31 36
32 #[test] 37 #[test]
33 fn include_macro_should_allow_empty_content() { 38 fn include_macro_should_allow_empty_content() {
34 check_diagnostics( 39 let mut config = DiagnosticsConfig::default();
40
41 // FIXME: This is a false-positive, the file is actually linked in via
42 // `include!` macro
43 config.disabled.insert("unlinked-file".to_string());
44
45 check_diagnostics_with_config(
46 config,
35 r#" 47 r#"
36//- /lib.rs 48//- /lib.rs
37#[rustc_builtin_macro] 49#[rustc_builtin_macro]
diff --git a/crates/ide/src/fixture.rs b/crates/ide/src/fixture.rs
index 6780af617..38e2e866b 100644
--- a/crates/ide/src/fixture.rs
+++ b/crates/ide/src/fixture.rs
@@ -1,6 +1,5 @@
1//! Utilities for creating `Analysis` instances for tests. 1//! Utilities for creating `Analysis` instances for tests.
2use ide_db::base_db::fixture::ChangeFixture; 2use ide_db::base_db::fixture::ChangeFixture;
3use syntax::{TextRange, TextSize};
4use test_utils::extract_annotations; 3use test_utils::extract_annotations;
5 4
6use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange}; 5use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange};
@@ -63,15 +62,8 @@ pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(Fil
63 62
64pub(crate) fn nav_target_annotation(ra_fixture: &str) -> (Analysis, FilePosition, FileRange) { 63pub(crate) fn nav_target_annotation(ra_fixture: &str) -> (Analysis, FilePosition, FileRange) {
65 let (analysis, position, mut annotations) = annotations(ra_fixture); 64 let (analysis, position, mut annotations) = annotations(ra_fixture);
66 let (mut expected, data) = annotations.pop().unwrap(); 65 let (expected, data) = annotations.pop().unwrap();
67 assert!(annotations.is_empty()); 66 assert!(annotations.is_empty());
68 match data.as_str() { 67 assert_eq!(data, "");
69 "" => (),
70 "file" => {
71 expected.range =
72 TextRange::up_to(TextSize::of(&*analysis.file_text(expected.file_id).unwrap()))
73 }
74 data => panic!("bad data: {}", data),
75 }
76 (analysis, position, expected) 68 (analysis, position, expected)
77} 69}
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index d29ee64a5..8dd643a0f 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -185,7 +185,7 @@ mod tests {
185extern crate std$0; 185extern crate std$0;
186//- /std/lib.rs crate:std 186//- /std/lib.rs crate:std
187// empty 187// empty
188//^ file 188//^file
189"#, 189"#,
190 ) 190 )
191 } 191 }
@@ -198,7 +198,7 @@ extern crate std$0;
198extern crate std as abc$0; 198extern crate std as abc$0;
199//- /std/lib.rs crate:std 199//- /std/lib.rs crate:std
200// empty 200// empty
201//^ file 201//^file
202"#, 202"#,
203 ) 203 )
204 } 204 }
@@ -253,7 +253,7 @@ mod $0foo;
253 253
254//- /foo.rs 254//- /foo.rs
255// empty 255// empty
256//^ file 256//^file
257"#, 257"#,
258 ); 258 );
259 259
@@ -264,7 +264,7 @@ mod $0foo;
264 264
265//- /foo/mod.rs 265//- /foo/mod.rs
266// empty 266// empty
267//^ file 267//^file
268"#, 268"#,
269 ); 269 );
270 } 270 }
@@ -395,7 +395,7 @@ use foo as bar$0;
395 395
396//- /foo/lib.rs crate:foo 396//- /foo/lib.rs crate:foo
397// empty 397// empty
398//^ file 398//^file
399"#, 399"#,
400 ); 400 );
401 } 401 }
@@ -1287,7 +1287,7 @@ fn main() {
1287} 1287}
1288//- /foo.txt 1288//- /foo.txt
1289// empty 1289// empty
1290//^ file 1290//^file
1291"#, 1291"#,
1292 ); 1292 );
1293 } 1293 }
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index ac5a9509d..b2fe25f82 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -190,10 +190,21 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
190 res 190 res
191} 191}
192 192
193/// Extracts `//^ some text` annotations 193/// Extracts `//^^^ some text` annotations.
194///
195/// A run of `^^^` can be arbitrary long and points to the corresponding range
196/// in the line above.
197///
198/// The `// ^file text` syntax can be used to attach `text` to the entirety of
199/// the file.
200///
201/// Multiline string values are supported:
202///
203/// // ^^^ first line
204/// // | second line
194pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { 205pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
195 let mut res = Vec::new(); 206 let mut res = Vec::new();
196 let mut prev_line_start: Option<TextSize> = None; 207 let mut prev_line_start: Option<TextSize> = Some(0.into());
197 let mut line_start: TextSize = 0.into(); 208 let mut line_start: TextSize = 0.into();
198 let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); 209 let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new();
199 for line in text.split_inclusive('\n') { 210 for line in text.split_inclusive('\n') {
@@ -202,10 +213,15 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
202 let annotation_offset = TextSize::of(&line[..idx + "//".len()]); 213 let annotation_offset = TextSize::of(&line[..idx + "//".len()]);
203 for annotation in extract_line_annotations(&line[idx + "//".len()..]) { 214 for annotation in extract_line_annotations(&line[idx + "//".len()..]) {
204 match annotation { 215 match annotation {
205 LineAnnotation::Annotation { mut range, content } => { 216 LineAnnotation::Annotation { mut range, content, file } => {
206 range += annotation_offset; 217 range += annotation_offset;
207 this_line_annotations.push((range.end(), res.len())); 218 this_line_annotations.push((range.end(), res.len()));
208 res.push((range + prev_line_start.unwrap(), content)) 219 let range = if file {
220 TextRange::up_to(TextSize::of(text))
221 } else {
222 range + prev_line_start.unwrap()
223 };
224 res.push((range, content))
209 } 225 }
210 LineAnnotation::Continuation { mut offset, content } => { 226 LineAnnotation::Continuation { mut offset, content } => {
211 offset += annotation_offset; 227 offset += annotation_offset;
@@ -226,11 +242,12 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> {
226 242
227 prev_line_annotations = this_line_annotations; 243 prev_line_annotations = this_line_annotations;
228 } 244 }
245
229 res 246 res
230} 247}
231 248
232enum LineAnnotation { 249enum LineAnnotation {
233 Annotation { range: TextRange, content: String }, 250 Annotation { range: TextRange, content: String, file: bool },
234 Continuation { offset: TextSize, content: String }, 251 Continuation { offset: TextSize, content: String },
235} 252}
236 253
@@ -251,12 +268,20 @@ fn extract_line_annotations(mut line: &str) -> Vec<LineAnnotation> {
251 } 268 }
252 let range = TextRange::at(offset, len.try_into().unwrap()); 269 let range = TextRange::at(offset, len.try_into().unwrap());
253 let next = line[len..].find(marker).map_or(line.len(), |it| it + len); 270 let next = line[len..].find(marker).map_or(line.len(), |it| it + len);
254 let content = line[len..][..next - len].trim().to_string(); 271 let mut content = &line[len..][..next - len];
272
273 let mut file = false;
274 if !continuation && content.starts_with("file") {
275 file = true;
276 content = &content["file".len()..]
277 }
278
279 let content = content.trim().to_string();
255 280
256 let annotation = if continuation { 281 let annotation = if continuation {
257 LineAnnotation::Continuation { offset: range.end(), content } 282 LineAnnotation::Continuation { offset: range.end(), content }
258 } else { 283 } else {
259 LineAnnotation::Annotation { range, content } 284 LineAnnotation::Annotation { range, content, file }
260 }; 285 };
261 res.push(annotation); 286 res.push(annotation);
262 287
@@ -277,16 +302,20 @@ fn main() {
277 zoo + 1 302 zoo + 1
278} //^^^ type: 303} //^^^ type:
279 // | i32 304 // | i32
305
306// ^file
280 "#, 307 "#,
281 ); 308 );
282 let res = extract_annotations(&text) 309 let res = extract_annotations(&text)
283 .into_iter() 310 .into_iter()
284 .map(|(range, ann)| (&text[range], ann)) 311 .map(|(range, ann)| (&text[range], ann))
285 .collect::<Vec<_>>(); 312 .collect::<Vec<_>>();
313
286 assert_eq!( 314 assert_eq!(
287 res, 315 res[..3],
288 vec![("x", "def".into()), ("y", "def".into()), ("zoo", "type:\ni32\n".into()),] 316 [("x", "def".into()), ("y", "def".into()), ("zoo", "type:\ni32\n".into())]
289 ); 317 );
318 assert_eq!(res[3].0.len(), 115);
290} 319}
291 320
292/// Returns `false` if slow tests should not run, otherwise returns `true` and 321/// Returns `false` if slow tests should not run, otherwise returns `true` and