diff options
Diffstat (limited to 'crates/ide_completion')
-rw-r--r-- | crates/ide_completion/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/completions.rs | 10 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/flyimport.rs | 18 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/unqualified_path.rs | 34 | ||||
-rw-r--r-- | crates/ide_completion/src/patterns.rs | 7 | ||||
-rw-r--r-- | crates/ide_completion/src/render.rs | 18 | ||||
-rw-r--r-- | crates/ide_completion/src/render/function.rs | 26 | ||||
-rw-r--r-- | crates/ide_completion/src/render/type_alias.rs | 23 |
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" | |||
10 | doctest = false | 10 | doctest = false |
11 | 11 | ||
12 | [dependencies] | 12 | [dependencies] |
13 | cov-mark = { version = "1.1", features = ["thread-local"] } | 13 | cov-mark = "2.0.0-pre.1" |
14 | itertools = "0.10.0" | 14 | itertools = "0.10.0" |
15 | log = "0.4.8" | 15 | log = "0.4.8" |
16 | rustc-hash = "1.1.0" | 16 | rustc-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 | ||
93 | use ide_db::helpers::{ | 93 | use 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 | ||
3 | use hir::ScopeDef; | 3 | use hir::ScopeDef; |
4 | use syntax::{ast, AstNode}; | ||
4 | 5 | ||
5 | use crate::{CompletionContext, Completions}; | 6 | use crate::{patterns::ImmediateLocation, CompletionContext, Completions}; |
6 | 7 | ||
7 | pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) { | 8 | pub(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#" | ||
800 | trait Foo { | ||
801 | type Bar; | ||
802 | } | ||
803 | |||
804 | fn 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#" |
268 | struct S {} | 268 | struct S {} |
269 | impl S { | 269 | impl 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 | |||
22 | pub(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 | } |