Add annotation-based nameres diagnostic tests

This commit is contained in:
Jonas Schievink 2020-09-16 17:26:16 +02:00
parent 603613a302
commit f792bc7ddd
4 changed files with 150 additions and 38 deletions

View File

@ -2,6 +2,7 @@
mod incremental;
mod macros;
mod mod_resolution;
mod diagnostics;
mod primitives;
use std::sync::Arc;

View File

@ -0,0 +1,107 @@
use base_db::fixture::WithFixture;
use base_db::FileId;
use base_db::SourceDatabaseExt;
use hir_expand::db::AstDatabase;
use rustc_hash::FxHashMap;
use syntax::TextRange;
use syntax::TextSize;
use crate::test_db::TestDB;
fn check_diagnostics(ra_fixture: &str) {
let db: TestDB = TestDB::with_files(ra_fixture);
let annotations = db.extract_annotations();
assert!(!annotations.is_empty());
let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
db.diagnostics(|d| {
let src = d.display_source();
let root = db.parse_or_expand(src.file_id).unwrap();
// FIXME: macros...
let file_id = src.file_id.original_file(&db);
let range = src.value.to_node(&root).text_range();
let message = d.message().to_owned();
actual.entry(file_id).or_default().push((range, message));
});
for (file_id, diags) in actual.iter_mut() {
diags.sort_by_key(|it| it.0.start());
let text = db.file_text(*file_id);
// For multiline spans, place them on line start
for (range, content) in diags {
if text[*range].contains('\n') {
*range = TextRange::new(range.start(), range.start() + TextSize::from(1));
*content = format!("... {}", content);
}
}
}
assert_eq!(annotations, actual);
}
#[test]
fn unresolved_import() {
check_diagnostics(
r"
use does_exist;
use does_not_exist;
//^^^^^^^^^^^^^^ unresolved import
mod does_exist {}
",
);
}
#[test]
fn unresolved_import_in_use_tree() {
// Only the relevant part of a nested `use` item should be highlighted.
check_diagnostics(
r"
use does_exist::{Exists, DoesntExist};
//^^^^^^^^^^^ unresolved import
use {does_not_exist::*, does_exist};
//^^^^^^^^^^^^^^^^^ unresolved import
use does_not_exist::{
a,
//^ unresolved import
b,
//^ unresolved import
c,
//^ unresolved import
};
mod does_exist {
pub struct Exists;
}
",
);
}
#[test]
fn unresolved_extern_crate() {
check_diagnostics(
r"
//- /main.rs crate:main deps:core
extern crate core;
extern crate doesnotexist;
//^^^^^^^^^^^^^^^^^^^^^^^^^^ unresolved extern crate
//- /lib.rs crate:core
",
);
}
#[test]
fn unresolved_module() {
check_diagnostics(
r"
//- /lib.rs
mod foo;
mod bar;
//^^^^^^^^ unresolved module
mod baz {}
//- /foo.rs
",
);
}

View File

@ -671,44 +671,6 @@ mod bar {
);
}
#[test]
fn unresolved_module_diagnostics() {
let db = TestDB::with_files(
r"
//- /lib.rs
mod foo;
mod bar;
mod baz {}
//- /foo.rs
",
);
let krate = db.test_crate();
let crate_def_map = db.crate_def_map(krate);
expect![[r#"
[
DefDiagnostic {
in_module: Idx::<ModuleData>(0),
kind: UnresolvedModule {
declaration: InFile {
file_id: HirFileId(
FileId(
FileId(
0,
),
),
),
value: FileAstId::<syntax::ast::generated::nodes::Module>(1),
},
candidate: "bar.rs",
},
},
]
"#]]
.assert_debug_eq(&crate_def_map.diagnostics);
}
#[test]
fn module_resolution_decl_inside_module_in_non_crate_root_2() {
check(

View File

@ -5,9 +5,15 @@
sync::{Arc, Mutex},
};
use base_db::SourceDatabase;
use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast};
use hir_expand::db::AstDatabase;
use hir_expand::diagnostics::Diagnostic;
use hir_expand::diagnostics::DiagnosticSinkBuilder;
use rustc_hash::FxHashMap;
use rustc_hash::FxHashSet;
use syntax::TextRange;
use test_utils::extract_annotations;
use crate::db::DefDatabase;
@ -98,4 +104,40 @@ pub fn log_executed(&self, f: impl FnOnce()) -> Vec<String> {
})
.collect()
}
pub fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
let mut files = Vec::new();
let crate_graph = self.crate_graph();
for krate in crate_graph.iter() {
let crate_def_map = self.crate_def_map(krate);
for (module_id, _) in crate_def_map.modules.iter() {
let file_id = crate_def_map[module_id].origin.file_id();
files.extend(file_id)
}
}
assert!(!files.is_empty());
files
.into_iter()
.filter_map(|file_id| {
let text = self.file_text(file_id);
let annotations = extract_annotations(&text);
if annotations.is_empty() {
return None;
}
Some((file_id, annotations))
})
.collect()
}
pub fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) {
let crate_graph = self.crate_graph();
for krate in crate_graph.iter() {
let crate_def_map = self.crate_def_map(krate);
let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
for (module_id, _) in crate_def_map.modules.iter() {
crate_def_map.add_diagnostics(self, module_id, &mut sink);
}
}
}
}