use expect_test::{Expect, expect}; use hir::HirDisplay; use crate::{ context::CompletionContext, tests::{TEST_CONFIG, position}, }; fn check_expected_type_and_name(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (db, pos) = position(ra_fixture); let config = TEST_CONFIG; let (completion_context, _analysis) = hir::attach_db(&db, || CompletionContext::new(&db, pos, &config, None).unwrap()); let ty = completion_context .expected_type .map(|t| { hir::attach_db(&db, || { t.display_test(&db, completion_context.krate.to_display_target(&db)).to_string() }) }) .unwrap_or("?".to_owned()); let name = completion_context.expected_name.map_or_else(|| "?".to_owned(), |name| name.to_string()); expect.assert_eq(&format!("ty: {ty}, name: {name}")); } #[test] fn expected_type_let_without_leading_char() { cov_mark::check!(expected_type_let_without_leading_char); check_expected_type_and_name( r#" fn foo() { let x: u32 = $0; } "#, expect![[r#"ty: u32, name: x"#]], ); } #[test] fn expected_type_let_with_leading_char() { cov_mark::check!(expected_type_let_with_leading_char); check_expected_type_and_name( r#" fn foo() { let x: u32 = c$0; } "#, expect![[r#"ty: u32, name: x"#]], ); } #[test] fn expected_type_let_pat() { check_expected_type_and_name( r#" fn foo() { let x$0 = 0u32; } "#, expect![[r#"ty: u32, name: ?"#]], ); check_expected_type_and_name( r#" fn foo() { let $0 = 0u32; } "#, expect![[r#"ty: u32, name: ?"#]], ); } #[test] fn expected_type_fn_param() { cov_mark::check!(expected_type_fn_param); check_expected_type_and_name( r#" fn foo() { bar($0); } fn bar(x: u32) {} "#, expect![[r#"ty: u32, name: x"#]], ); check_expected_type_and_name( r#" fn foo() { bar(c$0); } fn bar(x: u32) {} "#, expect![[r#"ty: u32, name: x"#]], ); check_expected_type_and_name( r#" fn foo() { bar(, $0); } fn bar(x: u32, y: i32) {} "#, expect![[r#"ty: i32, name: y"#]], ); check_expected_type_and_name( r#" fn foo() { bar(, c$0); } fn bar(x: u32, y: i32) {} "#, expect![[r#"ty: i32, name: y"#]], ); } #[test] fn expected_type_fn_param_ref() { cov_mark::check!(expected_type_fn_param_ref); check_expected_type_and_name( r#" fn foo() { bar(&$0); } fn bar(x: &u32) {} "#, expect![[r#"ty: u32, name: x"#]], ); check_expected_type_and_name( r#" fn foo() { bar(&mut $0); } fn bar(x: &mut u32) {} "#, expect![[r#"ty: u32, name: x"#]], ); check_expected_type_and_name( r#" fn foo() { bar(& c$0); } fn bar(x: &u32) {} "#, expect![[r#"ty: u32, name: x"#]], ); check_expected_type_and_name( r#" fn foo() { bar(&mut c$0); } fn bar(x: &mut u32) {} "#, expect![[r#"ty: u32, name: x"#]], ); check_expected_type_and_name( r#" fn foo() { bar(&c$0); } fn bar(x: &u32) {} "#, expect![[r#"ty: u32, name: x"#]], ); } #[test] fn expected_type_fn_param_deref() { cov_mark::check!(expected_type_fn_param_deref); check_expected_type_and_name( r#" fn foo() { bar(*$0); } fn bar(x: &u32) {} "#, expect!["ty: &'_ &'_ u32, name: x"], ); } #[test] fn expected_type_struct_field_without_leading_char() { cov_mark::check!(expected_type_struct_field_without_leading_char); check_expected_type_and_name( r#" struct Foo { a: u32 } fn foo() { Foo { a: $0 }; } "#, expect![[r#"ty: u32, name: a"#]], ) } #[test] fn expected_type_struct_field_followed_by_comma() { cov_mark::check!(expected_type_struct_field_followed_by_comma); check_expected_type_and_name( r#" struct Foo { a: u32 } fn foo() { Foo { a: $0, }; } "#, expect![[r#"ty: u32, name: a"#]], ) } #[test] fn expected_type_generic_struct_field() { check_expected_type_and_name( r#" struct Foo { a: T } fn foo() -> Foo { Foo { a: $0 } } "#, expect![[r#"ty: u32, name: a"#]], ) } #[test] fn expected_type_struct_field_with_leading_char() { cov_mark::check!(expected_type_struct_field_with_leading_char); check_expected_type_and_name( r#" struct Foo { a: u32 } fn foo() { Foo { a: c$0 }; } "#, expect![[r#"ty: u32, name: a"#]], ); } #[test] fn expected_type_match_arm_without_leading_char() { cov_mark::check!(expected_type_match_arm_without_leading_char); check_expected_type_and_name( r#" enum E { X } fn foo() { match E::X { $0 } } "#, expect![[r#"ty: E, name: ?"#]], ); } #[test] fn expected_type_match_arm_with_leading_char() { cov_mark::check!(expected_type_match_arm_with_leading_char); check_expected_type_and_name( r#" enum E { X } fn foo() { match E::X { c$0 } } "#, expect![[r#"ty: E, name: ?"#]], ); } #[test] fn expected_type_match_arm_body_without_leading_char() { cov_mark::check!(expected_type_match_arm_body_without_leading_char); check_expected_type_and_name( r#" struct Foo; enum E { X } fn foo() -> Foo { match E::X { E::X => $0 } } "#, expect![[r#"ty: Foo, name: ?"#]], ); } #[test] fn expected_type_match_arm_block_body_without_leading_char() { cov_mark::check!(expected_type_match_arm_body_without_leading_char); cov_mark::check!(expected_type_match_arm_body_with_leading_char); check_expected_type_and_name( r#" struct Foo; enum E { X } fn foo() -> Foo { match E::X { Foo::X => { $0 } } } "#, expect![[r#"ty: Foo, name: ?"#]], ); } #[test] fn expected_type_match_body_arm_with_leading_char() { cov_mark::check!(expected_type_match_arm_body_with_leading_char); check_expected_type_and_name( r#" struct Foo; enum E { X } fn foo() -> Foo { match E::X { E::X => c$0 } } "#, expect![[r#"ty: Foo, name: ?"#]], ); } #[test] fn expected_type_if_let_without_leading_char() { cov_mark::check!(expected_type_if_let_without_leading_char); check_expected_type_and_name( r#" enum Foo { Bar, Baz, Quux } fn foo() { let f = Foo::Quux; if let $0 = f { } } "#, expect![[r#"ty: Foo, name: ?"#]], ) } #[test] fn expected_type_if_let_with_leading_char() { cov_mark::check!(expected_type_if_let_with_leading_char); check_expected_type_and_name( r#" enum Foo { Bar, Baz, Quux } fn foo() { let f = Foo::Quux; if let c$0 = f { } } "#, expect![[r#"ty: Foo, name: ?"#]], ) } #[test] fn expected_type_if_let_chain_bool() { check_expected_type_and_name( r#" fn foo() { let f = Foo::Quux; if let c = f && $0 { } } "#, expect![[r#"ty: bool, name: ?"#]], ); } #[test] fn expected_type_if_condition() { check_expected_type_and_name( r#" fn foo() { if a$0 { } } "#, expect![[r#"ty: bool, name: ?"#]], ); } #[test] fn expected_type_if_body() { check_expected_type_and_name( r#" enum Foo { Bar, Baz, Quux } fn foo() { let _: Foo = if true { $0 }; } "#, expect![[r#"ty: Foo, name: ?"#]], ); check_expected_type_and_name( r#" enum Foo { Bar, Baz, Quux } fn foo() { let _: Foo = if true { Foo::Bar } else { $0 }; } "#, expect![[r#"ty: Foo, name: ?"#]], ); } #[test] fn expected_type_fn_ret_without_leading_char() { cov_mark::check!(expected_type_fn_ret_without_leading_char); check_expected_type_and_name( r#" fn foo() -> u32 { $0 } "#, expect![[r#"ty: u32, name: ?"#]], ) } #[test] fn expected_type_fn_ret_with_leading_char() { cov_mark::check!(expected_type_fn_ret_with_leading_char); check_expected_type_and_name( r#" fn foo() -> u32 { c$0 } "#, expect![[r#"ty: u32, name: ?"#]], ) } #[test] fn expected_type_fn_ret_fn_ref_fully_typed() { check_expected_type_and_name( r#" fn foo() -> u32 { foo$0 } "#, expect![[r#"ty: u32, name: ?"#]], ) } #[test] fn expected_type_closure_param_return() { check_expected_type_and_name( r#" //- minicore: fn fn foo() { bar(|| a$0); } fn bar(f: impl FnOnce() -> u32) {} "#, expect![[r#"ty: u32, name: ?"#]], ); check_expected_type_and_name( r#" //- minicore: fn fn foo() { bar(|| $0); } fn bar(f: impl FnOnce() -> u32) {} "#, expect![[r#"ty: u32, name: ?"#]], ); } #[test] fn expected_type_generic_function() { check_expected_type_and_name( r#" fn foo() { bar::($0); } fn bar(t: T) {} "#, expect![[r#"ty: u32, name: t"#]], ); } #[test] fn expected_type_generic_method() { check_expected_type_and_name( r#" fn foo() { S(1u32).bar($0); } struct S(T); impl S { fn bar(self, t: T) {} } "#, expect![[r#"ty: u32, name: t"#]], ); } #[test] fn expected_type_functional_update() { cov_mark::check!(expected_type_struct_func_update); check_expected_type_and_name( r#" struct Foo { field: u32 } fn foo() { Foo { ..$0 } } "#, expect![[r#"ty: Foo, name: ?"#]], ); check_expected_type_and_name( r#" struct Foo { field: u32 } fn foo() { Foo { ..self::$0 } } "#, expect!["ty: ?, name: ?"], ); } #[test] fn expected_type_param_pat() { check_expected_type_and_name( r#" struct Foo { field: u32 } fn foo(a$0: Foo) {} "#, expect![[r#"ty: Foo, name: ?"#]], ); check_expected_type_and_name( r#" struct Foo { field: u32 } fn foo($0: Foo) {} "#, // FIXME make this work, currently fails due to pattern recovery eating the `:` expect![[r#"ty: ?, name: ?"#]], ); } #[test] fn expected_type_ref_prefix_on_field() { check_expected_type_and_name( r#" fn foo(_: &mut i32) {} struct S { field: i32, } fn main() { let s = S { field: 100, }; foo(&mut s.f$0); } "#, expect!["ty: i32, name: ?"], ); } #[test] fn expected_type_ref_return_pos() { check_expected_type_and_name( r#" fn f(thing: u32) -> &u32 { &thin$0 } "#, expect!["ty: u32, name: ?"], ); } #[test] fn expected_type_assign() { check_expected_type_and_name( r#" enum State { Stop } fn foo() { let x: &mut State = &mut State::Stop; x = $0; } "#, expect![[r#"ty: &'_ mut State, name: ?"#]], ); } #[test] fn expected_type_deref_assign() { check_expected_type_and_name( r#" enum State { Stop } fn foo() { let x: &mut State = &mut State::Stop; match x { State::Stop => { *x = $0; }, } } "#, expect![[r#"ty: State, name: ?"#]], ); } #[test] fn expected_type_deref_assign_at_block_end() { check_expected_type_and_name( r#" enum State { Stop } fn foo() { let x: &mut State = &mut State::Stop; match x { State::Stop => { *x = $0 }, } } "#, expect![[r#"ty: State, name: ?"#]], ); } #[test] fn expected_type_return_expr() { check_expected_type_and_name( r#" enum State { Stop } fn foo() -> State { let _: i32 = if true { 8 } else { return $0; }; } "#, expect![[r#"ty: State, name: ?"#]], ); } #[test] fn expected_type_return_expr_in_closure() { check_expected_type_and_name( r#" enum State { Stop } fn foo() { let _f: fn() -> State = || { let _: i32 = if true { 8 } else { return $0; }; }; } "#, expect![[r#"ty: State, name: ?"#]], ); } #[test] fn expected_type_break_expr_in_loop() { check_expected_type_and_name( r#" enum State { Stop } fn foo() { let _x: State = loop { { break State::Stop; break $0; } }; } "#, expect![[r#"ty: State, name: ?"#]], ); check_expected_type_and_name( r#" enum State { Stop } fn foo() { let _x: State = 'a: loop { { break State::Stop; break $0; } }; } "#, expect![[r#"ty: State, name: ?"#]], ); check_expected_type_and_name( r#" enum State { Stop } fn foo() { let _x: State = 'a: loop { while true { break $0; } }; } "#, expect![[r#"ty: (), name: ?"#]], ); } #[test] fn expected_type_break_expr_in_labeled_loop() { check_expected_type_and_name( r#" enum State { Stop } fn foo() { let _x: State = 'a: loop { let _y: i32 = loop { { break 'a State::Stop; break 'a $0; } }; }; } "#, expect![[r#"ty: State, name: ?"#]], ); check_expected_type_and_name( r#" enum State { Stop } fn foo() { let _x: State = 'a: loop { let _y: i32 = loop { while true { break 'a State::Stop; break 'a $0; } }; }; } "#, expect![[r#"ty: State, name: ?"#]], ); check_expected_type_and_name( r#" enum State { Stop } fn foo() { 'a: while true { let _x: State = loop { break State::Stop; break 'a $0; }; } } "#, expect![[r#"ty: (), name: ?"#]], ); } #[test] fn expected_type_break_expr_in_labeled_block() { check_expected_type_and_name( r#" enum State { Stop } fn foo() { let _x: State = 'a: { let _y: i32 = 'b: { { break 'a State::Stop; break 'a $0; }; }; }; } "#, expect![[r#"ty: State, name: ?"#]], ); } #[test] fn expected_type_logic_op() { check_expected_type_and_name( r#" enum State { Stop } fn foo() { true && $0; } "#, expect![[r#"ty: bool, name: ?"#]], ); }