aboutsummaryrefslogtreecommitdiff
path: root/crates/completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/completion')
-rw-r--r--crates/completion/Cargo.toml1
-rw-r--r--crates/completion/src/completions.rs8
-rw-r--r--crates/completion/src/completions/pattern.rs57
-rw-r--r--crates/completion/src/completions/unqualified_path.rs134
-rw-r--r--crates/completion/src/config.rs6
-rw-r--r--crates/completion/src/context.rs3
-rw-r--r--crates/completion/src/item.rs59
-rw-r--r--crates/completion/src/lib.rs7
-rw-r--r--crates/completion/src/render.rs58
-rw-r--r--crates/completion/src/render/enum_variant.rs10
-rw-r--r--crates/completion/src/render/function.rs12
-rw-r--r--crates/completion/src/render/macro_.rs12
12 files changed, 324 insertions, 43 deletions
diff --git a/crates/completion/Cargo.toml b/crates/completion/Cargo.toml
index 3015ec9e0..e7df9d955 100644
--- a/crates/completion/Cargo.toml
+++ b/crates/completion/Cargo.toml
@@ -13,6 +13,7 @@ doctest = false
13itertools = "0.9.0" 13itertools = "0.9.0"
14log = "0.4.8" 14log = "0.4.8"
15rustc-hash = "1.1.0" 15rustc-hash = "1.1.0"
16either = "1.6.1"
16 17
17assists = { path = "../assists", version = "0.0.0" } 18assists = { path = "../assists", version = "0.0.0" }
18stdx = { path = "../stdx", version = "0.0.0" } 19stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/completion/src/completions.rs b/crates/completion/src/completions.rs
index 75dbb1a23..9b7d6c580 100644
--- a/crates/completion/src/completions.rs
+++ b/crates/completion/src/completions.rs
@@ -90,7 +90,7 @@ impl Completions {
90 Some(it) => it, 90 Some(it) => it,
91 None => return, 91 None => return,
92 }; 92 };
93 if let Some(item) = render_macro(RenderContext::new(ctx), name, macro_) { 93 if let Some(item) = render_macro(RenderContext::new(ctx), None, name, macro_) {
94 self.add(item); 94 self.add(item);
95 } 95 }
96 } 96 }
@@ -101,7 +101,7 @@ impl Completions {
101 func: hir::Function, 101 func: hir::Function,
102 local_name: Option<String>, 102 local_name: Option<String>,
103 ) { 103 ) {
104 let item = render_fn(RenderContext::new(ctx), local_name, func); 104 let item = render_fn(RenderContext::new(ctx), None, local_name, func);
105 self.add(item) 105 self.add(item)
106 } 106 }
107 107
@@ -123,7 +123,7 @@ impl Completions {
123 variant: hir::EnumVariant, 123 variant: hir::EnumVariant,
124 path: ModPath, 124 path: ModPath,
125 ) { 125 ) {
126 let item = render_enum_variant(RenderContext::new(ctx), None, variant, Some(path)); 126 let item = render_enum_variant(RenderContext::new(ctx), None, None, variant, Some(path));
127 self.add(item); 127 self.add(item);
128 } 128 }
129 129
@@ -133,7 +133,7 @@ impl Completions {
133 variant: hir::EnumVariant, 133 variant: hir::EnumVariant,
134 local_name: Option<String>, 134 local_name: Option<String>,
135 ) { 135 ) {
136 let item = render_enum_variant(RenderContext::new(ctx), local_name, variant, None); 136 let item = render_enum_variant(RenderContext::new(ctx), None, local_name, variant, None);
137 self.add(item); 137 self.add(item);
138 } 138 }
139} 139}
diff --git a/crates/completion/src/completions/pattern.rs b/crates/completion/src/completions/pattern.rs
index 7ab7f09fe..4f63ff0ef 100644
--- a/crates/completion/src/completions/pattern.rs
+++ b/crates/completion/src/completions/pattern.rs
@@ -4,7 +4,7 @@ use crate::{CompletionContext, Completions};
4 4
5/// Completes constats and paths in patterns. 5/// Completes constats and paths in patterns.
6pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) { 6pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
7 if !ctx.is_pat_binding_or_const { 7 if !(ctx.is_pat_binding_or_const || ctx.is_irrefutable_let_pat_binding) {
8 return; 8 return;
9 } 9 }
10 if ctx.record_pat_syntax.is_some() { 10 if ctx.record_pat_syntax.is_some() {
@@ -14,20 +14,27 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
14 // FIXME: ideally, we should look at the type we are matching against and 14 // FIXME: ideally, we should look at the type we are matching against and
15 // suggest variants + auto-imports 15 // suggest variants + auto-imports
16 ctx.scope.process_all_names(&mut |name, res| { 16 ctx.scope.process_all_names(&mut |name, res| {
17 match &res { 17 let add_resolution = match &res {
18 hir::ScopeDef::ModuleDef(def) => match def { 18 hir::ScopeDef::ModuleDef(def) => {
19 hir::ModuleDef::Adt(hir::Adt::Enum(..)) 19 if ctx.is_irrefutable_let_pat_binding {
20 | hir::ModuleDef::Adt(hir::Adt::Struct(..)) 20 matches!(def, hir::ModuleDef::Adt(hir::Adt::Struct(_)))
21 | hir::ModuleDef::EnumVariant(..) 21 } else {
22 | hir::ModuleDef::Const(..) 22 matches!(
23 | hir::ModuleDef::Module(..) => (), 23 def,
24 _ => return, 24 hir::ModuleDef::Adt(hir::Adt::Enum(..))
25 }, 25 | hir::ModuleDef::Adt(hir::Adt::Struct(..))
26 hir::ScopeDef::MacroDef(_) => (), 26 | hir::ModuleDef::EnumVariant(..)
27 _ => return, 27 | hir::ModuleDef::Const(..)
28 | hir::ModuleDef::Module(..)
29 )
30 }
31 }
32 hir::ScopeDef::MacroDef(_) => true,
33 _ => false,
28 }; 34 };
29 35 if add_resolution {
30 acc.add_resolution(ctx, name.to_string(), &res) 36 acc.add_resolution(ctx, name.to_string(), &res);
37 }
31 }); 38 });
32} 39}
33 40
@@ -85,4 +92,26 @@ fn foo() {
85 "#]], 92 "#]],
86 ); 93 );
87 } 94 }
95
96 #[test]
97 fn completes_in_irrefutable_let() {
98 check(
99 r#"
100enum E { X }
101use self::E::X;
102const Z: E = E::X;
103mod m {}
104
105static FOO: E = E::X;
106struct Bar { f: u32 }
107
108fn foo() {
109 let <|>
110}
111"#,
112 expect![[r#"
113 st Bar
114 "#]],
115 );
116 }
88} 117}
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index 7df58e1da..3bd776905 100644
--- a/crates/completion/src/completions/unqualified_path.rs
+++ b/crates/completion/src/completions/unqualified_path.rs
@@ -1,10 +1,16 @@
1//! Completion of names from the current scope, e.g. locals and imported items. 1//! Completion of names from the current scope, e.g. locals and imported items.
2 2
3use assists::utils::ImportScope;
4use either::Either;
3use hir::{Adt, ModuleDef, ScopeDef, Type}; 5use hir::{Adt, ModuleDef, ScopeDef, Type};
6use ide_db::imports_locator;
4use syntax::AstNode; 7use syntax::AstNode;
5use test_utils::mark; 8use test_utils::mark;
6 9
7use crate::{CompletionContext, Completions}; 10use crate::{
11 render::{render_resolution_with_import, RenderContext},
12 CompletionContext, Completions,
13};
8 14
9pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 15pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
10 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) { 16 if !(ctx.is_trivial_path || ctx.is_pat_binding_or_const) {
@@ -37,6 +43,10 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
37 } 43 }
38 acc.add_resolution(ctx, name.to_string(), &res) 44 acc.add_resolution(ctx, name.to_string(), &res)
39 }); 45 });
46
47 if ctx.config.enable_experimental_completions {
48 fuzzy_completion(acc, ctx).unwrap_or_default()
49 }
40} 50}
41 51
42fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) { 52fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &Type) {
@@ -63,6 +73,47 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
63 } 73 }
64} 74}
65 75
76fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
77 let _p = profile::span("fuzzy_completion");
78 let current_module = ctx.scope.module()?;
79 let anchor = ctx.name_ref_syntax.as_ref()?;
80 let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
81
82 let potential_import_name = ctx.token.to_string();
83
84 let possible_imports = imports_locator::find_similar_imports(
85 &ctx.sema,
86 ctx.krate?,
87 &potential_import_name,
88 50,
89 true,
90 )
91 .filter_map(|import_candidate| {
92 Some(match import_candidate {
93 Either::Left(module_def) => {
94 (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def))
95 }
96 Either::Right(macro_def) => {
97 (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def))
98 }
99 })
100 })
101 .filter(|(mod_path, _)| mod_path.len() > 1)
102 .take(20)
103 .filter_map(|(import_path, definition)| {
104 render_resolution_with_import(
105 RenderContext::new(ctx),
106 import_path.clone(),
107 import_scope.clone(),
108 ctx.config.merge,
109 &definition,
110 )
111 });
112
113 acc.add_all(possible_imports);
114 Some(())
115}
116
66#[cfg(test)] 117#[cfg(test)]
67mod tests { 118mod tests {
68 use expect_test::{expect, Expect}; 119 use expect_test::{expect, Expect};
@@ -676,4 +727,85 @@ impl My<|>
676 "#]], 727 "#]],
677 ) 728 )
678 } 729 }
730
731 #[test]
732 fn function_fuzzy_completion() {
733 check_edit(
734 "stdin",
735 r#"
736//- /lib.rs crate:dep
737pub mod io {
738 pub fn stdin() {}
739};
740
741//- /main.rs crate:main deps:dep
742fn main() {
743 stdi<|>
744}
745"#,
746 r#"
747use dep::io::stdin;
748
749fn main() {
750 stdin()$0
751}
752"#,
753 );
754 }
755
756 #[test]
757 fn macro_fuzzy_completion() {
758 check_edit(
759 "macro_with_curlies!",
760 r#"
761//- /lib.rs crate:dep
762/// Please call me as macro_with_curlies! {}
763#[macro_export]
764macro_rules! macro_with_curlies {
765 () => {}
766}
767
768//- /main.rs crate:main deps:dep
769fn main() {
770 curli<|>
771}
772"#,
773 r#"
774use dep::macro_with_curlies;
775
776fn main() {
777 macro_with_curlies! {$0}
778}
779"#,
780 );
781 }
782
783 #[test]
784 fn struct_fuzzy_completion() {
785 check_edit(
786 "ThirdStruct",
787 r#"
788//- /lib.rs crate:dep
789pub struct FirstStruct;
790pub mod some_module {
791 pub struct SecondStruct;
792 pub struct ThirdStruct;
793}
794
795//- /main.rs crate:main deps:dep
796use dep::{FirstStruct, some_module::SecondStruct};
797
798fn main() {
799 this<|>
800}
801"#,
802 r#"
803use dep::{FirstStruct, some_module::{SecondStruct, ThirdStruct}};
804
805fn main() {
806 ThirdStruct
807}
808"#,
809 );
810 }
679} 811}
diff --git a/crates/completion/src/config.rs b/crates/completion/src/config.rs
index 71b49ace8..f50735372 100644
--- a/crates/completion/src/config.rs
+++ b/crates/completion/src/config.rs
@@ -4,12 +4,16 @@
4//! module, and we use to statically check that we only produce snippet 4//! module, and we use to statically check that we only produce snippet
5//! completions if we are allowed to. 5//! completions if we are allowed to.
6 6
7use assists::utils::MergeBehaviour;
8
7#[derive(Clone, Debug, PartialEq, Eq)] 9#[derive(Clone, Debug, PartialEq, Eq)]
8pub struct CompletionConfig { 10pub struct CompletionConfig {
9 pub enable_postfix_completions: bool, 11 pub enable_postfix_completions: bool,
12 pub enable_experimental_completions: bool,
10 pub add_call_parenthesis: bool, 13 pub add_call_parenthesis: bool,
11 pub add_call_argument_snippets: bool, 14 pub add_call_argument_snippets: bool,
12 pub snippet_cap: Option<SnippetCap>, 15 pub snippet_cap: Option<SnippetCap>,
16 pub merge: Option<MergeBehaviour>,
13} 17}
14 18
15impl CompletionConfig { 19impl CompletionConfig {
@@ -27,9 +31,11 @@ impl Default for CompletionConfig {
27 fn default() -> Self { 31 fn default() -> Self {
28 CompletionConfig { 32 CompletionConfig {
29 enable_postfix_completions: true, 33 enable_postfix_completions: true,
34 enable_experimental_completions: true,
30 add_call_parenthesis: true, 35 add_call_parenthesis: true,
31 add_call_argument_snippets: true, 36 add_call_argument_snippets: true,
32 snippet_cap: Some(SnippetCap { _private: () }), 37 snippet_cap: Some(SnippetCap { _private: () }),
38 merge: Some(MergeBehaviour::Full),
33 } 39 }
34 } 40 }
35} 41}
diff --git a/crates/completion/src/context.rs b/crates/completion/src/context.rs
index bf70ee478..5cd11cf77 100644
--- a/crates/completion/src/context.rs
+++ b/crates/completion/src/context.rs
@@ -51,6 +51,7 @@ pub(crate) struct CompletionContext<'a> {
51 /// If a name-binding or reference to a const in a pattern. 51 /// If a name-binding or reference to a const in a pattern.
52 /// Irrefutable patterns (like let) are excluded. 52 /// Irrefutable patterns (like let) are excluded.
53 pub(super) is_pat_binding_or_const: bool, 53 pub(super) is_pat_binding_or_const: bool,
54 pub(super) is_irrefutable_let_pat_binding: bool,
54 /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. 55 /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
55 pub(super) is_trivial_path: bool, 56 pub(super) is_trivial_path: bool,
56 /// If not a trivial path, the prefix (qualifier). 57 /// If not a trivial path, the prefix (qualifier).
@@ -146,6 +147,7 @@ impl<'a> CompletionContext<'a> {
146 active_parameter: ActiveParameter::at(db, position), 147 active_parameter: ActiveParameter::at(db, position),
147 is_param: false, 148 is_param: false,
148 is_pat_binding_or_const: false, 149 is_pat_binding_or_const: false,
150 is_irrefutable_let_pat_binding: false,
149 is_trivial_path: false, 151 is_trivial_path: false,
150 path_qual: None, 152 path_qual: None,
151 after_if: false, 153 after_if: false,
@@ -330,6 +332,7 @@ impl<'a> CompletionContext<'a> {
330 if pat.syntax().text_range().contains_range(bind_pat.syntax().text_range()) 332 if pat.syntax().text_range().contains_range(bind_pat.syntax().text_range())
331 { 333 {
332 self.is_pat_binding_or_const = false; 334 self.is_pat_binding_or_const = false;
335 self.is_irrefutable_let_pat_binding = true;
333 } 336 }
334 } 337 }
335 } 338 }
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs
index 6d1d085f4..b13c3f376 100644
--- a/crates/completion/src/item.rs
+++ b/crates/completion/src/item.rs
@@ -2,8 +2,9 @@
2 2
3use std::fmt; 3use std::fmt;
4 4
5use hir::{Documentation, Mutability}; 5use assists::utils::{insert_use, mod_path_to_ast, ImportScope, MergeBehaviour};
6use syntax::TextRange; 6use hir::{Documentation, ModPath, Mutability};
7use syntax::{algo, TextRange};
7use text_edit::TextEdit; 8use text_edit::TextEdit;
8 9
9use crate::config::SnippetCap; 10use crate::config::SnippetCap;
@@ -31,6 +32,7 @@ pub struct CompletionItem {
31 /// 32 ///
32 /// Typically, replaces `source_range` with new identifier. 33 /// Typically, replaces `source_range` with new identifier.
33 text_edit: TextEdit, 34 text_edit: TextEdit,
35
34 insert_text_format: InsertTextFormat, 36 insert_text_format: InsertTextFormat,
35 37
36 /// What item (struct, function, etc) are we completing. 38 /// What item (struct, function, etc) are we completing.
@@ -199,8 +201,10 @@ impl CompletionItem {
199 trigger_call_info: None, 201 trigger_call_info: None,
200 score: None, 202 score: None,
201 ref_match: None, 203 ref_match: None,
204 import_data: None,
202 } 205 }
203 } 206 }
207
204 /// What user sees in pop-up in the UI. 208 /// What user sees in pop-up in the UI.
205 pub fn label(&self) -> &str { 209 pub fn label(&self) -> &str {
206 &self.label 210 &self.label
@@ -257,6 +261,7 @@ impl CompletionItem {
257pub(crate) struct Builder { 261pub(crate) struct Builder {
258 source_range: TextRange, 262 source_range: TextRange,
259 completion_kind: CompletionKind, 263 completion_kind: CompletionKind,
264 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
260 label: String, 265 label: String,
261 insert_text: Option<String>, 266 insert_text: Option<String>,
262 insert_text_format: InsertTextFormat, 267 insert_text_format: InsertTextFormat,
@@ -273,23 +278,50 @@ pub(crate) struct Builder {
273 278
274impl Builder { 279impl Builder {
275 pub(crate) fn build(self) -> CompletionItem { 280 pub(crate) fn build(self) -> CompletionItem {
276 let label = self.label; 281 let mut label = self.label;
277 let text_edit = match self.text_edit { 282 let mut lookup = self.lookup;
283 let mut insert_text = self.insert_text;
284 let mut text_edits = TextEdit::builder();
285
286 if let Some((import_path, import_scope, merge_behaviour)) = self.import_data {
287 let import = mod_path_to_ast(&import_path);
288 let mut import_path_without_last_segment = import_path;
289 let _ = import_path_without_last_segment.segments.pop();
290
291 if !import_path_without_last_segment.segments.is_empty() {
292 if lookup.is_none() {
293 lookup = Some(label.clone());
294 }
295 if insert_text.is_none() {
296 insert_text = Some(label.clone());
297 }
298 label = format!("{}::{}", import_path_without_last_segment, label);
299 }
300
301 let rewriter = insert_use(&import_scope, import, merge_behaviour);
302 if let Some(old_ast) = rewriter.rewrite_root() {
303 algo::diff(&old_ast, &rewriter.rewrite(&old_ast)).into_text_edit(&mut text_edits);
304 }
305 }
306
307 let original_edit = match self.text_edit {
278 Some(it) => it, 308 Some(it) => it,
279 None => TextEdit::replace( 309 None => {
280 self.source_range, 310 TextEdit::replace(self.source_range, insert_text.unwrap_or_else(|| label.clone()))
281 self.insert_text.unwrap_or_else(|| label.clone()), 311 }
282 ),
283 }; 312 };
284 313
314 let mut resulting_edit = text_edits.finish();
315 resulting_edit.union(original_edit).expect("Failed to unite text edits");
316
285 CompletionItem { 317 CompletionItem {
286 source_range: self.source_range, 318 source_range: self.source_range,
287 label, 319 label,
288 insert_text_format: self.insert_text_format, 320 insert_text_format: self.insert_text_format,
289 text_edit, 321 text_edit: resulting_edit,
290 detail: self.detail, 322 detail: self.detail,
291 documentation: self.documentation, 323 documentation: self.documentation,
292 lookup: self.lookup, 324 lookup,
293 kind: self.kind, 325 kind: self.kind,
294 completion_kind: self.completion_kind, 326 completion_kind: self.completion_kind,
295 deprecated: self.deprecated.unwrap_or(false), 327 deprecated: self.deprecated.unwrap_or(false),
@@ -358,6 +390,13 @@ impl Builder {
358 self.trigger_call_info = Some(true); 390 self.trigger_call_info = Some(true);
359 self 391 self
360 } 392 }
393 pub(crate) fn import_data(
394 mut self,
395 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
396 ) -> Builder {
397 self.import_data = import_data;
398 self
399 }
361 pub(crate) fn set_ref_match( 400 pub(crate) fn set_ref_match(
362 mut self, 401 mut self,
363 ref_match: Option<(Mutability, CompletionScore)>, 402 ref_match: Option<(Mutability, CompletionScore)>,
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs
index cb6e0554e..aecc1378b 100644
--- a/crates/completion/src/lib.rs
+++ b/crates/completion/src/lib.rs
@@ -67,6 +67,13 @@ pub use crate::{
67// fn test_name() {} 67// fn test_name() {}
68// } 68// }
69// ``` 69// ```
70//
71// And experimental completions, enabled with the `rust-analyzer.completion.enableExperimental` setting.
72// This flag enables or disables:
73//
74// - Auto import: additional completion options with automatic `use` import and options from all project importable items, matched for the input
75//
76// Experimental completions might cause issues with performance and completion list look.
70 77
71/// Main entry point for completion. We run completion as a two-phase process. 78/// Main entry point for completion. We run completion as a two-phase process.
72/// 79///
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs
index 1fa02c375..bce02f577 100644
--- a/crates/completion/src/render.rs
+++ b/crates/completion/src/render.rs
@@ -9,7 +9,8 @@ pub(crate) mod type_alias;
9 9
10mod builder_ext; 10mod builder_ext;
11 11
12use hir::{Documentation, HasAttrs, HirDisplay, Mutability, ScopeDef, Type}; 12use assists::utils::{ImportScope, MergeBehaviour};
13use hir::{Documentation, HasAttrs, HirDisplay, ModPath, Mutability, ScopeDef, Type};
13use ide_db::RootDatabase; 14use ide_db::RootDatabase;
14use syntax::TextRange; 15use syntax::TextRange;
15use test_utils::mark; 16use test_utils::mark;
@@ -42,7 +43,22 @@ pub(crate) fn render_resolution<'a>(
42 local_name: String, 43 local_name: String,
43 resolution: &ScopeDef, 44 resolution: &ScopeDef,
44) -> Option<CompletionItem> { 45) -> Option<CompletionItem> {
45 Render::new(ctx).render_resolution(local_name, resolution) 46 Render::new(ctx).render_resolution(local_name, None, resolution)
47}
48
49pub(crate) fn render_resolution_with_import<'a>(
50 ctx: RenderContext<'a>,
51 import: ModPath,
52 import_scope: ImportScope,
53 merge_behaviour: Option<MergeBehaviour>,
54 resolution: &ScopeDef,
55) -> Option<CompletionItem> {
56 let local_name = import.segments.last()?.to_string();
57 Render::new(ctx).render_resolution(
58 local_name,
59 Some((import, import_scope, merge_behaviour)),
60 resolution,
61 )
46} 62}
47 63
48/// Interface for data and methods required for items rendering. 64/// Interface for data and methods required for items rendering.
@@ -131,8 +147,10 @@ impl<'a> Render<'a> {
131 fn render_resolution( 147 fn render_resolution(
132 self, 148 self,
133 local_name: String, 149 local_name: String,
150 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
134 resolution: &ScopeDef, 151 resolution: &ScopeDef,
135 ) -> Option<CompletionItem> { 152 ) -> Option<CompletionItem> {
153 let _p = profile::span("render_resolution");
136 use hir::ModuleDef::*; 154 use hir::ModuleDef::*;
137 155
138 let completion_kind = match resolution { 156 let completion_kind = match resolution {
@@ -142,15 +160,15 @@ impl<'a> Render<'a> {
142 160
143 let kind = match resolution { 161 let kind = match resolution {
144 ScopeDef::ModuleDef(Function(func)) => { 162 ScopeDef::ModuleDef(Function(func)) => {
145 let item = render_fn(self.ctx, Some(local_name), *func); 163 let item = render_fn(self.ctx, import_data, Some(local_name), *func);
146 return Some(item); 164 return Some(item);
147 } 165 }
148 ScopeDef::ModuleDef(EnumVariant(var)) => { 166 ScopeDef::ModuleDef(EnumVariant(var)) => {
149 let item = render_enum_variant(self.ctx, Some(local_name), *var, None); 167 let item = render_enum_variant(self.ctx, import_data, Some(local_name), *var, None);
150 return Some(item); 168 return Some(item);
151 } 169 }
152 ScopeDef::MacroDef(mac) => { 170 ScopeDef::MacroDef(mac) => {
153 let item = render_macro(self.ctx, local_name, *mac); 171 let item = render_macro(self.ctx, import_data, local_name, *mac);
154 return item; 172 return item;
155 } 173 }
156 174
@@ -175,6 +193,7 @@ impl<'a> Render<'a> {
175 local_name, 193 local_name,
176 ) 194 )
177 .kind(CompletionItemKind::UnresolvedReference) 195 .kind(CompletionItemKind::UnresolvedReference)
196 .import_data(import_data)
178 .build(); 197 .build();
179 return Some(item); 198 return Some(item);
180 } 199 }
@@ -227,7 +246,12 @@ impl<'a> Render<'a> {
227 } 246 }
228 } 247 }
229 248
230 let item = item.kind(kind).set_documentation(docs).set_ref_match(ref_match).build(); 249 let item = item
250 .kind(kind)
251 .import_data(import_data)
252 .set_documentation(docs)
253 .set_ref_match(ref_match)
254 .build();
231 Some(item) 255 Some(item)
232 } 256 }
233 257
@@ -426,6 +450,28 @@ fn main() { let _: m::Spam = S<|> }
426 kind: Module, 450 kind: Module,
427 }, 451 },
428 CompletionItem { 452 CompletionItem {
453 label: "m::Spam",
454 source_range: 75..76,
455 text_edit: TextEdit {
456 indels: [
457 Indel {
458 insert: "use m::Spam;",
459 delete: 0..0,
460 },
461 Indel {
462 insert: "\n\n",
463 delete: 0..0,
464 },
465 Indel {
466 insert: "Spam",
467 delete: 75..76,
468 },
469 ],
470 },
471 kind: Enum,
472 lookup: "Spam",
473 },
474 CompletionItem {
429 label: "m::Spam::Foo", 475 label: "m::Spam::Foo",
430 source_range: 75..76, 476 source_range: 75..76,
431 delete: 75..76, 477 delete: 75..76,
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs
index fd412ed0e..6070e9b1d 100644
--- a/crates/completion/src/render/enum_variant.rs
+++ b/crates/completion/src/render/enum_variant.rs
@@ -1,5 +1,6 @@
1//! Renderer for `enum` variants. 1//! Renderer for `enum` variants.
2 2
3use assists::utils::{ImportScope, MergeBehaviour};
3use hir::{HasAttrs, HirDisplay, ModPath, StructKind}; 4use hir::{HasAttrs, HirDisplay, ModPath, StructKind};
4use itertools::Itertools; 5use itertools::Itertools;
5use test_utils::mark; 6use test_utils::mark;
@@ -11,11 +12,12 @@ use crate::{
11 12
12pub(crate) fn render_enum_variant<'a>( 13pub(crate) fn render_enum_variant<'a>(
13 ctx: RenderContext<'a>, 14 ctx: RenderContext<'a>,
15 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
14 local_name: Option<String>, 16 local_name: Option<String>,
15 variant: hir::EnumVariant, 17 variant: hir::EnumVariant,
16 path: Option<ModPath>, 18 path: Option<ModPath>,
17) -> CompletionItem { 19) -> CompletionItem {
18 EnumVariantRender::new(ctx, local_name, variant, path).render() 20 EnumVariantRender::new(ctx, local_name, variant, path).render(import_data)
19} 21}
20 22
21#[derive(Debug)] 23#[derive(Debug)]
@@ -60,7 +62,10 @@ impl<'a> EnumVariantRender<'a> {
60 } 62 }
61 } 63 }
62 64
63 fn render(self) -> CompletionItem { 65 fn render(
66 self,
67 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
68 ) -> CompletionItem {
64 let mut builder = CompletionItem::new( 69 let mut builder = CompletionItem::new(
65 CompletionKind::Reference, 70 CompletionKind::Reference,
66 self.ctx.source_range(), 71 self.ctx.source_range(),
@@ -69,6 +74,7 @@ impl<'a> EnumVariantRender<'a> {
69 .kind(CompletionItemKind::EnumVariant) 74 .kind(CompletionItemKind::EnumVariant)
70 .set_documentation(self.variant.docs(self.ctx.db())) 75 .set_documentation(self.variant.docs(self.ctx.db()))
71 .set_deprecated(self.ctx.is_deprecated(self.variant)) 76 .set_deprecated(self.ctx.is_deprecated(self.variant))
77 .import_data(import_data)
72 .detail(self.detail()); 78 .detail(self.detail());
73 79
74 if self.variant_kind == StructKind::Tuple { 80 if self.variant_kind == StructKind::Tuple {
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs
index 4fa6eafd7..9dd5cd18c 100644
--- a/crates/completion/src/render/function.rs
+++ b/crates/completion/src/render/function.rs
@@ -1,6 +1,7 @@
1//! Renderer for function calls. 1//! Renderer for function calls.
2 2
3use hir::{HasSource, Type}; 3use assists::utils::{ImportScope, MergeBehaviour};
4use hir::{HasSource, ModPath, Type};
4use syntax::{ast::Fn, display::function_declaration}; 5use syntax::{ast::Fn, display::function_declaration};
5 6
6use crate::{ 7use crate::{
@@ -10,10 +11,11 @@ use crate::{
10 11
11pub(crate) fn render_fn<'a>( 12pub(crate) fn render_fn<'a>(
12 ctx: RenderContext<'a>, 13 ctx: RenderContext<'a>,
14 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
13 local_name: Option<String>, 15 local_name: Option<String>,
14 fn_: hir::Function, 16 fn_: hir::Function,
15) -> CompletionItem { 17) -> CompletionItem {
16 FunctionRender::new(ctx, local_name, fn_).render() 18 FunctionRender::new(ctx, local_name, fn_).render(import_data)
17} 19}
18 20
19#[derive(Debug)] 21#[derive(Debug)]
@@ -36,7 +38,10 @@ impl<'a> FunctionRender<'a> {
36 FunctionRender { ctx, name, fn_, ast_node } 38 FunctionRender { ctx, name, fn_, ast_node }
37 } 39 }
38 40
39 fn render(self) -> CompletionItem { 41 fn render(
42 self,
43 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
44 ) -> CompletionItem {
40 let params = self.params(); 45 let params = self.params();
41 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) 46 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone())
42 .kind(self.kind()) 47 .kind(self.kind())
@@ -44,6 +49,7 @@ impl<'a> FunctionRender<'a> {
44 .set_deprecated(self.ctx.is_deprecated(self.fn_)) 49 .set_deprecated(self.ctx.is_deprecated(self.fn_))
45 .detail(self.detail()) 50 .detail(self.detail())
46 .add_call_parens(self.ctx.completion, self.name, params) 51 .add_call_parens(self.ctx.completion, self.name, params)
52 .import_data(import_data)
47 .build() 53 .build()
48 } 54 }
49 55
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs
index 96be59cc3..fead59e41 100644
--- a/crates/completion/src/render/macro_.rs
+++ b/crates/completion/src/render/macro_.rs
@@ -1,6 +1,7 @@
1//! Renderer for macro invocations. 1//! Renderer for macro invocations.
2 2
3use hir::{Documentation, HasSource}; 3use assists::utils::{ImportScope, MergeBehaviour};
4use hir::{Documentation, HasSource, ModPath};
4use syntax::display::macro_label; 5use syntax::display::macro_label;
5use test_utils::mark; 6use test_utils::mark;
6 7
@@ -11,10 +12,11 @@ use crate::{
11 12
12pub(crate) fn render_macro<'a>( 13pub(crate) fn render_macro<'a>(
13 ctx: RenderContext<'a>, 14 ctx: RenderContext<'a>,
15 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
14 name: String, 16 name: String,
15 macro_: hir::MacroDef, 17 macro_: hir::MacroDef,
16) -> Option<CompletionItem> { 18) -> Option<CompletionItem> {
17 MacroRender::new(ctx, name, macro_).render() 19 MacroRender::new(ctx, name, macro_).render(import_data)
18} 20}
19 21
20#[derive(Debug)] 22#[derive(Debug)]
@@ -36,7 +38,10 @@ impl<'a> MacroRender<'a> {
36 MacroRender { ctx, name, macro_, docs, bra, ket } 38 MacroRender { ctx, name, macro_, docs, bra, ket }
37 } 39 }
38 40
39 fn render(&self) -> Option<CompletionItem> { 41 fn render(
42 &self,
43 import_data: Option<(ModPath, ImportScope, Option<MergeBehaviour>)>,
44 ) -> Option<CompletionItem> {
40 // FIXME: Currently proc-macro do not have ast-node, 45 // FIXME: Currently proc-macro do not have ast-node,
41 // such that it does not have source 46 // such that it does not have source
42 if self.macro_.is_proc_macro() { 47 if self.macro_.is_proc_macro() {
@@ -48,6 +53,7 @@ impl<'a> MacroRender<'a> {
48 .kind(CompletionItemKind::Macro) 53 .kind(CompletionItemKind::Macro)
49 .set_documentation(self.docs.clone()) 54 .set_documentation(self.docs.clone())
50 .set_deprecated(self.ctx.is_deprecated(self.macro_)) 55 .set_deprecated(self.ctx.is_deprecated(self.macro_))
56 .import_data(import_data)
51 .detail(self.detail()); 57 .detail(self.detail());
52 58
53 let needs_bang = self.needs_bang(); 59 let needs_bang = self.needs_bang();