blob: 2d3ebad9340c75ada8df960b186cecbfec2cc420 [file] [log] [blame]
use expect_test::{Expect, expect};
use crate::{
CompletionConfig,
context::{CompletionAnalysis, NameContext, NameKind, NameRefKind},
tests::{TEST_CONFIG, check_edit, check_edit_with_config},
};
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
check_with_config(TEST_CONFIG, ra_fixture, expect);
}
fn check_with_config(
config: CompletionConfig<'_>,
#[rust_analyzer::rust_fixture] ra_fixture: &str,
expect: Expect,
) {
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();
hir::attach_db(ctx.db, || {
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_prefix_matched() {
cov_mark::check!(flyimport_prefix_on_short_path);
check(
r#"
//- /lib.rs crate:dep
pub struct Barc;
pub struct Rcar;
pub struct Rc;
pub const RC: () = ();
pub mod some_module {
pub struct Bar;
pub struct Rcar;
pub struct Rc;
pub const RC: () = ();
}
//- /main.rs crate:main deps:dep
fn main() {
Rc$0
}
"#,
expect![[r#"
st Rc (use dep::Rc) Rc
st Rcar (use dep::Rcar) Rcar
st Rc (use dep::some_module::Rc) Rc
st Rcar (use dep::some_module::Rcar) Rcar
"#]],
);
check(
r#"
//- /lib.rs crate:dep
pub struct Barc;
pub struct Rcar;
pub struct Rc;
pub const RC: () = ();
pub mod some_module {
pub struct Bar;
pub struct Rcar;
pub struct Rc;
pub const RC: () = ();
}
//- /main.rs crate:main deps:dep
fn main() {
rc$0
}
"#,
expect![[r#"
ct RC (use dep::RC) ()
st Rc (use dep::Rc) Rc
st Rcar (use dep::Rcar) Rcar
ct RC (use dep::some_module::RC) ()
st Rc (use dep::some_module::Rc) Rc
st Rcar (use dep::some_module::Rcar) Rcar
"#]],
);
check(
r#"
//- /lib.rs crate:dep
pub struct Barc;
pub struct Rcar;
pub struct Rc;
pub const RC: () = ();
pub mod some_module {
pub struct Bar;
pub struct Rcar;
pub struct Rc;
pub const RC: () = ();
}
//- /main.rs crate:main deps:dep
fn main() {
RC$0
}
"#,
expect![[r#"
ct RC (use dep::RC) ()
ct 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) ThirdStruct
st AfterThirdStruct (use dep::some_module::AfterThirdStruct) AfterThirdStruct
st ThiiiiiirdStruct (use dep::some_module::ThiiiiiirdStruct) 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) u8
"#]],
);
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_fuzzy_completion_aware_of_fundamental_boxes() {
let fixture = r#"
//- /fundamental.rs crate:fundamental
#[lang = "owned_box"]
#[fundamental]
pub struct Box<T>(T);
//- /foo.rs crate:foo
pub trait TestTrait {
fn some_method(&self);
}
//- /main.rs crate:main deps:foo,fundamental
struct TestStruct;
impl foo::TestTrait for fundamental::Box<TestStruct> {
fn some_method(&self) {}
}
fn main() {
let t = fundamental::Box(TestStruct);
t.$0
}
"#;
check(
fixture,
expect![[r#"
me some_method() (use foo::TestTrait) fn(&self)
"#]],
);
check_edit(
"some_method",
fixture,
r#"
use foo::TestTrait;
struct TestStruct;
impl foo::TestTrait for fundamental::Box<TestStruct> {
fn some_method(&self) {}
}
fn main() {
let t = fundamental::Box(TestStruct);
t.some_method();$0
}
"#,
);
}
#[test]
fn trait_method_fuzzy_completion_aware_of_fundamental_references() {
let fixture = r#"
//- /foo.rs crate:foo
pub trait TestTrait {
fn some_method(&self);
}
//- /main.rs crate:main deps:foo
struct TestStruct;
impl foo::TestTrait for &TestStruct {
fn some_method(&self) {}
}
fn main() {
let t = &TestStruct;
t.$0
}
"#;
check(
fixture,
expect![[r#"
me some_method() (use foo::TestTrait) fn(&self)
"#]],
);
check_edit(
"some_method",
fixture,
r#"
use foo::TestTrait;
struct TestStruct;
impl foo::TestTrait for &TestStruct {
fn some_method(&self) {}
}
fn main() {
let t = &TestStruct;
t.some_method();$0
}
"#,
);
}
#[test]
fn trait_completions_handle_associated_types() {
let fixture = r#"
//- /foo.rs crate:foo
pub trait NotInScope {
fn not_in_scope(&self);
}
pub trait Wrapper {
type Inner: NotInScope;
fn inner(&self) -> Self::Inner;
}
//- /main.rs crate:main deps:foo
use foo::Wrapper;
fn completion<T: Wrapper>(whatever: T) {
whatever.inner().$0
}
"#;
check(
fixture,
expect![[r#"
me not_in_scope() (use foo::NotInScope) fn(&self)
"#]],
);
check_edit(
"not_in_scope",
fixture,
r#"
use foo::{NotInScope, Wrapper};
fn completion<T: Wrapper>(whatever: T) {
whatever.inner().not_in_scope();$0
}
"#,
);
}
#[test]
fn trait_method_fuzzy_completion_aware_of_unit_type() {
let fixture = r#"
//- /test_trait.rs crate:test_trait
pub trait TestInto<T> {
fn into(self) -> T;
}
//- /main.rs crate:main deps:test_trait
struct A;
impl test_trait::TestInto<A> for () {
fn into(self) -> A {
A
}
}
fn main() {
let a = ();
a.$0
}
"#;
check(
fixture,
expect![[r#"
me into() (use test_trait::TestInto) fn(self) -> T
"#]],
);
}
#[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<T> 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#"
ct SPECIAL_CONST (use dep::test_mod::TestTrait) u8 DEPRECATED
fn weird_function() (use dep::test_mod::TestTrait) fn() DEPRECATED
me random_method(…) (use dep::test_mod::TestTrait) fn(&self) 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 config_prefer_absolute() {
let fixture = r#"
//- /lib.rs crate:dep
pub mod foo {
pub mod bar {
pub struct Item;
}
}
//- /main.rs crate:main deps:dep
use ::dep::foo::bar;
fn main() {
Ite$0
}"#;
let mut config = TEST_CONFIG;
config.prefer_absolute = true;
check_edit_with_config(
config.clone(),
"Item",
fixture,
r#"
use ::dep::foo::bar::{self, Item};
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) 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) usize
"#]],
);
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) usize
"#]],
);
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) usize
"#]],
);
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) usize
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() {
Tes$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<T: crate::baz::HirDatabase>(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<T> 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<T> 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) 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_pattern_no_unstable_item_on_stable() {
check(
r#"
//- /main.rs crate:main deps:std
fn function() {
let foo$0
}
//- /std.rs crate:std
#[unstable]
pub struct FooStruct {}
"#,
expect![""],
);
}
#[test]
fn flyimport_pattern_unstable_path() {
check(
r#"
//- /main.rs crate:main deps:std
fn function() {
let foo$0
}
//- /std.rs crate:std
#[unstable]
pub mod unstable {
pub struct FooStruct {}
}
"#,
expect![""],
);
check(
r#"
//- toolchain:nightly
//- /main.rs crate:main deps:std
fn function() {
let foo$0
}
//- /std.rs crate:std
#[unstable]
pub mod unstable {
pub struct FooStruct {}
}
"#,
expect![[r#"
st FooStruct (use std::unstable::FooStruct)
"#]],
);
}
#[test]
fn flyimport_pattern_unstable_item_on_nightly() {
check(
r#"
//- toolchain:nightly
//- /main.rs crate:main deps:std
fn function() {
let foo$0
}
//- /std.rs crate:std
#[unstable]
pub struct FooStruct {}
"#,
expect![[r#"
st FooStruct (use std::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) 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<T>() 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
"#]],
);
}
#[test]
fn macro_use_prelude_is_in_scope() {
check(
r#"
//- /main.rs crate:main deps:dep
#[macro_use]
extern crate dep;
fn main() {
print$0
}
//- /lib.rs crate:dep
#[macro_export]
macro_rules! println {
() => {}
}
"#,
expect![""],
)
}
#[test]
fn no_completions_for_external_doc_hidden_in_path() {
check(
r#"
//- /main.rs crate:main deps:dep
fn main() {
Span$0
}
//- /lib.rs crate:dep
#[doc(hidden)]
pub mod bridge {
pub mod server {
pub trait Span
}
}
pub mod bridge2 {
#[doc(hidden)]
pub mod server2 {
pub trait Span
}
}
"#,
expect![""],
);
// unless re-exported
check(
r#"
//- /main.rs crate:main deps:dep
fn main() {
Span$0
}
//- /lib.rs crate:dep
#[doc(hidden)]
pub mod bridge {
pub mod server {
pub trait Span
}
}
pub use bridge::server::Span;
pub mod bridge2 {
#[doc(hidden)]
pub mod server2 {
pub trait Span2
}
}
pub use bridge2::server2::Span2;
"#,
expect![[r#"
tt Span (use dep::Span)
tt Span2 (use dep::Span2)
"#]],
);
}
#[test]
fn flyimport_only_traits_in_impl_trait_block() {
check(
r#"
//- /main.rs crate:main deps:dep
pub struct Bar;
impl Foo$0 for Bar { }
//- /lib.rs crate:dep
pub trait FooTrait;
pub struct FooStruct;
"#,
expect![[r#"
tt FooTrait (use dep::FooTrait)
"#]],
);
}
#[test]
fn primitive_mod() {
check(
r#"
//- minicore: str
fn main() {
str::from$0
}
"#,
expect![[r#"
fn from_utf8_unchecked(…) (use core::str) const unsafe fn(&[u8]) -> &str
"#]],
);
}
#[test]
fn trait_impl_on_slice_method_on_deref_slice_type() {
check(
r#"
//- minicore: deref, sized
struct SliceDeref;
impl core::ops::Deref for SliceDeref {
type Target = [()];
fn deref(&self) -> &Self::Target {
&[]
}
}
fn main() {
SliceDeref.choose$0();
}
mod module {
pub(super) trait SliceRandom {
type Item;
fn choose(&self);
}
impl<T> SliceRandom for [T] {
type Item = T;
fn choose(&self) {}
}
}
"#,
expect![[r#"
me choose (use module::SliceRandom) fn(&self)
"#]],
);
}
#[test]
fn re_export_aliased() {
check(
r#"
mod outer {
mod inner {
pub struct BarStruct;
pub fn bar_fun() {}
pub mod bar {}
}
pub use inner::bar as foo;
pub use inner::bar_fun as foo_fun;
pub use inner::BarStruct as FooStruct;
}
fn function() {
foo$0
}
"#,
expect![[r#"
st FooStruct (use outer::FooStruct) BarStruct
md foo (use outer::foo)
fn foo_fun() (use outer::foo_fun) fn()
"#]],
);
}
#[test]
fn re_export_aliased_pattern() {
check(
r#"
mod outer {
mod inner {
pub struct BarStruct;
pub fn bar_fun() {}
pub mod bar {}
}
pub use inner::bar as foo;
pub use inner::bar_fun as foo_fun;
pub use inner::BarStruct as FooStruct;
}
fn function() {
let foo$0
}
"#,
expect![[r#"
st FooStruct (use outer::FooStruct)
md foo (use outer::foo)
"#]],
);
}
#[test]
fn intrinsics() {
check(
r#"
//- /core.rs crate:core
pub mod intrinsics {
extern "rust-intrinsic" {
pub fn transmute<Src, Dst>(src: Src) -> Dst;
}
}
pub mod mem {
pub use crate::intrinsics::transmute;
}
//- /main.rs crate:main deps:core
fn function() {
transmute$0
}
"#,
expect![[r#"
fn transmute(…) (use core::mem::transmute) unsafe fn(Src) -> Dst
"#]],
);
check(
r#"
//- /core.rs crate:core
pub mod intrinsics {
extern "rust-intrinsic" {
pub fn transmute<Src, Dst>(src: Src) -> Dst;
}
}
pub mod mem {
pub use crate::intrinsics::transmute;
}
//- /main.rs crate:main deps:core
fn function() {
mem::transmute$0
}
"#,
expect![[r#"
fn transmute(…) (use core::mem) unsafe fn(Src) -> Dst
"#]],
);
}
#[test]
fn excluded_trait_item_included_when_exact_match() {
// FIXME: This does not work, we need to change the code.
check_with_config(
CompletionConfig {
exclude_traits: &["ra_test_fixture::module2::ExcludedTrait".to_owned()],
..TEST_CONFIG
},
r#"
mod module2 {
pub trait ExcludedTrait {
fn foo(&self) {}
fn bar(&self) {}
fn baz(&self) {}
}
impl<T> ExcludedTrait for T {}
}
fn foo() {
true.foo$0
}
"#,
expect![""],
);
}
#[test]
fn excluded_via_attr() {
check(
r#"
mod module2 {
#[rust_analyzer::completions(ignore_flyimport)]
pub trait ExcludedTrait {
fn foo(&self) {}
fn bar(&self) {}
fn baz(&self) {}
}
impl<T> ExcludedTrait for T {}
}
fn foo() {
true.$0
}
"#,
expect![""],
);
check(
r#"
mod module2 {
#[rust_analyzer::completions(ignore_flyimport_methods)]
pub trait ExcludedTrait {
fn foo(&self) {}
fn bar(&self) {}
fn baz(&self) {}
}
impl<T> ExcludedTrait for T {}
}
fn foo() {
true.$0
}
"#,
expect![""],
);
check(
r#"
mod module2 {
#[rust_analyzer::completions(ignore_methods)]
pub trait ExcludedTrait {
fn foo(&self) {}
fn bar(&self) {}
fn baz(&self) {}
}
impl<T> ExcludedTrait for T {}
}
fn foo() {
true.$0
}
"#,
expect![""],
);
check(
r#"
mod module2 {
#[rust_analyzer::completions(ignore_flyimport)]
pub trait ExcludedTrait {
fn foo(&self) {}
fn bar(&self) {}
fn baz(&self) {}
}
impl<T> ExcludedTrait for T {}
}
fn foo() {
ExcludedTrait$0
}
"#,
expect![""],
);
check(
r#"
mod module2 {
#[rust_analyzer::completions(ignore_methods)]
pub trait ExcludedTrait {
fn foo(&self) {}
fn bar(&self) {}
fn baz(&self) {}
}
impl<T> ExcludedTrait for T {}
}
fn foo() {
ExcludedTrait$0
}
"#,
expect![[r#"
tt ExcludedTrait (use module2::ExcludedTrait)
"#]],
);
check(
r#"
mod module2 {
#[rust_analyzer::completions(ignore_flyimport)]
pub struct Foo {}
}
fn foo() {
Foo$0
}
"#,
expect![""],
);
}