1 //! Completion of names from the current scope, e.g. locals and imported items.
6 use hir::{Adt, ModPath, ModuleDef, ScopeDef, Type};
7 use ide_db::helpers::insert_use::ImportScope;
8 use ide_db::imports_locator;
13 render::{render_resolution_with_import, RenderContext},
14 CompletionContext, Completions, ImportEdit,
17 pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
18 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) {
21 if ctx.record_lit_syntax.is_some()
22 || ctx.record_pat_syntax.is_some()
23 || ctx.attribute_under_caret.is_some()
24 || ctx.mod_declaration_under_caret.is_some()
29 if let Some(ty) = &ctx.expected_type {
30 complete_enum_variants(acc, ctx, ty);
33 if ctx.is_pat_binding_or_const {
37 ctx.scope.process_all_names(&mut |name, res| {
38 if ctx.use_item_syntax.is_some() {
39 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) {
40 if name_ref.syntax().text() == name.to_string().as_str() {
41 mark::hit!(self_fulfilling_completion);
46 acc.add_resolution(ctx, name.to_string(), &res)
49 if ctx.config.enable_autoimport_completions && ctx.config.resolve_additional_edits_lazily() {
50 fuzzy_completion(acc, ctx);
54 fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) {
55 if let Some(Adt::Enum(enum_data)) =
56 iter::successors(Some(ty.clone()), |ty| ty.remove_ref()).last().and_then(|ty| ty.as_adt())
58 let variants = enum_data.variants(ctx.db);
60 let module = if let Some(module) = ctx.scope.module() {
61 // Compute path from the completion site if available.
64 // Otherwise fall back to the enum's definition site.
65 enum_data.module(ctx.db)
68 for variant in variants {
69 if let Some(path) = module.find_use_path(ctx.db, ModuleDef::from(variant)) {
70 // Variants with trivial paths are already added by the existing completion logic,
71 // so we should avoid adding these twice
72 if path.segments.len() > 1 {
73 acc.add_qualified_enum_variant(ctx, variant, path);
80 // Feature: Fuzzy Completion and Autoimports
82 // When completing names in the current scope, proposes additional imports from other modules or crates,
83 // if they can be qualified in the scope and their name contains all symbols from the completion input
84 // (case-insensitive, in any order or places).
90 // # pub mod std { pub mod marker { pub struct PhantomData { } } }
94 // use std::marker::PhantomData;
99 // # pub mod std { pub mod marker { pub struct PhantomData { } } }
102 // .Fuzzy search details
104 // To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
105 // (i.e. in `HashMap` in the `std::collections::HashMap` path).
106 // For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols.
110 // It is possible to configure how use-trees are merged with the `importMergeBehavior` setting.
111 // Mimics the corresponding behavior of the `Auto Import` feature.
113 // .LSP and performance implications
115 // The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
116 // (case sensitive) resolve client capability in its client capabilities.
117 // This way the server is able to defer the costly computations, doing them for a selected completion item only.
118 // For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
119 // which might be slow ergo the feature is automatically disabled.
123 // The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag.
124 // Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding
125 // capability enabled.
126 fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
127 let potential_import_name = ctx.token.to_string();
128 let _p = profile::span("fuzzy_completion").detail(|| potential_import_name.clone());
130 if potential_import_name.len() < 2 {
134 let current_module = ctx.scope.module()?;
135 let anchor = ctx.name_ref_syntax.as_ref()?;
136 let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
138 let user_input_lowercased = potential_import_name.to_lowercase();
139 let mut all_mod_paths = imports_locator::find_similar_imports(
143 potential_import_name,
147 .filter_map(|import_candidate| {
148 Some(match import_candidate {
149 Either::Left(module_def) => {
150 (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def))
152 Either::Right(macro_def) => {
153 (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def))
157 .filter(|(mod_path, _)| mod_path.len() > 1)
158 .collect::<Vec<_>>();
160 all_mod_paths.sort_by_cached_key(|(mod_path, _)| {
161 compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased)
164 acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| {
165 render_resolution_with_import(
166 RenderContext::new(ctx),
167 ImportEdit { import_path, import_scope: import_scope.clone() },
174 fn compute_fuzzy_completion_order_key(
175 proposed_mod_path: &ModPath,
176 user_input_lowercased: &str,
178 mark::hit!(certain_fuzzy_order_test);
179 let proposed_import_name = match proposed_mod_path.segments.last() {
180 Some(name) => name.to_string().to_lowercase(),
181 None => return usize::MAX,
183 match proposed_import_name.match_indices(user_input_lowercased).next() {
184 Some((first_matching_index, _)) => first_matching_index,
191 use expect_test::{expect, Expect};
192 use test_utils::mark;
195 test_utils::{check_edit, check_edit_with_config, completion_list_with_config},
196 CompletionConfig, CompletionKind,
199 fn check(ra_fixture: &str, expect: Expect) {
200 check_with_config(CompletionConfig::default(), ra_fixture, expect);
203 fn check_with_config(config: CompletionConfig, ra_fixture: &str, expect: Expect) {
204 let actual = completion_list_with_config(config, ra_fixture, CompletionKind::Reference);
205 expect.assert_eq(&actual)
208 fn fuzzy_completion_config() -> CompletionConfig {
209 let mut completion_config = CompletionConfig::default();
211 .active_resolve_capabilities
212 .insert(crate::CompletionResolveCapability::AdditionalTextEdits);
217 fn self_fulfilling_completion() {
218 mark::check!(self_fulfilling_completion);
222 use std::collections;
231 fn bind_pat_and_path_ignore_at() {
235 fn quux(x: Option<Enum>) {
238 Some(en<|> @ Enum::A) => (),
247 fn bind_pat_and_path_ignore_ref() {
251 fn quux(x: Option<Enum>) {
254 Some(ref en<|>) => (),
263 fn bind_pat_and_path() {
267 fn quux(x: Option<Enum>) {
281 fn completes_bindings_from_let() {
293 fn quux(…) fn quux(x: i32)
299 fn completes_bindings_from_if_let() {
303 if let Some(x) = foo() {
306 if let Some(a) = bar() {
321 fn completes_bindings_from_for() {
325 for x in &[1, 2, 3] { <|> }
336 fn completes_if_prefix_is_keyword() {
337 mark::check!(completes_if_prefix_is_keyword);
356 fn completes_generic_params() {
358 r#"fn quux<T>() { <|> }"#,
361 fn quux() fn quux<T>()
367 fn completes_generic_params_in_struct() {
369 r#"struct S<T> { x: <|>}"#,
379 fn completes_self_in_enum() {
381 r#"enum X { Y(<|>) }"#,
390 fn completes_module_items() {
405 /// Regression test for issue #6091.
407 fn correctly_completes_module_items_prefixed_with_underscore() {
426 fn completes_extern_prelude() {
429 //- /lib.rs crate:main deps:other_crate
432 //- /other_crate/lib.rs crate:other_crate
442 fn completes_module_items_in_nested_modules() {
459 fn completes_return_type() {
473 fn dont_show_both_completions_for_shadowing() {
484 // FIXME: should be only one bar here
494 fn completes_self_in_methods() {
496 r#"impl S { fn foo(&self) { <|> } }"#,
505 fn completes_prelude() {
508 //- /main.rs crate:main deps:std
509 fn foo() { let x: <|> }
511 //- /std/lib.rs crate:std
515 mod prelude { struct Option; }
526 fn completes_std_prelude_if_core_is_defined() {
529 //- /main.rs crate:main deps:core,std
530 fn foo() { let x: <|> }
532 //- /core/lib.rs crate:core
536 mod prelude { struct Option; }
538 //- /std/lib.rs crate:std deps:core
542 mod prelude { struct String; }
554 fn completes_macros_as_value() {
557 macro_rules! foo { () => {} }
561 macro_rules! bar { () => {} }
565 macro_rules! nope { () => {} }
568 macro_rules! baz { () => {} }
571 fn main() { let v = <|> }
575 ma baz!(…) #[macro_export]
579 ma bar!(…) macro_rules! bar
580 ma foo!(…) macro_rules! foo
586 fn completes_both_macro_and_value() {
589 macro_rules! foo { () => {} }
594 ma foo!(…) macro_rules! foo
600 fn completes_macros_as_type() {
603 macro_rules! foo { () => {} }
604 fn main() { let x: <|> }
608 ma foo!(…) macro_rules! foo
614 fn completes_macros_as_stmt() {
617 macro_rules! foo { () => {} }
622 ma foo!(…) macro_rules! foo
628 fn completes_local_item() {
637 fn frobnicate() fn frobnicate()
644 fn completes_in_simple_macro_1() {
647 macro_rules! m { ($e:expr) => { $e } }
656 fn quux(…) fn quux(x: i32)
657 ma m!(…) macro_rules! m
663 fn completes_in_simple_macro_2() {
666 macro_rules! m { ($e:expr) => { $e } }
675 fn quux(…) fn quux(x: i32)
676 ma m!(…) macro_rules! m
682 fn completes_in_simple_macro_without_closing_parens() {
685 macro_rules! m { ($e:expr) => { $e } }
694 fn quux(…) fn quux(x: i32)
695 ma m!(…) macro_rules! m
701 fn completes_unresolved_uses() {
716 fn completes_enum_variant_matcharm() {
719 enum Foo { Bar, Baz, Quux }
736 fn completes_enum_variant_matcharm_ref() {
739 enum Foo { Bar, Baz, Quux }
756 fn completes_enum_variant_iflet() {
759 enum Foo { Bar, Baz, Quux }
763 if let Qu<|> = foo { }
776 fn completes_enum_variant_basic_expr() {
779 enum Foo { Bar, Baz, Quux }
780 fn main() { let foo: Foo = Q<|> }
793 fn completes_enum_variant_from_module() {
796 mod m { pub enum E { V } }
797 fn f() -> m::E { V<|> }
802 fn f() fn f() -> m::E
808 fn dont_complete_attr() {
820 fn completes_type_or_trait_in_impl_block() {
837 fn function_fuzzy_completion() {
838 check_edit_with_config(
839 fuzzy_completion_config(),
842 //- /lib.rs crate:dep
847 //- /main.rs crate:main deps:dep
863 fn macro_fuzzy_completion() {
864 check_edit_with_config(
865 fuzzy_completion_config(),
866 "macro_with_curlies!",
868 //- /lib.rs crate:dep
869 /// Please call me as macro_with_curlies! {}
871 macro_rules! macro_with_curlies {
875 //- /main.rs crate:main deps:dep
881 use dep::macro_with_curlies;
884 macro_with_curlies! {$0}
891 fn struct_fuzzy_completion() {
892 check_edit_with_config(
893 fuzzy_completion_config(),
896 //- /lib.rs crate:dep
897 pub struct FirstStruct;
898 pub mod some_module {
899 pub struct SecondStruct;
900 pub struct ThirdStruct;
903 //- /main.rs crate:main deps:dep
904 use dep::{FirstStruct, some_module::SecondStruct};
911 use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
921 fn fuzzy_completions_come_in_specific_order() {
922 mark::check!(certain_fuzzy_order_test);
924 fuzzy_completion_config(),
926 //- /lib.rs crate:dep
927 pub struct FirstStruct;
928 pub mod some_module {
929 // already imported, omitted
930 pub struct SecondStruct;
931 // does not contain all letters from the query, omitted
932 pub struct UnrelatedOne;
933 // contains all letters from the query, but not in sequence, displayed last
934 pub struct ThiiiiiirdStruct;
935 // contains all letters from the query, but not in the beginning, displayed second
936 pub struct AfterThirdStruct;
937 // contains all letters from the query in the begginning, displayed first
938 pub struct ThirdStruct;
941 //- /main.rs crate:main deps:dep
942 use dep::{FirstStruct, some_module::SecondStruct};
953 st dep::some_module::ThirdStruct
954 st dep::some_module::AfterThirdStruct
955 st dep::some_module::ThiiiiiirdStruct