From a5ffe53c9d185d790388760dfe09f265e352b6bf Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 7 Apr 2020 13:19:57 +0200 Subject: Better naming for path completion --- crates/ra_ide/src/completion.rs | 8 +- crates/ra_ide/src/completion/complete_path.rs | 1046 ------------------- .../src/completion/complete_qualified_path.rs | 1046 +++++++++++++++++++ crates/ra_ide/src/completion/complete_scope.rs | 1067 -------------------- .../src/completion/complete_unqualified_path.rs | 1067 ++++++++++++++++++++ 5 files changed, 2117 insertions(+), 2117 deletions(-) delete mode 100644 crates/ra_ide/src/completion/complete_path.rs create mode 100644 crates/ra_ide/src/completion/complete_qualified_path.rs delete mode 100644 crates/ra_ide/src/completion/complete_scope.rs create mode 100644 crates/ra_ide/src/completion/complete_unqualified_path.rs (limited to 'crates/ra_ide') diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs index 93157bbba..c9ba1d4ee 100644 --- a/crates/ra_ide/src/completion.rs +++ b/crates/ra_ide/src/completion.rs @@ -10,8 +10,8 @@ mod complete_pattern; mod complete_fn_param; mod complete_keyword; mod complete_snippet; -mod complete_path; -mod complete_scope; +mod complete_qualified_path; +mod complete_unqualified_path; mod complete_postfix; mod complete_macro_in_item_position; mod complete_trait_impl; @@ -85,8 +85,8 @@ pub(crate) fn completions( complete_keyword::complete_use_tree_keyword(&mut acc, &ctx); complete_snippet::complete_expr_snippet(&mut acc, &ctx); complete_snippet::complete_item_snippet(&mut acc, &ctx); - complete_path::complete_path(&mut acc, &ctx); - complete_scope::complete_scope(&mut acc, &ctx); + complete_qualified_path::complete_path(&mut acc, &ctx); + complete_unqualified_path::complete_scope(&mut acc, &ctx); complete_dot::complete_dot(&mut acc, &ctx); complete_record::complete_record(&mut acc, &ctx); complete_pattern::complete_pattern(&mut acc, &ctx); diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs deleted file mode 100644 index 3ed2ae2b6..000000000 --- a/crates/ra_ide/src/completion/complete_path.rs +++ /dev/null @@ -1,1046 +0,0 @@ -//! Completion of paths, i.e. `some::prefix::<|>`. - -use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; -use ra_syntax::AstNode; -use test_utils::tested_by; - -use crate::completion::{CompletionContext, Completions}; - -pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { - let path = match &ctx.path_prefix { - Some(path) => path.clone(), - _ => return, - }; - let def = match ctx.scope().resolve_hir_path(&path) { - Some(PathResolution::Def(def)) => def, - _ => return, - }; - let context_module = ctx.scope().module(); - match def { - hir::ModuleDef::Module(module) => { - let module_scope = module.scope(ctx.db, context_module); - for (name, def) in module_scope { - if ctx.use_item_syntax.is_some() { - if let ScopeDef::Unknown = def { - if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { - if name_ref.syntax().text() == name.to_string().as_str() { - // for `use self::foo<|>`, don't suggest `foo` as a completion - tested_by!(dont_complete_current_use); - continue; - } - } - } - } - - acc.add_resolution(ctx, name.to_string(), &def); - } - } - hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => { - if let hir::ModuleDef::Adt(Adt::Enum(e)) = def { - for variant in e.variants(ctx.db) { - acc.add_enum_variant(ctx, variant, None); - } - } - let ty = match def { - hir::ModuleDef::Adt(adt) => adt.ty(ctx.db), - hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db), - _ => unreachable!(), - }; - // Iterate assoc types separately - // FIXME: complete T::AssocType - let krate = ctx.krate; - if let Some(krate) = krate { - let traits_in_scope = ctx.scope().traits_in_scope(); - ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { - if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { - return None; - } - match item { - hir::AssocItem::Function(func) => { - if !func.has_self_param(ctx.db) { - acc.add_function(ctx, func, None); - } - } - hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), - hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), - } - None::<()> - }); - - ty.iterate_impl_items(ctx.db, krate, |item| { - if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { - return None; - } - match item { - hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {} - hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), - } - None::<()> - }); - } - } - hir::ModuleDef::Trait(t) => { - for item in t.items(ctx.db) { - if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { - continue; - } - match item { - hir::AssocItem::Function(func) => { - if !func.has_self_param(ctx.db) { - acc.add_function(ctx, func, None); - } - } - hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), - hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), - } - } - } - _ => {} - }; -} - -#[cfg(test)] -mod tests { - use test_utils::covers; - - use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; - use insta::assert_debug_snapshot; - - fn do_reference_completion(code: &str) -> Vec { - do_completion(code, CompletionKind::Reference) - } - - #[test] - fn dont_complete_current_use() { - covers!(dont_complete_current_use); - let completions = do_completion(r"use self::foo<|>;", CompletionKind::Reference); - assert!(completions.is_empty()); - } - - #[test] - fn dont_complete_current_use_in_braces_with_glob() { - let completions = do_completion( - r" - mod foo { pub struct S; } - use self::{foo::*, bar<|>}; - ", - CompletionKind::Reference, - ); - assert_eq!(completions.len(), 2); - } - - #[test] - fn dont_complete_primitive_in_use() { - let completions = do_completion(r"use self::<|>;", CompletionKind::BuiltinType); - assert!(completions.is_empty()); - } - - #[test] - fn dont_complete_primitive_in_module_scope() { - let completions = do_completion(r"fn foo() { self::<|> }", CompletionKind::BuiltinType); - assert!(completions.is_empty()); - } - - #[test] - fn completes_primitives() { - let completions = - do_completion(r"fn main() { let _: <|> = 92; }", CompletionKind::BuiltinType); - assert_eq!(completions.len(), 17); - } - - #[test] - fn completes_mod_with_docs() { - assert_debug_snapshot!( - do_reference_completion( - r" - use self::my<|>; - - /// Some simple - /// docs describing `mod my`. - mod my { - struct Bar; - } - " - ), - @r###" - [ - CompletionItem { - label: "my", - source_range: [27; 29), - delete: [27; 29), - insert: "my", - kind: Module, - documentation: Documentation( - "Some simple\ndocs describing `mod my`.", - ), - }, - ] - "### - ); - } - - #[test] - fn path_visibility() { - assert_debug_snapshot!( - do_reference_completion( - r" - use self::my::<|>; - - mod my { - struct Bar; - pub struct Foo; - pub use Bar as PublicBar; - } - " - ), - @r###" - [ - CompletionItem { - label: "Foo", - source_range: [31; 31), - delete: [31; 31), - insert: "Foo", - kind: Struct, - }, - CompletionItem { - label: "PublicBar", - source_range: [31; 31), - delete: [31; 31), - insert: "PublicBar", - kind: Struct, - }, - ] - "### - ); - } - - #[test] - fn completes_use_item_starting_with_self() { - assert_debug_snapshot!( - do_reference_completion( - r" - use self::m::<|>; - - mod m { - pub struct Bar; - } - " - ), - @r###" - [ - CompletionItem { - label: "Bar", - source_range: [30; 30), - delete: [30; 30), - insert: "Bar", - kind: Struct, - }, - ] - "### - ); - } - - #[test] - fn completes_use_item_starting_with_crate() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /lib.rs - mod foo; - struct Spam; - //- /foo.rs - use crate::Sp<|> - " - ), - @r###" - [ - CompletionItem { - label: "Spam", - source_range: [11; 13), - delete: [11; 13), - insert: "Spam", - kind: Struct, - }, - CompletionItem { - label: "foo", - source_range: [11; 13), - delete: [11; 13), - insert: "foo", - kind: Module, - }, - ] - "### - ); - } - - #[test] - fn completes_nested_use_tree() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /lib.rs - mod foo; - struct Spam; - //- /foo.rs - use crate::{Sp<|>}; - " - ), - @r###" - [ - CompletionItem { - label: "Spam", - source_range: [12; 14), - delete: [12; 14), - insert: "Spam", - kind: Struct, - }, - CompletionItem { - label: "foo", - source_range: [12; 14), - delete: [12; 14), - insert: "foo", - kind: Module, - }, - ] - "### - ); - } - - #[test] - fn completes_deeply_nested_use_tree() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /lib.rs - mod foo; - pub mod bar { - pub mod baz { - pub struct Spam; - } - } - //- /foo.rs - use crate::{bar::{baz::Sp<|>}}; - " - ), - @r###" - [ - CompletionItem { - label: "Spam", - source_range: [23; 25), - delete: [23; 25), - insert: "Spam", - kind: Struct, - }, - ] - "### - ); - } - - #[test] - fn completes_enum_variant() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /lib.rs - /// An enum - enum E { - /// Foo Variant - Foo, - /// Bar Variant with i32 - Bar(i32) - } - fn foo() { let _ = E::<|> } - " - ), - @r###" - [ - CompletionItem { - label: "Bar(…)", - source_range: [116; 116), - delete: [116; 116), - insert: "Bar($0)", - kind: EnumVariant, - lookup: "Bar", - detail: "(i32)", - documentation: Documentation( - "Bar Variant with i32", - ), - trigger_call_info: true, - }, - CompletionItem { - label: "Foo", - source_range: [116; 116), - delete: [116; 116), - insert: "Foo", - kind: EnumVariant, - detail: "()", - documentation: Documentation( - "Foo Variant", - ), - }, - ] - "### - ); - } - - #[test] - fn completes_enum_variant_with_details() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /lib.rs - struct S { field: u32 } - /// An enum - enum E { - /// Foo Variant (empty) - Foo, - /// Bar Variant with i32 and u32 - Bar(i32, u32), - /// - S(S), - } - fn foo() { let _ = E::<|> } - " - ), - @r###" - [ - CompletionItem { - label: "Bar(…)", - source_range: [180; 180), - delete: [180; 180), - insert: "Bar($0)", - kind: EnumVariant, - lookup: "Bar", - detail: "(i32, u32)", - documentation: Documentation( - "Bar Variant with i32 and u32", - ), - trigger_call_info: true, - }, - CompletionItem { - label: "Foo", - source_range: [180; 180), - delete: [180; 180), - insert: "Foo", - kind: EnumVariant, - detail: "()", - documentation: Documentation( - "Foo Variant (empty)", - ), - }, - CompletionItem { - label: "S(…)", - source_range: [180; 180), - delete: [180; 180), - insert: "S($0)", - kind: EnumVariant, - lookup: "S", - detail: "(S)", - documentation: Documentation( - "", - ), - trigger_call_info: true, - }, - ] - "### - ); - } - - #[test] - fn completes_struct_associated_method() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /lib.rs - /// A Struct - struct S; - - impl S { - /// An associated method - fn m() { } - } - - fn foo() { let _ = S::<|> } - " - ), - @r###" - [ - CompletionItem { - label: "m()", - source_range: [100; 100), - delete: [100; 100), - insert: "m()$0", - kind: Function, - lookup: "m", - detail: "fn m()", - documentation: Documentation( - "An associated method", - ), - }, - ] - "### - ); - } - - #[test] - fn completes_struct_associated_const() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /lib.rs - /// A Struct - struct S; - - impl S { - /// An associated const - const C: i32 = 42; - } - - fn foo() { let _ = S::<|> } - " - ), - @r###" - [ - CompletionItem { - label: "C", - source_range: [107; 107), - delete: [107; 107), - insert: "C", - kind: Const, - detail: "const C: i32 = 42;", - documentation: Documentation( - "An associated const", - ), - }, - ] - "### - ); - } - - #[test] - fn completes_struct_associated_type() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /lib.rs - /// A Struct - struct S; - - impl S { - /// An associated type - type T = i32; - } - - fn foo() { let _ = S::<|> } - " - ), - @r###" - [ - CompletionItem { - label: "T", - source_range: [101; 101), - delete: [101; 101), - insert: "T", - kind: TypeAlias, - detail: "type T = i32;", - documentation: Documentation( - "An associated type", - ), - }, - ] - "### - ); - } - - #[test] - fn associated_item_visibility() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /lib.rs - struct S; - - mod m { - impl super::S { - pub(super) fn public_method() { } - fn private_method() { } - pub(super) type PublicType = u32; - type PrivateType = u32; - pub(super) const PUBLIC_CONST: u32 = 1; - const PRIVATE_CONST: u32 = 1; - } - } - - fn foo() { let _ = S::<|> } - " - ), - @r###" - [ - CompletionItem { - label: "PUBLIC_CONST", - source_range: [302; 302), - delete: [302; 302), - insert: "PUBLIC_CONST", - kind: Const, - detail: "pub(super) const PUBLIC_CONST: u32 = 1;", - }, - CompletionItem { - label: "PublicType", - source_range: [302; 302), - delete: [302; 302), - insert: "PublicType", - kind: TypeAlias, - detail: "pub(super) type PublicType = u32;", - }, - CompletionItem { - label: "public_method()", - source_range: [302; 302), - delete: [302; 302), - insert: "public_method()$0", - kind: Function, - lookup: "public_method", - detail: "pub(super) fn public_method()", - }, - ] - "### - ); - } - - #[test] - fn completes_enum_associated_method() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /lib.rs - /// An enum - enum S {}; - - impl S { - /// An associated method - fn m() { } - } - - fn foo() { let _ = S::<|> } - " - ), - @r###" - [ - CompletionItem { - label: "m()", - source_range: [100; 100), - delete: [100; 100), - insert: "m()$0", - kind: Function, - lookup: "m", - detail: "fn m()", - documentation: Documentation( - "An associated method", - ), - }, - ] - "### - ); - } - - #[test] - fn completes_union_associated_method() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /lib.rs - /// A union - union U {}; - - impl U { - /// An associated method - fn m() { } - } - - fn foo() { let _ = U::<|> } - " - ), - @r###" - [ - CompletionItem { - label: "m()", - source_range: [101; 101), - delete: [101; 101), - insert: "m()$0", - kind: Function, - lookup: "m", - detail: "fn m()", - documentation: Documentation( - "An associated method", - ), - }, - ] - "### - ); - } - - #[test] - fn completes_use_paths_across_crates() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /main.rs - use foo::<|>; - - //- /foo/lib.rs - pub mod bar { - pub struct S; - } - " - ), - @r###" - [ - CompletionItem { - label: "bar", - source_range: [9; 9), - delete: [9; 9), - insert: "bar", - kind: Module, - }, - ] - "### - ); - } - - #[test] - fn completes_trait_associated_method_1() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /lib.rs - trait Trait { - /// A trait method - fn m(); - } - - fn foo() { let _ = Trait::<|> } - " - ), - @r###" - [ - CompletionItem { - label: "m()", - source_range: [73; 73), - delete: [73; 73), - insert: "m()$0", - kind: Function, - lookup: "m", - detail: "fn m()", - documentation: Documentation( - "A trait method", - ), - }, - ] - "### - ); - } - - #[test] - fn completes_trait_associated_method_2() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /lib.rs - trait Trait { - /// A trait method - fn m(); - } - - struct S; - impl Trait for S {} - - fn foo() { let _ = S::<|> } - " - ), - @r###" - [ - CompletionItem { - label: "m()", - source_range: [99; 99), - delete: [99; 99), - insert: "m()$0", - kind: Function, - lookup: "m", - detail: "fn m()", - documentation: Documentation( - "A trait method", - ), - }, - ] - "### - ); - } - - #[test] - fn completes_trait_associated_method_3() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /lib.rs - trait Trait { - /// A trait method - fn m(); - } - - struct S; - impl Trait for S {} - - fn foo() { let _ = ::<|> } - " - ), - @r###" - [ - CompletionItem { - label: "m()", - source_range: [110; 110), - delete: [110; 110), - insert: "m()$0", - kind: Function, - lookup: "m", - detail: "fn m()", - documentation: Documentation( - "A trait method", - ), - }, - ] - "### - ); - } - - #[test] - fn completes_type_alias() { - assert_debug_snapshot!( - do_reference_completion( - " - struct S; - impl S { fn foo() {} } - type T = S; - impl T { fn bar() {} } - - fn main() { - T::<|>; - } - " - ), - @r###" - [ - CompletionItem { - label: "bar()", - source_range: [185; 185), - delete: [185; 185), - insert: "bar()$0", - kind: Function, - lookup: "bar", - detail: "fn bar()", - }, - CompletionItem { - label: "foo()", - source_range: [185; 185), - delete: [185; 185), - insert: "foo()$0", - kind: Function, - lookup: "foo", - detail: "fn foo()", - }, - ] - "### - ); - } - - #[test] - fn completes_qualified_macros() { - assert_debug_snapshot!( - do_reference_completion( - " - #[macro_export] - macro_rules! foo { - () => {} - } - - fn main() { - let _ = crate::<|> - } - " - ), - @r###" - [ - CompletionItem { - label: "foo!", - source_range: [179; 179), - delete: [179; 179), - insert: "foo!($0)", - kind: Macro, - detail: "#[macro_export]\nmacro_rules! foo", - }, - CompletionItem { - label: "main()", - source_range: [179; 179), - delete: [179; 179), - insert: "main()$0", - kind: Function, - lookup: "main", - detail: "fn main()", - }, - ] - "### - ); - } - - #[test] - fn completes_reexported_items_under_correct_name() { - assert_debug_snapshot!( - do_reference_completion( - r" - fn foo() { - self::m::<|> - } - - mod m { - pub use super::p::wrong_fn as right_fn; - pub use super::p::WRONG_CONST as RIGHT_CONST; - pub use super::p::WrongType as RightType; - } - mod p { - fn wrong_fn() {} - const WRONG_CONST: u32 = 1; - struct WrongType {}; - } - " - ), - @r###" - [ - CompletionItem { - label: "RIGHT_CONST", - source_range: [57; 57), - delete: [57; 57), - insert: "RIGHT_CONST", - kind: Const, - }, - CompletionItem { - label: "RightType", - source_range: [57; 57), - delete: [57; 57), - insert: "RightType", - kind: Struct, - }, - CompletionItem { - label: "right_fn()", - source_range: [57; 57), - delete: [57; 57), - insert: "right_fn()$0", - kind: Function, - lookup: "right_fn", - detail: "fn wrong_fn()", - }, - ] - "### - ); - } - - #[test] - fn completes_in_simple_macro_call() { - let completions = do_reference_completion( - r#" - macro_rules! m { ($e:expr) => { $e } } - fn main() { m!(self::f<|>); } - fn foo() {} - "#, - ); - assert_debug_snapshot!(completions, @r###" - [ - CompletionItem { - label: "foo()", - source_range: [93; 94), - delete: [93; 94), - insert: "foo()$0", - kind: Function, - lookup: "foo", - detail: "fn foo()", - }, - CompletionItem { - label: "main()", - source_range: [93; 94), - delete: [93; 94), - insert: "main()$0", - kind: Function, - lookup: "main", - detail: "fn main()", - }, - ] - "###); - } - - #[test] - fn function_mod_share_name() { - assert_debug_snapshot!( - do_reference_completion( - r" - fn foo() { - self::m::<|> - } - - mod m { - pub mod z {} - pub fn z() {} - } - ", - ), - @r###" - [ - CompletionItem { - label: "z", - source_range: [57; 57), - delete: [57; 57), - insert: "z", - kind: Module, - }, - CompletionItem { - label: "z()", - source_range: [57; 57), - delete: [57; 57), - insert: "z()$0", - kind: Function, - lookup: "z", - detail: "pub fn z()", - }, - ] - "### - ); - } - - #[test] - fn completes_hashmap_new() { - assert_debug_snapshot!( - do_reference_completion( - r" - struct RandomState; - struct HashMap {} - - impl HashMap { - pub fn new() -> HashMap { } - } - fn foo() { - HashMap::<|> - } - " - ), - @r###" - [ - CompletionItem { - label: "new()", - source_range: [292; 292), - delete: [292; 292), - insert: "new()$0", - kind: Function, - lookup: "new", - detail: "pub fn new() -> HashMap", - }, - ] - "### - ); - } -} diff --git a/crates/ra_ide/src/completion/complete_qualified_path.rs b/crates/ra_ide/src/completion/complete_qualified_path.rs new file mode 100644 index 000000000..3ed2ae2b6 --- /dev/null +++ b/crates/ra_ide/src/completion/complete_qualified_path.rs @@ -0,0 +1,1046 @@ +//! Completion of paths, i.e. `some::prefix::<|>`. + +use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; +use ra_syntax::AstNode; +use test_utils::tested_by; + +use crate::completion::{CompletionContext, Completions}; + +pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { + let path = match &ctx.path_prefix { + Some(path) => path.clone(), + _ => return, + }; + let def = match ctx.scope().resolve_hir_path(&path) { + Some(PathResolution::Def(def)) => def, + _ => return, + }; + let context_module = ctx.scope().module(); + match def { + hir::ModuleDef::Module(module) => { + let module_scope = module.scope(ctx.db, context_module); + for (name, def) in module_scope { + if ctx.use_item_syntax.is_some() { + if let ScopeDef::Unknown = def { + if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { + if name_ref.syntax().text() == name.to_string().as_str() { + // for `use self::foo<|>`, don't suggest `foo` as a completion + tested_by!(dont_complete_current_use); + continue; + } + } + } + } + + acc.add_resolution(ctx, name.to_string(), &def); + } + } + hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => { + if let hir::ModuleDef::Adt(Adt::Enum(e)) = def { + for variant in e.variants(ctx.db) { + acc.add_enum_variant(ctx, variant, None); + } + } + let ty = match def { + hir::ModuleDef::Adt(adt) => adt.ty(ctx.db), + hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db), + _ => unreachable!(), + }; + // Iterate assoc types separately + // FIXME: complete T::AssocType + let krate = ctx.krate; + if let Some(krate) = krate { + let traits_in_scope = ctx.scope().traits_in_scope(); + ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { + if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { + return None; + } + match item { + hir::AssocItem::Function(func) => { + if !func.has_self_param(ctx.db) { + acc.add_function(ctx, func, None); + } + } + hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), + hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), + } + None::<()> + }); + + ty.iterate_impl_items(ctx.db, krate, |item| { + if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { + return None; + } + match item { + hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {} + hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), + } + None::<()> + }); + } + } + hir::ModuleDef::Trait(t) => { + for item in t.items(ctx.db) { + if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { + continue; + } + match item { + hir::AssocItem::Function(func) => { + if !func.has_self_param(ctx.db) { + acc.add_function(ctx, func, None); + } + } + hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), + hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), + } + } + } + _ => {} + }; +} + +#[cfg(test)] +mod tests { + use test_utils::covers; + + use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; + use insta::assert_debug_snapshot; + + fn do_reference_completion(code: &str) -> Vec { + do_completion(code, CompletionKind::Reference) + } + + #[test] + fn dont_complete_current_use() { + covers!(dont_complete_current_use); + let completions = do_completion(r"use self::foo<|>;", CompletionKind::Reference); + assert!(completions.is_empty()); + } + + #[test] + fn dont_complete_current_use_in_braces_with_glob() { + let completions = do_completion( + r" + mod foo { pub struct S; } + use self::{foo::*, bar<|>}; + ", + CompletionKind::Reference, + ); + assert_eq!(completions.len(), 2); + } + + #[test] + fn dont_complete_primitive_in_use() { + let completions = do_completion(r"use self::<|>;", CompletionKind::BuiltinType); + assert!(completions.is_empty()); + } + + #[test] + fn dont_complete_primitive_in_module_scope() { + let completions = do_completion(r"fn foo() { self::<|> }", CompletionKind::BuiltinType); + assert!(completions.is_empty()); + } + + #[test] + fn completes_primitives() { + let completions = + do_completion(r"fn main() { let _: <|> = 92; }", CompletionKind::BuiltinType); + assert_eq!(completions.len(), 17); + } + + #[test] + fn completes_mod_with_docs() { + assert_debug_snapshot!( + do_reference_completion( + r" + use self::my<|>; + + /// Some simple + /// docs describing `mod my`. + mod my { + struct Bar; + } + " + ), + @r###" + [ + CompletionItem { + label: "my", + source_range: [27; 29), + delete: [27; 29), + insert: "my", + kind: Module, + documentation: Documentation( + "Some simple\ndocs describing `mod my`.", + ), + }, + ] + "### + ); + } + + #[test] + fn path_visibility() { + assert_debug_snapshot!( + do_reference_completion( + r" + use self::my::<|>; + + mod my { + struct Bar; + pub struct Foo; + pub use Bar as PublicBar; + } + " + ), + @r###" + [ + CompletionItem { + label: "Foo", + source_range: [31; 31), + delete: [31; 31), + insert: "Foo", + kind: Struct, + }, + CompletionItem { + label: "PublicBar", + source_range: [31; 31), + delete: [31; 31), + insert: "PublicBar", + kind: Struct, + }, + ] + "### + ); + } + + #[test] + fn completes_use_item_starting_with_self() { + assert_debug_snapshot!( + do_reference_completion( + r" + use self::m::<|>; + + mod m { + pub struct Bar; + } + " + ), + @r###" + [ + CompletionItem { + label: "Bar", + source_range: [30; 30), + delete: [30; 30), + insert: "Bar", + kind: Struct, + }, + ] + "### + ); + } + + #[test] + fn completes_use_item_starting_with_crate() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /lib.rs + mod foo; + struct Spam; + //- /foo.rs + use crate::Sp<|> + " + ), + @r###" + [ + CompletionItem { + label: "Spam", + source_range: [11; 13), + delete: [11; 13), + insert: "Spam", + kind: Struct, + }, + CompletionItem { + label: "foo", + source_range: [11; 13), + delete: [11; 13), + insert: "foo", + kind: Module, + }, + ] + "### + ); + } + + #[test] + fn completes_nested_use_tree() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /lib.rs + mod foo; + struct Spam; + //- /foo.rs + use crate::{Sp<|>}; + " + ), + @r###" + [ + CompletionItem { + label: "Spam", + source_range: [12; 14), + delete: [12; 14), + insert: "Spam", + kind: Struct, + }, + CompletionItem { + label: "foo", + source_range: [12; 14), + delete: [12; 14), + insert: "foo", + kind: Module, + }, + ] + "### + ); + } + + #[test] + fn completes_deeply_nested_use_tree() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /lib.rs + mod foo; + pub mod bar { + pub mod baz { + pub struct Spam; + } + } + //- /foo.rs + use crate::{bar::{baz::Sp<|>}}; + " + ), + @r###" + [ + CompletionItem { + label: "Spam", + source_range: [23; 25), + delete: [23; 25), + insert: "Spam", + kind: Struct, + }, + ] + "### + ); + } + + #[test] + fn completes_enum_variant() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /lib.rs + /// An enum + enum E { + /// Foo Variant + Foo, + /// Bar Variant with i32 + Bar(i32) + } + fn foo() { let _ = E::<|> } + " + ), + @r###" + [ + CompletionItem { + label: "Bar(…)", + source_range: [116; 116), + delete: [116; 116), + insert: "Bar($0)", + kind: EnumVariant, + lookup: "Bar", + detail: "(i32)", + documentation: Documentation( + "Bar Variant with i32", + ), + trigger_call_info: true, + }, + CompletionItem { + label: "Foo", + source_range: [116; 116), + delete: [116; 116), + insert: "Foo", + kind: EnumVariant, + detail: "()", + documentation: Documentation( + "Foo Variant", + ), + }, + ] + "### + ); + } + + #[test] + fn completes_enum_variant_with_details() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /lib.rs + struct S { field: u32 } + /// An enum + enum E { + /// Foo Variant (empty) + Foo, + /// Bar Variant with i32 and u32 + Bar(i32, u32), + /// + S(S), + } + fn foo() { let _ = E::<|> } + " + ), + @r###" + [ + CompletionItem { + label: "Bar(…)", + source_range: [180; 180), + delete: [180; 180), + insert: "Bar($0)", + kind: EnumVariant, + lookup: "Bar", + detail: "(i32, u32)", + documentation: Documentation( + "Bar Variant with i32 and u32", + ), + trigger_call_info: true, + }, + CompletionItem { + label: "Foo", + source_range: [180; 180), + delete: [180; 180), + insert: "Foo", + kind: EnumVariant, + detail: "()", + documentation: Documentation( + "Foo Variant (empty)", + ), + }, + CompletionItem { + label: "S(…)", + source_range: [180; 180), + delete: [180; 180), + insert: "S($0)", + kind: EnumVariant, + lookup: "S", + detail: "(S)", + documentation: Documentation( + "", + ), + trigger_call_info: true, + }, + ] + "### + ); + } + + #[test] + fn completes_struct_associated_method() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /lib.rs + /// A Struct + struct S; + + impl S { + /// An associated method + fn m() { } + } + + fn foo() { let _ = S::<|> } + " + ), + @r###" + [ + CompletionItem { + label: "m()", + source_range: [100; 100), + delete: [100; 100), + insert: "m()$0", + kind: Function, + lookup: "m", + detail: "fn m()", + documentation: Documentation( + "An associated method", + ), + }, + ] + "### + ); + } + + #[test] + fn completes_struct_associated_const() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /lib.rs + /// A Struct + struct S; + + impl S { + /// An associated const + const C: i32 = 42; + } + + fn foo() { let _ = S::<|> } + " + ), + @r###" + [ + CompletionItem { + label: "C", + source_range: [107; 107), + delete: [107; 107), + insert: "C", + kind: Const, + detail: "const C: i32 = 42;", + documentation: Documentation( + "An associated const", + ), + }, + ] + "### + ); + } + + #[test] + fn completes_struct_associated_type() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /lib.rs + /// A Struct + struct S; + + impl S { + /// An associated type + type T = i32; + } + + fn foo() { let _ = S::<|> } + " + ), + @r###" + [ + CompletionItem { + label: "T", + source_range: [101; 101), + delete: [101; 101), + insert: "T", + kind: TypeAlias, + detail: "type T = i32;", + documentation: Documentation( + "An associated type", + ), + }, + ] + "### + ); + } + + #[test] + fn associated_item_visibility() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /lib.rs + struct S; + + mod m { + impl super::S { + pub(super) fn public_method() { } + fn private_method() { } + pub(super) type PublicType = u32; + type PrivateType = u32; + pub(super) const PUBLIC_CONST: u32 = 1; + const PRIVATE_CONST: u32 = 1; + } + } + + fn foo() { let _ = S::<|> } + " + ), + @r###" + [ + CompletionItem { + label: "PUBLIC_CONST", + source_range: [302; 302), + delete: [302; 302), + insert: "PUBLIC_CONST", + kind: Const, + detail: "pub(super) const PUBLIC_CONST: u32 = 1;", + }, + CompletionItem { + label: "PublicType", + source_range: [302; 302), + delete: [302; 302), + insert: "PublicType", + kind: TypeAlias, + detail: "pub(super) type PublicType = u32;", + }, + CompletionItem { + label: "public_method()", + source_range: [302; 302), + delete: [302; 302), + insert: "public_method()$0", + kind: Function, + lookup: "public_method", + detail: "pub(super) fn public_method()", + }, + ] + "### + ); + } + + #[test] + fn completes_enum_associated_method() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /lib.rs + /// An enum + enum S {}; + + impl S { + /// An associated method + fn m() { } + } + + fn foo() { let _ = S::<|> } + " + ), + @r###" + [ + CompletionItem { + label: "m()", + source_range: [100; 100), + delete: [100; 100), + insert: "m()$0", + kind: Function, + lookup: "m", + detail: "fn m()", + documentation: Documentation( + "An associated method", + ), + }, + ] + "### + ); + } + + #[test] + fn completes_union_associated_method() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /lib.rs + /// A union + union U {}; + + impl U { + /// An associated method + fn m() { } + } + + fn foo() { let _ = U::<|> } + " + ), + @r###" + [ + CompletionItem { + label: "m()", + source_range: [101; 101), + delete: [101; 101), + insert: "m()$0", + kind: Function, + lookup: "m", + detail: "fn m()", + documentation: Documentation( + "An associated method", + ), + }, + ] + "### + ); + } + + #[test] + fn completes_use_paths_across_crates() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /main.rs + use foo::<|>; + + //- /foo/lib.rs + pub mod bar { + pub struct S; + } + " + ), + @r###" + [ + CompletionItem { + label: "bar", + source_range: [9; 9), + delete: [9; 9), + insert: "bar", + kind: Module, + }, + ] + "### + ); + } + + #[test] + fn completes_trait_associated_method_1() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /lib.rs + trait Trait { + /// A trait method + fn m(); + } + + fn foo() { let _ = Trait::<|> } + " + ), + @r###" + [ + CompletionItem { + label: "m()", + source_range: [73; 73), + delete: [73; 73), + insert: "m()$0", + kind: Function, + lookup: "m", + detail: "fn m()", + documentation: Documentation( + "A trait method", + ), + }, + ] + "### + ); + } + + #[test] + fn completes_trait_associated_method_2() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /lib.rs + trait Trait { + /// A trait method + fn m(); + } + + struct S; + impl Trait for S {} + + fn foo() { let _ = S::<|> } + " + ), + @r###" + [ + CompletionItem { + label: "m()", + source_range: [99; 99), + delete: [99; 99), + insert: "m()$0", + kind: Function, + lookup: "m", + detail: "fn m()", + documentation: Documentation( + "A trait method", + ), + }, + ] + "### + ); + } + + #[test] + fn completes_trait_associated_method_3() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /lib.rs + trait Trait { + /// A trait method + fn m(); + } + + struct S; + impl Trait for S {} + + fn foo() { let _ = ::<|> } + " + ), + @r###" + [ + CompletionItem { + label: "m()", + source_range: [110; 110), + delete: [110; 110), + insert: "m()$0", + kind: Function, + lookup: "m", + detail: "fn m()", + documentation: Documentation( + "A trait method", + ), + }, + ] + "### + ); + } + + #[test] + fn completes_type_alias() { + assert_debug_snapshot!( + do_reference_completion( + " + struct S; + impl S { fn foo() {} } + type T = S; + impl T { fn bar() {} } + + fn main() { + T::<|>; + } + " + ), + @r###" + [ + CompletionItem { + label: "bar()", + source_range: [185; 185), + delete: [185; 185), + insert: "bar()$0", + kind: Function, + lookup: "bar", + detail: "fn bar()", + }, + CompletionItem { + label: "foo()", + source_range: [185; 185), + delete: [185; 185), + insert: "foo()$0", + kind: Function, + lookup: "foo", + detail: "fn foo()", + }, + ] + "### + ); + } + + #[test] + fn completes_qualified_macros() { + assert_debug_snapshot!( + do_reference_completion( + " + #[macro_export] + macro_rules! foo { + () => {} + } + + fn main() { + let _ = crate::<|> + } + " + ), + @r###" + [ + CompletionItem { + label: "foo!", + source_range: [179; 179), + delete: [179; 179), + insert: "foo!($0)", + kind: Macro, + detail: "#[macro_export]\nmacro_rules! foo", + }, + CompletionItem { + label: "main()", + source_range: [179; 179), + delete: [179; 179), + insert: "main()$0", + kind: Function, + lookup: "main", + detail: "fn main()", + }, + ] + "### + ); + } + + #[test] + fn completes_reexported_items_under_correct_name() { + assert_debug_snapshot!( + do_reference_completion( + r" + fn foo() { + self::m::<|> + } + + mod m { + pub use super::p::wrong_fn as right_fn; + pub use super::p::WRONG_CONST as RIGHT_CONST; + pub use super::p::WrongType as RightType; + } + mod p { + fn wrong_fn() {} + const WRONG_CONST: u32 = 1; + struct WrongType {}; + } + " + ), + @r###" + [ + CompletionItem { + label: "RIGHT_CONST", + source_range: [57; 57), + delete: [57; 57), + insert: "RIGHT_CONST", + kind: Const, + }, + CompletionItem { + label: "RightType", + source_range: [57; 57), + delete: [57; 57), + insert: "RightType", + kind: Struct, + }, + CompletionItem { + label: "right_fn()", + source_range: [57; 57), + delete: [57; 57), + insert: "right_fn()$0", + kind: Function, + lookup: "right_fn", + detail: "fn wrong_fn()", + }, + ] + "### + ); + } + + #[test] + fn completes_in_simple_macro_call() { + let completions = do_reference_completion( + r#" + macro_rules! m { ($e:expr) => { $e } } + fn main() { m!(self::f<|>); } + fn foo() {} + "#, + ); + assert_debug_snapshot!(completions, @r###" + [ + CompletionItem { + label: "foo()", + source_range: [93; 94), + delete: [93; 94), + insert: "foo()$0", + kind: Function, + lookup: "foo", + detail: "fn foo()", + }, + CompletionItem { + label: "main()", + source_range: [93; 94), + delete: [93; 94), + insert: "main()$0", + kind: Function, + lookup: "main", + detail: "fn main()", + }, + ] + "###); + } + + #[test] + fn function_mod_share_name() { + assert_debug_snapshot!( + do_reference_completion( + r" + fn foo() { + self::m::<|> + } + + mod m { + pub mod z {} + pub fn z() {} + } + ", + ), + @r###" + [ + CompletionItem { + label: "z", + source_range: [57; 57), + delete: [57; 57), + insert: "z", + kind: Module, + }, + CompletionItem { + label: "z()", + source_range: [57; 57), + delete: [57; 57), + insert: "z()$0", + kind: Function, + lookup: "z", + detail: "pub fn z()", + }, + ] + "### + ); + } + + #[test] + fn completes_hashmap_new() { + assert_debug_snapshot!( + do_reference_completion( + r" + struct RandomState; + struct HashMap {} + + impl HashMap { + pub fn new() -> HashMap { } + } + fn foo() { + HashMap::<|> + } + " + ), + @r###" + [ + CompletionItem { + label: "new()", + source_range: [292; 292), + delete: [292; 292), + insert: "new()$0", + kind: Function, + lookup: "new", + detail: "pub fn new() -> HashMap", + }, + ] + "### + ); + } +} diff --git a/crates/ra_ide/src/completion/complete_scope.rs b/crates/ra_ide/src/completion/complete_scope.rs deleted file mode 100644 index 665597e4c..000000000 --- a/crates/ra_ide/src/completion/complete_scope.rs +++ /dev/null @@ -1,1067 +0,0 @@ -//! Completion of names from the current scope, e.g. locals and imported items. - -use crate::completion::{CompletionContext, Completions}; - -pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { - if !(ctx.is_trivial_path && !ctx.is_pat_binding_or_const) { - return; - } - - ctx.scope().process_all_names(&mut |name, res| acc.add_resolution(ctx, name.to_string(), &res)); -} - -#[cfg(test)] -mod tests { - use insta::assert_debug_snapshot; - - use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; - - fn do_reference_completion(ra_fixture: &str) -> Vec { - do_completion(ra_fixture, CompletionKind::Reference) - } - - #[test] - fn bind_pat_and_path_ignore_at() { - assert_debug_snapshot!( - do_reference_completion( - r" - enum Enum { - A, - B, - } - fn quux(x: Option) { - match x { - None => (), - Some(en<|> @ Enum::A) => (), - } - } - " - ), - @r###"[]"### - ); - } - - #[test] - fn bind_pat_and_path_ignore_ref() { - assert_debug_snapshot!( - do_reference_completion( - r" - enum Enum { - A, - B, - } - fn quux(x: Option) { - match x { - None => (), - Some(ref en<|>) => (), - } - } - " - ), - @r###"[]"### - ); - } - - #[test] - fn bind_pat_and_path() { - assert_debug_snapshot!( - do_reference_completion( - r" - enum Enum { - A, - B, - } - fn quux(x: Option) { - match x { - None => (), - Some(En<|>) => (), - } - } - " - ), - @r###" - [ - CompletionItem { - label: "Enum", - source_range: [231; 233), - delete: [231; 233), - insert: "Enum", - kind: Enum, - }, - ] - "### - ); - } - - #[test] - fn completes_bindings_from_let() { - assert_debug_snapshot!( - do_reference_completion( - r" - fn quux(x: i32) { - let y = 92; - 1 + <|>; - let z = (); - } - " - ), - @r###" - [ - CompletionItem { - label: "quux(…)", - source_range: [91; 91), - delete: [91; 91), - insert: "quux(${1:x})$0", - kind: Function, - lookup: "quux", - detail: "fn quux(x: i32)", - trigger_call_info: true, - }, - CompletionItem { - label: "x", - source_range: [91; 91), - delete: [91; 91), - insert: "x", - kind: Binding, - detail: "i32", - }, - CompletionItem { - label: "y", - source_range: [91; 91), - delete: [91; 91), - insert: "y", - kind: Binding, - detail: "i32", - }, - ] - "### - ); - } - - #[test] - fn completes_bindings_from_if_let() { - assert_debug_snapshot!( - do_reference_completion( - r" - fn quux() { - if let Some(x) = foo() { - let y = 92; - }; - if let Some(a) = bar() { - let b = 62; - 1 + <|> - } - } - " - ), - @r###" - [ - CompletionItem { - label: "a", - source_range: [242; 242), - delete: [242; 242), - insert: "a", - kind: Binding, - }, - CompletionItem { - label: "b", - source_range: [242; 242), - delete: [242; 242), - insert: "b", - kind: Binding, - detail: "i32", - }, - CompletionItem { - label: "quux()", - source_range: [242; 242), - delete: [242; 242), - insert: "quux()$0", - kind: Function, - lookup: "quux", - detail: "fn quux()", - }, - ] - "### - ); - } - - #[test] - fn completes_bindings_from_for() { - assert_debug_snapshot!( - do_reference_completion( - r" - fn quux() { - for x in &[1, 2, 3] { - <|> - } - } - " - ), - @r###" - [ - CompletionItem { - label: "quux()", - source_range: [95; 95), - delete: [95; 95), - insert: "quux()$0", - kind: Function, - lookup: "quux", - detail: "fn quux()", - }, - CompletionItem { - label: "x", - source_range: [95; 95), - delete: [95; 95), - insert: "x", - kind: Binding, - }, - ] - "### - ); - } - - #[test] - fn completes_generic_params() { - assert_debug_snapshot!( - do_reference_completion( - r" - fn quux() { - <|> - } - " - ), - @r###" - [ - CompletionItem { - label: "T", - source_range: [52; 52), - delete: [52; 52), - insert: "T", - kind: TypeParam, - }, - CompletionItem { - label: "quux()", - source_range: [52; 52), - delete: [52; 52), - insert: "quux()$0", - kind: Function, - lookup: "quux", - detail: "fn quux()", - }, - ] - "### - ); - } - - #[test] - fn completes_generic_params_in_struct() { - assert_debug_snapshot!( - do_reference_completion( - r" - struct X { - x: <|> - } - " - ), - @r###" - [ - CompletionItem { - label: "Self", - source_range: [54; 54), - delete: [54; 54), - insert: "Self", - kind: TypeParam, - }, - CompletionItem { - label: "T", - source_range: [54; 54), - delete: [54; 54), - insert: "T", - kind: TypeParam, - }, - CompletionItem { - label: "X<…>", - source_range: [54; 54), - delete: [54; 54), - insert: "X<$0>", - kind: Struct, - lookup: "X", - }, - ] - "### - ); - } - - #[test] - fn completes_self_in_enum() { - assert_debug_snapshot!( - do_reference_completion( - r" - enum X { - Y(<|>) - } - " - ), - @r###" - [ - CompletionItem { - label: "Self", - source_range: [48; 48), - delete: [48; 48), - insert: "Self", - kind: TypeParam, - }, - CompletionItem { - label: "X", - source_range: [48; 48), - delete: [48; 48), - insert: "X", - kind: Enum, - }, - ] - "### - ); - } - - #[test] - fn completes_module_items() { - assert_debug_snapshot!( - do_reference_completion( - r" - struct Foo; - enum Baz {} - fn quux() { - <|> - } - " - ), - @r###" - [ - CompletionItem { - label: "Baz", - source_range: [105; 105), - delete: [105; 105), - insert: "Baz", - kind: Enum, - }, - CompletionItem { - label: "Foo", - source_range: [105; 105), - delete: [105; 105), - insert: "Foo", - kind: Struct, - }, - CompletionItem { - label: "quux()", - source_range: [105; 105), - delete: [105; 105), - insert: "quux()$0", - kind: Function, - lookup: "quux", - detail: "fn quux()", - }, - ] - "### - ); - } - - #[test] - fn completes_extern_prelude() { - assert_debug_snapshot!( - do_reference_completion( - r" - //- /lib.rs - use <|>; - - //- /other_crate/lib.rs - // nothing here - " - ), - @r###" - [ - CompletionItem { - label: "other_crate", - source_range: [4; 4), - delete: [4; 4), - insert: "other_crate", - kind: Module, - }, - ] - "### - ); - } - - #[test] - fn completes_module_items_in_nested_modules() { - assert_debug_snapshot!( - do_reference_completion( - r" - struct Foo; - mod m { - struct Bar; - fn quux() { <|> } - } - " - ), - @r###" - [ - CompletionItem { - label: "Bar", - source_range: [117; 117), - delete: [117; 117), - insert: "Bar", - kind: Struct, - }, - CompletionItem { - label: "quux()", - source_range: [117; 117), - delete: [117; 117), - insert: "quux()$0", - kind: Function, - lookup: "quux", - detail: "fn quux()", - }, - ] - "### - ); - } - - #[test] - fn completes_return_type() { - assert_debug_snapshot!( - do_reference_completion( - r" - struct Foo; - fn x() -> <|> - " - ), - @r###" - [ - CompletionItem { - label: "Foo", - source_range: [55; 55), - delete: [55; 55), - insert: "Foo", - kind: Struct, - }, - CompletionItem { - label: "x()", - source_range: [55; 55), - delete: [55; 55), - insert: "x()$0", - kind: Function, - lookup: "x", - detail: "fn x()", - }, - ] - "### - ); - } - - #[test] - fn dont_show_both_completions_for_shadowing() { - assert_debug_snapshot!( - do_reference_completion( - r" - fn foo() { - let bar = 92; - { - let bar = 62; - <|> - } - } - " - ), - @r###" - [ - CompletionItem { - label: "bar", - source_range: [146; 146), - delete: [146; 146), - insert: "bar", - kind: Binding, - detail: "i32", - }, - CompletionItem { - label: "foo()", - source_range: [146; 146), - delete: [146; 146), - insert: "foo()$0", - kind: Function, - lookup: "foo", - detail: "fn foo()", - }, - ] - "### - ); - } - - #[test] - fn completes_self_in_methods() { - assert_debug_snapshot!( - do_reference_completion(r"impl S { fn foo(&self) { <|> } }"), - @r###" - [ - CompletionItem { - label: "Self", - source_range: [25; 25), - delete: [25; 25), - insert: "Self", - kind: TypeParam, - }, - CompletionItem { - label: "self", - source_range: [25; 25), - delete: [25; 25), - insert: "self", - kind: Binding, - detail: "&{unknown}", - }, - ] - "### - ); - } - - #[test] - fn completes_prelude() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /main.rs - fn foo() { let x: <|> } - - //- /std/lib.rs - #[prelude_import] - use prelude::*; - - mod prelude { - struct Option; - } - " - ), - @r###" - [ - CompletionItem { - label: "Option", - source_range: [18; 18), - delete: [18; 18), - insert: "Option", - kind: Struct, - }, - CompletionItem { - label: "foo()", - source_range: [18; 18), - delete: [18; 18), - insert: "foo()$0", - kind: Function, - lookup: "foo", - detail: "fn foo()", - }, - CompletionItem { - label: "std", - source_range: [18; 18), - delete: [18; 18), - insert: "std", - kind: Module, - }, - ] - "### - ); - } - - #[test] - fn completes_std_prelude_if_core_is_defined() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /main.rs - fn foo() { let x: <|> } - - //- /core/lib.rs - #[prelude_import] - use prelude::*; - - mod prelude { - struct Option; - } - - //- /std/lib.rs - #[prelude_import] - use prelude::*; - - mod prelude { - struct String; - } - " - ), - @r###" - [ - CompletionItem { - label: "String", - source_range: [18; 18), - delete: [18; 18), - insert: "String", - kind: Struct, - }, - CompletionItem { - label: "core", - source_range: [18; 18), - delete: [18; 18), - insert: "core", - kind: Module, - }, - CompletionItem { - label: "foo()", - source_range: [18; 18), - delete: [18; 18), - insert: "foo()$0", - kind: Function, - lookup: "foo", - detail: "fn foo()", - }, - CompletionItem { - label: "std", - source_range: [18; 18), - delete: [18; 18), - insert: "std", - kind: Module, - }, - ] - "### - ); - } - - #[test] - fn completes_macros_as_value() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /main.rs - macro_rules! foo { - () => {} - } - - #[macro_use] - mod m1 { - macro_rules! bar { - () => {} - } - } - - mod m2 { - macro_rules! nope { - () => {} - } - - #[macro_export] - macro_rules! baz { - () => {} - } - } - - fn main() { - let v = <|> - } - " - ), - @r###" - [ - CompletionItem { - label: "bar!", - source_range: [252; 252), - delete: [252; 252), - insert: "bar!($0)", - kind: Macro, - detail: "macro_rules! bar", - }, - CompletionItem { - label: "baz!", - source_range: [252; 252), - delete: [252; 252), - insert: "baz!($0)", - kind: Macro, - detail: "#[macro_export]\nmacro_rules! baz", - }, - CompletionItem { - label: "foo!", - source_range: [252; 252), - delete: [252; 252), - insert: "foo!($0)", - kind: Macro, - detail: "macro_rules! foo", - }, - CompletionItem { - label: "m1", - source_range: [252; 252), - delete: [252; 252), - insert: "m1", - kind: Module, - }, - CompletionItem { - label: "m2", - source_range: [252; 252), - delete: [252; 252), - insert: "m2", - kind: Module, - }, - CompletionItem { - label: "main()", - source_range: [252; 252), - delete: [252; 252), - insert: "main()$0", - kind: Function, - lookup: "main", - detail: "fn main()", - }, - ] - "### - ); - } - - #[test] - fn completes_both_macro_and_value() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /main.rs - macro_rules! foo { - () => {} - } - - fn foo() { - <|> - } - " - ), - @r###" - [ - CompletionItem { - label: "foo!", - source_range: [49; 49), - delete: [49; 49), - insert: "foo!($0)", - kind: Macro, - detail: "macro_rules! foo", - }, - CompletionItem { - label: "foo()", - source_range: [49; 49), - delete: [49; 49), - insert: "foo()$0", - kind: Function, - lookup: "foo", - detail: "fn foo()", - }, - ] - "### - ); - } - - #[test] - fn completes_macros_as_type() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /main.rs - macro_rules! foo { - () => {} - } - - fn main() { - let x: <|> - } - " - ), - @r###" - [ - CompletionItem { - label: "foo!", - source_range: [57; 57), - delete: [57; 57), - insert: "foo!($0)", - kind: Macro, - detail: "macro_rules! foo", - }, - CompletionItem { - label: "main()", - source_range: [57; 57), - delete: [57; 57), - insert: "main()$0", - kind: Function, - lookup: "main", - detail: "fn main()", - }, - ] - "### - ); - } - - #[test] - fn completes_macros_as_stmt() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /main.rs - macro_rules! foo { - () => {} - } - - fn main() { - <|> - } - " - ), - @r###" - [ - CompletionItem { - label: "foo!", - source_range: [50; 50), - delete: [50; 50), - insert: "foo!($0)", - kind: Macro, - detail: "macro_rules! foo", - }, - CompletionItem { - label: "main()", - source_range: [50; 50), - delete: [50; 50), - insert: "main()$0", - kind: Function, - lookup: "main", - detail: "fn main()", - }, - ] - "### - ); - } - - #[test] - fn completes_local_item() { - assert_debug_snapshot!( - do_reference_completion( - " - //- /main.rs - fn main() { - return f<|>; - fn frobnicate() {} - } - " - ), - @r###" - [ - CompletionItem { - label: "frobnicate()", - source_range: [23; 24), - delete: [23; 24), - insert: "frobnicate()$0", - kind: Function, - lookup: "frobnicate", - detail: "fn frobnicate()", - }, - CompletionItem { - label: "main()", - source_range: [23; 24), - delete: [23; 24), - insert: "main()$0", - kind: Function, - lookup: "main", - detail: "fn main()", - }, - ] - "### - ) - } - - #[test] - fn completes_in_simple_macro_1() { - assert_debug_snapshot!( - do_reference_completion( - r" - macro_rules! m { ($e:expr) => { $e } } - fn quux(x: i32) { - let y = 92; - m!(<|>); - } - " - ), - @r###" - [ - CompletionItem { - label: "m!", - source_range: [145; 145), - delete: [145; 145), - insert: "m!($0)", - kind: Macro, - detail: "macro_rules! m", - }, - CompletionItem { - label: "quux(…)", - source_range: [145; 145), - delete: [145; 145), - insert: "quux(${1:x})$0", - kind: Function, - lookup: "quux", - detail: "fn quux(x: i32)", - trigger_call_info: true, - }, - CompletionItem { - label: "x", - source_range: [145; 145), - delete: [145; 145), - insert: "x", - kind: Binding, - detail: "i32", - }, - CompletionItem { - label: "y", - source_range: [145; 145), - delete: [145; 145), - insert: "y", - kind: Binding, - detail: "i32", - }, - ] - "### - ); - } - - #[test] - fn completes_in_simple_macro_2() { - assert_debug_snapshot!( - do_reference_completion( - r" - macro_rules! m { ($e:expr) => { $e } } - fn quux(x: i32) { - let y = 92; - m!(x<|>); - } - " - ), - @r###" - [ - CompletionItem { - label: "m!", - source_range: [145; 146), - delete: [145; 146), - insert: "m!($0)", - kind: Macro, - detail: "macro_rules! m", - }, - CompletionItem { - label: "quux(…)", - source_range: [145; 146), - delete: [145; 146), - insert: "quux(${1:x})$0", - kind: Function, - lookup: "quux", - detail: "fn quux(x: i32)", - trigger_call_info: true, - }, - CompletionItem { - label: "x", - source_range: [145; 146), - delete: [145; 146), - insert: "x", - kind: Binding, - detail: "i32", - }, - CompletionItem { - label: "y", - source_range: [145; 146), - delete: [145; 146), - insert: "y", - kind: Binding, - detail: "i32", - }, - ] - "### - ); - } - - #[test] - fn completes_in_simple_macro_without_closing_parens() { - assert_debug_snapshot!( - do_reference_completion( - r" - macro_rules! m { ($e:expr) => { $e } } - fn quux(x: i32) { - let y = 92; - m!(x<|> - } - " - ), - @r###" - [ - CompletionItem { - label: "m!", - source_range: [145; 146), - delete: [145; 146), - insert: "m!($0)", - kind: Macro, - detail: "macro_rules! m", - }, - CompletionItem { - label: "quux(…)", - source_range: [145; 146), - delete: [145; 146), - insert: "quux(${1:x})$0", - kind: Function, - lookup: "quux", - detail: "fn quux(x: i32)", - trigger_call_info: true, - }, - CompletionItem { - label: "x", - source_range: [145; 146), - delete: [145; 146), - insert: "x", - kind: Binding, - detail: "i32", - }, - CompletionItem { - label: "y", - source_range: [145; 146), - delete: [145; 146), - insert: "y", - kind: Binding, - detail: "i32", - }, - ] - "### - ); - } - - #[test] - fn completes_unresolved_uses() { - assert_debug_snapshot!( - do_reference_completion( - r" - use spam::Quux; - - fn main() { - <|> - } - " - ), - @r###" - [ - CompletionItem { - label: "Quux", - source_range: [82; 82), - delete: [82; 82), - insert: "Quux", - }, - CompletionItem { - label: "main()", - source_range: [82; 82), - delete: [82; 82), - insert: "main()$0", - kind: Function, - lookup: "main", - detail: "fn main()", - }, - ] - "### - ); - } -} diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs new file mode 100644 index 000000000..665597e4c --- /dev/null +++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs @@ -0,0 +1,1067 @@ +//! Completion of names from the current scope, e.g. locals and imported items. + +use crate::completion::{CompletionContext, Completions}; + +pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { + if !(ctx.is_trivial_path && !ctx.is_pat_binding_or_const) { + return; + } + + ctx.scope().process_all_names(&mut |name, res| acc.add_resolution(ctx, name.to_string(), &res)); +} + +#[cfg(test)] +mod tests { + use insta::assert_debug_snapshot; + + use crate::completion::{test_utils::do_completion, CompletionItem, CompletionKind}; + + fn do_reference_completion(ra_fixture: &str) -> Vec { + do_completion(ra_fixture, CompletionKind::Reference) + } + + #[test] + fn bind_pat_and_path_ignore_at() { + assert_debug_snapshot!( + do_reference_completion( + r" + enum Enum { + A, + B, + } + fn quux(x: Option) { + match x { + None => (), + Some(en<|> @ Enum::A) => (), + } + } + " + ), + @r###"[]"### + ); + } + + #[test] + fn bind_pat_and_path_ignore_ref() { + assert_debug_snapshot!( + do_reference_completion( + r" + enum Enum { + A, + B, + } + fn quux(x: Option) { + match x { + None => (), + Some(ref en<|>) => (), + } + } + " + ), + @r###"[]"### + ); + } + + #[test] + fn bind_pat_and_path() { + assert_debug_snapshot!( + do_reference_completion( + r" + enum Enum { + A, + B, + } + fn quux(x: Option) { + match x { + None => (), + Some(En<|>) => (), + } + } + " + ), + @r###" + [ + CompletionItem { + label: "Enum", + source_range: [231; 233), + delete: [231; 233), + insert: "Enum", + kind: Enum, + }, + ] + "### + ); + } + + #[test] + fn completes_bindings_from_let() { + assert_debug_snapshot!( + do_reference_completion( + r" + fn quux(x: i32) { + let y = 92; + 1 + <|>; + let z = (); + } + " + ), + @r###" + [ + CompletionItem { + label: "quux(…)", + source_range: [91; 91), + delete: [91; 91), + insert: "quux(${1:x})$0", + kind: Function, + lookup: "quux", + detail: "fn quux(x: i32)", + trigger_call_info: true, + }, + CompletionItem { + label: "x", + source_range: [91; 91), + delete: [91; 91), + insert: "x", + kind: Binding, + detail: "i32", + }, + CompletionItem { + label: "y", + source_range: [91; 91), + delete: [91; 91), + insert: "y", + kind: Binding, + detail: "i32", + }, + ] + "### + ); + } + + #[test] + fn completes_bindings_from_if_let() { + assert_debug_snapshot!( + do_reference_completion( + r" + fn quux() { + if let Some(x) = foo() { + let y = 92; + }; + if let Some(a) = bar() { + let b = 62; + 1 + <|> + } + } + " + ), + @r###" + [ + CompletionItem { + label: "a", + source_range: [242; 242), + delete: [242; 242), + insert: "a", + kind: Binding, + }, + CompletionItem { + label: "b", + source_range: [242; 242), + delete: [242; 242), + insert: "b", + kind: Binding, + detail: "i32", + }, + CompletionItem { + label: "quux()", + source_range: [242; 242), + delete: [242; 242), + insert: "quux()$0", + kind: Function, + lookup: "quux", + detail: "fn quux()", + }, + ] + "### + ); + } + + #[test] + fn completes_bindings_from_for() { + assert_debug_snapshot!( + do_reference_completion( + r" + fn quux() { + for x in &[1, 2, 3] { + <|> + } + } + " + ), + @r###" + [ + CompletionItem { + label: "quux()", + source_range: [95; 95), + delete: [95; 95), + insert: "quux()$0", + kind: Function, + lookup: "quux", + detail: "fn quux()", + }, + CompletionItem { + label: "x", + source_range: [95; 95), + delete: [95; 95), + insert: "x", + kind: Binding, + }, + ] + "### + ); + } + + #[test] + fn completes_generic_params() { + assert_debug_snapshot!( + do_reference_completion( + r" + fn quux() { + <|> + } + " + ), + @r###" + [ + CompletionItem { + label: "T", + source_range: [52; 52), + delete: [52; 52), + insert: "T", + kind: TypeParam, + }, + CompletionItem { + label: "quux()", + source_range: [52; 52), + delete: [52; 52), + insert: "quux()$0", + kind: Function, + lookup: "quux", + detail: "fn quux()", + }, + ] + "### + ); + } + + #[test] + fn completes_generic_params_in_struct() { + assert_debug_snapshot!( + do_reference_completion( + r" + struct X { + x: <|> + } + " + ), + @r###" + [ + CompletionItem { + label: "Self", + source_range: [54; 54), + delete: [54; 54), + insert: "Self", + kind: TypeParam, + }, + CompletionItem { + label: "T", + source_range: [54; 54), + delete: [54; 54), + insert: "T", + kind: TypeParam, + }, + CompletionItem { + label: "X<…>", + source_range: [54; 54), + delete: [54; 54), + insert: "X<$0>", + kind: Struct, + lookup: "X", + }, + ] + "### + ); + } + + #[test] + fn completes_self_in_enum() { + assert_debug_snapshot!( + do_reference_completion( + r" + enum X { + Y(<|>) + } + " + ), + @r###" + [ + CompletionItem { + label: "Self", + source_range: [48; 48), + delete: [48; 48), + insert: "Self", + kind: TypeParam, + }, + CompletionItem { + label: "X", + source_range: [48; 48), + delete: [48; 48), + insert: "X", + kind: Enum, + }, + ] + "### + ); + } + + #[test] + fn completes_module_items() { + assert_debug_snapshot!( + do_reference_completion( + r" + struct Foo; + enum Baz {} + fn quux() { + <|> + } + " + ), + @r###" + [ + CompletionItem { + label: "Baz", + source_range: [105; 105), + delete: [105; 105), + insert: "Baz", + kind: Enum, + }, + CompletionItem { + label: "Foo", + source_range: [105; 105), + delete: [105; 105), + insert: "Foo", + kind: Struct, + }, + CompletionItem { + label: "quux()", + source_range: [105; 105), + delete: [105; 105), + insert: "quux()$0", + kind: Function, + lookup: "quux", + detail: "fn quux()", + }, + ] + "### + ); + } + + #[test] + fn completes_extern_prelude() { + assert_debug_snapshot!( + do_reference_completion( + r" + //- /lib.rs + use <|>; + + //- /other_crate/lib.rs + // nothing here + " + ), + @r###" + [ + CompletionItem { + label: "other_crate", + source_range: [4; 4), + delete: [4; 4), + insert: "other_crate", + kind: Module, + }, + ] + "### + ); + } + + #[test] + fn completes_module_items_in_nested_modules() { + assert_debug_snapshot!( + do_reference_completion( + r" + struct Foo; + mod m { + struct Bar; + fn quux() { <|> } + } + " + ), + @r###" + [ + CompletionItem { + label: "Bar", + source_range: [117; 117), + delete: [117; 117), + insert: "Bar", + kind: Struct, + }, + CompletionItem { + label: "quux()", + source_range: [117; 117), + delete: [117; 117), + insert: "quux()$0", + kind: Function, + lookup: "quux", + detail: "fn quux()", + }, + ] + "### + ); + } + + #[test] + fn completes_return_type() { + assert_debug_snapshot!( + do_reference_completion( + r" + struct Foo; + fn x() -> <|> + " + ), + @r###" + [ + CompletionItem { + label: "Foo", + source_range: [55; 55), + delete: [55; 55), + insert: "Foo", + kind: Struct, + }, + CompletionItem { + label: "x()", + source_range: [55; 55), + delete: [55; 55), + insert: "x()$0", + kind: Function, + lookup: "x", + detail: "fn x()", + }, + ] + "### + ); + } + + #[test] + fn dont_show_both_completions_for_shadowing() { + assert_debug_snapshot!( + do_reference_completion( + r" + fn foo() { + let bar = 92; + { + let bar = 62; + <|> + } + } + " + ), + @r###" + [ + CompletionItem { + label: "bar", + source_range: [146; 146), + delete: [146; 146), + insert: "bar", + kind: Binding, + detail: "i32", + }, + CompletionItem { + label: "foo()", + source_range: [146; 146), + delete: [146; 146), + insert: "foo()$0", + kind: Function, + lookup: "foo", + detail: "fn foo()", + }, + ] + "### + ); + } + + #[test] + fn completes_self_in_methods() { + assert_debug_snapshot!( + do_reference_completion(r"impl S { fn foo(&self) { <|> } }"), + @r###" + [ + CompletionItem { + label: "Self", + source_range: [25; 25), + delete: [25; 25), + insert: "Self", + kind: TypeParam, + }, + CompletionItem { + label: "self", + source_range: [25; 25), + delete: [25; 25), + insert: "self", + kind: Binding, + detail: "&{unknown}", + }, + ] + "### + ); + } + + #[test] + fn completes_prelude() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /main.rs + fn foo() { let x: <|> } + + //- /std/lib.rs + #[prelude_import] + use prelude::*; + + mod prelude { + struct Option; + } + " + ), + @r###" + [ + CompletionItem { + label: "Option", + source_range: [18; 18), + delete: [18; 18), + insert: "Option", + kind: Struct, + }, + CompletionItem { + label: "foo()", + source_range: [18; 18), + delete: [18; 18), + insert: "foo()$0", + kind: Function, + lookup: "foo", + detail: "fn foo()", + }, + CompletionItem { + label: "std", + source_range: [18; 18), + delete: [18; 18), + insert: "std", + kind: Module, + }, + ] + "### + ); + } + + #[test] + fn completes_std_prelude_if_core_is_defined() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /main.rs + fn foo() { let x: <|> } + + //- /core/lib.rs + #[prelude_import] + use prelude::*; + + mod prelude { + struct Option; + } + + //- /std/lib.rs + #[prelude_import] + use prelude::*; + + mod prelude { + struct String; + } + " + ), + @r###" + [ + CompletionItem { + label: "String", + source_range: [18; 18), + delete: [18; 18), + insert: "String", + kind: Struct, + }, + CompletionItem { + label: "core", + source_range: [18; 18), + delete: [18; 18), + insert: "core", + kind: Module, + }, + CompletionItem { + label: "foo()", + source_range: [18; 18), + delete: [18; 18), + insert: "foo()$0", + kind: Function, + lookup: "foo", + detail: "fn foo()", + }, + CompletionItem { + label: "std", + source_range: [18; 18), + delete: [18; 18), + insert: "std", + kind: Module, + }, + ] + "### + ); + } + + #[test] + fn completes_macros_as_value() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /main.rs + macro_rules! foo { + () => {} + } + + #[macro_use] + mod m1 { + macro_rules! bar { + () => {} + } + } + + mod m2 { + macro_rules! nope { + () => {} + } + + #[macro_export] + macro_rules! baz { + () => {} + } + } + + fn main() { + let v = <|> + } + " + ), + @r###" + [ + CompletionItem { + label: "bar!", + source_range: [252; 252), + delete: [252; 252), + insert: "bar!($0)", + kind: Macro, + detail: "macro_rules! bar", + }, + CompletionItem { + label: "baz!", + source_range: [252; 252), + delete: [252; 252), + insert: "baz!($0)", + kind: Macro, + detail: "#[macro_export]\nmacro_rules! baz", + }, + CompletionItem { + label: "foo!", + source_range: [252; 252), + delete: [252; 252), + insert: "foo!($0)", + kind: Macro, + detail: "macro_rules! foo", + }, + CompletionItem { + label: "m1", + source_range: [252; 252), + delete: [252; 252), + insert: "m1", + kind: Module, + }, + CompletionItem { + label: "m2", + source_range: [252; 252), + delete: [252; 252), + insert: "m2", + kind: Module, + }, + CompletionItem { + label: "main()", + source_range: [252; 252), + delete: [252; 252), + insert: "main()$0", + kind: Function, + lookup: "main", + detail: "fn main()", + }, + ] + "### + ); + } + + #[test] + fn completes_both_macro_and_value() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /main.rs + macro_rules! foo { + () => {} + } + + fn foo() { + <|> + } + " + ), + @r###" + [ + CompletionItem { + label: "foo!", + source_range: [49; 49), + delete: [49; 49), + insert: "foo!($0)", + kind: Macro, + detail: "macro_rules! foo", + }, + CompletionItem { + label: "foo()", + source_range: [49; 49), + delete: [49; 49), + insert: "foo()$0", + kind: Function, + lookup: "foo", + detail: "fn foo()", + }, + ] + "### + ); + } + + #[test] + fn completes_macros_as_type() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /main.rs + macro_rules! foo { + () => {} + } + + fn main() { + let x: <|> + } + " + ), + @r###" + [ + CompletionItem { + label: "foo!", + source_range: [57; 57), + delete: [57; 57), + insert: "foo!($0)", + kind: Macro, + detail: "macro_rules! foo", + }, + CompletionItem { + label: "main()", + source_range: [57; 57), + delete: [57; 57), + insert: "main()$0", + kind: Function, + lookup: "main", + detail: "fn main()", + }, + ] + "### + ); + } + + #[test] + fn completes_macros_as_stmt() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /main.rs + macro_rules! foo { + () => {} + } + + fn main() { + <|> + } + " + ), + @r###" + [ + CompletionItem { + label: "foo!", + source_range: [50; 50), + delete: [50; 50), + insert: "foo!($0)", + kind: Macro, + detail: "macro_rules! foo", + }, + CompletionItem { + label: "main()", + source_range: [50; 50), + delete: [50; 50), + insert: "main()$0", + kind: Function, + lookup: "main", + detail: "fn main()", + }, + ] + "### + ); + } + + #[test] + fn completes_local_item() { + assert_debug_snapshot!( + do_reference_completion( + " + //- /main.rs + fn main() { + return f<|>; + fn frobnicate() {} + } + " + ), + @r###" + [ + CompletionItem { + label: "frobnicate()", + source_range: [23; 24), + delete: [23; 24), + insert: "frobnicate()$0", + kind: Function, + lookup: "frobnicate", + detail: "fn frobnicate()", + }, + CompletionItem { + label: "main()", + source_range: [23; 24), + delete: [23; 24), + insert: "main()$0", + kind: Function, + lookup: "main", + detail: "fn main()", + }, + ] + "### + ) + } + + #[test] + fn completes_in_simple_macro_1() { + assert_debug_snapshot!( + do_reference_completion( + r" + macro_rules! m { ($e:expr) => { $e } } + fn quux(x: i32) { + let y = 92; + m!(<|>); + } + " + ), + @r###" + [ + CompletionItem { + label: "m!", + source_range: [145; 145), + delete: [145; 145), + insert: "m!($0)", + kind: Macro, + detail: "macro_rules! m", + }, + CompletionItem { + label: "quux(…)", + source_range: [145; 145), + delete: [145; 145), + insert: "quux(${1:x})$0", + kind: Function, + lookup: "quux", + detail: "fn quux(x: i32)", + trigger_call_info: true, + }, + CompletionItem { + label: "x", + source_range: [145; 145), + delete: [145; 145), + insert: "x", + kind: Binding, + detail: "i32", + }, + CompletionItem { + label: "y", + source_range: [145; 145), + delete: [145; 145), + insert: "y", + kind: Binding, + detail: "i32", + }, + ] + "### + ); + } + + #[test] + fn completes_in_simple_macro_2() { + assert_debug_snapshot!( + do_reference_completion( + r" + macro_rules! m { ($e:expr) => { $e } } + fn quux(x: i32) { + let y = 92; + m!(x<|>); + } + " + ), + @r###" + [ + CompletionItem { + label: "m!", + source_range: [145; 146), + delete: [145; 146), + insert: "m!($0)", + kind: Macro, + detail: "macro_rules! m", + }, + CompletionItem { + label: "quux(…)", + source_range: [145; 146), + delete: [145; 146), + insert: "quux(${1:x})$0", + kind: Function, + lookup: "quux", + detail: "fn quux(x: i32)", + trigger_call_info: true, + }, + CompletionItem { + label: "x", + source_range: [145; 146), + delete: [145; 146), + insert: "x", + kind: Binding, + detail: "i32", + }, + CompletionItem { + label: "y", + source_range: [145; 146), + delete: [145; 146), + insert: "y", + kind: Binding, + detail: "i32", + }, + ] + "### + ); + } + + #[test] + fn completes_in_simple_macro_without_closing_parens() { + assert_debug_snapshot!( + do_reference_completion( + r" + macro_rules! m { ($e:expr) => { $e } } + fn quux(x: i32) { + let y = 92; + m!(x<|> + } + " + ), + @r###" + [ + CompletionItem { + label: "m!", + source_range: [145; 146), + delete: [145; 146), + insert: "m!($0)", + kind: Macro, + detail: "macro_rules! m", + }, + CompletionItem { + label: "quux(…)", + source_range: [145; 146), + delete: [145; 146), + insert: "quux(${1:x})$0", + kind: Function, + lookup: "quux", + detail: "fn quux(x: i32)", + trigger_call_info: true, + }, + CompletionItem { + label: "x", + source_range: [145; 146), + delete: [145; 146), + insert: "x", + kind: Binding, + detail: "i32", + }, + CompletionItem { + label: "y", + source_range: [145; 146), + delete: [145; 146), + insert: "y", + kind: Binding, + detail: "i32", + }, + ] + "### + ); + } + + #[test] + fn completes_unresolved_uses() { + assert_debug_snapshot!( + do_reference_completion( + r" + use spam::Quux; + + fn main() { + <|> + } + " + ), + @r###" + [ + CompletionItem { + label: "Quux", + source_range: [82; 82), + delete: [82; 82), + insert: "Quux", + }, + CompletionItem { + label: "main()", + source_range: [82; 82), + delete: [82; 82), + insert: "main()$0", + kind: Function, + lookup: "main", + detail: "fn main()", + }, + ] + "### + ); + } +} -- cgit v1.2.3