use expect_test::{expect, Expect}; use crate::{ context::{CompletionAnalysis, NameContext, NameKind, NameRefKind}, tests::{check_edit, check_edit_with_config, TEST_CONFIG}, }; fn check(ra_fixture: &str, expect: Expect) { let config = TEST_CONFIG; let (db, position) = crate::tests::position(ra_fixture); let (ctx, analysis) = crate::context::CompletionContext::new(&db, position, &config).unwrap(); let mut acc = crate::completions::Completions::default(); if let CompletionAnalysis::Name(NameContext { kind: NameKind::IdentPat(pat_ctx), .. }) = &analysis { crate::completions::flyimport::import_on_the_fly_pat(&mut acc, &ctx, pat_ctx); } if let CompletionAnalysis::NameRef(name_ref_ctx) = &analysis { match &name_ref_ctx.kind { NameRefKind::Path(path) => { crate::completions::flyimport::import_on_the_fly_path(&mut acc, &ctx, path); } NameRefKind::DotAccess(dot_access) => { crate::completions::flyimport::import_on_the_fly_dot(&mut acc, &ctx, dot_access); } NameRefKind::Pattern(pattern) => { crate::completions::flyimport::import_on_the_fly_pat(&mut acc, &ctx, pattern); } _ => (), } } expect.assert_eq(&super::render_completion_list(Vec::from(acc))); } #[test] fn function_fuzzy_completion() { check_edit( "stdin", r#" //- /lib.rs crate:dep pub mod io { pub fn stdin() {} }; //- /main.rs crate:main deps:dep fn main() { stdi$0 } "#, r#" use dep::io::stdin; fn main() { stdin()$0 } "#, ); } #[test] fn macro_fuzzy_completion() { check_edit( "macro_with_curlies!", r#" //- /lib.rs crate:dep /// Please call me as macro_with_curlies! {} #[macro_export] macro_rules! macro_with_curlies { () => {} } //- /main.rs crate:main deps:dep fn main() { curli$0 } "#, r#" use dep::macro_with_curlies; fn main() { macro_with_curlies! {$0} } "#, ); } #[test] fn struct_fuzzy_completion() { check_edit( "ThirdStruct", r#" //- /lib.rs crate:dep pub struct FirstStruct; pub mod some_module { pub struct SecondStruct; pub struct ThirdStruct; } //- /main.rs crate:main deps:dep use dep::{FirstStruct, some_module::SecondStruct}; fn main() { this$0 } "#, r#" use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}}; fn main() { ThirdStruct } "#, ); } #[test] fn short_paths_are_ignored() { cov_mark::check!(flyimport_exact_on_short_path); check( r#" //- /lib.rs crate:dep pub struct Bar; pub struct Rcar; pub struct Rc; pub mod some_module { pub struct Bar; pub struct Rcar; pub struct Rc; } //- /main.rs crate:main deps:dep fn main() { rc$0 } "#, expect![[r#" st Rc (use dep::Rc) st Rc (use dep::some_module::Rc) "#]], ); } #[test] fn fuzzy_completions_come_in_specific_order() { cov_mark::check!(certain_fuzzy_order_test); check( r#" //- /lib.rs crate:dep pub struct FirstStruct; pub mod some_module { // already imported, omitted pub struct SecondStruct; // does not contain all letters from the query, omitted pub struct UnrelatedOne; // contains all letters from the query, but not in sequence, displayed last pub struct ThiiiiiirdStruct; // contains all letters from the query, but not in the beginning, displayed second pub struct AfterThirdStruct; // contains all letters from the query in the beginning, displayed first pub struct ThirdStruct; } //- /main.rs crate:main deps:dep use dep::{FirstStruct, some_module::SecondStruct}; fn main() { hir$0 } "#, expect![[r#" st ThirdStruct (use dep::some_module::ThirdStruct) st AfterThirdStruct (use dep::some_module::AfterThirdStruct) st ThiiiiiirdStruct (use dep::some_module::ThiiiiiirdStruct) "#]], ); } #[test] fn trait_function_fuzzy_completion() { let fixture = r#" //- /lib.rs crate:dep pub mod test_mod { pub trait TestTrait { const SPECIAL_CONST: u8; type HumbleType; fn weird_function(); fn random_method(&self); } pub struct TestStruct {} impl TestTrait for TestStruct { const SPECIAL_CONST: u8 = 42; type HumbleType = (); fn weird_function() {} fn random_method(&self) {} } } //- /main.rs crate:main deps:dep fn main() { dep::test_mod::TestStruct::wei$0 } "#; check( fixture, expect![[r#" fn weird_function() (use dep::test_mod::TestTrait) fn() "#]], ); check_edit( "weird_function", fixture, r#" use dep::test_mod::TestTrait; fn main() { dep::test_mod::TestStruct::weird_function()$0 } "#, ); } #[test] fn trait_const_fuzzy_completion() { let fixture = r#" //- /lib.rs crate:dep pub mod test_mod { pub trait TestTrait { const SPECIAL_CONST: u8; type HumbleType; fn weird_function(); fn random_method(&self); } pub struct TestStruct {} impl TestTrait for TestStruct { const SPECIAL_CONST: u8 = 42; type HumbleType = (); fn weird_function() {} fn random_method(&self) {} } } //- /main.rs crate:main deps:dep fn main() { dep::test_mod::TestStruct::spe$0 } "#; check( fixture, expect![[r#" ct SPECIAL_CONST (use dep::test_mod::TestTrait) "#]], ); check_edit( "SPECIAL_CONST", fixture, r#" use dep::test_mod::TestTrait; fn main() { dep::test_mod::TestStruct::SPECIAL_CONST } "#, ); } #[test] fn trait_method_fuzzy_completion() { let fixture = r#" //- /lib.rs crate:dep pub mod test_mod { pub trait TestTrait { const SPECIAL_CONST: u8; type HumbleType; fn weird_function(); fn random_method(&self); } pub struct TestStruct {} impl TestTrait for TestStruct { const SPECIAL_CONST: u8 = 42; type HumbleType = (); fn weird_function() {} fn random_method(&self) {} } } //- /main.rs crate:main deps:dep fn main() { let test_struct = dep::test_mod::TestStruct {}; test_struct.ran$0 } "#; check( fixture, expect![[r#" me random_method() (use dep::test_mod::TestTrait) fn(&self) "#]], ); check_edit( "random_method", fixture, r#" use dep::test_mod::TestTrait; fn main() { let test_struct = dep::test_mod::TestStruct {}; test_struct.random_method()$0 } "#, ); } #[test] fn trait_method_from_alias() { let fixture = r#" //- /lib.rs crate:dep pub mod test_mod { pub trait TestTrait { fn random_method(); } pub struct TestStruct {} impl TestTrait for TestStruct { fn random_method() {} } pub type TestAlias = TestStruct; } //- /main.rs crate:main deps:dep fn main() { dep::test_mod::TestAlias::ran$0 } "#; check( fixture, expect![[r#" fn random_method() (use dep::test_mod::TestTrait) fn() "#]], ); check_edit( "random_method", fixture, r#" use dep::test_mod::TestTrait; fn main() { dep::test_mod::TestAlias::random_method()$0 } "#, ); } #[test] fn no_trait_type_fuzzy_completion() { check( r#" //- /lib.rs crate:dep pub mod test_mod { pub trait TestTrait { const SPECIAL_CONST: u8; type HumbleType; fn weird_function(); fn random_method(&self); } pub struct TestStruct {} impl TestTrait for TestStruct { const SPECIAL_CONST: u8 = 42; type HumbleType = (); fn weird_function() {} fn random_method(&self) {} } } //- /main.rs crate:main deps:dep fn main() { dep::test_mod::TestStruct::hum$0 } "#, expect![[r#""#]], ); } #[test] fn does_not_propose_names_in_scope() { check( r#" //- /lib.rs crate:dep pub mod test_mod { pub trait TestTrait { const SPECIAL_CONST: u8; type HumbleType; fn weird_function(); fn random_method(&self); } pub struct TestStruct {} impl TestTrait for TestStruct { const SPECIAL_CONST: u8 = 42; type HumbleType = (); fn weird_function() {} fn random_method(&self) {} } } //- /main.rs crate:main deps:dep use dep::test_mod::TestStruct; fn main() { TestSt$0 } "#, expect![[r#""#]], ); } #[test] fn does_not_propose_traits_in_scope() { check( r#" //- /lib.rs crate:dep pub mod test_mod { pub trait TestTrait { const SPECIAL_CONST: u8; type HumbleType; fn weird_function(); fn random_method(&self); } pub struct TestStruct {} impl TestTrait for TestStruct { const SPECIAL_CONST: u8 = 42; type HumbleType = (); fn weird_function() {} fn random_method(&self) {} } } //- /main.rs crate:main deps:dep use dep::test_mod::{TestStruct, TestTrait}; fn main() { dep::test_mod::TestStruct::hum$0 } "#, expect![[r#""#]], ); } #[test] fn blanket_trait_impl_import() { check_edit( "another_function", r#" //- /lib.rs crate:dep pub mod test_mod { pub struct TestStruct {} pub trait TestTrait { fn another_function(); } impl TestTrait for T { fn another_function() {} } } //- /main.rs crate:main deps:dep fn main() { dep::test_mod::TestStruct::ano$0 } "#, r#" use dep::test_mod::TestTrait; fn main() { dep::test_mod::TestStruct::another_function()$0 } "#, ); } #[test] fn zero_input_deprecated_assoc_item_completion() { check( r#" //- /lib.rs crate:dep pub mod test_mod { #[deprecated] pub trait TestTrait { const SPECIAL_CONST: u8; type HumbleType; fn weird_function(); fn random_method(&self); } pub struct TestStruct {} impl TestTrait for TestStruct { const SPECIAL_CONST: u8 = 42; type HumbleType = (); fn weird_function() {} fn random_method(&self) {} } } //- /main.rs crate:main deps:dep fn main() { let test_struct = dep::test_mod::TestStruct {}; test_struct.$0 } "#, expect![[r#" me random_method() (use dep::test_mod::TestTrait) fn(&self) DEPRECATED "#]], ); check( r#" //- /lib.rs crate:dep pub mod test_mod { #[deprecated] pub trait TestTrait { const SPECIAL_CONST: u8; type HumbleType; fn weird_function(); fn random_method(&self); } pub struct TestStruct {} impl TestTrait for TestStruct { const SPECIAL_CONST: u8 = 42; type HumbleType = (); fn weird_function() {} fn random_method(&self) {} } } //- /main.rs crate:main deps:dep fn main() { dep::test_mod::TestStruct::$0 } "#, expect![[r#" fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED ct SPECIAL_CONST (use dep::test_mod::TestTrait) DEPRECATED "#]], ); } #[test] fn no_completions_in_use_statements() { check( r#" //- /lib.rs crate:dep pub mod io { pub fn stdin() {} }; //- /main.rs crate:main deps:dep use stdi$0 fn main() {} "#, expect![[]], ); } #[test] fn prefix_config_usage() { let fixture = r#" mod foo { pub mod bar { pub struct Item; } } use crate::foo::bar; fn main() { Ite$0 }"#; let mut config = TEST_CONFIG; config.insert_use.prefix_kind = hir::PrefixKind::ByCrate; check_edit_with_config( config.clone(), "Item", fixture, r#" mod foo { pub mod bar { pub struct Item; } } use crate::foo::bar::{self, Item}; fn main() { Item }"#, ); config.insert_use.prefix_kind = hir::PrefixKind::BySelf; check_edit_with_config( config.clone(), "Item", fixture, r#" mod foo { pub mod bar { pub struct Item; } } use crate::foo::bar; use self::foo::bar::Item; fn main() { Item }"#, ); config.insert_use.prefix_kind = hir::PrefixKind::Plain; check_edit_with_config( config, "Item", fixture, r#" mod foo { pub mod bar { pub struct Item; } } use foo::bar::Item; use crate::foo::bar; fn main() { Item }"#, ); } #[test] fn unresolved_qualifier() { let fixture = r#" mod foo { pub mod bar { pub mod baz { pub struct Item; } } } fn main() { bar::baz::Ite$0 }"#; check( fixture, expect![[r#" st Item (use foo::bar::baz::Item) "#]], ); check_edit( "Item", fixture, r#" use foo::bar; mod foo { pub mod bar { pub mod baz { pub struct Item; } } } fn main() { bar::baz::Item }"#, ); } #[test] fn unresolved_assoc_item_container() { let fixture = r#" mod foo { pub struct Item; impl Item { pub const TEST_ASSOC: usize = 3; } } fn main() { Item::TEST_A$0 }"#; check( fixture, expect![[r#" ct TEST_ASSOC (use foo::Item) "#]], ); check_edit( "TEST_ASSOC", fixture, r#" use foo::Item; mod foo { pub struct Item; impl Item { pub const TEST_ASSOC: usize = 3; } } fn main() { Item::TEST_ASSOC }"#, ); } #[test] fn unresolved_assoc_item_container_with_path() { let fixture = r#" mod foo { pub mod bar { pub struct Item; impl Item { pub const TEST_ASSOC: usize = 3; } } } fn main() { bar::Item::TEST_A$0 }"#; check( fixture, expect![[r#" ct TEST_ASSOC (use foo::bar::Item) "#]], ); check_edit( "TEST_ASSOC", fixture, r#" use foo::bar; mod foo { pub mod bar { pub struct Item; impl Item { pub const TEST_ASSOC: usize = 3; } } } fn main() { bar::Item::TEST_ASSOC }"#, ); } #[test] fn fuzzy_unresolved_path() { check( r#" mod foo { pub mod bar { pub struct Item; impl Item { pub const TEST_ASSOC: usize = 3; } } } fn main() { bar::ASS$0 }"#, expect![[]], ) } #[test] fn unqualified_assoc_items_are_omitted() { check( r#" mod something { pub trait BaseTrait { fn test_function() -> i32; } pub struct Item1; pub struct Item2; impl BaseTrait for Item1 { fn test_function() -> i32 { 1 } } impl BaseTrait for Item2 { fn test_function() -> i32 { 2 } } } fn main() { test_f$0 }"#, expect![[]], ) } #[test] fn case_matters() { check( r#" mod foo { pub const TEST_CONST: usize = 3; pub fn test_function() -> i32 { 4 } } fn main() { TES$0 }"#, expect![[r#" ct TEST_CONST (use foo::TEST_CONST) "#]], ); check( r#" mod foo { pub const TEST_CONST: usize = 3; pub fn test_function() -> i32 { 4 } } fn main() { tes$0 }"#, expect![[r#" ct TEST_CONST (use foo::TEST_CONST) fn test_function() (use foo::test_function) fn() -> i32 "#]], ); check( r#" mod foo { pub const TEST_CONST: usize = 3; pub fn test_function() -> i32 { 4 } } fn main() { Te$0 }"#, expect![[]], ); } #[test] fn no_fuzzy_during_fields_of_record_lit_syntax() { check( r#" mod m { pub fn some_fn() -> i32 { 42 } } struct Foo { some_field: i32, } fn main() { let _ = Foo { so$0 }; } "#, expect![[]], ); } #[test] fn fuzzy_after_fields_of_record_lit_syntax() { check( r#" mod m { pub fn some_fn() -> i32 { 42 } } struct Foo { some_field: i32, } fn main() { let _ = Foo { some_field: som$0 }; } "#, expect![[r#" fn some_fn() (use m::some_fn) fn() -> i32 "#]], ); } #[test] fn no_flyimports_in_traits_and_impl_declarations() { check( r#" mod m { pub fn some_fn() -> i32 { 42 } } trait Foo { som$0 } "#, expect![[r#""#]], ); check( r#" mod m { pub fn some_fn() -> i32 { 42 } } struct Foo; impl Foo { som$0 } "#, expect![[r#""#]], ); check( r#" mod m { pub fn some_fn() -> i32 { 42 } } struct Foo; trait Bar {} impl Bar for Foo { som$0 } "#, expect![[r#""#]], ); } #[test] fn no_inherent_candidates_proposed() { check( r#" mod baz { pub trait DefDatabase { fn method1(&self); } pub trait HirDatabase: DefDatabase { fn method2(&self); } } mod bar { fn test(db: &dyn crate::baz::HirDatabase) { db.metho$0 } } "#, expect![[r#""#]], ); check( r#" mod baz { pub trait DefDatabase { fn method1(&self); } pub trait HirDatabase: DefDatabase { fn method2(&self); } } mod bar { fn test(db: &impl crate::baz::HirDatabase) { db.metho$0 } } "#, expect![[r#""#]], ); check( r#" mod baz { pub trait DefDatabase { fn method1(&self); } pub trait HirDatabase: DefDatabase { fn method2(&self); } } mod bar { fn test(db: T) { db.metho$0 } } "#, expect![[r#""#]], ); } #[test] fn respects_doc_hidden() { check( r#" //- /lib.rs crate:lib deps:dep fn f() { ().fro$0 } //- /dep.rs crate:dep #[doc(hidden)] pub trait Private { fn frob(&self) {} } impl Private for T {} "#, expect![[r#""#]], ); check( r#" //- /lib.rs crate:lib deps:dep fn f() { ().fro$0 } //- /dep.rs crate:dep pub trait Private { #[doc(hidden)] fn frob(&self) {} } impl Private for T {} "#, expect![[r#""#]], ); } #[test] fn regression_9760() { check( r#" struct Struct; fn main() {} mod mud { fn func() { let struct_instance = Stru$0 } } "#, expect![[r#" st Struct (use crate::Struct) "#]], ); } #[test] fn flyimport_pattern() { check( r#" mod module { pub struct FooStruct {} pub const FooConst: () = (); pub fn foo_fun() {} } fn function() { let foo$0 } "#, expect![[r#" ct FooConst (use module::FooConst) st FooStruct (use module::FooStruct) "#]], ); } #[test] fn flyimport_item_name() { check( r#" mod module { pub struct Struct; } struct Str$0 "#, expect![[r#""#]], ); } #[test] fn flyimport_rename() { check( r#" mod module { pub struct Struct; } use self as Str$0; "#, expect![[r#""#]], ); } #[test] fn flyimport_enum_variant() { check( r#" mod foo { pub struct Barbara; } enum Foo { Barba$0() } }"#, expect![[r#""#]], ); check( r#" mod foo { pub struct Barbara; } enum Foo { Barba(Barba$0) } }"#, expect![[r#" st Barbara (use foo::Barbara) "#]], ) } #[test] fn flyimport_attribute() { check( r#" //- proc_macros:identity #[ide$0] struct Foo; "#, expect![[r#" at identity (use proc_macros::identity) proc_macro identity "#]], ); check_edit( "identity", r#" //- proc_macros:identity #[ide$0] struct Foo; "#, r#" use proc_macros::identity; #[identity] struct Foo; "#, ); } #[test] fn flyimport_in_type_bound_omits_types() { check( r#" mod module { pub struct CompletemeStruct; pub type CompletemeType = (); pub enum CompletemeEnum {} pub trait CompletemeTrait {} } fn f() where T: Comp$0 "#, expect![[r#" tt CompletemeTrait (use module::CompletemeTrait) "#]], ); } #[test] fn flyimport_source_file() { check( r#" //- /main.rs crate:main deps:dep def$0 //- /lib.rs crate:dep #[macro_export] macro_rules! define_struct { () => { pub struct Foo; }; } "#, expect![[r#" ma define_struct!(…) (use dep::define_struct) macro_rules! define_struct "#]], ); }