aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion')
-rw-r--r--crates/ide_completion/Cargo.toml2
-rw-r--r--crates/ide_completion/src/completions.rs10
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs18
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs34
-rw-r--r--crates/ide_completion/src/patterns.rs7
-rw-r--r--crates/ide_completion/src/render.rs18
-rw-r--r--crates/ide_completion/src/render/function.rs26
-rw-r--r--crates/ide_completion/src/render/type_alias.rs23
8 files changed, 99 insertions, 39 deletions
diff --git a/crates/ide_completion/Cargo.toml b/crates/ide_completion/Cargo.toml
index ba81c9e04..3c45fe1cb 100644
--- a/crates/ide_completion/Cargo.toml
+++ b/crates/ide_completion/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = { version = "1.1", features = ["thread-local"] } 13cov-mark = "2.0.0-pre.1"
14itertools = "0.10.0" 14itertools = "0.10.0"
15log = "0.4.8" 15log = "0.4.8"
16rustc-hash = "1.1.0" 16rustc-hash = "1.1.0"
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs
index fbd499900..bd90cefb2 100644
--- a/crates/ide_completion/src/completions.rs
+++ b/crates/ide_completion/src/completions.rs
@@ -29,7 +29,7 @@ use crate::{
29 macro_::render_macro, 29 macro_::render_macro,
30 pattern::{render_struct_pat, render_variant_pat}, 30 pattern::{render_struct_pat, render_variant_pat},
31 render_field, render_resolution, render_tuple_field, 31 render_field, render_resolution, render_tuple_field,
32 type_alias::render_type_alias, 32 type_alias::{render_type_alias, render_type_alias_with_eq},
33 RenderContext, 33 RenderContext,
34 }, 34 },
35 CompletionContext, CompletionItem, CompletionItemKind, 35 CompletionContext, CompletionItem, CompletionItemKind,
@@ -188,6 +188,14 @@ impl Completions {
188 self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias)); 188 self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias));
189 } 189 }
190 190
191 pub(crate) fn add_type_alias_with_eq(
192 &mut self,
193 ctx: &CompletionContext,
194 type_alias: hir::TypeAlias,
195 ) {
196 self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias));
197 }
198
191 pub(crate) fn add_qualified_enum_variant( 199 pub(crate) fn add_qualified_enum_variant(
192 &mut self, 200 &mut self,
193 ctx: &CompletionContext, 201 ctx: &CompletionContext,
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index c010cbbca..30b8d44bd 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -1,10 +1,10 @@
1//! Feature: completion with imports-on-the-fly 1//! Feature: completion with imports-on-the-fly
2//! 2//!
3//! When completing names in the current scope, proposes additional imports from other modules or crates, 3//! When completing names in the current scope, proposes additional imports from other modules or crates,
4//! if they can be qualified in the scope and their name contains all symbols from the completion input. 4//! if they can be qualified in the scope, and their name contains all symbols from the completion input.
5//! 5//!
6//! To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent. 6//! To be considered applicable, the name must contain all input symbols in the given order, not necessarily adjacent.
7//! If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the contaning is checked case-insensitively. 7//! If any input symbol is not lowercased, the name must contain all symbols in exact case; otherwise the containing is checked case-insensitively.
8//! 8//!
9//! ``` 9//! ```
10//! fn main() { 10//! fn main() {
@@ -23,8 +23,8 @@
23//! ``` 23//! ```
24//! 24//!
25//! Also completes associated items, that require trait imports. 25//! Also completes associated items, that require trait imports.
26//! If any unresolved and/or partially-qualified path predeces the input, it will be taken into account. 26//! If any unresolved and/or partially-qualified path precedes the input, it will be taken into account.
27//! Currently, only the imports with their import path ending with the whole qialifier will be proposed 27//! Currently, only the imports with their import path ending with the whole qualifier will be proposed
28//! (no fuzzy matching for qualifier). 28//! (no fuzzy matching for qualifier).
29//! 29//!
30//! ``` 30//! ```
@@ -61,14 +61,14 @@
61//! } 61//! }
62//! ``` 62//! ```
63//! 63//!
64//! NOTE: currently, if an assoc item comes from a trait that's not currently imported and it also has an unresolved and/or partially-qualified path, 64//! NOTE: currently, if an assoc item comes from a trait that's not currently imported, and it also has an unresolved and/or partially-qualified path,
65//! no imports will be proposed. 65//! no imports will be proposed.
66//! 66//!
67//! .Fuzzy search details 67//! .Fuzzy search details
68//! 68//!
69//! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only 69//! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
70//! (i.e. in `HashMap` in the `std::collections::HashMap` path). 70//! (i.e. in `HashMap` in the `std::collections::HashMap` path).
71//! For the same reasons, avoids searching for any path imports for inputs with their length less that 2 symbols 71//! For the same reasons, avoids searching for any path imports for inputs with their length less than 2 symbols
72//! (but shows all associated items for any input length). 72//! (but shows all associated items for any input length).
73//! 73//!
74//! .Import configuration 74//! .Import configuration
@@ -79,15 +79,15 @@
79//! .LSP and performance implications 79//! .LSP and performance implications
80//! 80//!
81//! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits` 81//! The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
82//! (case sensitive) resolve client capability in its client capabilities. 82//! (case-sensitive) resolve client capability in its client capabilities.
83//! This way the server is able to defer the costly computations, doing them for a selected completion item only. 83//! This way the server is able to defer the costly computations, doing them for a selected completion item only.
84//! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones, 84//! For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
85//! which might be slow ergo the feature is automatically disabled. 85//! which might be slow ergo the feature is automatically disabled.
86//! 86//!
87//! .Feature toggle 87//! .Feature toggle
88//! 88//!
89//! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.enableAutoimportCompletions` flag. 89//! The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.autoimport.enable` flag.
90//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding 90//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corresponding
91//! capability enabled. 91//! capability enabled.
92 92
93use ide_db::helpers::{ 93use ide_db::helpers::{
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index b1e6b2b77..952f052a1 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -1,8 +1,9 @@
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 hir::ScopeDef; 3use hir::ScopeDef;
4use syntax::{ast, AstNode};
4 5
5use crate::{CompletionContext, Completions}; 6use crate::{patterns::ImmediateLocation, CompletionContext, Completions};
6 7
7pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { 8pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
8 if ctx.is_path_disallowed() || !ctx.is_trivial_path() { 9 if ctx.is_path_disallowed() || !ctx.is_trivial_path() {
@@ -43,6 +44,20 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
43 }); 44 });
44 } 45 }
45 46
47 if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location {
48 if let Some(path_seg) = arg_list.syntax().parent().and_then(ast::PathSegment::cast) {
49 if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(trait_))) =
50 ctx.sema.resolve_path(&path_seg.parent_path())
51 {
52 trait_.items(ctx.sema.db).into_iter().for_each(|it| {
53 if let hir::AssocItem::TypeAlias(alias) = it {
54 acc.add_type_alias_with_eq(ctx, alias)
55 }
56 });
57 }
58 }
59 }
60
46 ctx.scope.process_all_names(&mut |name, res| { 61 ctx.scope.process_all_names(&mut |name, res| {
47 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { 62 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
48 cov_mark::hit!(skip_lifetime_completion); 63 cov_mark::hit!(skip_lifetime_completion);
@@ -777,4 +792,21 @@ $0
777 "#]], 792 "#]],
778 ) 793 )
779 } 794 }
795
796 #[test]
797 fn completes_assoc_types_in_dynimpl_trait() {
798 check(
799 r#"
800trait Foo {
801 type Bar;
802}
803
804fn foo(_: impl Foo<B$0>) {}
805"#,
806 expect![[r#"
807 ta Bar = type Bar;
808 tt Foo
809 "#]],
810 );
811 }
780} 812}
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs
index ee87bf461..81d7a1a1d 100644
--- a/crates/ide_completion/src/patterns.rs
+++ b/crates/ide_completion/src/patterns.rs
@@ -47,6 +47,9 @@ pub(crate) enum ImmediateLocation {
47 receiver_is_ambiguous_float_literal: bool, 47 receiver_is_ambiguous_float_literal: bool,
48 }, 48 },
49 // Original file ast node 49 // Original file ast node
50 // Only set from a type arg
51 GenericArgList(ast::GenericArgList),
52 // Original file ast node
50 /// The record expr of the field name we are completing 53 /// The record expr of the field name we are completing
51 RecordExpr(ast::RecordExpr), 54 RecordExpr(ast::RecordExpr),
52 // Original file ast node 55 // Original file ast node
@@ -159,7 +162,6 @@ pub(crate) fn determine_location(
159 } 162 }
160 } 163 }
161 }; 164 };
162
163 let res = match_ast! { 165 let res = match_ast! {
164 match parent { 166 match parent {
165 ast::IdentPat(_it) => ImmediateLocation::IdentPat, 167 ast::IdentPat(_it) => ImmediateLocation::IdentPat,
@@ -174,6 +176,9 @@ pub(crate) fn determine_location(
174 Some(TRAIT) => ImmediateLocation::Trait, 176 Some(TRAIT) => ImmediateLocation::Trait,
175 _ => return None, 177 _ => return None,
176 }, 178 },
179 ast::GenericArgList(_it) => sema
180 .find_node_at_offset_with_macros(original_file, offset)
181 .map(ImmediateLocation::GenericArgList)?,
177 ast::Module(it) => { 182 ast::Module(it) => {
178 if it.item_list().is_none() { 183 if it.item_list().is_none() {
179 ImmediateLocation::ModDeclaration(it) 184 ImmediateLocation::ModDeclaration(it)
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 902df46ca..d3db55c35 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -111,7 +111,10 @@ impl<'a> RenderContext<'a> {
111 hir::AssocItem::TypeAlias(it) => self.is_deprecated(it), 111 hir::AssocItem::TypeAlias(it) => self.is_deprecated(it),
112 }; 112 };
113 is_assoc_deprecated 113 is_assoc_deprecated
114 || assoc.containing_trait(db).map(|trait_| self.is_deprecated(trait_)).unwrap_or(false) 114 || assoc
115 .containing_trait_or_trait_impl(db)
116 .map(|trait_| self.is_deprecated(trait_))
117 .unwrap_or(false)
115 } 118 }
116 119
117 fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> { 120 fn docs(&self, node: impl HasAttrs) -> Option<hir::Documentation> {
@@ -132,16 +135,17 @@ fn render_field_(
132 ctx.source_range(), 135 ctx.source_range(),
133 receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)), 136 receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)),
134 ); 137 );
135 item.kind(SymbolKind::Field)
136 .detail(ty.display(ctx.db()).to_string())
137 .set_documentation(field.docs(ctx.db()))
138 .set_deprecated(is_deprecated);
139 138
140 item.set_relevance(CompletionRelevance { 139 item.set_relevance(CompletionRelevance {
141 type_match: compute_type_match(ctx.completion, ty), 140 type_match: compute_type_match(ctx.completion, ty),
142 exact_name_match: compute_exact_name_match(ctx.completion, &name), 141 exact_name_match: compute_exact_name_match(ctx.completion, &name),
143 ..CompletionRelevance::default() 142 ..CompletionRelevance::default()
144 }); 143 });
144 item.kind(SymbolKind::Field)
145 .detail(ty.display(ctx.db()).to_string())
146 .set_documentation(field.docs(ctx.db()))
147 .set_deprecated(is_deprecated)
148 .lookup_by(name);
145 149
146 if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) { 150 if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) {
147 // FIXME 151 // FIXME
@@ -164,7 +168,9 @@ fn render_tuple_field_(
164 receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)), 168 receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)),
165 ); 169 );
166 170
167 item.kind(SymbolKind::Field).detail(ty.display(ctx.db()).to_string()); 171 item.kind(SymbolKind::Field)
172 .detail(ty.display(ctx.db()).to_string())
173 .lookup_by(field.to_string());
168 174
169 item.build() 175 item.build()
170} 176}
diff --git a/crates/ide_completion/src/render/function.rs b/crates/ide_completion/src/render/function.rs
index 1abeed96d..1357b9f4a 100644
--- a/crates/ide_completion/src/render/function.rs
+++ b/crates/ide_completion/src/render/function.rs
@@ -58,29 +58,29 @@ impl<'a> FunctionRender<'a> {
58 Some(FunctionRender { ctx, name, receiver, func: fn_, ast_node, is_method }) 58 Some(FunctionRender { ctx, name, receiver, func: fn_, ast_node, is_method })
59 } 59 }
60 60
61 fn render(mut self, import_to_add: Option<ImportEdit>) -> CompletionItem { 61 fn render(self, import_to_add: Option<ImportEdit>) -> CompletionItem {
62 let params = self.params(); 62 let params = self.params();
63 if let Some(receiver) = &self.receiver { 63 let call = if let Some(receiver) = &self.receiver {
64 self.name = format!("{}.{}", receiver, &self.name) 64 format!("{}.{}", receiver, &self.name)
65 } 65 } else {
66 let mut item = CompletionItem::new( 66 self.name.clone()
67 CompletionKind::Reference, 67 };
68 self.ctx.source_range(), 68 let mut item =
69 self.name.clone(), 69 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), call.clone());
70 );
71 item.kind(self.kind()) 70 item.kind(self.kind())
72 .set_documentation(self.ctx.docs(self.func)) 71 .set_documentation(self.ctx.docs(self.func))
73 .set_deprecated( 72 .set_deprecated(
74 self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func), 73 self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func),
75 ) 74 )
76 .detail(self.detail()) 75 .detail(self.detail())
77 .add_call_parens(self.ctx.completion, self.name.clone(), params) 76 .add_call_parens(self.ctx.completion, call.clone(), params)
78 .add_import(import_to_add); 77 .add_import(import_to_add)
78 .lookup_by(self.name);
79 79
80 let ret_type = self.func.ret_type(self.ctx.db()); 80 let ret_type = self.func.ret_type(self.ctx.db());
81 item.set_relevance(CompletionRelevance { 81 item.set_relevance(CompletionRelevance {
82 type_match: compute_type_match(self.ctx.completion, &ret_type), 82 type_match: compute_type_match(self.ctx.completion, &ret_type),
83 exact_name_match: compute_exact_name_match(self.ctx.completion, &self.name), 83 exact_name_match: compute_exact_name_match(self.ctx.completion, &call),
84 ..CompletionRelevance::default() 84 ..CompletionRelevance::default()
85 }); 85 });
86 86
@@ -263,7 +263,7 @@ fn bar(s: &S) {
263 ); 263 );
264 264
265 check_edit( 265 check_edit(
266 "self.foo", 266 "foo",
267 r#" 267 r#"
268struct S {} 268struct S {}
269impl S { 269impl S {
diff --git a/crates/ide_completion/src/render/type_alias.rs b/crates/ide_completion/src/render/type_alias.rs
index e47b4c745..e0234171a 100644
--- a/crates/ide_completion/src/render/type_alias.rs
+++ b/crates/ide_completion/src/render/type_alias.rs
@@ -16,7 +16,14 @@ pub(crate) fn render_type_alias<'a>(
16 ctx: RenderContext<'a>, 16 ctx: RenderContext<'a>,
17 type_alias: hir::TypeAlias, 17 type_alias: hir::TypeAlias,
18) -> Option<CompletionItem> { 18) -> Option<CompletionItem> {
19 TypeAliasRender::new(ctx, type_alias)?.render() 19 TypeAliasRender::new(ctx, type_alias)?.render(false)
20}
21
22pub(crate) fn render_type_alias_with_eq<'a>(
23 ctx: RenderContext<'a>,
24 type_alias: hir::TypeAlias,
25) -> Option<CompletionItem> {
26 TypeAliasRender::new(ctx, type_alias)?.render(true)
20} 27}
21 28
22#[derive(Debug)] 29#[derive(Debug)]
@@ -32,8 +39,14 @@ impl<'a> TypeAliasRender<'a> {
32 Some(TypeAliasRender { ctx, type_alias, ast_node }) 39 Some(TypeAliasRender { ctx, type_alias, ast_node })
33 } 40 }
34 41
35 fn render(self) -> Option<CompletionItem> { 42 fn render(self, with_eq: bool) -> Option<CompletionItem> {
36 let name = self.name()?; 43 let name = self.ast_node.name().map(|name| {
44 if with_eq {
45 format!("{} = ", name.text())
46 } else {
47 name.text().to_string()
48 }
49 })?;
37 let detail = self.detail(); 50 let detail = self.detail();
38 51
39 let mut item = 52 let mut item =
@@ -49,10 +62,6 @@ impl<'a> TypeAliasRender<'a> {
49 Some(item.build()) 62 Some(item.build())
50 } 63 }
51 64
52 fn name(&self) -> Option<String> {
53 self.ast_node.name().map(|name| name.text().to_string())
54 }
55
56 fn detail(&self) -> String { 65 fn detail(&self) -> String {
57 type_label(&self.ast_node) 66 type_label(&self.ast_node)
58 } 67 }