diff options
Diffstat (limited to 'crates/ide_completion/src')
-rw-r--r-- | crates/ide_completion/src/completions.rs | 31 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/attribute.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/attribute/derive.rs | 49 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/dot.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/flyimport.rs | 18 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/keyword.rs | 20 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/postfix.rs | 20 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/postfix/format_like.rs | 4 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/qualified_path.rs | 87 | ||||
-rw-r--r-- | crates/ide_completion/src/completions/unqualified_path.rs | 72 | ||||
-rw-r--r-- | crates/ide_completion/src/context.rs | 8 | ||||
-rw-r--r-- | crates/ide_completion/src/patterns.rs | 19 | ||||
-rw-r--r-- | crates/ide_completion/src/render.rs | 118 | ||||
-rw-r--r-- | crates/ide_completion/src/render/macro_.rs | 4 | ||||
-rw-r--r-- | crates/ide_completion/src/render/pattern.rs | 6 | ||||
-rw-r--r-- | crates/ide_completion/src/render/type_alias.rs | 23 |
16 files changed, 247 insertions, 236 deletions
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs index fbd499900..783305005 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, |
@@ -109,9 +109,6 @@ impl Completions { | |||
109 | local_name: hir::Name, | 109 | local_name: hir::Name, |
110 | resolution: &hir::ScopeDef, | 110 | resolution: &hir::ScopeDef, |
111 | ) { | 111 | ) { |
112 | if ctx.expects_type() && resolution.is_value_def() { | ||
113 | return; | ||
114 | } | ||
115 | self.add_opt(render_resolution(RenderContext::new(ctx), local_name, resolution)); | 112 | self.add_opt(render_resolution(RenderContext::new(ctx), local_name, resolution)); |
116 | } | 113 | } |
117 | 114 | ||
@@ -134,9 +131,6 @@ impl Completions { | |||
134 | func: hir::Function, | 131 | func: hir::Function, |
135 | local_name: Option<hir::Name>, | 132 | local_name: Option<hir::Name>, |
136 | ) { | 133 | ) { |
137 | if ctx.expects_type() { | ||
138 | return; | ||
139 | } | ||
140 | self.add_opt(render_fn(RenderContext::new(ctx), None, local_name, func)); | 134 | self.add_opt(render_fn(RenderContext::new(ctx), None, local_name, func)); |
141 | } | 135 | } |
142 | 136 | ||
@@ -178,9 +172,6 @@ impl Completions { | |||
178 | } | 172 | } |
179 | 173 | ||
180 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { | 174 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { |
181 | if ctx.expects_type() { | ||
182 | return; | ||
183 | } | ||
184 | self.add_opt(render_const(RenderContext::new(ctx), constant)); | 175 | self.add_opt(render_const(RenderContext::new(ctx), constant)); |
185 | } | 176 | } |
186 | 177 | ||
@@ -188,6 +179,14 @@ impl Completions { | |||
188 | self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias)); | 179 | self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias)); |
189 | } | 180 | } |
190 | 181 | ||
182 | pub(crate) fn add_type_alias_with_eq( | ||
183 | &mut self, | ||
184 | ctx: &CompletionContext, | ||
185 | type_alias: hir::TypeAlias, | ||
186 | ) { | ||
187 | self.add_opt(render_type_alias_with_eq(RenderContext::new(ctx), type_alias)); | ||
188 | } | ||
189 | |||
191 | pub(crate) fn add_qualified_enum_variant( | 190 | pub(crate) fn add_qualified_enum_variant( |
192 | &mut self, | 191 | &mut self, |
193 | ctx: &CompletionContext, | 192 | ctx: &CompletionContext, |
@@ -204,32 +203,30 @@ impl Completions { | |||
204 | variant: hir::Variant, | 203 | variant: hir::Variant, |
205 | local_name: Option<hir::Name>, | 204 | local_name: Option<hir::Name>, |
206 | ) { | 205 | ) { |
207 | if ctx.expects_type() { | ||
208 | return; | ||
209 | } | ||
210 | let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); | 206 | let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); |
211 | self.add(item); | 207 | self.add(item); |
212 | } | 208 | } |
213 | } | 209 | } |
214 | 210 | ||
211 | /// Calls the callback for each variant of the provided enum with the path to the variant. | ||
215 | fn complete_enum_variants( | 212 | fn complete_enum_variants( |
216 | acc: &mut Completions, | 213 | acc: &mut Completions, |
217 | ctx: &CompletionContext, | 214 | ctx: &CompletionContext, |
218 | enum_data: hir::Enum, | 215 | enum_: hir::Enum, |
219 | cb: impl Fn(&mut Completions, &CompletionContext, hir::Variant, hir::ModPath), | 216 | cb: impl Fn(&mut Completions, &CompletionContext, hir::Variant, hir::ModPath), |
220 | ) { | 217 | ) { |
221 | let variants = enum_data.variants(ctx.db); | 218 | let variants = enum_.variants(ctx.db); |
222 | 219 | ||
223 | let module = if let Some(module) = ctx.scope.module() { | 220 | let module = if let Some(module) = ctx.scope.module() { |
224 | // Compute path from the completion site if available. | 221 | // Compute path from the completion site if available. |
225 | module | 222 | module |
226 | } else { | 223 | } else { |
227 | // Otherwise fall back to the enum's definition site. | 224 | // Otherwise fall back to the enum's definition site. |
228 | enum_data.module(ctx.db) | 225 | enum_.module(ctx.db) |
229 | }; | 226 | }; |
230 | 227 | ||
231 | if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { | 228 | if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { |
232 | if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_data)) { | 229 | if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) { |
233 | for &variant in &variants { | 230 | for &variant in &variants { |
234 | let self_path = hir::ModPath::from_segments( | 231 | let self_path = hir::ModPath::from_segments( |
235 | hir::PathKind::Plain, | 232 | hir::PathKind::Plain, |
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs index 7f76e357e..6df569c2a 100644 --- a/crates/ide_completion/src/completions/attribute.rs +++ b/crates/ide_completion/src/completions/attribute.rs | |||
@@ -219,7 +219,7 @@ static KIND_TO_ATTRIBUTES: Lazy<FxHashMap<SyntaxKind, &[&str]>> = Lazy::new(|| { | |||
219 | }); | 219 | }); |
220 | const EXPR_ATTRIBUTES: &[&str] = attrs!(); | 220 | const EXPR_ATTRIBUTES: &[&str] = attrs!(); |
221 | 221 | ||
222 | /// https://doc.rust-lang.org/reference/attributes.html#built-in-attributes-index | 222 | /// <https://doc.rust-lang.org/reference/attributes.html#built-in-attributes-index> |
223 | // Keep these sorted for the binary search! | 223 | // Keep these sorted for the binary search! |
224 | const ATTRIBUTES: &[AttrCompletion] = &[ | 224 | const ATTRIBUTES: &[AttrCompletion] = &[ |
225 | attr("allow(…)", Some("allow"), Some("allow(${0:lint})")), | 225 | attr("allow(…)", Some("allow"), Some("allow(${0:lint})")), |
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs index d526824fb..7b3133e53 100644 --- a/crates/ide_completion/src/completions/attribute/derive.rs +++ b/crates/ide_completion/src/completions/attribute/derive.rs | |||
@@ -93,57 +93,20 @@ mod tests { | |||
93 | } | 93 | } |
94 | 94 | ||
95 | #[test] | 95 | #[test] |
96 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
97 | fn empty_derive() { | 96 | fn empty_derive() { |
98 | check( | 97 | // FIXME: Add build-in derives to fixture. |
99 | r#"#[derive($0)] struct Test;"#, | 98 | check(r#"#[derive($0)] struct Test;"#, expect![[r#""#]]); |
100 | expect![[r#" | ||
101 | at Clone | ||
102 | at Clone, Copy | ||
103 | at Debug | ||
104 | at Default | ||
105 | at Hash | ||
106 | at PartialEq | ||
107 | at PartialEq, Eq | ||
108 | at PartialEq, PartialOrd | ||
109 | at PartialEq, Eq, PartialOrd, Ord | ||
110 | "#]], | ||
111 | ); | ||
112 | } | 99 | } |
113 | 100 | ||
114 | #[test] | 101 | #[test] |
115 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
116 | fn derive_with_input() { | 102 | fn derive_with_input() { |
117 | check( | 103 | // FIXME: Add build-in derives to fixture. |
118 | r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, | 104 | check(r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, expect![[r#""#]]) |
119 | expect![[r#" | ||
120 | at Clone | ||
121 | at Clone, Copy | ||
122 | at Debug | ||
123 | at Default | ||
124 | at Hash | ||
125 | at Eq | ||
126 | at PartialOrd | ||
127 | at Eq, PartialOrd, Ord | ||
128 | "#]], | ||
129 | ) | ||
130 | } | 105 | } |
131 | 106 | ||
132 | #[test] | 107 | #[test] |
133 | #[ignore] // FIXME: Fixtures cant test proc-macros/derives yet as we cant specify them in fixtures | ||
134 | fn derive_with_input2() { | 108 | fn derive_with_input2() { |
135 | check( | 109 | // FIXME: Add build-in derives to fixture. |
136 | r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, | 110 | check(r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, expect![[r#""#]]) |
137 | expect![[r#" | ||
138 | at Clone | ||
139 | at Clone, Copy | ||
140 | at Debug | ||
141 | at Default | ||
142 | at Hash | ||
143 | at Eq | ||
144 | at PartialOrd | ||
145 | at Eq, PartialOrd, Ord | ||
146 | "#]], | ||
147 | ) | ||
148 | } | 111 | } |
149 | } | 112 | } |
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs index 8ad57a069..9552875c1 100644 --- a/crates/ide_completion/src/completions/dot.rs +++ b/crates/ide_completion/src/completions/dot.rs | |||
@@ -13,7 +13,7 @@ pub(crate) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | |||
13 | _ => return complete_undotted_self(acc, ctx), | 13 | _ => return complete_undotted_self(acc, ctx), |
14 | }; | 14 | }; |
15 | 15 | ||
16 | let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { | 16 | let receiver_ty = match ctx.sema.type_of_expr(dot_receiver) { |
17 | Some(ty) => ty, | 17 | Some(ty) => ty, |
18 | _ => return, | 18 | _ => return, |
19 | }; | 19 | }; |
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/keyword.rs b/crates/ide_completion/src/completions/keyword.rs index ba13d3707..0fccbeccf 100644 --- a/crates/ide_completion/src/completions/keyword.rs +++ b/crates/ide_completion/src/completions/keyword.rs | |||
@@ -536,17 +536,11 @@ Some multi-line comment$0 | |||
536 | fn test_completion_await_impls_future() { | 536 | fn test_completion_await_impls_future() { |
537 | check( | 537 | check( |
538 | r#" | 538 | r#" |
539 | //- /main.rs crate:main deps:std | 539 | //- minicore: future |
540 | use std::future::*; | 540 | use core::future::*; |
541 | struct A {} | 541 | struct A {} |
542 | impl Future for A {} | 542 | impl Future for A {} |
543 | fn foo(a: A) { a.$0 } | 543 | fn foo(a: A) { a.$0 } |
544 | |||
545 | //- /std/lib.rs crate:std | ||
546 | pub mod future { | ||
547 | #[lang = "future_trait"] | ||
548 | pub trait Future {} | ||
549 | } | ||
550 | "#, | 544 | "#, |
551 | expect![[r#" | 545 | expect![[r#" |
552 | kw await expr.await | 546 | kw await expr.await |
@@ -555,20 +549,12 @@ pub mod future { | |||
555 | 549 | ||
556 | check( | 550 | check( |
557 | r#" | 551 | r#" |
558 | //- /main.rs crate:main deps:std | 552 | //- minicore: future |
559 | use std::future::*; | 553 | use std::future::*; |
560 | fn foo() { | 554 | fn foo() { |
561 | let a = async {}; | 555 | let a = async {}; |
562 | a.$0 | 556 | a.$0 |
563 | } | 557 | } |
564 | |||
565 | //- /std/lib.rs crate:std | ||
566 | pub mod future { | ||
567 | #[lang = "future_trait"] | ||
568 | pub trait Future { | ||
569 | type Output; | ||
570 | } | ||
571 | } | ||
572 | "#, | 558 | "#, |
573 | expect![[r#" | 559 | expect![[r#" |
574 | kw await expr.await | 560 | kw await expr.await |
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs index 86eb21714..9f98b21be 100644 --- a/crates/ide_completion/src/completions/postfix.rs +++ b/crates/ide_completion/src/completions/postfix.rs | |||
@@ -34,7 +34,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
34 | 34 | ||
35 | let receiver_text = get_receiver_text(dot_receiver, receiver_is_ambiguous_float_literal); | 35 | let receiver_text = get_receiver_text(dot_receiver, receiver_is_ambiguous_float_literal); |
36 | 36 | ||
37 | let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { | 37 | let receiver_ty = match ctx.sema.type_of_expr(dot_receiver) { |
38 | Some(it) => it, | 38 | Some(it) => it, |
39 | None => return, | 39 | None => return, |
40 | }; | 40 | }; |
@@ -50,7 +50,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
50 | postfix_snippet( | 50 | postfix_snippet( |
51 | ctx, | 51 | ctx, |
52 | cap, | 52 | cap, |
53 | &dot_receiver, | 53 | dot_receiver, |
54 | "ifl", | 54 | "ifl", |
55 | "if let Ok {}", | 55 | "if let Ok {}", |
56 | &format!("if let Ok($1) = {} {{\n $0\n}}", receiver_text), | 56 | &format!("if let Ok($1) = {} {{\n $0\n}}", receiver_text), |
@@ -60,7 +60,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
60 | postfix_snippet( | 60 | postfix_snippet( |
61 | ctx, | 61 | ctx, |
62 | cap, | 62 | cap, |
63 | &dot_receiver, | 63 | dot_receiver, |
64 | "while", | 64 | "while", |
65 | "while let Ok {}", | 65 | "while let Ok {}", |
66 | &format!("while let Ok($1) = {} {{\n $0\n}}", receiver_text), | 66 | &format!("while let Ok($1) = {} {{\n $0\n}}", receiver_text), |
@@ -71,7 +71,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
71 | postfix_snippet( | 71 | postfix_snippet( |
72 | ctx, | 72 | ctx, |
73 | cap, | 73 | cap, |
74 | &dot_receiver, | 74 | dot_receiver, |
75 | "ifl", | 75 | "ifl", |
76 | "if let Some {}", | 76 | "if let Some {}", |
77 | &format!("if let Some($1) = {} {{\n $0\n}}", receiver_text), | 77 | &format!("if let Some($1) = {} {{\n $0\n}}", receiver_text), |
@@ -81,7 +81,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
81 | postfix_snippet( | 81 | postfix_snippet( |
82 | ctx, | 82 | ctx, |
83 | cap, | 83 | cap, |
84 | &dot_receiver, | 84 | dot_receiver, |
85 | "while", | 85 | "while", |
86 | "while let Some {}", | 86 | "while let Some {}", |
87 | &format!("while let Some($1) = {} {{\n $0\n}}", receiver_text), | 87 | &format!("while let Some($1) = {} {{\n $0\n}}", receiver_text), |
@@ -93,7 +93,7 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
93 | postfix_snippet( | 93 | postfix_snippet( |
94 | ctx, | 94 | ctx, |
95 | cap, | 95 | cap, |
96 | &dot_receiver, | 96 | dot_receiver, |
97 | "if", | 97 | "if", |
98 | "if expr {}", | 98 | "if expr {}", |
99 | &format!("if {} {{\n $0\n}}", receiver_text), | 99 | &format!("if {} {{\n $0\n}}", receiver_text), |
@@ -102,22 +102,22 @@ pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
102 | postfix_snippet( | 102 | postfix_snippet( |
103 | ctx, | 103 | ctx, |
104 | cap, | 104 | cap, |
105 | &dot_receiver, | 105 | dot_receiver, |
106 | "while", | 106 | "while", |
107 | "while expr {}", | 107 | "while expr {}", |
108 | &format!("while {} {{\n $0\n}}", receiver_text), | 108 | &format!("while {} {{\n $0\n}}", receiver_text), |
109 | ) | 109 | ) |
110 | .add_to(acc); | 110 | .add_to(acc); |
111 | postfix_snippet(ctx, cap, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text)) | 111 | postfix_snippet(ctx, cap, dot_receiver, "not", "!expr", &format!("!{}", receiver_text)) |
112 | .add_to(acc); | 112 | .add_to(acc); |
113 | } | 113 | } |
114 | 114 | ||
115 | postfix_snippet(ctx, cap, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)) | 115 | postfix_snippet(ctx, cap, dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)) |
116 | .add_to(acc); | 116 | .add_to(acc); |
117 | postfix_snippet( | 117 | postfix_snippet( |
118 | ctx, | 118 | ctx, |
119 | cap, | 119 | cap, |
120 | &dot_receiver, | 120 | dot_receiver, |
121 | "refm", | 121 | "refm", |
122 | "&mut expr", | 122 | "&mut expr", |
123 | &format!("&mut {}", receiver_text), | 123 | &format!("&mut {}", receiver_text), |
diff --git a/crates/ide_completion/src/completions/postfix/format_like.rs b/crates/ide_completion/src/completions/postfix/format_like.rs index 9ebe1dcc0..2dc13c293 100644 --- a/crates/ide_completion/src/completions/postfix/format_like.rs +++ b/crates/ide_completion/src/completions/postfix/format_like.rs | |||
@@ -53,7 +53,7 @@ pub(crate) fn add_format_like_completions( | |||
53 | for (label, macro_name) in KINDS { | 53 | for (label, macro_name) in KINDS { |
54 | let snippet = parser.into_suggestion(macro_name); | 54 | let snippet = parser.into_suggestion(macro_name); |
55 | 55 | ||
56 | postfix_snippet(ctx, cap, &dot_receiver, label, macro_name, &snippet).add_to(acc); | 56 | postfix_snippet(ctx, cap, dot_receiver, label, macro_name, &snippet).add_to(acc); |
57 | } | 57 | } |
58 | } | 58 | } |
59 | } | 59 | } |
@@ -91,7 +91,7 @@ enum State { | |||
91 | impl FormatStrParser { | 91 | impl FormatStrParser { |
92 | pub(crate) fn new(input: String) -> Self { | 92 | pub(crate) fn new(input: String) -> Self { |
93 | Self { | 93 | Self { |
94 | input: input, | 94 | input, |
95 | output: String::new(), | 95 | output: String::new(), |
96 | extracted_expressions: Vec::new(), | 96 | extracted_expressions: Vec::new(), |
97 | state: State::NotExpr, | 97 | state: State::NotExpr, |
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs index 58d4dd9ee..1643eeed4 100644 --- a/crates/ide_completion/src/completions/qualified_path.rs +++ b/crates/ide_completion/src/completions/qualified_path.rs | |||
@@ -15,10 +15,11 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
15 | None => return, | 15 | None => return, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | let resolution = match ctx.sema.resolve_path(&path) { | 18 | let resolution = match ctx.sema.resolve_path(path) { |
19 | Some(res) => res, | 19 | Some(res) => res, |
20 | None => return, | 20 | None => return, |
21 | }; | 21 | }; |
22 | |||
22 | let context_module = ctx.scope.module(); | 23 | let context_module = ctx.scope.module(); |
23 | 24 | ||
24 | if ctx.expects_item() || ctx.expects_assoc_item() { | 25 | if ctx.expects_item() || ctx.expects_assoc_item() { |
@@ -60,21 +61,31 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
60 | } | 61 | } |
61 | } | 62 | } |
62 | 63 | ||
63 | if let hir::ScopeDef::MacroDef(macro_def) = def { | 64 | let add_resolution = match def { |
64 | if !macro_def.is_fn_like() { | 65 | // Don't suggest attribute macros and derives. |
65 | // Don't suggest attribute macros and derives. | 66 | hir::ScopeDef::MacroDef(mac) => mac.is_fn_like(), |
66 | continue; | 67 | // no values in type places |
68 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(_)) | ||
69 | | hir::ScopeDef::ModuleDef(hir::ModuleDef::Variant(_)) | ||
70 | | hir::ScopeDef::ModuleDef(hir::ModuleDef::Static(_)) | ||
71 | | hir::ScopeDef::Local(_) => !ctx.expects_type(), | ||
72 | // unless its a constant in a generic arg list position | ||
73 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) => { | ||
74 | !ctx.expects_type() || ctx.expects_generic_arg() | ||
67 | } | 75 | } |
68 | } | 76 | _ => true, |
77 | }; | ||
69 | 78 | ||
70 | acc.add_resolution(ctx, name, &def); | 79 | if add_resolution { |
80 | acc.add_resolution(ctx, name, &def); | ||
81 | } | ||
71 | } | 82 | } |
72 | } | 83 | } |
73 | hir::PathResolution::Def(def @ hir::ModuleDef::Adt(_)) | 84 | hir::PathResolution::Def(def @ hir::ModuleDef::Adt(_)) |
74 | | hir::PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_)) | 85 | | hir::PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_)) |
75 | | hir::PathResolution::Def(def @ hir::ModuleDef::BuiltinType(_)) => { | 86 | | hir::PathResolution::Def(def @ hir::ModuleDef::BuiltinType(_)) => { |
76 | if let hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def { | 87 | if let hir::ModuleDef::Adt(hir::Adt::Enum(e)) = def { |
77 | add_enum_variants(ctx, acc, e); | 88 | add_enum_variants(acc, ctx, e); |
78 | } | 89 | } |
79 | let ty = match def { | 90 | let ty = match def { |
80 | hir::ModuleDef::Adt(adt) => adt.ty(ctx.db), | 91 | hir::ModuleDef::Adt(adt) => adt.ty(ctx.db), |
@@ -82,7 +93,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
82 | let ty = a.ty(ctx.db); | 93 | let ty = a.ty(ctx.db); |
83 | if let Some(hir::Adt::Enum(e)) = ty.as_adt() { | 94 | if let Some(hir::Adt::Enum(e)) = ty.as_adt() { |
84 | cov_mark::hit!(completes_variant_through_alias); | 95 | cov_mark::hit!(completes_variant_through_alias); |
85 | add_enum_variants(ctx, acc, e); | 96 | add_enum_variants(acc, ctx, e); |
86 | } | 97 | } |
87 | ty | 98 | ty |
88 | } | 99 | } |
@@ -107,11 +118,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
107 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | 118 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { |
108 | return None; | 119 | return None; |
109 | } | 120 | } |
110 | match item { | 121 | add_assoc_item(acc, ctx, item); |
111 | hir::AssocItem::Function(func) => acc.add_function(ctx, func, None), | ||
112 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
113 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
114 | } | ||
115 | None::<()> | 122 | None::<()> |
116 | }); | 123 | }); |
117 | 124 | ||
@@ -133,11 +140,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
133 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | 140 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { |
134 | continue; | 141 | continue; |
135 | } | 142 | } |
136 | match item { | 143 | add_assoc_item(acc, ctx, item); |
137 | hir::AssocItem::Function(func) => acc.add_function(ctx, func, None), | ||
138 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
139 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
140 | } | ||
141 | } | 144 | } |
142 | } | 145 | } |
143 | hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => { | 146 | hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => { |
@@ -149,7 +152,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
149 | }; | 152 | }; |
150 | 153 | ||
151 | if let Some(hir::Adt::Enum(e)) = ty.as_adt() { | 154 | if let Some(hir::Adt::Enum(e)) = ty.as_adt() { |
152 | add_enum_variants(ctx, acc, e); | 155 | add_enum_variants(acc, ctx, e); |
153 | } | 156 | } |
154 | 157 | ||
155 | let traits_in_scope = ctx.scope.traits_in_scope(); | 158 | let traits_in_scope = ctx.scope.traits_in_scope(); |
@@ -162,11 +165,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
162 | // We might iterate candidates of a trait multiple times here, so deduplicate | 165 | // We might iterate candidates of a trait multiple times here, so deduplicate |
163 | // them. | 166 | // them. |
164 | if seen.insert(item) { | 167 | if seen.insert(item) { |
165 | match item { | 168 | add_assoc_item(acc, ctx, item); |
166 | hir::AssocItem::Function(func) => acc.add_function(ctx, func, None), | ||
167 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
168 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
169 | } | ||
170 | } | 169 | } |
171 | None::<()> | 170 | None::<()> |
172 | }); | 171 | }); |
@@ -176,10 +175,22 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon | |||
176 | } | 175 | } |
177 | } | 176 | } |
178 | 177 | ||
179 | fn add_enum_variants(ctx: &CompletionContext, acc: &mut Completions, e: hir::Enum) { | 178 | fn add_assoc_item(acc: &mut Completions, ctx: &CompletionContext, item: hir::AssocItem) { |
180 | for variant in e.variants(ctx.db) { | 179 | match item { |
181 | acc.add_enum_variant(ctx, variant, None); | 180 | hir::AssocItem::Function(func) if !ctx.expects_type() => acc.add_function(ctx, func, None), |
181 | hir::AssocItem::Const(ct) if !ctx.expects_type() || ctx.expects_generic_arg() => { | ||
182 | acc.add_const(ctx, ct) | ||
183 | } | ||
184 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
185 | _ => (), | ||
186 | } | ||
187 | } | ||
188 | |||
189 | fn add_enum_variants(acc: &mut Completions, ctx: &CompletionContext, e: hir::Enum) { | ||
190 | if ctx.expects_type() { | ||
191 | return; | ||
182 | } | 192 | } |
193 | e.variants(ctx.db).into_iter().for_each(|variant| acc.add_enum_variant(ctx, variant, None)); | ||
183 | } | 194 | } |
184 | 195 | ||
185 | #[cfg(test)] | 196 | #[cfg(test)] |
@@ -927,4 +938,24 @@ fn main() { | |||
927 | "#]], | 938 | "#]], |
928 | ); | 939 | ); |
929 | } | 940 | } |
941 | |||
942 | #[test] | ||
943 | fn completes_types_and_const_in_arg_list() { | ||
944 | check( | ||
945 | r#" | ||
946 | mod foo { | ||
947 | pub const CONST: () = (); | ||
948 | pub type Type = (); | ||
949 | } | ||
950 | |||
951 | struct Foo<T>(t); | ||
952 | |||
953 | fn foo(_: Foo<foo::$0>) {} | ||
954 | "#, | ||
955 | expect![[r#" | ||
956 | ta Type | ||
957 | ct CONST | ||
958 | "#]], | ||
959 | ); | ||
960 | } | ||
930 | } | 961 | } |
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs index b1e6b2b77..b5af1c810 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() { |
@@ -35,21 +36,50 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC | |||
35 | return; | 36 | return; |
36 | } | 37 | } |
37 | 38 | ||
38 | if let Some(hir::Adt::Enum(e)) = | 39 | if !ctx.expects_type() { |
39 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) | 40 | if let Some(hir::Adt::Enum(e)) = |
40 | { | 41 | ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt()) |
41 | super::complete_enum_variants(acc, ctx, e, |acc, ctx, variant, path| { | 42 | { |
42 | acc.add_qualified_enum_variant(ctx, variant, path) | 43 | super::complete_enum_variants(acc, ctx, e, |acc, ctx, variant, path| { |
43 | }); | 44 | acc.add_qualified_enum_variant(ctx, variant, path) |
45 | }); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | if let Some(ImmediateLocation::GenericArgList(arg_list)) = &ctx.completion_location { | ||
50 | if let Some(path_seg) = arg_list.syntax().parent().and_then(ast::PathSegment::cast) { | ||
51 | if let Some(hir::PathResolution::Def(hir::ModuleDef::Trait(trait_))) = | ||
52 | ctx.sema.resolve_path(&path_seg.parent_path()) | ||
53 | { | ||
54 | trait_.items(ctx.sema.db).into_iter().for_each(|it| { | ||
55 | if let hir::AssocItem::TypeAlias(alias) = it { | ||
56 | acc.add_type_alias_with_eq(ctx, alias) | ||
57 | } | ||
58 | }); | ||
59 | } | ||
60 | } | ||
44 | } | 61 | } |
45 | 62 | ||
46 | ctx.scope.process_all_names(&mut |name, res| { | 63 | ctx.scope.process_all_names(&mut |name, res| { |
47 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res { | 64 | if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) = |
65 | res | ||
66 | { | ||
48 | cov_mark::hit!(skip_lifetime_completion); | 67 | cov_mark::hit!(skip_lifetime_completion); |
49 | return; | 68 | return; |
50 | } | 69 | } |
51 | let add_resolution = match res { | 70 | let add_resolution = match res { |
71 | // Don't suggest attribute macros and derives. | ||
52 | ScopeDef::MacroDef(mac) => mac.is_fn_like(), | 72 | ScopeDef::MacroDef(mac) => mac.is_fn_like(), |
73 | // no values in type places | ||
74 | ScopeDef::ModuleDef(hir::ModuleDef::Function(_)) | ||
75 | | ScopeDef::ModuleDef(hir::ModuleDef::Variant(_)) | ||
76 | | ScopeDef::ModuleDef(hir::ModuleDef::Static(_)) | ||
77 | | ScopeDef::Local(_) => !ctx.expects_type(), | ||
78 | // unless its a constant in a generic arg list position | ||
79 | ScopeDef::ModuleDef(hir::ModuleDef::Const(_)) | ||
80 | | ScopeDef::GenericParam(hir::GenericParam::ConstParam(_)) => { | ||
81 | !ctx.expects_type() || ctx.expects_generic_arg() | ||
82 | } | ||
53 | _ => true, | 83 | _ => true, |
54 | }; | 84 | }; |
55 | if add_resolution { | 85 | if add_resolution { |
@@ -777,4 +807,30 @@ $0 | |||
777 | "#]], | 807 | "#]], |
778 | ) | 808 | ) |
779 | } | 809 | } |
810 | |||
811 | #[test] | ||
812 | fn completes_types_and_const_in_arg_list() { | ||
813 | check( | ||
814 | r#" | ||
815 | enum Bar { | ||
816 | Baz | ||
817 | } | ||
818 | trait Foo { | ||
819 | type Bar; | ||
820 | } | ||
821 | |||
822 | const CONST: () = (); | ||
823 | |||
824 | fn foo<T: Foo<$0>, const CONST_PARAM: usize>(_: T) {} | ||
825 | "#, | ||
826 | expect![[r#" | ||
827 | ta Bar = type Bar; | ||
828 | tp T | ||
829 | cp CONST_PARAM | ||
830 | tt Foo | ||
831 | en Bar | ||
832 | ct CONST | ||
833 | "#]], | ||
834 | ); | ||
835 | } | ||
780 | } | 836 | } |
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs index 2c2a4aa6b..a8437d81c 100644 --- a/crates/ide_completion/src/context.rs +++ b/crates/ide_completion/src/context.rs | |||
@@ -276,6 +276,10 @@ impl<'a> CompletionContext<'a> { | |||
276 | matches!(self.completion_location, Some(ImmediateLocation::ItemList)) | 276 | matches!(self.completion_location, Some(ImmediateLocation::ItemList)) |
277 | } | 277 | } |
278 | 278 | ||
279 | pub(crate) fn expects_generic_arg(&self) -> bool { | ||
280 | matches!(self.completion_location, Some(ImmediateLocation::GenericArgList(_))) | ||
281 | } | ||
282 | |||
279 | pub(crate) fn has_block_expr_parent(&self) -> bool { | 283 | pub(crate) fn has_block_expr_parent(&self) -> bool { |
280 | matches!(self.completion_location, Some(ImmediateLocation::BlockExpr)) | 284 | matches!(self.completion_location, Some(ImmediateLocation::BlockExpr)) |
281 | } | 285 | } |
@@ -380,7 +384,7 @@ impl<'a> CompletionContext<'a> { | |||
380 | (|| { | 384 | (|| { |
381 | let expr_field = self.token.prev_sibling_or_token()? | 385 | let expr_field = self.token.prev_sibling_or_token()? |
382 | .into_node() | 386 | .into_node() |
383 | .and_then(|node| ast::RecordExprField::cast(node))?; | 387 | .and_then(ast::RecordExprField::cast)?; |
384 | let (_, _, ty) = self.sema.resolve_record_field(&expr_field)?; | 388 | let (_, _, ty) = self.sema.resolve_record_field(&expr_field)?; |
385 | Some(( | 389 | Some(( |
386 | Some(ty), | 390 | Some(ty), |
@@ -467,7 +471,7 @@ impl<'a> CompletionContext<'a> { | |||
467 | self.expected_type = expected_type; | 471 | self.expected_type = expected_type; |
468 | self.expected_name = expected_name; | 472 | self.expected_name = expected_name; |
469 | 473 | ||
470 | let name_like = match find_node_at_offset(&&file_with_fake_ident, offset) { | 474 | let name_like = match find_node_at_offset(&file_with_fake_ident, offset) { |
471 | Some(it) => it, | 475 | Some(it) => it, |
472 | None => return, | 476 | None => return, |
473 | }; | 477 | }; |
diff --git a/crates/ide_completion/src/patterns.rs b/crates/ide_completion/src/patterns.rs index ee87bf461..72e67e3c4 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 |
@@ -112,12 +115,12 @@ pub(crate) fn determine_location( | |||
112 | ) -> Option<ImmediateLocation> { | 115 | ) -> Option<ImmediateLocation> { |
113 | let node = match name_like { | 116 | let node = match name_like { |
114 | ast::NameLike::NameRef(name_ref) => { | 117 | ast::NameLike::NameRef(name_ref) => { |
115 | if ast::RecordExprField::for_field_name(&name_ref).is_some() { | 118 | if ast::RecordExprField::for_field_name(name_ref).is_some() { |
116 | return sema | 119 | return sema |
117 | .find_node_at_offset_with_macros(original_file, offset) | 120 | .find_node_at_offset_with_macros(original_file, offset) |
118 | .map(ImmediateLocation::RecordExpr); | 121 | .map(ImmediateLocation::RecordExpr); |
119 | } | 122 | } |
120 | if ast::RecordPatField::for_field_name_ref(&name_ref).is_some() { | 123 | if ast::RecordPatField::for_field_name_ref(name_ref).is_some() { |
121 | return sema | 124 | return sema |
122 | .find_node_at_offset_with_macros(original_file, offset) | 125 | .find_node_at_offset_with_macros(original_file, offset) |
123 | .map(ImmediateLocation::RecordPat); | 126 | .map(ImmediateLocation::RecordPat); |
@@ -125,7 +128,7 @@ pub(crate) fn determine_location( | |||
125 | maximize_name_ref(name_ref) | 128 | maximize_name_ref(name_ref) |
126 | } | 129 | } |
127 | ast::NameLike::Name(name) => { | 130 | ast::NameLike::Name(name) => { |
128 | if ast::RecordPatField::for_field_name(&name).is_some() { | 131 | if ast::RecordPatField::for_field_name(name).is_some() { |
129 | return sema | 132 | return sema |
130 | .find_node_at_offset_with_macros(original_file, offset) | 133 | .find_node_at_offset_with_macros(original_file, offset) |
131 | .map(ImmediateLocation::RecordPat); | 134 | .map(ImmediateLocation::RecordPat); |
@@ -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) |
@@ -254,7 +259,7 @@ fn test_inside_impl_trait_block() { | |||
254 | } | 259 | } |
255 | 260 | ||
256 | pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> { | 261 | pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> { |
257 | element.into_token().and_then(|it| previous_non_trivia_token(it)) | 262 | element.into_token().and_then(previous_non_trivia_token) |
258 | } | 263 | } |
259 | 264 | ||
260 | /// Check if the token previous to the previous one is `for`. | 265 | /// Check if the token previous to the previous one is `for`. |
@@ -262,8 +267,8 @@ pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> { | |||
262 | pub(crate) fn for_is_prev2(element: SyntaxElement) -> bool { | 267 | pub(crate) fn for_is_prev2(element: SyntaxElement) -> bool { |
263 | element | 268 | element |
264 | .into_token() | 269 | .into_token() |
265 | .and_then(|it| previous_non_trivia_token(it)) | 270 | .and_then(previous_non_trivia_token) |
266 | .and_then(|it| previous_non_trivia_token(it)) | 271 | .and_then(previous_non_trivia_token) |
267 | .filter(|it| it.kind() == T![for]) | 272 | .filter(|it| it.kind() == T![for]) |
268 | .is_some() | 273 | .is_some() |
269 | } | 274 | } |
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index d3db55c35..2bd2c44d0 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -23,53 +23,6 @@ use crate::{ | |||
23 | render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}, | 23 | render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}, |
24 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, | 24 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, |
25 | }; | 25 | }; |
26 | |||
27 | pub(crate) fn render_field( | ||
28 | ctx: RenderContext<'_>, | ||
29 | receiver: Option<hir::Name>, | ||
30 | field: hir::Field, | ||
31 | ty: &hir::Type, | ||
32 | ) -> CompletionItem { | ||
33 | render_field_(ctx, receiver, field, ty) | ||
34 | } | ||
35 | |||
36 | pub(crate) fn render_tuple_field( | ||
37 | ctx: RenderContext<'_>, | ||
38 | receiver: Option<hir::Name>, | ||
39 | field: usize, | ||
40 | ty: &hir::Type, | ||
41 | ) -> CompletionItem { | ||
42 | render_tuple_field_(ctx, receiver, field, ty) | ||
43 | } | ||
44 | |||
45 | pub(crate) fn render_resolution( | ||
46 | ctx: RenderContext<'_>, | ||
47 | local_name: hir::Name, | ||
48 | resolution: &hir::ScopeDef, | ||
49 | ) -> Option<CompletionItem> { | ||
50 | render_resolution_(ctx, local_name, None, resolution) | ||
51 | } | ||
52 | |||
53 | pub(crate) fn render_resolution_with_import( | ||
54 | ctx: RenderContext<'_>, | ||
55 | import_edit: ImportEdit, | ||
56 | ) -> Option<CompletionItem> { | ||
57 | let resolution = hir::ScopeDef::from(import_edit.import.original_item); | ||
58 | if ctx.completion.expects_type() && resolution.is_value_def() { | ||
59 | return None; | ||
60 | } | ||
61 | let local_name = match resolution { | ||
62 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db), | ||
63 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?, | ||
64 | hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db), | ||
65 | _ => item_name(ctx.db(), import_edit.import.original_item)?, | ||
66 | }; | ||
67 | render_resolution_(ctx, local_name, Some(import_edit), &resolution).map(|mut item| { | ||
68 | item.completion_kind = CompletionKind::Magic; | ||
69 | item | ||
70 | }) | ||
71 | } | ||
72 | |||
73 | /// Interface for data and methods required for items rendering. | 26 | /// Interface for data and methods required for items rendering. |
74 | #[derive(Debug)] | 27 | #[derive(Debug)] |
75 | pub(crate) struct RenderContext<'a> { | 28 | pub(crate) struct RenderContext<'a> { |
@@ -86,7 +39,7 @@ impl<'a> RenderContext<'a> { | |||
86 | } | 39 | } |
87 | 40 | ||
88 | fn db(&self) -> &'a RootDatabase { | 41 | fn db(&self) -> &'a RootDatabase { |
89 | &self.completion.db | 42 | self.completion.db |
90 | } | 43 | } |
91 | 44 | ||
92 | fn source_range(&self) -> TextRange { | 45 | fn source_range(&self) -> TextRange { |
@@ -122,7 +75,7 @@ impl<'a> RenderContext<'a> { | |||
122 | } | 75 | } |
123 | } | 76 | } |
124 | 77 | ||
125 | fn render_field_( | 78 | pub(crate) fn render_field( |
126 | ctx: RenderContext<'_>, | 79 | ctx: RenderContext<'_>, |
127 | receiver: Option<hir::Name>, | 80 | receiver: Option<hir::Name>, |
128 | field: hir::Field, | 81 | field: hir::Field, |
@@ -135,7 +88,6 @@ fn render_field_( | |||
135 | ctx.source_range(), | 88 | ctx.source_range(), |
136 | receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)), | 89 | receiver.map_or_else(|| name.clone(), |receiver| format!("{}.{}", receiver, name)), |
137 | ); | 90 | ); |
138 | |||
139 | item.set_relevance(CompletionRelevance { | 91 | item.set_relevance(CompletionRelevance { |
140 | type_match: compute_type_match(ctx.completion, ty), | 92 | type_match: compute_type_match(ctx.completion, ty), |
141 | exact_name_match: compute_exact_name_match(ctx.completion, &name), | 93 | exact_name_match: compute_exact_name_match(ctx.completion, &name), |
@@ -146,17 +98,15 @@ fn render_field_( | |||
146 | .set_documentation(field.docs(ctx.db())) | 98 | .set_documentation(field.docs(ctx.db())) |
147 | .set_deprecated(is_deprecated) | 99 | .set_deprecated(is_deprecated) |
148 | .lookup_by(name); | 100 | .lookup_by(name); |
149 | |||
150 | if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) { | 101 | if let Some(_ref_match) = compute_ref_match(ctx.completion, ty) { |
151 | // FIXME | 102 | // FIXME |
152 | // For now we don't properly calculate the edits for ref match | 103 | // For now we don't properly calculate the edits for ref match |
153 | // completions on struct fields, so we've disabled them. See #8058. | 104 | // completions on struct fields, so we've disabled them. See #8058. |
154 | } | 105 | } |
155 | |||
156 | item.build() | 106 | item.build() |
157 | } | 107 | } |
158 | 108 | ||
159 | fn render_tuple_field_( | 109 | pub(crate) fn render_tuple_field( |
160 | ctx: RenderContext<'_>, | 110 | ctx: RenderContext<'_>, |
161 | receiver: Option<hir::Name>, | 111 | receiver: Option<hir::Name>, |
162 | field: usize, | 112 | field: usize, |
@@ -167,14 +117,37 @@ fn render_tuple_field_( | |||
167 | ctx.source_range(), | 117 | ctx.source_range(), |
168 | receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)), | 118 | receiver.map_or_else(|| field.to_string(), |receiver| format!("{}.{}", receiver, field)), |
169 | ); | 119 | ); |
170 | |||
171 | item.kind(SymbolKind::Field) | 120 | item.kind(SymbolKind::Field) |
172 | .detail(ty.display(ctx.db()).to_string()) | 121 | .detail(ty.display(ctx.db()).to_string()) |
173 | .lookup_by(field.to_string()); | 122 | .lookup_by(field.to_string()); |
174 | |||
175 | item.build() | 123 | item.build() |
176 | } | 124 | } |
177 | 125 | ||
126 | pub(crate) fn render_resolution( | ||
127 | ctx: RenderContext<'_>, | ||
128 | local_name: hir::Name, | ||
129 | resolution: &hir::ScopeDef, | ||
130 | ) -> Option<CompletionItem> { | ||
131 | render_resolution_(ctx, local_name, None, resolution) | ||
132 | } | ||
133 | |||
134 | pub(crate) fn render_resolution_with_import( | ||
135 | ctx: RenderContext<'_>, | ||
136 | import_edit: ImportEdit, | ||
137 | ) -> Option<CompletionItem> { | ||
138 | let resolution = hir::ScopeDef::from(import_edit.import.original_item); | ||
139 | let local_name = match resolution { | ||
140 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db), | ||
141 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?, | ||
142 | hir::ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db), | ||
143 | _ => item_name(ctx.db(), import_edit.import.original_item)?, | ||
144 | }; | ||
145 | render_resolution_(ctx, local_name, Some(import_edit), &resolution).map(|mut item| { | ||
146 | item.completion_kind = CompletionKind::Magic; | ||
147 | item | ||
148 | }) | ||
149 | } | ||
150 | |||
178 | fn render_resolution_( | 151 | fn render_resolution_( |
179 | ctx: RenderContext<'_>, | 152 | ctx: RenderContext<'_>, |
180 | local_name: hir::Name, | 153 | local_name: hir::Name, |
@@ -1007,6 +980,7 @@ fn go(world: &WorldSnapshot) { go(w$0) } | |||
1007 | 980 | ||
1008 | #[test] | 981 | #[test] |
1009 | fn too_many_arguments() { | 982 | fn too_many_arguments() { |
983 | cov_mark::check!(too_many_arguments); | ||
1010 | check_relevance( | 984 | check_relevance( |
1011 | r#" | 985 | r#" |
1012 | struct Foo; | 986 | struct Foo; |
@@ -1151,16 +1125,11 @@ fn main() { | |||
1151 | fn suggest_deref() { | 1125 | fn suggest_deref() { |
1152 | check_relevance( | 1126 | check_relevance( |
1153 | r#" | 1127 | r#" |
1154 | #[lang = "deref"] | 1128 | //- minicore: deref |
1155 | trait Deref { | ||
1156 | type Target; | ||
1157 | fn deref(&self) -> &Self::Target; | ||
1158 | } | ||
1159 | |||
1160 | struct S; | 1129 | struct S; |
1161 | struct T(S); | 1130 | struct T(S); |
1162 | 1131 | ||
1163 | impl Deref for T { | 1132 | impl core::ops::Deref for T { |
1164 | type Target = S; | 1133 | type Target = S; |
1165 | 1134 | ||
1166 | fn deref(&self) -> &Self::Target { | 1135 | fn deref(&self) -> &Self::Target { |
@@ -1184,8 +1153,9 @@ fn main() { | |||
1184 | st T [] | 1153 | st T [] |
1185 | st S [] | 1154 | st S [] |
1186 | fn main() [] | 1155 | fn main() [] |
1187 | tt Deref [] | ||
1188 | fn foo(…) [] | 1156 | fn foo(…) [] |
1157 | md core [] | ||
1158 | tt Sized [] | ||
1189 | "#]], | 1159 | "#]], |
1190 | ) | 1160 | ) |
1191 | } | 1161 | } |
@@ -1194,21 +1164,11 @@ fn main() { | |||
1194 | fn suggest_deref_mut() { | 1164 | fn suggest_deref_mut() { |
1195 | check_relevance( | 1165 | check_relevance( |
1196 | r#" | 1166 | r#" |
1197 | #[lang = "deref"] | 1167 | //- minicore: deref_mut |
1198 | trait Deref { | ||
1199 | type Target; | ||
1200 | fn deref(&self) -> &Self::Target; | ||
1201 | } | ||
1202 | |||
1203 | #[lang = "deref_mut"] | ||
1204 | pub trait DerefMut: Deref { | ||
1205 | fn deref_mut(&mut self) -> &mut Self::Target; | ||
1206 | } | ||
1207 | |||
1208 | struct S; | 1168 | struct S; |
1209 | struct T(S); | 1169 | struct T(S); |
1210 | 1170 | ||
1211 | impl Deref for T { | 1171 | impl core::ops::Deref for T { |
1212 | type Target = S; | 1172 | type Target = S; |
1213 | 1173 | ||
1214 | fn deref(&self) -> &Self::Target { | 1174 | fn deref(&self) -> &Self::Target { |
@@ -1216,7 +1176,7 @@ impl Deref for T { | |||
1216 | } | 1176 | } |
1217 | } | 1177 | } |
1218 | 1178 | ||
1219 | impl DerefMut for T { | 1179 | impl core::ops::DerefMut for T { |
1220 | fn deref_mut(&mut self) -> &mut Self::Target { | 1180 | fn deref_mut(&mut self) -> &mut Self::Target { |
1221 | &mut self.0 | 1181 | &mut self.0 |
1222 | } | 1182 | } |
@@ -1235,12 +1195,12 @@ fn main() { | |||
1235 | lc m [local] | 1195 | lc m [local] |
1236 | lc t [local] | 1196 | lc t [local] |
1237 | lc &mut t [type+local] | 1197 | lc &mut t [type+local] |
1238 | tt DerefMut [] | ||
1239 | tt Deref [] | ||
1240 | fn foo(…) [] | ||
1241 | st T [] | 1198 | st T [] |
1242 | st S [] | 1199 | st S [] |
1243 | fn main() [] | 1200 | fn main() [] |
1201 | fn foo(…) [] | ||
1202 | md core [] | ||
1203 | tt Sized [] | ||
1244 | "#]], | 1204 | "#]], |
1245 | ) | 1205 | ) |
1246 | } | 1206 | } |
diff --git a/crates/ide_completion/src/render/macro_.rs b/crates/ide_completion/src/render/macro_.rs index 429d937c8..3a7238bb8 100644 --- a/crates/ide_completion/src/render/macro_.rs +++ b/crates/ide_completion/src/render/macro_.rs | |||
@@ -180,7 +180,7 @@ fn main() { frobnicate!(); } | |||
180 | /// ``` | 180 | /// ``` |
181 | macro_rules! vec { () => {} } | 181 | macro_rules! vec { () => {} } |
182 | 182 | ||
183 | fn fn main() { v$0 } | 183 | fn main() { v$0 } |
184 | "#, | 184 | "#, |
185 | r#" | 185 | r#" |
186 | /// Creates a [`Vec`] containing the arguments. | 186 | /// Creates a [`Vec`] containing the arguments. |
@@ -193,7 +193,7 @@ fn fn main() { v$0 } | |||
193 | /// ``` | 193 | /// ``` |
194 | macro_rules! vec { () => {} } | 194 | macro_rules! vec { () => {} } |
195 | 195 | ||
196 | fn fn main() { vec![$0] } | 196 | fn main() { vec![$0] } |
197 | "#, | 197 | "#, |
198 | ); | 198 | ); |
199 | 199 | ||
diff --git a/crates/ide_completion/src/render/pattern.rs b/crates/ide_completion/src/render/pattern.rs index b4e80f424..3717a0409 100644 --- a/crates/ide_completion/src/render/pattern.rs +++ b/crates/ide_completion/src/render/pattern.rs | |||
@@ -75,10 +75,10 @@ fn render_pat( | |||
75 | ) -> Option<String> { | 75 | ) -> Option<String> { |
76 | let mut pat = match kind { | 76 | let mut pat = match kind { |
77 | StructKind::Tuple if ctx.snippet_cap().is_some() => { | 77 | StructKind::Tuple if ctx.snippet_cap().is_some() => { |
78 | render_tuple_as_pat(&fields, &name, fields_omitted) | 78 | render_tuple_as_pat(fields, name, fields_omitted) |
79 | } | 79 | } |
80 | StructKind::Record => { | 80 | StructKind::Record => { |
81 | render_record_as_pat(ctx.db(), ctx.snippet_cap(), &fields, &name, fields_omitted) | 81 | render_record_as_pat(ctx.db(), ctx.snippet_cap(), fields, name, fields_omitted) |
82 | } | 82 | } |
83 | _ => return None, | 83 | _ => return None, |
84 | }; | 84 | }; |
@@ -86,7 +86,7 @@ fn render_pat( | |||
86 | if ctx.completion.is_param { | 86 | if ctx.completion.is_param { |
87 | pat.push(':'); | 87 | pat.push(':'); |
88 | pat.push(' '); | 88 | pat.push(' '); |
89 | pat.push_str(&name); | 89 | pat.push_str(name); |
90 | } | 90 | } |
91 | if ctx.snippet_cap().is_some() { | 91 | if ctx.snippet_cap().is_some() { |
92 | pat.push_str("$0"); | 92 | pat.push_str("$0"); |
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 | } |