mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 20:43:21 +00:00
(T): make typification tests more data driven
This commit is contained in:
parent
82ce5792ab
commit
e805e8c1d5
5 changed files with 137 additions and 133 deletions
|
@ -154,6 +154,19 @@ impl TestDB {
|
||||||
});
|
});
|
||||||
(buf, count)
|
(buf, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn all_files(&self) -> Vec<FileId> {
|
||||||
|
let mut res = 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();
|
||||||
|
res.extend(file_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestDB {
|
impl TestDB {
|
||||||
|
|
|
@ -28,6 +28,7 @@ use ra_syntax::{
|
||||||
SyntaxNode,
|
SyntaxNode,
|
||||||
};
|
};
|
||||||
use stdx::format_to;
|
use stdx::format_to;
|
||||||
|
use test_utils::extract_annotations;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty,
|
db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty,
|
||||||
|
@ -37,6 +38,21 @@ use crate::{
|
||||||
// against snapshots of the expected results using insta. Use cargo-insta to
|
// against snapshots of the expected results using insta. Use cargo-insta to
|
||||||
// update the snapshots.
|
// update the snapshots.
|
||||||
|
|
||||||
|
fn check_types(ra_fixture: &str) {
|
||||||
|
let db = TestDB::with_files(ra_fixture);
|
||||||
|
let mut checked_one = false;
|
||||||
|
for file_id in db.all_files() {
|
||||||
|
let text = db.parse(file_id).syntax_node().to_string();
|
||||||
|
let annotations = extract_annotations(&text);
|
||||||
|
for (offset, expected) in annotations {
|
||||||
|
let actual = type_at_pos(&db, FilePosition { file_id, offset });
|
||||||
|
assert_eq!(expected, actual);
|
||||||
|
checked_one = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert!(checked_one, "no `//^` annotations found");
|
||||||
|
}
|
||||||
|
|
||||||
fn type_at_pos(db: &TestDB, pos: FilePosition) -> String {
|
fn type_at_pos(db: &TestDB, pos: FilePosition) -> String {
|
||||||
type_at_pos_displayed(db, pos, |ty, _| ty.display(db).to_string())
|
type_at_pos_displayed(db, pos, |ty, _| ty.display(db).to_string())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,99 +1,91 @@
|
||||||
use insta::assert_snapshot;
|
use insta::assert_snapshot;
|
||||||
|
|
||||||
use super::{infer_with_mismatches, type_at};
|
use super::{check_types, infer_with_mismatches};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_never1() {
|
fn infer_never1() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
fn test() {
|
fn test() {
|
||||||
let t = return;
|
let t = return;
|
||||||
t<|>;
|
t;
|
||||||
}
|
} //^ !
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_never2() {
|
fn infer_never2() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
fn gen<T>() -> T { loop {} }
|
fn gen<T>() -> T { loop {} }
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
let a = gen();
|
let a = gen();
|
||||||
if false { a } else { loop {} };
|
if false { a } else { loop {} };
|
||||||
a<|>;
|
a;
|
||||||
}
|
} //^ !
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_never3() {
|
fn infer_never3() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
fn gen<T>() -> T { loop {} }
|
fn gen<T>() -> T { loop {} }
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
let a = gen();
|
let a = gen();
|
||||||
if false { loop {} } else { a };
|
if false { loop {} } else { a };
|
||||||
a<|>;
|
a;
|
||||||
|
//^ !
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn never_type_in_generic_args() {
|
fn never_type_in_generic_args() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
enum Option<T> { None, Some(T) }
|
enum Option<T> { None, Some(T) }
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
let a = if true { Option::None } else { Option::Some(return) };
|
let a = if true { Option::None } else { Option::Some(return) };
|
||||||
a<|>;
|
a;
|
||||||
}
|
} //^ Option<!>
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "Option<!>");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn never_type_can_be_reinferred1() {
|
fn never_type_can_be_reinferred1() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
fn gen<T>() -> T { loop {} }
|
fn gen<T>() -> T { loop {} }
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
let a = gen();
|
let a = gen();
|
||||||
if false { loop {} } else { a };
|
if false { loop {} } else { a };
|
||||||
a<|>;
|
a;
|
||||||
|
//^ ()
|
||||||
if false { a };
|
if false { a };
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "()");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn never_type_can_be_reinferred2() {
|
fn never_type_can_be_reinferred2() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
enum Option<T> { None, Some(T) }
|
enum Option<T> { None, Some(T) }
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
let a = if true { Option::None } else { Option::Some(return) };
|
let a = if true { Option::None } else { Option::Some(return) };
|
||||||
a<|>;
|
a;
|
||||||
|
//^ Option<i32>
|
||||||
match 42 {
|
match 42 {
|
||||||
42 => a,
|
42 => a,
|
||||||
_ => Option::Some(42),
|
_ => Option::Some(42),
|
||||||
|
@ -101,19 +93,18 @@ fn test() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "Option<i32>");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn never_type_can_be_reinferred3() {
|
fn never_type_can_be_reinferred3() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
enum Option<T> { None, Some(T) }
|
enum Option<T> { None, Some(T) }
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
let a = if true { Option::None } else { Option::Some(return) };
|
let a = if true { Option::None } else { Option::Some(return) };
|
||||||
a<|>;
|
a;
|
||||||
|
//^ Option<&str>
|
||||||
match 42 {
|
match 42 {
|
||||||
42 => a,
|
42 => a,
|
||||||
_ => Option::Some("str"),
|
_ => Option::Some("str"),
|
||||||
|
@ -121,82 +112,72 @@ fn test() {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "Option<&str>");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn match_no_arm() {
|
fn match_no_arm() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
enum Void {}
|
enum Void {}
|
||||||
|
|
||||||
fn test(a: Void) {
|
fn test(a: Void) {
|
||||||
let t = match a {};
|
let t = match a {};
|
||||||
t<|>;
|
t;
|
||||||
}
|
} //^ !
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn match_unknown_arm() {
|
fn match_unknown_arm() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
fn test(a: Option) {
|
fn test(a: Option) {
|
||||||
let t = match 0 {
|
let t = match 0 {
|
||||||
_ => unknown,
|
_ => unknown,
|
||||||
};
|
};
|
||||||
t<|>;
|
t;
|
||||||
}
|
} //^ {unknown}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "{unknown}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn if_never() {
|
fn if_never() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
fn test() {
|
fn test() {
|
||||||
let i = if true {
|
let i = if true {
|
||||||
loop {}
|
loop {}
|
||||||
} else {
|
} else {
|
||||||
3.0
|
3.0
|
||||||
};
|
};
|
||||||
i<|>;
|
i;
|
||||||
}
|
} //^ f64
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "f64");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn if_else_never() {
|
fn if_else_never() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
fn test(input: bool) {
|
fn test(input: bool) {
|
||||||
let i = if input {
|
let i = if input {
|
||||||
2.0
|
2.0
|
||||||
} else {
|
} else {
|
||||||
return
|
return
|
||||||
};
|
};
|
||||||
i<|>;
|
i;
|
||||||
}
|
} //^ f64
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "f64");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn match_first_arm_never() {
|
fn match_first_arm_never() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
fn test(a: i32) {
|
fn test(a: i32) {
|
||||||
let i = match a {
|
let i = match a {
|
||||||
1 => return,
|
1 => return,
|
||||||
|
@ -204,18 +185,16 @@ fn test(a: i32) {
|
||||||
3 => loop {},
|
3 => loop {},
|
||||||
_ => 3.0,
|
_ => 3.0,
|
||||||
};
|
};
|
||||||
i<|>;
|
i;
|
||||||
}
|
} //^ f64
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "f64");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn match_second_arm_never() {
|
fn match_second_arm_never() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
fn test(a: i32) {
|
fn test(a: i32) {
|
||||||
let i = match a {
|
let i = match a {
|
||||||
1 => 3.0,
|
1 => 3.0,
|
||||||
|
@ -223,45 +202,40 @@ fn test(a: i32) {
|
||||||
3 => 3.0,
|
3 => 3.0,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
i<|>;
|
i;
|
||||||
}
|
} //^ f64
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "f64");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn match_all_arms_never() {
|
fn match_all_arms_never() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
fn test(a: i32) {
|
fn test(a: i32) {
|
||||||
let i = match a {
|
let i = match a {
|
||||||
2 => return,
|
2 => return,
|
||||||
_ => loop {},
|
_ => loop {},
|
||||||
};
|
};
|
||||||
i<|>;
|
i;
|
||||||
}
|
} //^ !
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn match_no_never_arms() {
|
fn match_no_never_arms() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
fn test(a: i32) {
|
fn test(a: i32) {
|
||||||
let i = match a {
|
let i = match a {
|
||||||
2 => 2.0,
|
2 => 2.0,
|
||||||
_ => 3.0,
|
_ => 3.0,
|
||||||
};
|
};
|
||||||
i<|>;
|
i;
|
||||||
}
|
} //^ f64
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "f64");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
use super::{infer, type_at, type_at_pos};
|
|
||||||
use crate::test_db::TestDB;
|
|
||||||
use insta::assert_snapshot;
|
use insta::assert_snapshot;
|
||||||
use ra_db::fixture::WithFixture;
|
|
||||||
|
use super::{check_types, infer};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_box() {
|
fn infer_box() {
|
||||||
let (db, pos) = TestDB::with_position(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs crate:main deps:std
|
//- /main.rs crate:main deps:std
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
let x = box 1;
|
let x = box 1;
|
||||||
let t = (x, box x, box &1, box [1]);
|
let t = (x, box x, box &1, box [1]);
|
||||||
t<|>;
|
t;
|
||||||
}
|
} //^ (Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; _]>)
|
||||||
|
|
||||||
//- /std.rs crate:std
|
//- /std.rs crate:std
|
||||||
#[prelude_import] use prelude::*;
|
#[prelude_import] use prelude::*;
|
||||||
|
@ -25,29 +23,24 @@ mod boxed {
|
||||||
inner: *mut T,
|
inner: *mut T,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!("(Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32; _]>)", type_at_pos(&db, pos));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_adt_self() {
|
fn infer_adt_self() {
|
||||||
let (db, pos) = TestDB::with_position(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
enum Nat { Succ(Self), Demo(Nat), Zero }
|
enum Nat { Succ(Self), Demo(Nat), Zero }
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
let foo: Nat = Nat::Zero;
|
let foo: Nat = Nat::Zero;
|
||||||
if let Nat::Succ(x) = foo {
|
if let Nat::Succ(x) = foo {
|
||||||
x<|>
|
x
|
||||||
|
} //^ Nat
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!("Nat", type_at_pos(&db, pos));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -93,7 +86,7 @@ fn foo() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_ranges() {
|
fn infer_ranges() {
|
||||||
let (db, pos) = TestDB::with_position(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs crate:main deps:core
|
//- /main.rs crate:main deps:core
|
||||||
fn test() {
|
fn test() {
|
||||||
|
@ -105,8 +98,8 @@ fn test() {
|
||||||
let f = 'a'..='z';
|
let f = 'a'..='z';
|
||||||
|
|
||||||
let t = (a, b, c, d, e, f);
|
let t = (a, b, c, d, e, f);
|
||||||
t<|>;
|
t;
|
||||||
}
|
} //^ (RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>)
|
||||||
|
|
||||||
//- /core.rs crate:core
|
//- /core.rs crate:core
|
||||||
#[prelude_import] use prelude::*;
|
#[prelude_import] use prelude::*;
|
||||||
|
@ -135,29 +128,22 @@ pub mod ops {
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!(
|
|
||||||
"(RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>)",
|
|
||||||
type_at_pos(&db, pos),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn infer_while_let() {
|
fn infer_while_let() {
|
||||||
let (db, pos) = TestDB::with_position(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
enum Option<T> { Some(T), None }
|
enum Option<T> { Some(T), None }
|
||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
let foo: Option<f32> = None;
|
let foo: Option<f32> = None;
|
||||||
while let Option::Some(x) = foo {
|
while let Option::Some(x) = foo {
|
||||||
<|>x
|
x
|
||||||
|
} //^ f32
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
assert_eq!("f32", type_at_pos(&db, pos));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1687,9 +1673,8 @@ fn test() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn shadowing_primitive() {
|
fn shadowing_primitive() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /main.rs
|
|
||||||
struct i32;
|
struct i32;
|
||||||
struct Foo;
|
struct Foo;
|
||||||
|
|
||||||
|
@ -1697,15 +1682,15 @@ impl i32 { fn foo(&self) -> Foo { Foo } }
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x: i32 = i32;
|
let x: i32 = i32;
|
||||||
x.foo()<|>;
|
x.foo();
|
||||||
|
//^ Foo
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "Foo");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn not_shadowing_primitive_by_module() {
|
fn not_shadowing_primitive_by_module() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /str.rs
|
//- /str.rs
|
||||||
fn foo() {}
|
fn foo() {}
|
||||||
|
@ -1715,15 +1700,15 @@ mod str;
|
||||||
fn foo() -> &'static str { "" }
|
fn foo() -> &'static str { "" }
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
foo()<|>;
|
foo();
|
||||||
|
//^ &str
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "&str");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn not_shadowing_module_by_primitive() {
|
fn not_shadowing_module_by_primitive() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
//- /str.rs
|
//- /str.rs
|
||||||
fn foo() -> u32 {0}
|
fn foo() -> u32 {0}
|
||||||
|
@ -1733,10 +1718,10 @@ mod str;
|
||||||
fn foo() -> &'static str { "" }
|
fn foo() -> &'static str { "" }
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
str::foo()<|>;
|
str::foo();
|
||||||
|
//^ u32
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "u32");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This test is actually testing the shadowing behavior within ra_hir_def. It
|
// This test is actually testing the shadowing behavior within ra_hir_def. It
|
||||||
|
@ -1744,7 +1729,7 @@ fn main() {
|
||||||
// capable of asserting the necessary conditions.
|
// capable of asserting the necessary conditions.
|
||||||
#[test]
|
#[test]
|
||||||
fn should_be_shadowing_imports() {
|
fn should_be_shadowing_imports() {
|
||||||
let t = type_at(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
mod a {
|
mod a {
|
||||||
pub fn foo() -> i8 {0}
|
pub fn foo() -> i8 {0}
|
||||||
|
@ -1759,30 +1744,12 @@ mod d {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
d::foo()<|>;
|
d::foo();
|
||||||
|
//^ u8
|
||||||
|
d::foo{a:0};
|
||||||
|
//^ u8
|
||||||
}"#,
|
}"#,
|
||||||
);
|
);
|
||||||
assert_eq!(t, "u8");
|
|
||||||
|
|
||||||
let t = type_at(
|
|
||||||
r#"
|
|
||||||
mod a {
|
|
||||||
pub fn foo() -> i8 {0}
|
|
||||||
pub struct foo { a: i8 }
|
|
||||||
}
|
|
||||||
mod b { pub fn foo () -> u8 {0} }
|
|
||||||
mod c { pub struct foo { a: u8 } }
|
|
||||||
mod d {
|
|
||||||
pub use super::a::*;
|
|
||||||
pub use super::c::foo;
|
|
||||||
pub use super::b::foo;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
d::foo{a:0<|>};
|
|
||||||
}"#,
|
|
||||||
);
|
|
||||||
assert_eq!(t, "u8");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -16,6 +16,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
use stdx::lines_with_ends;
|
||||||
use text_size::{TextRange, TextSize};
|
use text_size::{TextRange, TextSize};
|
||||||
|
|
||||||
pub use difference::Changeset as __Changeset;
|
pub use difference::Changeset as __Changeset;
|
||||||
|
@ -159,6 +160,39 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extracts `//^ some text` annotations
|
||||||
|
pub fn extract_annotations(text: &str) -> Vec<(TextSize, String)> {
|
||||||
|
let mut res = Vec::new();
|
||||||
|
let mut prev_line_start: Option<TextSize> = None;
|
||||||
|
let mut line_start: TextSize = 0.into();
|
||||||
|
for line in lines_with_ends(text) {
|
||||||
|
if let Some(idx) = line.find("//^") {
|
||||||
|
let offset = prev_line_start.unwrap() + TextSize::of(&line[..idx + "//".len()]);
|
||||||
|
let data = line[idx + "//^".len()..].trim().to_string();
|
||||||
|
res.push((offset, data))
|
||||||
|
}
|
||||||
|
prev_line_start = Some(line_start);
|
||||||
|
line_start += TextSize::of(line);
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_extract_annotations() {
|
||||||
|
let res = extract_annotations(&trim_indent(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
let x = 92;
|
||||||
|
//^ def
|
||||||
|
|
||||||
|
x + 1
|
||||||
|
} //^ i32
|
||||||
|
"#,
|
||||||
|
));
|
||||||
|
|
||||||
|
assert_eq!(res, vec![(20.into(), "def".into()), (47.into(), "i32".into())]);
|
||||||
|
}
|
||||||
|
|
||||||
// Comparison functionality borrowed from cargo:
|
// Comparison functionality borrowed from cargo:
|
||||||
|
|
||||||
/// Compare a line with an expected pattern.
|
/// Compare a line with an expected pattern.
|
||||||
|
|
Loading…
Reference in a new issue