Merge #9250
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:
commit
a8d8155908
@ -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]
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user