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.rs51
-rw-r--r--crates/ide_completion/src/completions/attribute.rs4
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs3
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs30
-rw-r--r--crates/ide_completion/src/completions/unqualified_path.rs26
-rw-r--r--crates/ide_completion/src/context.rs42
-rw-r--r--crates/ide_completion/src/render.rs15
7 files changed, 117 insertions, 54 deletions
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs
index 7a4d71e91..fbd499900 100644
--- a/crates/ide_completion/src/completions.rs
+++ b/crates/ide_completion/src/completions.rs
@@ -56,10 +56,16 @@ impl Builder {
56} 56}
57 57
58impl Completions { 58impl Completions {
59 pub(crate) fn add(&mut self, item: CompletionItem) { 59 fn add(&mut self, item: CompletionItem) {
60 self.buf.push(item) 60 self.buf.push(item)
61 } 61 }
62 62
63 fn add_opt(&mut self, item: Option<CompletionItem>) {
64 if let Some(item) = item {
65 self.buf.push(item)
66 }
67 }
68
63 pub(crate) fn add_all<I>(&mut self, items: I) 69 pub(crate) fn add_all<I>(&mut self, items: I)
64 where 70 where
65 I: IntoIterator, 71 I: IntoIterator,
@@ -103,9 +109,10 @@ impl Completions {
103 local_name: hir::Name, 109 local_name: hir::Name,
104 resolution: &hir::ScopeDef, 110 resolution: &hir::ScopeDef,
105 ) { 111 ) {
106 if let Some(item) = render_resolution(RenderContext::new(ctx), local_name, resolution) { 112 if ctx.expects_type() && resolution.is_value_def() {
107 self.add(item); 113 return;
108 } 114 }
115 self.add_opt(render_resolution(RenderContext::new(ctx), local_name, resolution));
109 } 116 }
110 117
111 pub(crate) fn add_macro( 118 pub(crate) fn add_macro(
@@ -118,9 +125,7 @@ impl Completions {
118 Some(it) => it, 125 Some(it) => it,
119 None => return, 126 None => return,
120 }; 127 };
121 if let Some(item) = render_macro(RenderContext::new(ctx), None, name, macro_) { 128 self.add_opt(render_macro(RenderContext::new(ctx), None, name, macro_));
122 self.add(item);
123 }
124 } 129 }
125 130
126 pub(crate) fn add_function( 131 pub(crate) fn add_function(
@@ -129,9 +134,10 @@ impl Completions {
129 func: hir::Function, 134 func: hir::Function,
130 local_name: Option<hir::Name>, 135 local_name: Option<hir::Name>,
131 ) { 136 ) {
132 if let Some(item) = render_fn(RenderContext::new(ctx), None, local_name, func) { 137 if ctx.expects_type() {
133 self.add(item) 138 return;
134 } 139 }
140 self.add_opt(render_fn(RenderContext::new(ctx), None, local_name, func));
135 } 141 }
136 142
137 pub(crate) fn add_method( 143 pub(crate) fn add_method(
@@ -141,10 +147,7 @@ impl Completions {
141 receiver: Option<hir::Name>, 147 receiver: Option<hir::Name>,
142 local_name: Option<hir::Name>, 148 local_name: Option<hir::Name>,
143 ) { 149 ) {
144 if let Some(item) = render_method(RenderContext::new(ctx), None, receiver, local_name, func) 150 self.add_opt(render_method(RenderContext::new(ctx), None, receiver, local_name, func));
145 {
146 self.add(item)
147 }
148 } 151 }
149 152
150 pub(crate) fn add_variant_pat( 153 pub(crate) fn add_variant_pat(
@@ -153,9 +156,7 @@ impl Completions {
153 variant: hir::Variant, 156 variant: hir::Variant,
154 local_name: Option<hir::Name>, 157 local_name: Option<hir::Name>,
155 ) { 158 ) {
156 if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, local_name, None) { 159 self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, local_name, None));
157 self.add(item);
158 }
159 } 160 }
160 161
161 pub(crate) fn add_qualified_variant_pat( 162 pub(crate) fn add_qualified_variant_pat(
@@ -164,9 +165,7 @@ impl Completions {
164 variant: hir::Variant, 165 variant: hir::Variant,
165 path: hir::ModPath, 166 path: hir::ModPath,
166 ) { 167 ) {
167 if let Some(item) = render_variant_pat(RenderContext::new(ctx), variant, None, Some(path)) { 168 self.add_opt(render_variant_pat(RenderContext::new(ctx), variant, None, Some(path)));
168 self.add(item);
169 }
170 } 169 }
171 170
172 pub(crate) fn add_struct_pat( 171 pub(crate) fn add_struct_pat(
@@ -175,21 +174,18 @@ impl Completions {
175 strukt: hir::Struct, 174 strukt: hir::Struct,
176 local_name: Option<hir::Name>, 175 local_name: Option<hir::Name>,
177 ) { 176 ) {
178 if let Some(item) = render_struct_pat(RenderContext::new(ctx), strukt, local_name) { 177 self.add_opt(render_struct_pat(RenderContext::new(ctx), strukt, local_name));
179 self.add(item);
180 }
181 } 178 }
182 179
183 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { 180 pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) {
184 if let Some(item) = render_const(RenderContext::new(ctx), constant) { 181 if ctx.expects_type() {
185 self.add(item); 182 return;
186 } 183 }
184 self.add_opt(render_const(RenderContext::new(ctx), constant));
187 } 185 }
188 186
189 pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { 187 pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) {
190 if let Some(item) = render_type_alias(RenderContext::new(ctx), type_alias) { 188 self.add_opt(render_type_alias(RenderContext::new(ctx), type_alias));
191 self.add(item)
192 }
193 } 189 }
194 190
195 pub(crate) fn add_qualified_enum_variant( 191 pub(crate) fn add_qualified_enum_variant(
@@ -208,6 +204,9 @@ impl Completions {
208 variant: hir::Variant, 204 variant: hir::Variant,
209 local_name: Option<hir::Name>, 205 local_name: Option<hir::Name>,
210 ) { 206 ) {
207 if ctx.expects_type() {
208 return;
209 }
211 let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None); 210 let item = render_variant(RenderContext::new(ctx), None, local_name, variant, None);
212 self.add(item); 211 self.add(item);
213 } 212 }
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index d3392100d..7f76e357e 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -69,7 +69,7 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib
69 } 69 }
70 70
71 if is_inner || !attr_completion.prefer_inner { 71 if is_inner || !attr_completion.prefer_inner {
72 acc.add(item.build()); 72 item.add_to(acc);
73 } 73 }
74 }; 74 };
75 75
@@ -96,7 +96,7 @@ fn complete_new_attribute(acc: &mut Completions, ctx: &CompletionContext, attrib
96 if let Some(docs) = mac.docs(ctx.sema.db) { 96 if let Some(docs) = mac.docs(ctx.sema.db) {
97 item.documentation(docs); 97 item.documentation(docs);
98 } 98 }
99 acc.add(item.build()); 99 item.add_to(acc);
100 } 100 }
101 } 101 }
102 }); 102 });
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 7bf47bf75..c010cbbca 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -90,7 +90,6 @@
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 corredponding
91//! capability enabled. 91//! capability enabled.
92 92
93use hir::ModPath;
94use ide_db::helpers::{ 93use ide_db::helpers::{
95 import_assets::{ImportAssets, ImportCandidate}, 94 import_assets::{ImportAssets, ImportCandidate},
96 insert_use::ImportScope, 95 insert_use::ImportScope,
@@ -208,7 +207,7 @@ fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAs
208} 207}
209 208
210fn compute_fuzzy_completion_order_key( 209fn compute_fuzzy_completion_order_key(
211 proposed_mod_path: &ModPath, 210 proposed_mod_path: &hir::ModPath,
212 user_input_lowercased: &str, 211 user_input_lowercased: &str,
213) -> usize { 212) -> usize {
214 cov_mark::hit!(certain_fuzzy_order_test); 213 cov_mark::hit!(certain_fuzzy_order_test);
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index 4dfdc5ced..0b0a81410 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -208,6 +208,36 @@ mod tests {
208 } 208 }
209 209
210 #[test] 210 #[test]
211 fn dont_complete_values_in_type_pos() {
212 check(
213 r#"
214const FOO: () = ();
215static BAR: () = ();
216struct Baz;
217fn foo() {
218 let _: self::$0;
219}
220"#,
221 expect![[r#"
222 st Baz
223 "#]],
224 );
225 }
226
227 #[test]
228 fn dont_complete_enum_variants_in_type_pos() {
229 check(
230 r#"
231enum Foo { Bar }
232fn foo() {
233 let _: Foo::$0;
234}
235"#,
236 expect![[r#""#]],
237 );
238 }
239
240 #[test]
211 fn dont_complete_current_use_in_braces_with_glob() { 241 fn dont_complete_current_use_in_braces_with_glob() {
212 check( 242 check(
213 r#" 243 r#"
diff --git a/crates/ide_completion/src/completions/unqualified_path.rs b/crates/ide_completion/src/completions/unqualified_path.rs
index 52f40d496..1f6c4069f 100644
--- a/crates/ide_completion/src/completions/unqualified_path.rs
+++ b/crates/ide_completion/src/completions/unqualified_path.rs
@@ -77,6 +77,28 @@ mod tests {
77 } 77 }
78 78
79 #[test] 79 #[test]
80 fn dont_complete_values_in_type_pos() {
81 check(
82 r#"
83const FOO: () = ();
84static BAR: () = ();
85enum Foo {
86 Bar
87}
88struct Baz;
89fn foo() {
90 let local = ();
91 let _: $0;
92}
93"#,
94 expect![[r#"
95 en Foo
96 st Baz
97 "#]],
98 );
99 }
100
101 #[test]
80 fn only_completes_modules_in_import() { 102 fn only_completes_modules_in_import() {
81 cov_mark::check!(only_completes_modules_in_import); 103 cov_mark::check!(only_completes_modules_in_import);
82 check( 104 check(
@@ -347,7 +369,6 @@ fn x() -> $0
347"#, 369"#,
348 expect![[r#" 370 expect![[r#"
349 st Foo 371 st Foo
350 fn x() fn()
351 "#]], 372 "#]],
352 ); 373 );
353 } 374 }
@@ -399,7 +420,6 @@ pub mod prelude {
399} 420}
400"#, 421"#,
401 expect![[r#" 422 expect![[r#"
402 fn foo() fn()
403 md std 423 md std
404 st Option 424 st Option
405 "#]], 425 "#]],
@@ -494,7 +514,6 @@ pub mod prelude {
494} 514}
495"#, 515"#,
496 expect![[r#" 516 expect![[r#"
497 fn foo() fn()
498 md std 517 md std
499 md core 518 md core
500 st String 519 st String
@@ -555,7 +574,6 @@ macro_rules! foo { () => {} }
555fn main() { let x: $0 } 574fn main() { let x: $0 }
556"#, 575"#,
557 expect![[r#" 576 expect![[r#"
558 fn main() fn()
559 ma foo!(…) macro_rules! foo 577 ma foo!(…) macro_rules! foo
560 "#]], 578 "#]],
561 ); 579 );
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 6177caa12..2c2a4aa6b 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -30,19 +30,24 @@ pub(crate) enum PatternRefutability {
30} 30}
31 31
32#[derive(Debug)] 32#[derive(Debug)]
33pub(super) enum PathKind {
34 Expr,
35 Type,
36}
37
38#[derive(Debug)]
33pub(crate) struct PathCompletionContext { 39pub(crate) struct PathCompletionContext {
34 /// If this is a call with () already there 40 /// If this is a call with () already there
35 call_kind: Option<CallKind>, 41 call_kind: Option<CallKind>,
36 /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path. 42 /// A single-indent path, like `foo`. `::foo` should not be considered a trivial path.
37 pub(super) is_trivial_path: bool, 43 pub(super) is_trivial_path: bool,
38 /// If not a trivial path, the prefix (qualifier). 44 /// If not a trivial path, the prefix (qualifier).
39 pub(super) path_qual: Option<ast::Path>, 45 pub(super) qualifier: Option<ast::Path>,
40 pub(super) is_path_type: bool, 46 pub(super) kind: Option<PathKind>,
47 /// Whether the path segment has type args or not.
41 pub(super) has_type_args: bool, 48 pub(super) has_type_args: bool,
42 /// `true` if we are a statement or a last expr in the block. 49 /// `true` if we are a statement or a last expr in the block.
43 pub(super) can_be_stmt: bool, 50 pub(super) can_be_stmt: bool,
44 /// `true` if we expect an expression at the cursor position.
45 pub(super) is_expr: bool,
46 pub(super) in_loop_body: bool, 51 pub(super) in_loop_body: bool,
47} 52}
48 53
@@ -308,7 +313,11 @@ impl<'a> CompletionContext<'a> {
308 } 313 }
309 314
310 pub(crate) fn expects_expression(&self) -> bool { 315 pub(crate) fn expects_expression(&self) -> bool {
311 self.path_context.as_ref().map_or(false, |it| it.is_expr) 316 matches!(self.path_context, Some(PathCompletionContext { kind: Some(PathKind::Expr), .. }))
317 }
318
319 pub(crate) fn expects_type(&self) -> bool {
320 matches!(self.path_context, Some(PathCompletionContext { kind: Some(PathKind::Type), .. }))
312 } 321 }
313 322
314 pub(crate) fn path_call_kind(&self) -> Option<CallKind> { 323 pub(crate) fn path_call_kind(&self) -> Option<CallKind> {
@@ -316,11 +325,11 @@ impl<'a> CompletionContext<'a> {
316 } 325 }
317 326
318 pub(crate) fn is_trivial_path(&self) -> bool { 327 pub(crate) fn is_trivial_path(&self) -> bool {
319 self.path_context.as_ref().map_or(false, |it| it.is_trivial_path) 328 matches!(self.path_context, Some(PathCompletionContext { is_trivial_path: true, .. }))
320 } 329 }
321 330
322 pub(crate) fn path_qual(&self) -> Option<&ast::Path> { 331 pub(crate) fn path_qual(&self) -> Option<&ast::Path> {
323 self.path_context.as_ref().and_then(|it| it.path_qual.as_ref()) 332 self.path_context.as_ref().and_then(|it| it.qualifier.as_ref())
324 } 333 }
325 334
326 fn fill_impl_def(&mut self) { 335 fn fill_impl_def(&mut self) {
@@ -573,12 +582,11 @@ impl<'a> CompletionContext<'a> {
573 let path_ctx = self.path_context.get_or_insert(PathCompletionContext { 582 let path_ctx = self.path_context.get_or_insert(PathCompletionContext {
574 call_kind: None, 583 call_kind: None,
575 is_trivial_path: false, 584 is_trivial_path: false,
576 path_qual: None, 585 qualifier: None,
577 has_type_args: false, 586 has_type_args: false,
578 is_path_type: false,
579 can_be_stmt: false, 587 can_be_stmt: false,
580 is_expr: false,
581 in_loop_body: false, 588 in_loop_body: false,
589 kind: None,
582 }); 590 });
583 path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax()); 591 path_ctx.in_loop_body = is_in_loop_body(name_ref.syntax());
584 let path = segment.parent_path(); 592 let path = segment.parent_path();
@@ -593,11 +601,20 @@ impl<'a> CompletionContext<'a> {
593 } 601 }
594 }; 602 };
595 } 603 }
596 path_ctx.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); 604
605 if let Some(parent) = path.syntax().parent() {
606 path_ctx.kind = match_ast! {
607 match parent {
608 ast::PathType(_it) => Some(PathKind::Type),
609 ast::PathExpr(_it) => Some(PathKind::Expr),
610 _ => None,
611 }
612 };
613 }
597 path_ctx.has_type_args = segment.generic_arg_list().is_some(); 614 path_ctx.has_type_args = segment.generic_arg_list().is_some();
598 615
599 if let Some(path) = path_or_use_tree_qualifier(&path) { 616 if let Some(path) = path_or_use_tree_qualifier(&path) {
600 path_ctx.path_qual = path 617 path_ctx.qualifier = path
601 .segment() 618 .segment()
602 .and_then(|it| { 619 .and_then(|it| {
603 find_node_with_range::<ast::PathSegment>( 620 find_node_with_range::<ast::PathSegment>(
@@ -635,7 +652,6 @@ impl<'a> CompletionContext<'a> {
635 None 652 None
636 }) 653 })
637 .unwrap_or(false); 654 .unwrap_or(false);
638 path_ctx.is_expr = path.syntax().parent().and_then(ast::PathExpr::cast).is_some();
639 } 655 }
640 } 656 }
641} 657}
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 750694432..7118183fe 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -18,6 +18,7 @@ use ide_db::{
18use syntax::TextRange; 18use syntax::TextRange;
19 19
20use crate::{ 20use crate::{
21 context::{PathCompletionContext, PathKind},
21 item::{CompletionRelevanceTypeMatch, ImportEdit}, 22 item::{CompletionRelevanceTypeMatch, ImportEdit},
22 render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}, 23 render::{enum_variant::render_variant, function::render_fn, macro_::render_macro},
23 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance, 24 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, CompletionRelevance,
@@ -54,6 +55,9 @@ pub(crate) fn render_resolution_with_import<'a>(
54 import_edit: ImportEdit, 55 import_edit: ImportEdit,
55) -> Option<CompletionItem> { 56) -> Option<CompletionItem> {
56 let resolution = hir::ScopeDef::from(import_edit.import.original_item); 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 }
57 let local_name = match resolution { 61 let local_name = match resolution {
58 hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db), 62 hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
59 hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?, 63 hir::ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
@@ -275,13 +279,10 @@ impl<'a> Render<'a> {
275 }; 279 };
276 280
277 // Add `<>` for generic types 281 // Add `<>` for generic types
278 if self 282 if matches!(
279 .ctx 283 self.ctx.completion.path_context,
280 .completion 284 Some(PathCompletionContext { kind: Some(PathKind::Type), has_type_args: false, .. })
281 .path_context 285 ) && self.ctx.completion.config.add_call_parenthesis
282 .as_ref()
283 .map_or(false, |it| it.is_path_type && !it.has_type_args)
284 && self.ctx.completion.config.add_call_parenthesis
285 { 286 {
286 if let Some(cap) = self.ctx.snippet_cap() { 287 if let Some(cap) = self.ctx.snippet_cap() {
287 let has_non_default_type_params = match resolution { 288 let has_non_default_type_params = match resolution {