From a1940d8c75bee8c319e7e7f19607bdc4b01c28d4 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 13 Jun 2021 19:23:37 +0300 Subject: internal: check diagnostics in all files and not just the first one --- crates/ide/src/diagnostics.rs | 31 +++++++++---------- crates/ide/src/diagnostics/inactive_code.rs | 16 +++++----- crates/ide/src/diagnostics/macro_error.rs | 16 ++++++++-- crates/ide/src/fixture.rs | 12 ++------ crates/ide/src/goto_definition.rs | 12 ++++---- 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 { #[cfg(test)] mod tests { use expect_test::Expect; - use hir::diagnostics::DiagnosticCode; use ide_assists::AssistResolveStrategy; use stdx::trim_indent; use test_utils::{assert_eq_text, extract_annotations}; @@ -442,24 +441,24 @@ mod tests { #[track_caller] pub(crate) fn check_diagnostics(ra_fixture: &str) { - check_diagnostics_with_inactive_code(ra_fixture, false) + let mut config = DiagnosticsConfig::default(); + config.disabled.insert("inactive-code".to_string()); + check_diagnostics_with_config(config, ra_fixture) } #[track_caller] - pub(crate) fn check_diagnostics_with_inactive_code(ra_fixture: &str, with_inactive_code: bool) { - let (analysis, file_id) = fixture::file(ra_fixture); - let diagnostics = analysis - .diagnostics(&DiagnosticsConfig::default(), AssistResolveStrategy::All, file_id) - .unwrap(); - - let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); - let mut actual = diagnostics - .into_iter() - .filter(|d| d.code != Some(DiagnosticCode("inactive-code")) || with_inactive_code) - .map(|d| (d.range, d.message)) - .collect::>(); - actual.sort_by_key(|(range, _)| range.start()); - assert_eq!(expected, actual); + pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixture: &str) { + let (analysis, files) = fixture::files(ra_fixture); + for file_id in files { + let diagnostics = + analysis.diagnostics(&config, AssistResolveStrategy::All, file_id).unwrap(); + + let expected = extract_annotations(&*analysis.file_text(file_id).unwrap()); + let mut actual = + diagnostics.into_iter().map(|d| (d.range, d.message)).collect::>(); + actual.sort_by_key(|(range, _)| range.start()); + assert_eq!(expected, actual); + } } #[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( #[cfg(test)] mod tests { - use crate::diagnostics::tests::check_diagnostics_with_inactive_code; + use crate::{diagnostics::tests::check_diagnostics_with_config, DiagnosticsConfig}; + + pub(crate) fn check(ra_fixture: &str) { + let config = DiagnosticsConfig::default(); + check_diagnostics_with_config(config, ra_fixture) + } #[test] fn cfg_diagnostics() { - check_diagnostics_with_inactive_code( + check( r#" fn f() { // The three g̶e̶n̶d̶e̶r̶s̶ statements: @@ -69,7 +74,6 @@ fn f() { //^^^^^^^^^^^ code is inactive due to #[cfg] directives: a is disabled } "#, - true, ); } @@ -77,7 +81,7 @@ fn f() { fn inactive_item() { // Additional tests in `cfg` crate. This only tests disabled cfgs. - check_diagnostics_with_inactive_code( + check( r#" #[cfg(no)] pub fn f() {} //^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled @@ -91,7 +95,6 @@ fn f() { #[cfg(feature = "std")] use std; //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: feature = "std" is disabled "#, - true, ); } @@ -99,7 +102,7 @@ fn f() { #[test] fn inactive_via_cfg_attr() { cov_mark::check!(cfg_attr_active); - check_diagnostics_with_inactive_code( + check( r#" #[cfg_attr(not(never), cfg(no))] fn f() {} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled @@ -111,7 +114,6 @@ fn f() { #[cfg_attr(not(never), inline, cfg(no))] fn h() {} //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ code is inactive due to #[cfg] directives: no is disabled "#, - true, ); } } 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) -> #[cfg(test)] mod tests { - use crate::diagnostics::tests::{check_diagnostics, check_no_diagnostics}; + use crate::{ + diagnostics::tests::{ + check_diagnostics, check_diagnostics_with_config, check_no_diagnostics, + }, + DiagnosticsConfig, + }; #[test] fn builtin_macro_fails_expansion() { @@ -31,7 +36,14 @@ macro_rules! include { () => {} } #[test] fn include_macro_should_allow_empty_content() { - check_diagnostics( + let mut config = DiagnosticsConfig::default(); + + // FIXME: This is a false-positive, the file is actually linked in via + // `include!` macro + config.disabled.insert("unlinked-file".to_string()); + + check_diagnostics_with_config( + config, r#" //- /lib.rs #[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 @@ //! Utilities for creating `Analysis` instances for tests. use ide_db::base_db::fixture::ChangeFixture; -use syntax::{TextRange, TextSize}; use test_utils::extract_annotations; use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange}; @@ -63,15 +62,8 @@ pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(Fil pub(crate) fn nav_target_annotation(ra_fixture: &str) -> (Analysis, FilePosition, FileRange) { let (analysis, position, mut annotations) = annotations(ra_fixture); - let (mut expected, data) = annotations.pop().unwrap(); + let (expected, data) = annotations.pop().unwrap(); assert!(annotations.is_empty()); - match data.as_str() { - "" => (), - "file" => { - expected.range = - TextRange::up_to(TextSize::of(&*analysis.file_text(expected.file_id).unwrap())) - } - data => panic!("bad data: {}", data), - } + assert_eq!(data, ""); (analysis, position, expected) } 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 { extern crate std$0; //- /std/lib.rs crate:std // empty -//^ file +//^file "#, ) } @@ -198,7 +198,7 @@ extern crate std$0; extern crate std as abc$0; //- /std/lib.rs crate:std // empty -//^ file +//^file "#, ) } @@ -253,7 +253,7 @@ mod $0foo; //- /foo.rs // empty -//^ file +//^file "#, ); @@ -264,7 +264,7 @@ mod $0foo; //- /foo/mod.rs // empty -//^ file +//^file "#, ); } @@ -395,7 +395,7 @@ use foo as bar$0; //- /foo/lib.rs crate:foo // empty -//^ file +//^file "#, ); } @@ -1287,7 +1287,7 @@ fn main() { } //- /foo.txt // empty -//^ file +//^file "#, ); } 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 { res } -/// Extracts `//^ some text` annotations +/// Extracts `//^^^ some text` annotations. +/// +/// A run of `^^^` can be arbitrary long and points to the corresponding range +/// in the line above. +/// +/// The `// ^file text` syntax can be used to attach `text` to the entirety of +/// the file. +/// +/// Multiline string values are supported: +/// +/// // ^^^ first line +/// // | second line pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { let mut res = Vec::new(); - let mut prev_line_start: Option = None; + let mut prev_line_start: Option = Some(0.into()); let mut line_start: TextSize = 0.into(); let mut prev_line_annotations: Vec<(TextSize, usize)> = Vec::new(); for line in text.split_inclusive('\n') { @@ -202,10 +213,15 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { let annotation_offset = TextSize::of(&line[..idx + "//".len()]); for annotation in extract_line_annotations(&line[idx + "//".len()..]) { match annotation { - LineAnnotation::Annotation { mut range, content } => { + LineAnnotation::Annotation { mut range, content, file } => { range += annotation_offset; this_line_annotations.push((range.end(), res.len())); - res.push((range + prev_line_start.unwrap(), content)) + let range = if file { + TextRange::up_to(TextSize::of(text)) + } else { + range + prev_line_start.unwrap() + }; + res.push((range, content)) } LineAnnotation::Continuation { mut offset, content } => { offset += annotation_offset; @@ -226,11 +242,12 @@ pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { prev_line_annotations = this_line_annotations; } + res } enum LineAnnotation { - Annotation { range: TextRange, content: String }, + Annotation { range: TextRange, content: String, file: bool }, Continuation { offset: TextSize, content: String }, } @@ -251,12 +268,20 @@ fn extract_line_annotations(mut line: &str) -> Vec { } let range = TextRange::at(offset, len.try_into().unwrap()); let next = line[len..].find(marker).map_or(line.len(), |it| it + len); - let content = line[len..][..next - len].trim().to_string(); + let mut content = &line[len..][..next - len]; + + let mut file = false; + if !continuation && content.starts_with("file") { + file = true; + content = &content["file".len()..] + } + + let content = content.trim().to_string(); let annotation = if continuation { LineAnnotation::Continuation { offset: range.end(), content } } else { - LineAnnotation::Annotation { range, content } + LineAnnotation::Annotation { range, content, file } }; res.push(annotation); @@ -277,16 +302,20 @@ fn main() { zoo + 1 } //^^^ type: // | i32 + +// ^file "#, ); let res = extract_annotations(&text) .into_iter() .map(|(range, ann)| (&text[range], ann)) .collect::>(); + assert_eq!( - res, - vec![("x", "def".into()), ("y", "def".into()), ("zoo", "type:\ni32\n".into()),] + res[..3], + [("x", "def".into()), ("y", "def".into()), ("zoo", "type:\ni32\n".into())] ); + assert_eq!(res[3].0.len(), 115); } /// Returns `false` if slow tests should not run, otherwise returns `true` and -- cgit v1.2.3