mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 13:03:31 +00:00
Rewrite goto implementation tests
This commit is contained in:
parent
4484908a86
commit
34072d53b6
3 changed files with 119 additions and 104 deletions
|
@ -279,13 +279,17 @@ impl ToNav for hir::Module {
|
|||
impl ToNav for hir::ImplDef {
|
||||
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
|
||||
let src = self.source(db);
|
||||
let frange = if let Some(item) = self.is_builtin_derive(db) {
|
||||
let derive_attr = self.is_builtin_derive(db);
|
||||
let frange = if let Some(item) = &derive_attr {
|
||||
original_range(db, item.syntax())
|
||||
} else {
|
||||
original_range(db, src.as_ref().map(|it| it.syntax()))
|
||||
};
|
||||
let focus_range =
|
||||
src.value.target_type().map(|ty| original_range(db, src.with_value(ty.syntax())).range);
|
||||
let focus_range = if derive_attr.is_some() {
|
||||
None
|
||||
} else {
|
||||
src.value.target_type().map(|ty| original_range(db, src.with_value(ty.syntax())).range)
|
||||
};
|
||||
|
||||
NavigationTarget::from_syntax(
|
||||
frange.file_id,
|
||||
|
|
|
@ -74,135 +74,152 @@ fn impls_for_trait(
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::mock_analysis::analysis_and_position;
|
||||
use ra_db::FileRange;
|
||||
|
||||
fn check_goto(fixture: &str, expected: &[&str]) {
|
||||
let (analysis, pos) = analysis_and_position(fixture);
|
||||
use crate::mock_analysis::{analysis_and_position, MockAnalysis};
|
||||
|
||||
let mut navs = analysis.goto_implementation(pos).unwrap().unwrap().info;
|
||||
assert_eq!(navs.len(), expected.len());
|
||||
navs.sort_by_key(|nav| (nav.file_id(), nav.full_range().start()));
|
||||
navs.into_iter().enumerate().for_each(|(i, nav)| nav.assert_match(expected[i]));
|
||||
fn check(ra_fixture: &str) {
|
||||
let (mock, position) = MockAnalysis::with_files_and_position(ra_fixture);
|
||||
let annotations = mock.annotations();
|
||||
let analysis = mock.analysis();
|
||||
|
||||
let navs = analysis.goto_implementation(position).unwrap().unwrap().info;
|
||||
|
||||
let key = |frange: &FileRange| (frange.file_id, frange.range.start());
|
||||
|
||||
let mut expected = annotations
|
||||
.into_iter()
|
||||
.map(|(range, data)| {
|
||||
assert!(data.is_empty());
|
||||
range
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
expected.sort_by_key(key);
|
||||
|
||||
let mut actual = navs
|
||||
.into_iter()
|
||||
.map(|nav| FileRange { file_id: nav.file_id(), range: nav.range() })
|
||||
.collect::<Vec<_>>();
|
||||
actual.sort_by_key(key);
|
||||
|
||||
assert_eq!(expected, actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_implementation_works() {
|
||||
check_goto(
|
||||
"
|
||||
//- /lib.rs
|
||||
struct Foo<|>;
|
||||
impl Foo {}
|
||||
",
|
||||
&["impl IMPL_DEF FileId(1) 12..23"],
|
||||
check(
|
||||
r#"
|
||||
struct Foo<|>;
|
||||
impl Foo {}
|
||||
//^^^
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_implementation_works_multiple_blocks() {
|
||||
check_goto(
|
||||
"
|
||||
//- /lib.rs
|
||||
struct Foo<|>;
|
||||
impl Foo {}
|
||||
impl Foo {}
|
||||
",
|
||||
&["impl IMPL_DEF FileId(1) 12..23", "impl IMPL_DEF FileId(1) 24..35"],
|
||||
check(
|
||||
r#"
|
||||
struct Foo<|>;
|
||||
impl Foo {}
|
||||
//^^^
|
||||
impl Foo {}
|
||||
//^^^
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_implementation_works_multiple_mods() {
|
||||
check_goto(
|
||||
"
|
||||
//- /lib.rs
|
||||
struct Foo<|>;
|
||||
mod a {
|
||||
impl super::Foo {}
|
||||
}
|
||||
mod b {
|
||||
impl super::Foo {}
|
||||
}
|
||||
",
|
||||
&["impl IMPL_DEF FileId(1) 24..42", "impl IMPL_DEF FileId(1) 57..75"],
|
||||
check(
|
||||
r#"
|
||||
struct Foo<|>;
|
||||
mod a {
|
||||
impl super::Foo {}
|
||||
//^^^^^^^^^^
|
||||
}
|
||||
mod b {
|
||||
impl super::Foo {}
|
||||
//^^^^^^^^^^
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_implementation_works_multiple_files() {
|
||||
check_goto(
|
||||
"
|
||||
//- /lib.rs
|
||||
struct Foo<|>;
|
||||
mod a;
|
||||
mod b;
|
||||
//- /a.rs
|
||||
impl crate::Foo {}
|
||||
//- /b.rs
|
||||
impl crate::Foo {}
|
||||
",
|
||||
&["impl IMPL_DEF FileId(2) 0..18", "impl IMPL_DEF FileId(3) 0..18"],
|
||||
check(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
struct Foo<|>;
|
||||
mod a;
|
||||
mod b;
|
||||
//- /a.rs
|
||||
impl crate::Foo {}
|
||||
//^^^^^^^^^^
|
||||
//- /b.rs
|
||||
impl crate::Foo {}
|
||||
//^^^^^^^^^^
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_implementation_for_trait() {
|
||||
check_goto(
|
||||
"
|
||||
//- /lib.rs
|
||||
trait T<|> {}
|
||||
struct Foo;
|
||||
impl T for Foo {}
|
||||
",
|
||||
&["impl IMPL_DEF FileId(1) 23..40"],
|
||||
check(
|
||||
r#"
|
||||
trait T<|> {}
|
||||
struct Foo;
|
||||
impl T for Foo {}
|
||||
//^^^
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_implementation_for_trait_multiple_files() {
|
||||
check_goto(
|
||||
"
|
||||
//- /lib.rs
|
||||
trait T<|> {};
|
||||
struct Foo;
|
||||
mod a;
|
||||
mod b;
|
||||
//- /a.rs
|
||||
impl crate::T for crate::Foo {}
|
||||
//- /b.rs
|
||||
impl crate::T for crate::Foo {}
|
||||
",
|
||||
&["impl IMPL_DEF FileId(2) 0..31", "impl IMPL_DEF FileId(3) 0..31"],
|
||||
check(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
trait T<|> {};
|
||||
struct Foo;
|
||||
mod a;
|
||||
mod b;
|
||||
//- /a.rs
|
||||
impl crate::T for crate::Foo {}
|
||||
//^^^^^^^^^^
|
||||
//- /b.rs
|
||||
impl crate::T for crate::Foo {}
|
||||
//^^^^^^^^^^
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_implementation_all_impls() {
|
||||
check_goto(
|
||||
"
|
||||
//- /lib.rs
|
||||
trait T {}
|
||||
struct Foo<|>;
|
||||
impl Foo {}
|
||||
impl T for Foo {}
|
||||
impl T for &Foo {}
|
||||
",
|
||||
&[
|
||||
"impl IMPL_DEF FileId(1) 23..34",
|
||||
"impl IMPL_DEF FileId(1) 35..52",
|
||||
"impl IMPL_DEF FileId(1) 53..71",
|
||||
],
|
||||
check(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
trait T {}
|
||||
struct Foo<|>;
|
||||
impl Foo {}
|
||||
//^^^
|
||||
impl T for Foo {}
|
||||
//^^^
|
||||
impl T for &Foo {}
|
||||
//^^^^
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_implementation_to_builtin_derive() {
|
||||
check_goto(
|
||||
"
|
||||
//- /lib.rs
|
||||
#[derive(Copy)]
|
||||
struct Foo<|>;
|
||||
",
|
||||
&["impl IMPL_DEF FileId(1) 0..15"],
|
||||
check(
|
||||
r#"
|
||||
#[derive(Copy)]
|
||||
//^^^^^^^^^^^^^^^
|
||||
struct Foo<|>;
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,6 @@ use test_utils::{
|
|||
use crate::{
|
||||
Analysis, AnalysisChange, AnalysisHost, CrateGraph, Edition, FileId, FilePosition, FileRange,
|
||||
};
|
||||
use ra_syntax::TextRange;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
|
||||
/// from a set of in-memory files.
|
||||
|
@ -81,27 +79,23 @@ impl MockAnalysis {
|
|||
.expect("no file in this mock");
|
||||
FileId(idx as u32 + 1)
|
||||
}
|
||||
pub fn annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
|
||||
pub fn annotations(&self) -> Vec<(FileRange, String)> {
|
||||
self.files
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(idx, fixture)| {
|
||||
.flat_map(|(idx, fixture)| {
|
||||
let file_id = FileId(idx as u32 + 1);
|
||||
let annotations = extract_annotations(&fixture.text);
|
||||
if annotations.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some((file_id, annotations))
|
||||
annotations
|
||||
.into_iter()
|
||||
.map(move |(range, data)| (FileRange { file_id, range }, data))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
pub fn annotation(&self) -> (FileRange, String) {
|
||||
let all = self.annotations();
|
||||
let mut all = self.annotations();
|
||||
assert_eq!(all.len(), 1);
|
||||
let (file_id, mut for_file) = all.into_iter().next().unwrap();
|
||||
assert_eq!(for_file.len(), 1);
|
||||
let (range, data) = for_file.pop().unwrap();
|
||||
(FileRange { file_id, range}, data)
|
||||
all.pop().unwrap()
|
||||
}
|
||||
pub fn analysis_host(self) -> AnalysisHost {
|
||||
let mut host = AnalysisHost::default();
|
||||
|
|
Loading…
Reference in a new issue