diff options
author | Aleksey Kladov <[email protected]> | 2021-06-13 17:23:37 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2021-06-13 17:23:37 +0100 |
commit | a1940d8c75bee8c319e7e7f19607bdc4b01c28d4 (patch) | |
tree | 9286c07c119c3d7bbf95a9b4aa7047944cbb1990 | |
parent | 7bff76d8ae1e8c3fbada1ade9ccf5111a1c0547e (diff) |
internal: check diagnostics in all files and not just the first one
-rw-r--r-- | crates/ide/src/diagnostics.rs | 31 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/inactive_code.rs | 16 | ||||
-rw-r--r-- | crates/ide/src/diagnostics/macro_error.rs | 16 | ||||
-rw-r--r-- | crates/ide/src/fixture.rs | 12 | ||||
-rw-r--r-- | crates/ide/src/goto_definition.rs | 12 | ||||
-rw-r--r-- | crates/test_utils/src/lib.rs | 47 |
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)] |
342 | mod tests { | 342 | mod 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)] |
39 | mod tests { | 39 | mod 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#" |
46 | fn f() { | 51 | fn 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)] |
16 | mod tests { | 16 | mod 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. |
2 | use ide_db::base_db::fixture::ChangeFixture; | 2 | use ide_db::base_db::fixture::ChangeFixture; |
3 | use syntax::{TextRange, TextSize}; | ||
4 | use test_utils::extract_annotations; | 3 | use test_utils::extract_annotations; |
5 | 4 | ||
6 | use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange}; | 5 | use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange}; |
@@ -63,15 +62,8 @@ pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(Fil | |||
63 | 62 | ||
64 | pub(crate) fn nav_target_annotation(ra_fixture: &str) -> (Analysis, FilePosition, FileRange) { | 63 | pub(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 { | |||
185 | extern crate std$0; | 185 | extern 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; | |||
198 | extern crate std as abc$0; | 198 | extern 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 | ||
194 | pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { | 205 | pub 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 | ||
232 | enum LineAnnotation { | 249 | enum 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 |