9250: internal: check diagnostics in all files and not just the first one r=matklad a=matklad

bors r+
🤖

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2021-06-13 16:24:35 +00:00 committed by GitHub
commit a8d8155908
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 83 additions and 49 deletions

View File

@ -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();
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()
.filter(|d| d.code != Some(DiagnosticCode("inactive-code")) || with_inactive_code)
.map(|d| (d.range, d.message))
.collect::<Vec<_>>();
actual.sort_by_key(|(range, _)| range.start());
assert_eq!(expected, actual);
let expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
let mut actual =
diagnostics.into_iter().map(|d| (d.range, d.message)).collect::<Vec<_>>();
actual.sort_by_key(|(range, _)| range.start());
assert_eq!(expected, actual);
}
}
#[test]

View File

@ -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,
);
}
}

View File

@ -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]

View File

@ -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)
}

View File

@ -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
"#,
);
}

View File

@ -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<TextSize> = None;
let mut prev_line_start: Option<TextSize> = 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<LineAnnotation> {
}
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::<Vec<_>>();
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