diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs index 4d0dc30115..5424e6bb19 100644 --- a/crates/ra_hir_ty/src/tests.rs +++ b/crates/ra_hir_ty/src/tests.rs @@ -17,11 +17,11 @@ use hir_def::{ item_scope::ItemScope, keys, nameres::CrateDefMap, - AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, ModuleId, + AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, }; use hir_expand::{db::AstDatabase, InFile}; use insta::assert_snapshot; -use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; +use ra_db::{fixture::WithFixture, salsa::Database, FileRange, SourceDatabase}; use ra_syntax::{ algo, ast::{self, AstNode}, @@ -39,13 +39,27 @@ use crate::{ // update the snapshots. fn check_types(ra_fixture: &str) { + check_types_impl(ra_fixture, false) +} + +fn check_types_source_code(ra_fixture: &str) { + check_types_impl(ra_fixture, true) +} + +fn check_types_impl(ra_fixture: &str, display_source: bool) { 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 }); + for (range, expected) in annotations { + let ty = type_at_range(&db, FileRange { file_id, range }); + let actual = if display_source { + let module = db.module_for_file(file_id); + ty.display_source_code(&db, module).unwrap() + } else { + ty.display(&db).to_string() + }; assert_eq!(expected, actual); checked_one = true; } @@ -53,21 +67,9 @@ fn check_types(ra_fixture: &str) { assert!(checked_one, "no `//^` annotations found"); } -fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { - type_at_pos_displayed(db, pos, |ty, _| ty.display(db).to_string()) -} - -fn displayed_source_at_pos(db: &TestDB, pos: FilePosition) -> String { - type_at_pos_displayed(db, pos, |ty, module_id| ty.display_source_code(db, module_id).unwrap()) -} - -fn type_at_pos_displayed( - db: &TestDB, - pos: FilePosition, - display_fn: impl FnOnce(&Ty, ModuleId) -> String, -) -> String { +fn type_at_range(db: &TestDB, pos: FileRange) -> Ty { let file = db.parse(pos.file_id).ok().unwrap(); - let expr = algo::find_node_at_offset::(file.syntax(), pos.offset).unwrap(); + let expr = algo::find_node_at_range::(file.syntax(), pos.range).unwrap(); let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); let module = db.module_for_file(pos.file_id); let func = *module.child_by_source(db)[keys::FUNCTION] @@ -77,17 +79,11 @@ fn type_at_pos_displayed( let (_body, source_map) = db.body_with_source_map(func.into()); if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) { let infer = db.infer(func.into()); - let ty = &infer[expr_id]; - return display_fn(ty, module); + return infer[expr_id].clone(); } panic!("Can't find expression") } -fn type_at(ra_fixture: &str) -> String { - let (db, file_pos) = TestDB::with_position(ra_fixture); - type_at_pos(&db, file_pos) -} - fn infer(ra_fixture: &str) -> String { infer_with_mismatches(ra_fixture, false) } diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index 5a1c6ccc35..136d28a916 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs @@ -1,7 +1,8 @@ -use super::infer_with_mismatches; use insta::assert_snapshot; use test_utils::mark; +use super::infer_with_mismatches; + // Infer with some common definitions and impls. fn infer(source: &str) -> String { let defs = r#" diff --git a/crates/ra_hir_ty/src/tests/display_source_code.rs b/crates/ra_hir_ty/src/tests/display_source_code.rs index 5dfa0a0145..b502135d8e 100644 --- a/crates/ra_hir_ty/src/tests/display_source_code.rs +++ b/crates/ra_hir_ty/src/tests/display_source_code.rs @@ -1,50 +1,41 @@ -use super::displayed_source_at_pos; -use crate::test_db::TestDB; -use ra_db::fixture::WithFixture; +use super::check_types_source_code; #[test] fn qualify_path_to_submodule() { - let (db, pos) = TestDB::with_position( + check_types_source_code( r#" -//- /main.rs - mod foo { pub struct Foo; } fn bar() { let foo: foo::Foo = foo::Foo; - foo<|> -} + foo +} //^ foo::Foo "#, ); - assert_eq!("foo::Foo", displayed_source_at_pos(&db, pos)); } #[test] fn omit_default_type_parameters() { - let (db, pos) = TestDB::with_position( - r" - //- /main.rs - struct Foo { t: T } - fn main() { - let foo = Foo { t: 5u8 }; - foo<|>; - } - ", + check_types_source_code( + r#" +struct Foo { t: T } +fn main() { + let foo = Foo { t: 5u8 }; + foo; +} //^ Foo +"#, ); - assert_eq!("Foo", displayed_source_at_pos(&db, pos)); - let (db, pos) = TestDB::with_position( - r" - //- /main.rs - struct Foo { k: K, t: T } - fn main() { - let foo = Foo { k: 400, t: 5u8 }; - foo<|>; - } - ", + check_types_source_code( + r#" +struct Foo { k: K, t: T } +fn main() { + let foo = Foo { k: 400, t: 5u8 }; + foo; +} //^ Foo +"#, ); - assert_eq!("Foo", displayed_source_at_pos(&db, pos)); } diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs index be2b48dcc0..45c4e309e2 100644 --- a/crates/ra_hir_ty/src/tests/macros.rs +++ b/crates/ra_hir_ty/src/tests/macros.rs @@ -1,16 +1,13 @@ use std::fs; use insta::assert_snapshot; -use ra_db::fixture::WithFixture; use test_utils::project_dir; -use crate::test_db::TestDB; - -use super::{infer, type_at, type_at_pos}; +use super::{check_types, infer}; #[test] fn cfg_impl_def() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:foo cfg:test use foo::S as T; @@ -28,8 +25,8 @@ impl S { fn test() { let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4()); - t<|>; -} + t; +} //^ (i32, {unknown}, i32, {unknown}) //- /foo.rs crate:foo struct S; @@ -45,7 +42,6 @@ impl S { } "#, ); - assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos)); } #[test] @@ -253,26 +249,24 @@ fn foo() { #[test] fn processes_impls_generated_by_macros() { - let t = type_at( + check_types( r#" -//- /main.rs macro_rules! m { ($ident:ident) => (impl Trait for $ident {}) } trait Trait { fn foo(self) -> u128 {} } struct S; m!(S); -fn test() { S.foo()<|>; } +fn test() { S.foo(); } + //^ u128 "#, ); - assert_eq!(t, "u128"); } #[test] fn infer_assoc_items_generated_by_macros() { - let t = type_at( + check_types( r#" -//- /main.rs macro_rules! m { () => (fn foo(&self) -> u128 {0}) } @@ -281,17 +275,16 @@ impl S { m!(); } -fn test() { S.foo()<|>; } +fn test() { S.foo(); } + //^ u128 "#, ); - assert_eq!(t, "u128"); } #[test] fn infer_assoc_items_generated_by_macros_chain() { - let t = type_at( + check_types( r#" -//- /main.rs macro_rules! m_inner { () => {fn foo(&self) -> u128 {0}} } @@ -304,21 +297,21 @@ impl S { m!(); } -fn test() { S.foo()<|>; } +fn test() { S.foo(); } + //^ u128 "#, ); - assert_eq!(t, "u128"); } #[test] fn infer_macro_with_dollar_crate_is_correct_in_expr() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:foo fn test() { let x = (foo::foo!(1), foo::foo!(2)); - x<|>; -} + x; +} //^ (i32, usize) //- /lib.rs crate:foo #[macro_export] @@ -335,12 +328,11 @@ macro_rules! bar { pub fn baz() -> usize { 31usize } "#, ); - assert_eq!("(i32, usize)", type_at_pos(&db, pos)); } #[test] fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:foo use foo::Trait; @@ -348,7 +340,8 @@ use foo::Trait; fn test() { let msg = foo::Message(foo::MessageRef); let r = msg.deref(); - r<|>; + r; + //^ &MessageRef } //- /lib.rs crate:foo @@ -375,7 +368,6 @@ macro_rules! expand { expand!(); "#, ); - assert_eq!("&MessageRef", type_at_pos(&db, pos)); } #[test] @@ -429,13 +421,13 @@ fn main() { #[test] fn infer_local_inner_macros() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:foo fn test() { let x = foo::foo!(1); - x<|>; -} + x; +} //^ i32 //- /lib.rs crate:foo #[macro_export(local_inner_macros)] @@ -450,7 +442,6 @@ macro_rules! bar { "#, ); - assert_eq!("i32", type_at_pos(&db, pos)); } #[test] @@ -531,7 +522,7 @@ fn main() { #[test] fn infer_builtin_macros_include() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs #[rustc_builtin_macro] @@ -540,14 +531,13 @@ macro_rules! include {() => {}} include!("foo.rs"); fn main() { - bar()<|>; -} + bar(); +} //^ u32 //- /foo.rs fn bar() -> u32 {0} "#, ); - assert_eq!("u32", type_at_pos(&db, pos)); } #[test] @@ -565,18 +555,17 @@ macro_rules! include {() => {}} include!("foo.rs"); fn main() { - RegisterBlock { }<|>; + RegisterBlock { }; + //^ RegisterBlock } "#; let fixture = format!("{}\n//- /foo.rs\n{}", fixture, big_file); - - let (db, pos) = TestDB::with_position(&fixture); - assert_eq!("RegisterBlock", type_at_pos(&db, pos)); + check_types(&fixture); } #[test] fn infer_builtin_macros_include_concat() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs #[rustc_builtin_macro] @@ -588,19 +577,18 @@ macro_rules! concat {() => {}} include!(concat!("f", "oo.rs")); fn main() { - bar()<|>; -} + bar(); +} //^ u32 //- /foo.rs fn bar() -> u32 {0} "#, ); - assert_eq!("u32", type_at_pos(&db, pos)); } #[test] fn infer_builtin_macros_include_concat_with_bad_env_should_failed() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs #[rustc_builtin_macro] @@ -615,32 +603,29 @@ macro_rules! env {() => {}} include!(concat!(env!("OUT_DIR"), "/foo.rs")); fn main() { - bar()<|>; -} + bar(); +} //^ {unknown} //- /foo.rs fn bar() -> u32 {0} "#, ); - assert_eq!("{unknown}", type_at_pos(&db, pos)); } #[test] fn infer_builtin_macros_include_itself_should_failed() { - let (db, pos) = TestDB::with_position( + check_types( r#" -//- /main.rs #[rustc_builtin_macro] macro_rules! include {() => {}} include!("main.rs"); fn main() { - 0<|> -} + 0 +} //^ i32 "#, ); - assert_eq!("i32", type_at_pos(&db, pos)); } #[test] @@ -686,14 +671,14 @@ fn main() { #[test] fn infer_derive_clone_simple() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:core #[derive(Clone)] struct S; fn test() { - S.clone()<|>; -} + S.clone(); +} //^ S //- /lib.rs crate:core #[prelude_import] @@ -705,12 +690,11 @@ mod clone { } "#, ); - assert_eq!("S", type_at_pos(&db, pos)); } #[test] fn infer_derive_clone_in_core() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /lib.rs crate:core #[prelude_import] @@ -726,16 +710,15 @@ pub struct S; //- /main.rs crate:main deps:core use core::S; fn test() { - S.clone()<|>; -} + S.clone(); +} //^ S "#, ); - assert_eq!("S", type_at_pos(&db, pos)); } #[test] fn infer_derive_clone_with_params() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:core #[derive(Clone)] @@ -744,7 +727,8 @@ struct S; struct Wrapper(T); struct NonClone; fn test() { - (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>; + (Wrapper(S).clone(), Wrapper(NonClone).clone()); + //^ (Wrapper, {unknown}) } //- /lib.rs crate:core @@ -757,13 +741,12 @@ mod clone { } "#, ); - assert_eq!("(Wrapper, {unknown})", type_at_pos(&db, pos)); } #[test] fn infer_custom_derive_simple() { // FIXME: this test current now do nothing - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main use foo::Foo; @@ -772,11 +755,10 @@ use foo::Foo; struct S{} fn test() { - S{}<|>; -} + S{}; +} //^ S "#, ); - assert_eq!("S", type_at_pos(&db, pos)); } #[test] diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs index 20329bae47..9c8f223141 100644 --- a/crates/ra_hir_ty/src/tests/method_resolution.rs +++ b/crates/ra_hir_ty/src/tests/method_resolution.rs @@ -1,7 +1,6 @@ -use super::{infer, type_at, type_at_pos}; -use crate::test_db::TestDB; use insta::assert_snapshot; -use ra_db::fixture::WithFixture; + +use super::{check_types, infer}; #[test] fn infer_slice_method() { @@ -246,13 +245,13 @@ fn test() { #[test] fn cross_crate_associated_method_call() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:other_crate fn test() { let x = other_crate::foo::S::thing(); - x<|>; -} + x; +} //^ i128 //- /lib.rs crate:other_crate mod foo { @@ -263,7 +262,6 @@ mod foo { } "#, ); - assert_eq!("i128", type_at_pos(&db, pos)); } #[test] @@ -684,135 +682,127 @@ fn test() { #[test] fn method_resolution_unify_impl_self_type() { - let t = type_at( + check_types( r#" -//- /main.rs struct S; impl S { fn foo(&self) -> u8 {} } impl S { fn foo(&self) -> i8 {} } -fn test() { (S::.foo(), S::.foo())<|>; } +fn test() { (S::.foo(), S::.foo()); } + //^ (u8, i8) "#, ); - assert_eq!(t, "(u8, i8)"); } #[test] fn method_resolution_trait_before_autoref() { - let t = type_at( + check_types( r#" -//- /main.rs trait Trait { fn foo(self) -> u128; } struct S; impl S { fn foo(&self) -> i8 { 0 } } impl Trait for S { fn foo(self) -> u128 { 0 } } -fn test() { S.foo()<|>; } +fn test() { S.foo(); } + //^ u128 "#, ); - assert_eq!(t, "u128"); } #[test] fn method_resolution_by_value_before_autoref() { - let t = type_at( + check_types( r#" -//- /main.rs trait Clone { fn clone(&self) -> Self; } struct S; impl Clone for S {} impl Clone for &S {} -fn test() { (S.clone(), (&S).clone(), (&&S).clone())<|>; } +fn test() { (S.clone(), (&S).clone(), (&&S).clone()); } + //^ (S, S, &S) "#, ); - assert_eq!(t, "(S, S, &S)"); } #[test] fn method_resolution_trait_before_autoderef() { - let t = type_at( + check_types( r#" -//- /main.rs trait Trait { fn foo(self) -> u128; } struct S; impl S { fn foo(self) -> i8 { 0 } } impl Trait for &S { fn foo(self) -> u128 { 0 } } -fn test() { (&S).foo()<|>; } +fn test() { (&S).foo(); } + //^ u128 "#, ); - assert_eq!(t, "u128"); } #[test] fn method_resolution_impl_before_trait() { - let t = type_at( + check_types( r#" -//- /main.rs trait Trait { fn foo(self) -> u128; } struct S; impl S { fn foo(self) -> i8 { 0 } } impl Trait for S { fn foo(self) -> u128 { 0 } } -fn test() { S.foo()<|>; } +fn test() { S.foo(); } + //^ i8 "#, ); - assert_eq!(t, "i8"); } #[test] fn method_resolution_impl_ref_before_trait() { - let t = type_at( + check_types( r#" -//- /main.rs trait Trait { fn foo(self) -> u128; } struct S; impl S { fn foo(&self) -> i8 { 0 } } impl Trait for &S { fn foo(self) -> u128 { 0 } } -fn test() { S.foo()<|>; } +fn test() { S.foo(); } + //^ i8 "#, ); - assert_eq!(t, "i8"); } #[test] fn method_resolution_trait_autoderef() { - let t = type_at( + check_types( r#" -//- /main.rs trait Trait { fn foo(self) -> u128; } struct S; impl Trait for S { fn foo(self) -> u128 { 0 } } -fn test() { (&S).foo()<|>; } +fn test() { (&S).foo(); } + //^ u128 "#, ); - assert_eq!(t, "u128"); } #[test] fn method_resolution_unsize_array() { - let t = type_at( + check_types( r#" -//- /main.rs #[lang = "slice"] impl [T] { fn len(&self) -> usize { loop {} } } fn test() { let a = [1, 2, 3]; - a.len()<|>; -} + a.len(); +} //^ usize "#, ); - assert_eq!(t, "usize"); } #[test] fn method_resolution_trait_from_prelude() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:other_crate struct S; impl Clone for S {} fn test() { - S.clone()<|>; + S.clone(); + //^ S } //- /lib.rs crate:other_crate @@ -825,115 +815,107 @@ mod foo { } "#, ); - assert_eq!("S", type_at_pos(&db, pos)); } #[test] fn method_resolution_where_clause_for_unknown_trait() { // The blanket impl currently applies because we ignore the unresolved where clause - let t = type_at( + check_types( r#" -//- /main.rs trait Trait { fn foo(self) -> u128; } struct S; impl Trait for T where T: UnknownTrait {} -fn test() { (&S).foo()<|>; } +fn test() { (&S).foo(); } + //^ u128 "#, ); - assert_eq!(t, "u128"); } #[test] fn method_resolution_where_clause_not_met() { // The blanket impl shouldn't apply because we can't prove S: Clone - let t = type_at( + // This is also to make sure that we don't resolve to the foo method just + // because that's the only method named foo we can find, which would make + // the below tests not work + check_types( r#" -//- /main.rs trait Clone {} trait Trait { fn foo(self) -> u128; } struct S; impl Trait for T where T: Clone {} -fn test() { (&S).foo()<|>; } +fn test() { (&S).foo(); } + //^ {unknown} "#, ); - // This is also to make sure that we don't resolve to the foo method just - // because that's the only method named foo we can find, which would make - // the below tests not work - assert_eq!(t, "{unknown}"); } #[test] fn method_resolution_where_clause_inline_not_met() { // The blanket impl shouldn't apply because we can't prove S: Clone - let t = type_at( + check_types( r#" -//- /main.rs trait Clone {} trait Trait { fn foo(self) -> u128; } struct S; impl Trait for T {} -fn test() { (&S).foo()<|>; } +fn test() { (&S).foo(); } + //^ {unknown} "#, ); - assert_eq!(t, "{unknown}"); } #[test] fn method_resolution_where_clause_1() { - let t = type_at( + check_types( r#" -//- /main.rs trait Clone {} trait Trait { fn foo(self) -> u128; } struct S; impl Clone for S {} impl Trait for T where T: Clone {} -fn test() { S.foo()<|>; } +fn test() { S.foo(); } + //^ u128 "#, ); - assert_eq!(t, "u128"); } #[test] fn method_resolution_where_clause_2() { - let t = type_at( + check_types( r#" -//- /main.rs trait Into { fn into(self) -> T; } trait From { fn from(other: T) -> Self; } struct S1; struct S2; impl From for S1 {} impl Into for T where U: From {} -fn test() { S2.into()<|>; } +fn test() { S2.into(); } + //^ {unknown} "#, ); - assert_eq!(t, "{unknown}"); } #[test] fn method_resolution_where_clause_inline() { - let t = type_at( + check_types( r#" -//- /main.rs trait Into { fn into(self) -> T; } trait From { fn from(other: T) -> Self; } struct S1; struct S2; impl From for S1 {} impl> Into for T {} -fn test() { S2.into()<|>; } +fn test() { S2.into(); } + //^ {unknown} "#, ); - assert_eq!(t, "{unknown}"); } #[test] fn method_resolution_overloaded_method() { test_utils::mark::check!(impl_self_type_match_without_receiver); - let t = type_at( + check_types( r#" -//- /main.rs struct Wrapper(T); struct Foo(T); struct Bar(T); @@ -953,30 +935,30 @@ impl Wrapper> { fn main() { let a = Wrapper::>::new(1.0); let b = Wrapper::>::new(1.0); - (a, b)<|>; + (a, b); + //^ (Wrapper>, Wrapper>) } "#, ); - assert_eq!(t, "(Wrapper>, Wrapper>)") } #[test] fn method_resolution_encountering_fn_type() { - type_at( + check_types( r#" //- /main.rs fn foo() {} trait FnOnce { fn call(self); } -fn test() { foo.call()<|>; } +fn test() { foo.call(); } + //^ {unknown} "#, ); } #[test] fn method_resolution_non_parameter_type() { - let t = type_at( + check_types( r#" -//- /main.rs mod a { pub trait Foo { fn foo(&self); @@ -988,18 +970,16 @@ fn foo(t: Wrapper) where Wrapper: a::Foo, { - t.foo()<|>; -} + t.foo(); +} //^ {unknown} "#, ); - assert_eq!(t, "{unknown}"); } #[test] fn method_resolution_3373() { - let t = type_at( + check_types( r#" -//- /main.rs struct A(T); impl A { @@ -1007,19 +987,17 @@ impl A { } fn main() { - A::from(3)<|>; -} + A::from(3); +} //^ A "#, ); - assert_eq!(t, "A"); } #[test] fn method_resolution_slow() { // this can get quite slow if we set the solver size limit too high - let t = type_at( + check_types( r#" -//- /main.rs trait SendX {} struct S1; impl SendX for S1 {} @@ -1037,10 +1015,10 @@ trait FnX {} impl Trait for S where C: FnX, B: SendX {} -fn test() { (S {}).method()<|>; } +fn test() { (S {}).method(); } + //^ () "#, ); - assert_eq!(t, "()"); } #[test] diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs index aa37326dff..d806e0ffb3 100644 --- a/crates/ra_hir_ty/src/tests/regression.rs +++ b/crates/ra_hir_ty/src/tests/regression.rs @@ -1,10 +1,7 @@ use insta::assert_snapshot; -use ra_db::fixture::WithFixture; use test_utils::mark; -use crate::test_db::TestDB; - -use super::infer; +use super::{check_types, infer}; #[test] fn bug_484() { @@ -404,13 +401,13 @@ fn test() { #[test] fn issue_2683_chars_impl() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:std fn test() { let chars: std::str::Chars<'_>; - (chars.next(), chars.nth(1))<|>; -} + (chars.next(), chars.nth(1)); +} //^ (Option, Option) //- /std.rs crate:std #[prelude_import] @@ -449,15 +446,12 @@ pub mod str { } "#, ); - - assert_eq!("(Option, Option)", super::type_at_pos(&db, pos)); } #[test] fn issue_3642_bad_macro_stackover() { - let (db, pos) = TestDB::with_position( + check_types( r#" -//- /main.rs #[macro_export] macro_rules! match_ast { (match $node:ident { $($tt:tt)* }) => { match_ast!(match ($node) { $($tt)* }) }; @@ -472,7 +466,8 @@ macro_rules! match_ast { } fn main() { - let anchor<|> = match_ast! { + let anchor = match_ast! { + //^ () match parent { as => {}, _ => return None @@ -480,8 +475,6 @@ fn main() { }; }"#, ); - - assert_eq!("()", super::type_at_pos(&db, pos)); } #[test] diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 71c0c2d27e..01c919a7ec 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs @@ -1,17 +1,13 @@ use insta::assert_snapshot; -use ra_db::fixture::WithFixture; use test_utils::mark; -use crate::test_db::TestDB; - -use super::{infer, infer_with_mismatches, type_at, type_at_pos}; +use super::{check_types, infer, infer_with_mismatches}; #[test] fn infer_await() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:core - struct IntFuture; impl Future for IntFuture { @@ -21,8 +17,8 @@ impl Future for IntFuture { fn test() { let r = IntFuture; let v = r.await; - v<|>; -} + v; +} //^ u64 //- /core.rs crate:core #[prelude_import] use future::*; @@ -32,18 +28,15 @@ mod future { type Output; } } - "#, ); - assert_eq!("u64", type_at_pos(&db, pos)); } #[test] fn infer_async() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:core - async fn foo() -> u64 { 128 } @@ -51,8 +44,8 @@ async fn foo() -> u64 { fn test() { let r = foo(); let v = r.await; - v<|>; -} + v; +} //^ u64 //- /core.rs crate:core #[prelude_import] use future::*; @@ -62,26 +55,23 @@ mod future { type Output; } } - "#, ); - assert_eq!("u64", type_at_pos(&db, pos)); } #[test] fn infer_desugar_async() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:core - async fn foo() -> u64 { 128 } fn test() { let r = foo(); - r<|>; -} + r; +} //^ impl Future //- /core.rs crate:core #[prelude_import] use future::*; @@ -93,23 +83,20 @@ mod future { "#, ); - assert_eq!("impl Future", type_at_pos(&db, pos)); } #[test] fn infer_try() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:core - fn test() { let r: Result = Result::Ok(1); let v = r?; - v<|>; -} + v; +} //^ i32 //- /core.rs crate:core - #[prelude_import] use ops::*; mod ops { trait Try { @@ -130,30 +117,26 @@ mod result { type Error = E; } } - "#, ); - assert_eq!("i32", type_at_pos(&db, pos)); } #[test] fn infer_for_loop() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:core,alloc - use alloc::collections::Vec; fn test() { let v = Vec::new(); v.push("foo"); for x in v { - x<|>; - } + x; + } //^ &str } //- /core.rs crate:core - #[prelude_import] use iter::*; mod iter { trait IntoIterator { @@ -162,7 +145,6 @@ mod iter { } //- /alloc.rs crate:alloc deps:core - mod collections { struct Vec {} impl Vec { @@ -176,15 +158,13 @@ mod collections { } "#, ); - assert_eq!("&str", type_at_pos(&db, pos)); } #[test] fn infer_ops_neg() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:std - struct Bar; struct Foo; @@ -195,11 +175,10 @@ impl std::ops::Neg for Bar { fn test() { let a = Bar; let b = -a; - b<|>; -} + b; +} //^ Foo //- /std.rs crate:std - #[prelude_import] use ops::*; mod ops { #[lang = "neg"] @@ -209,15 +188,13 @@ mod ops { } "#, ); - assert_eq!("Foo", type_at_pos(&db, pos)); } #[test] fn infer_ops_not() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:std - struct Bar; struct Foo; @@ -228,11 +205,10 @@ impl std::ops::Not for Bar { fn test() { let a = Bar; let b = !a; - b<|>; -} + b; +} //^ Foo //- /std.rs crate:std - #[prelude_import] use ops::*; mod ops { #[lang = "not"] @@ -242,7 +218,6 @@ mod ops { } "#, ); - assert_eq!("Foo", type_at_pos(&db, pos)); } #[test] @@ -537,10 +512,9 @@ fn indexing_arrays() { #[test] fn infer_ops_index() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:std - struct Bar; struct Foo; @@ -551,11 +525,10 @@ impl std::ops::Index for Bar { fn test() { let a = Bar; let b = a[1u32]; - b<|>; -} + b; +} //^ Foo //- /std.rs crate:std - #[prelude_import] use ops::*; mod ops { #[lang = "index"] @@ -565,19 +538,18 @@ mod ops { } "#, ); - assert_eq!("Foo", type_at_pos(&db, pos)); } #[test] fn infer_ops_index_autoderef() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:std fn test() { let a = &[1u32, 2, 3]; let b = a[1u32]; - b<|>; -} + b; +} //^ u32 //- /std.rs crate:std impl ops::Index for [T] { @@ -593,14 +565,12 @@ mod ops { } "#, ); - assert_eq!("u32", type_at_pos(&db, pos)); } #[test] fn deref_trait() { - let t = type_at( + check_types( r#" -//- /main.rs #[lang = "deref"] trait Deref { type Target; @@ -618,16 +588,15 @@ impl S { } fn test(s: Arc) { - (*s, s.foo())<|>; -} + (*s, s.foo()); +} //^ (S, u128) "#, ); - assert_eq!(t, "(S, u128)"); } #[test] fn deref_trait_with_inference_var() { - let t = type_at( + check_types( r#" //- /main.rs #[lang = "deref"] @@ -647,19 +616,18 @@ fn foo(a: Arc) {} fn test() { let a = new_arc(); - let b = (*a)<|>; + let b = (*a); + //^ S foo(a); } "#, ); - assert_eq!(t, "S"); } #[test] fn deref_trait_infinite_recursion() { - let t = type_at( + check_types( r#" -//- /main.rs #[lang = "deref"] trait Deref { type Target; @@ -673,18 +641,16 @@ impl Deref for S { } fn test(s: S) { - s.foo()<|>; -} + s.foo(); +} //^ {unknown} "#, ); - assert_eq!(t, "{unknown}"); } #[test] fn deref_trait_with_question_mark_size() { - let t = type_at( + check_types( r#" -//- /main.rs #[lang = "deref"] trait Deref { type Target; @@ -702,18 +668,16 @@ impl S { } fn test(s: Arc) { - (*s, s.foo())<|>; -} + (*s, s.foo()); +} //^ (S, u128) "#, ); - assert_eq!(t, "(S, u128)"); } #[test] fn obligation_from_function_clause() { - let t = type_at( + check_types( r#" -//- /main.rs struct S; trait Trait {} @@ -722,16 +686,15 @@ impl Trait for S {} fn foo, U>(t: T) -> U {} fn test(s: S) { - foo(s)<|>; -} + (foo(s)); +} //^ u32 "#, ); - assert_eq!(t, "u32"); } #[test] fn obligation_from_method_clause() { - let t = type_at( + check_types( r#" //- /main.rs struct S; @@ -745,18 +708,16 @@ impl O { } fn test() { - O.foo(S)<|>; -} + O.foo(S); +} //^ isize "#, ); - assert_eq!(t, "isize"); } #[test] fn obligation_from_self_method_clause() { - let t = type_at( + check_types( r#" -//- /main.rs struct S; trait Trait {} @@ -767,18 +728,16 @@ impl S { } fn test() { - S.foo()<|>; -} + S.foo(); +} //^ i64 "#, ); - assert_eq!(t, "i64"); } #[test] fn obligation_from_impl_clause() { - let t = type_at( + check_types( r#" -//- /main.rs struct S; trait Trait {} @@ -790,32 +749,30 @@ impl> O { } fn test(o: O) { - o.foo()<|>; -} + o.foo(); +} //^ &str "#, ); - assert_eq!(t, "&str"); } #[test] fn generic_param_env_1() { - let t = type_at( + check_types( r#" -//- /main.rs trait Clone {} trait Trait { fn foo(self) -> u128; } struct S; impl Clone for S {} impl Trait for T where T: Clone {} -fn test(t: T) { t.foo()<|>; } +fn test(t: T) { t.foo(); } + //^ u128 "#, ); - assert_eq!(t, "u128"); } #[test] fn generic_param_env_1_not_met() { - let t = type_at( + check_types( r#" //- /main.rs trait Clone {} @@ -823,45 +780,42 @@ trait Trait { fn foo(self) -> u128; } struct S; impl Clone for S {} impl Trait for T where T: Clone {} -fn test(t: T) { t.foo()<|>; } +fn test(t: T) { t.foo(); } + //^ {unknown} "#, ); - assert_eq!(t, "{unknown}"); } #[test] fn generic_param_env_2() { - let t = type_at( + check_types( r#" -//- /main.rs trait Trait { fn foo(self) -> u128; } struct S; impl Trait for S {} -fn test(t: T) { t.foo()<|>; } +fn test(t: T) { t.foo(); } + //^ u128 "#, ); - assert_eq!(t, "u128"); } #[test] fn generic_param_env_2_not_met() { - let t = type_at( + check_types( r#" -//- /main.rs trait Trait { fn foo(self) -> u128; } struct S; impl Trait for S {} -fn test(t: T) { t.foo()<|>; } +fn test(t: T) { t.foo(); } + //^ {unknown} "#, ); - assert_eq!(t, "{unknown}"); } #[test] fn generic_param_env_deref() { - let t = type_at( + check_types( r#" -//- /main.rs #[lang = "deref"] trait Deref { type Target; @@ -870,17 +824,17 @@ trait Trait {} impl Deref for T where T: Trait { type Target = i128; } -fn test(t: T) { (*t)<|>; } +fn test(t: T) { (*t); } + //^ i128 "#, ); - assert_eq!(t, "i128"); } #[test] fn associated_type_placeholder() { - let t = type_at( + // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types]. + check_types( r#" -//- /main.rs pub trait ApplyL { type Out; } @@ -893,19 +847,16 @@ impl ApplyL for RefMutL { fn test() { let y: as ApplyL>::Out = no_matter; - y<|>; -} + y; +} //^ ApplyL::Out "#, ); - // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types]. - assert_eq!(t, "ApplyL::Out"); } #[test] fn associated_type_placeholder_2() { - let t = type_at( + check_types( r#" -//- /main.rs pub trait ApplyL { type Out; } @@ -913,11 +864,10 @@ fn foo(t: T) -> ::Out; fn test(t: T) { let y = foo(t); - y<|>; -} + y; +} //^ ApplyL::Out "#, ); - assert_eq!(t, "ApplyL::Out"); } #[test] @@ -1398,19 +1348,17 @@ fn test(a: impl Trait + 'lifetime, b: impl 'lifetime, c: impl (Trait), d: impl ( #[test] #[ignore] fn error_bound_chalk() { - let t = type_at( + check_types( r#" -//- /main.rs trait Trait { fn foo(&self) -> u32 {} } fn test(x: (impl Trait + UnknownTrait)) { - x.foo()<|>; -} + x.foo(); +} //^ u32 "#, ); - assert_eq!(t, "u32"); } #[test] @@ -1480,7 +1428,7 @@ fn test>(x: T, y: impl Trait) { #[test] fn impl_trait_assoc_binding_projection_bug() { - let (db, pos) = TestDB::with_position( + check_types( r#" //- /main.rs crate:main deps:std pub trait Language { @@ -1499,8 +1447,8 @@ trait Clone { fn api_walkthrough() { for node in foo() { - node.clone()<|>; - } + node.clone(); + } //^ {unknown} } //- /std.rs crate:std @@ -1518,7 +1466,6 @@ mod iter { } "#, ); - assert_eq!("{unknown}", type_at_pos(&db, pos)); } #[test] @@ -1549,9 +1496,8 @@ fn test>(x: T) { #[test] fn where_clause_trait_in_scope_for_method_resolution() { - let t = type_at( + check_types( r#" -//- /main.rs mod foo { trait Trait { fn foo(&self) -> u32 {} @@ -1559,11 +1505,10 @@ mod foo { } fn test(x: T) { - x.foo()<|>; -} + x.foo(); +} //^ u32 "#, ); - assert_eq!(t, "u32"); } #[test] @@ -2012,7 +1957,7 @@ fn test() { #[test] fn unselected_projection_in_trait_env_1() { - let t = type_at( + check_types( r#" //- /main.rs trait Trait { @@ -2025,18 +1970,16 @@ trait Trait2 { fn test() where T::Item: Trait2 { let x: T::Item = no_matter; - x.foo()<|>; -} + x.foo(); +} //^ u32 "#, ); - assert_eq!(t, "u32"); } #[test] fn unselected_projection_in_trait_env_2() { - let t = type_at( + check_types( r#" -//- /main.rs trait Trait { type Item; } @@ -2047,11 +1990,10 @@ trait Trait2 { fn test() where T::Item: Trait2, T: Trait, U: Trait<()> { let x: T::Item = no_matter; - x.foo()<|>; -} + x.foo(); +} //^ u32 "#, ); - assert_eq!(t, "u32"); } #[test] @@ -2097,9 +2039,8 @@ impl Trait for S2 { #[test] fn unselected_projection_on_trait_self() { - let t = type_at( + check_types( r#" -//- /main.rs trait Trait { type Item; @@ -2112,18 +2053,16 @@ impl Trait for S { } fn test() { - S.f()<|>; -} + S.f(); +} //^ u32 "#, ); - assert_eq!(t, "u32"); } #[test] fn unselected_projection_chalk_fold() { - let t = type_at( + check_types( r#" -//- /main.rs trait Interner {} trait Fold { type Result; @@ -2142,18 +2081,16 @@ where } fn foo(interner: &I, t: Ty) { - fold(interner, t)<|>; -} + fold(interner, t); +} //^ Ty "#, ); - assert_eq!(t, "Ty"); } #[test] fn trait_impl_self_ty() { - let t = type_at( + check_types( r#" -//- /main.rs trait Trait { fn foo(&self); } @@ -2163,18 +2100,16 @@ struct S; impl Trait for S {} fn test() { - S.foo()<|>; -} + S.foo(); +} //^ () "#, ); - assert_eq!(t, "()"); } #[test] fn trait_impl_self_ty_cycle() { - let t = type_at( + check_types( r#" -//- /main.rs trait Trait { fn foo(&self); } @@ -2184,18 +2119,17 @@ struct S; impl Trait for S {} fn test() { - S.foo()<|>; -} + S.foo(); +} //^ {unknown} "#, ); - assert_eq!(t, "{unknown}"); } #[test] fn unselected_projection_in_trait_env_cycle_1() { - let t = type_at( + // this is a legitimate cycle + check_types( r#" -//- /main.rs trait Trait { type Item; } @@ -2203,17 +2137,16 @@ trait Trait { trait Trait2 {} fn test() where T: Trait2 { - let x: T::Item = no_matter<|>; -} + let x: T::Item = no_matter; +} //^ {unknown} "#, ); - // this is a legitimate cycle - assert_eq!(t, "{unknown}"); } #[test] fn unselected_projection_in_trait_env_cycle_2() { - let t = type_at( + // this is a legitimate cycle + check_types( r#" //- /main.rs trait Trait { @@ -2221,19 +2154,16 @@ trait Trait { } fn test() where T: Trait, U: Trait { - let x: T::Item = no_matter<|>; -} + let x: T::Item = no_matter; +} //^ {unknown} "#, ); - // this is a legitimate cycle - assert_eq!(t, "{unknown}"); } #[test] fn inline_assoc_type_bounds_1() { - let t = type_at( + check_types( r#" -//- /main.rs trait Iterator { type Item; } @@ -2249,29 +2179,26 @@ impl Iterator for S { fn test>>() { let x: as Iterator>::Item; - x.foo()<|>; -} + x.foo(); +} //^ u32 "#, ); - assert_eq!(t, "u32"); } #[test] fn inline_assoc_type_bounds_2() { - let t = type_at( + check_types( r#" -//- /main.rs trait Iterator { type Item; } fn test>>() { let x: <::Item as Iterator>::Item; - x<|>; -} + x; +} //^ u32 "#, ); - assert_eq!(t, "u32"); } #[test] @@ -2445,9 +2372,8 @@ fn main() { #[test] fn associated_type_bound() { - let t = type_at( + check_types( r#" -//- /main.rs pub trait Trait { type Item: OtherTrait; } @@ -2463,18 +2389,16 @@ impl Trait for S { fn test() { let y: as Trait>::Item = no_matter; - y.foo()<|>; -} + y.foo(); +} //^ u32 "#, ); - assert_eq!(t, "u32"); } #[test] fn dyn_trait_through_chalk() { - let t = type_at( + check_types( r#" -//- /main.rs struct Box {} #[lang = "deref"] trait Deref { @@ -2488,18 +2412,16 @@ trait Trait { } fn test(x: Box) { - x.foo()<|>; -} + x.foo(); +} //^ () "#, ); - assert_eq!(t, "()"); } #[test] fn string_to_owned() { - let t = type_at( + check_types( r#" -//- /main.rs struct String {} pub trait ToOwned { type Owned; @@ -2509,11 +2431,10 @@ impl ToOwned for str { type Owned = String; } fn test() { - "foo".to_owned()<|>; -} + "foo".to_owned(); +} //^ String "#, ); - assert_eq!(t, "String"); } #[test] @@ -2637,9 +2558,8 @@ fn main() { #[test] fn nested_assoc() { - let t = type_at( + check_types( r#" -//- /main.rs struct Bar; struct Foo; @@ -2662,11 +2582,10 @@ impl B for T { } fn main() { - Bar::foo()<|>; -} + Bar::foo(); +} //^ Foo "#, ); - assert_eq!(t, "Foo"); } #[test] @@ -2846,12 +2765,12 @@ fn test() { #[test] fn integer_range_iterate() { - let t = type_at( + check_types( r#" //- /main.rs crate:main deps:core fn test() { - for x in 0..100 { x<|>; } -} + for x in 0..100 { x; } +} //^ i32 //- /core.rs crate:core pub mod ops { @@ -2886,7 +2805,6 @@ impl iter::Iterator for ops::Range { } "#, ); - assert_eq!(t, "i32"); } #[test] diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs index f7a885eb3e..26b3c813a1 100644 --- a/crates/ra_syntax/src/algo.rs +++ b/crates/ra_syntax/src/algo.rs @@ -41,6 +41,10 @@ pub fn find_node_at_offset(syntax: &SyntaxNode, offset: TextSize) -> ancestors_at_offset(syntax, offset).find_map(N::cast) } +pub fn find_node_at_range(syntax: &SyntaxNode, range: TextRange) -> Option { + find_covering_element(syntax, range).ancestors().find_map(N::cast) +} + /// Skip to next non `trivia` token pub fn skip_trivia_token(mut token: SyntaxToken, direction: Direction) -> Option { while token.kind().is_trivia() { diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index e74f3b263c..caf847273b 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs @@ -161,7 +161,7 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String { } /// Extracts `//^ some text` annotations -pub fn extract_annotations(text: &str) -> Vec<(TextSize, String)> { +pub fn extract_annotations(text: &str) -> Vec<(TextRange, String)> { let mut res = Vec::new(); let mut prev_line_start: Option = None; let mut line_start: TextSize = 0.into(); @@ -169,7 +169,7 @@ pub fn extract_annotations(text: &str) -> Vec<(TextSize, String)> { 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)) + res.push((TextRange::at(offset, 1.into()), data)) } prev_line_start = Some(line_start); line_start += TextSize::of(line); @@ -179,18 +179,20 @@ pub fn extract_annotations(text: &str) -> Vec<(TextSize, String)> { #[test] fn test_extract_annotations() { - let res = extract_annotations(&trim_indent( + let text = stdx::trim_indent( r#" fn main() { let x = 92; //^ def - - x + 1 + z + 1 } //^ i32 "#, - )); - - assert_eq!(res, vec![(20.into(), "def".into()), (47.into(), "i32".into())]); + ); + let res = extract_annotations(&text) + .into_iter() + .map(|(range, ann)| (&text[range], ann)) + .collect::>(); + assert_eq!(res, vec![("x", "def".into()), ("z", "i32".into()),]); } // Comparison functionality borrowed from cargo: