aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src')
-rw-r--r--crates/ide_completion/src/completions.rs31
-rw-r--r--crates/ide_completion/src/completions/attribute.rs2
-rw-r--r--crates/ide_completion/src/completions/attribute/derive.rs49
-rw-r--r--crates/ide_completion/src/completions/dot.rs2
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs18
-rw-r--r--crates/ide_completion/src/completions/keyword.rs20
-rw-r--r--crates/ide_completion/src/completions/postfix.rs20
-rw-r--r--crates/ide_completion/src/completions/postfix/format_like.rs4
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs87
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs72
-rw-r--r--crates/ide_completion/src/context.rs8
-rw-r--r--crates/ide_completion/src/patterns.rs19
-rw-r--r--crates/ide_completion/src/render.rs118
-rw-r--r--crates/ide_completion/src/render/macro_.rs4
-rw-r--r--crates/ide_completion/src/render/pattern.rs6
-rw-r--r--crates/ide_completion/src/render/type_alias.rs23
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.
215fn complete_enum_variants( 212fn 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});
220const EXPR_ATTRIBUTES: &[&str] = attrs!(); 220const 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!
224const ATTRIBUTES: &[AttrCompletion] = &[ 224const 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
93use ide_db::helpers::{ 93use 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
540use std::future::*; 540use core::future::*;
541struct A {} 541struct A {}
542impl Future for A {} 542impl Future for A {}
543fn foo(a: A) { a.$0 } 543fn foo(a: A) { a.$0 }
544
545//- /std/lib.rs crate:std
546pub 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
559use std::future::*; 553use std::future::*;
560fn foo() { 554fn foo() {
561 let a = async {}; 555 let a = async {};
562 a.$0 556 a.$0
563} 557}
564
565//- /std/lib.rs crate:std
566pub 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 {
91impl FormatStrParser { 91impl 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
179fn add_enum_variants(ctx: &CompletionContext, acc: &mut Completions, e: hir::Enum) { 178fn 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
189fn 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#"
946mod foo {
947 pub const CONST: () = ();
948 pub type Type = ();
949}
950
951struct Foo<T>(t);
952
953fn 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
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() {
@@ -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#"
815enum Bar {
816 Baz
817}
818trait Foo {
819 type Bar;
820}
821
822const CONST: () = ();
823
824fn 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
256pub(crate) fn previous_token(element: SyntaxElement) -> Option<SyntaxToken> { 261pub(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> {
262pub(crate) fn for_is_prev2(element: SyntaxElement) -> bool { 267pub(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
27pub(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
36pub(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
45pub(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
53pub(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)]
75pub(crate) struct RenderContext<'a> { 28pub(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
125fn render_field_( 78pub(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
159fn render_tuple_field_( 109pub(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
126pub(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
134pub(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
178fn render_resolution_( 151fn 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#"
1012struct Foo; 986struct 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
1155trait Deref {
1156 type Target;
1157 fn deref(&self) -> &Self::Target;
1158}
1159
1160struct S; 1129struct S;
1161struct T(S); 1130struct T(S);
1162 1131
1163impl Deref for T { 1132impl 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
1198trait Deref {
1199 type Target;
1200 fn deref(&self) -> &Self::Target;
1201}
1202
1203#[lang = "deref_mut"]
1204pub trait DerefMut: Deref {
1205 fn deref_mut(&mut self) -> &mut Self::Target;
1206}
1207
1208struct S; 1168struct S;
1209struct T(S); 1169struct T(S);
1210 1170
1211impl Deref for T { 1171impl 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
1219impl DerefMut for T { 1179impl 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/// ```
181macro_rules! vec { () => {} } 181macro_rules! vec { () => {} }
182 182
183fn fn main() { v$0 } 183fn 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/// ```
194macro_rules! vec { () => {} } 194macro_rules! vec { () => {} }
195 195
196fn fn main() { vec![$0] } 196fn 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
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 }