aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/completion')
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs185
-rw-r--r--crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs62
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs166
-rw-r--r--crates/ra_ide_api/src/completion/complete_postfix.rs67
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs679
-rw-r--r--crates/ra_ide_api/src/completion/completion_context.rs19
-rw-r--r--crates/ra_ide_api/src/completion/completion_item.rs4
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs389
8 files changed, 999 insertions, 572 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs
index 28c8324d0..b4df6ee2a 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -119,27 +119,28 @@ mod tests {
119 ", 119 ",
120 ), 120 ),
121 @r###" 121 @r###"
122 ⋮[ 122 [
123 ⋮ CompletionItem { 123 CompletionItem {
124 ⋮ label: "foo", 124 label: "foo()",
125 ⋮ source_range: [187; 187), 125 source_range: [187; 187),
126 ⋮ delete: [187; 187), 126 delete: [187; 187),
127 ⋮ insert: "foo()$0", 127 insert: "foo()$0",
128 ⋮ kind: Method, 128 kind: Method,
129 ⋮ detail: "fn foo(self)", 129 lookup: "foo",
130 ⋮ }, 130 detail: "fn foo(self)",
131 ⋮ CompletionItem { 131 },
132 ⋮ label: "the_field", 132 CompletionItem {
133 ⋮ source_range: [187; 187), 133 label: "the_field",
134 ⋮ delete: [187; 187), 134 source_range: [187; 187),
135 ⋮ insert: "the_field", 135 delete: [187; 187),
136 ⋮ kind: Field, 136 insert: "the_field",
137 ⋮ detail: "(u32,)", 137 kind: Field,
138 ⋮ documentation: Documentation( 138 detail: "(u32,)",
139 ⋮ "This is the_field", 139 documentation: Documentation(
140 ⋮ ), 140 "This is the_field",
141 ⋮ }, 141 ),
142 ⋮] 142 },
143 ]
143 "### 144 "###
144 ); 145 );
145 } 146 }
@@ -158,24 +159,25 @@ mod tests {
158 ", 159 ",
159 ), 160 ),
160 @r###" 161 @r###"
161 ⋮[ 162 [
162 ⋮ CompletionItem { 163 CompletionItem {
163 ⋮ label: "foo", 164 label: "foo()",
164 ⋮ source_range: [126; 126), 165 source_range: [126; 126),
165 ⋮ delete: [126; 126), 166 delete: [126; 126),
166 ⋮ insert: "foo()$0", 167 insert: "foo()$0",
167 ⋮ kind: Method, 168 kind: Method,
168 ⋮ detail: "fn foo(&self)", 169 lookup: "foo",
169 ⋮ }, 170 detail: "fn foo(&self)",
170 ⋮ CompletionItem { 171 },
171 ⋮ label: "the_field", 172 CompletionItem {
172 ⋮ source_range: [126; 126), 173 label: "the_field",
173 ⋮ delete: [126; 126), 174 source_range: [126; 126),
174 ⋮ insert: "the_field", 175 delete: [126; 126),
175 ⋮ kind: Field, 176 insert: "the_field",
176 ⋮ detail: "(u32, i32)", 177 kind: Field,
177 ⋮ }, 178 detail: "(u32, i32)",
178 ⋮] 179 },
180 ]
179 "### 181 "###
180 ); 182 );
181 } 183 }
@@ -210,16 +212,17 @@ mod tests {
210 ", 212 ",
211 ), 213 ),
212 @r###" 214 @r###"
213 ⋮[ 215 [
214 ⋮ CompletionItem { 216 CompletionItem {
215 ⋮ label: "the_method", 217 label: "the_method()",
216 ⋮ source_range: [144; 144), 218 source_range: [144; 144),
217 ⋮ delete: [144; 144), 219 delete: [144; 144),
218 ⋮ insert: "the_method()$0", 220 insert: "the_method()$0",
219 ⋮ kind: Method, 221 kind: Method,
220 ⋮ detail: "fn the_method(&self)", 222 lookup: "the_method",
221 ⋮ }, 223 detail: "fn the_method(&self)",
222 ⋮] 224 },
225 ]
223 "### 226 "###
224 ); 227 );
225 } 228 }
@@ -238,16 +241,17 @@ mod tests {
238 ", 241 ",
239 ), 242 ),
240 @r###" 243 @r###"
241 ⋮[ 244 [
242 ⋮ CompletionItem { 245 CompletionItem {
243 ⋮ label: "the_method", 246 label: "the_method()",
244 ⋮ source_range: [151; 151), 247 source_range: [151; 151),
245 ⋮ delete: [151; 151), 248 delete: [151; 151),
246 ⋮ insert: "the_method()$0", 249 insert: "the_method()$0",
247 ⋮ kind: Method, 250 kind: Method,
248 ⋮ detail: "fn the_method(&self)", 251 lookup: "the_method",
249 ⋮ }, 252 detail: "fn the_method(&self)",
250 ⋮] 253 },
254 ]
251 "### 255 "###
252 ); 256 );
253 } 257 }
@@ -266,16 +270,17 @@ mod tests {
266 ", 270 ",
267 ), 271 ),
268 @r###" 272 @r###"
269 ⋮[ 273 [
270 ⋮ CompletionItem { 274 CompletionItem {
271 ⋮ label: "the_method", 275 label: "the_method()",
272 ⋮ source_range: [155; 155), 276 source_range: [155; 155),
273 ⋮ delete: [155; 155), 277 delete: [155; 155),
274 ⋮ insert: "the_method()$0", 278 insert: "the_method()$0",
275 ⋮ kind: Method, 279 kind: Method,
276 ⋮ detail: "fn the_method(&self)", 280 lookup: "the_method",
277 ⋮ }, 281 detail: "fn the_method(&self)",
278 ⋮] 282 },
283 ]
279 "### 284 "###
280 ); 285 );
281 } 286 }
@@ -317,16 +322,17 @@ mod tests {
317 ", 322 ",
318 ), 323 ),
319 @r###" 324 @r###"
320 ⋮[ 325 [
321 ⋮ CompletionItem { 326 CompletionItem {
322 ⋮ label: "the_method", 327 label: "the_method()",
323 ⋮ source_range: [249; 249), 328 source_range: [249; 249),
324 ⋮ delete: [249; 249), 329 delete: [249; 249),
325 ⋮ insert: "the_method()$0", 330 insert: "the_method()$0",
326 ⋮ kind: Method, 331 kind: Method,
327 ⋮ detail: "fn the_method(&self)", 332 lookup: "the_method",
328 ⋮ }, 333 detail: "fn the_method(&self)",
329 ⋮] 334 },
335 ]
330 "### 336 "###
331 ); 337 );
332 } 338 }
@@ -386,16 +392,17 @@ mod tests {
386 ", 392 ",
387 ), 393 ),
388 @r###" 394 @r###"
389 ⋮[ 395 [
390 ⋮ CompletionItem { 396 CompletionItem {
391 ⋮ label: "blah", 397 label: "blah()",
392 ⋮ source_range: [299; 300), 398 source_range: [299; 300),
393 ⋮ delete: [299; 300), 399 delete: [299; 300),
394 ⋮ insert: "blah()$0", 400 insert: "blah()$0",
395 ⋮ kind: Method, 401 kind: Method,
396 ⋮ detail: "pub fn blah(&self)", 402 lookup: "blah",
397 ⋮ }, 403 detail: "pub fn blah(&self)",
398 ⋮] 404 },
405 ]
399 "### 406 "###
400 ); 407 );
401 } 408 }
diff --git a/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs b/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs
index d808b2357..09f743c66 100644
--- a/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs
+++ b/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs
@@ -56,6 +56,16 @@ mod tests {
56 do_reference_completion( 56 do_reference_completion(
57 " 57 "
58 //- /main.rs 58 //- /main.rs
59 /// Creates a [`Vec`] containing the arguments.
60 ///
61 /// - Create a [`Vec`] containing a given list of elements:
62 ///
63 /// ```
64 /// let v = vec![1, 2, 3];
65 /// assert_eq!(v[0], 1);
66 /// assert_eq!(v[1], 2);
67 /// assert_eq!(v[2], 3);
68 /// ```
59 macro_rules! vec { 69 macro_rules! vec {
60 () => {} 70 () => {}
61 } 71 }
@@ -68,13 +78,61 @@ mod tests {
68 @r##"[ 78 @r##"[
69 CompletionItem { 79 CompletionItem {
70 label: "vec!", 80 label: "vec!",
71 source_range: [46; 46), 81 source_range: [280; 280),
72 delete: [46; 46), 82 delete: [280; 280),
73 insert: "vec![$0]", 83 insert: "vec![$0]",
74 kind: Macro, 84 kind: Macro,
75 detail: "macro_rules! vec", 85 detail: "macro_rules! vec",
86 documentation: Documentation(
87 "Creates a [`Vec`] containing the arguments.\n\n- Create a [`Vec`] containing a given list of elements:\n\n```\nlet v = vec![1, 2, 3];\nassert_eq!(v[0], 1);\nassert_eq!(v[1], 2);\nassert_eq!(v[2], 3);\n```",
88 ),
76 }, 89 },
77]"## 90]"##
78 ); 91 );
79 } 92 }
93
94 #[test]
95 fn completes_macros_braces_guessing() {
96 assert_debug_snapshot!(
97 do_reference_completion(
98 "
99 //- /main.rs
100 /// Foo
101 ///
102 /// Not call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.
103 /// Call as `let _=foo! { hello world };`
104 macro_rules! foo {
105 () => {}
106 }
107
108 fn main() {
109 <|>
110 }
111 "
112 ),
113 @r###"[
114 CompletionItem {
115 label: "foo!",
116 source_range: [163; 163),
117 delete: [163; 163),
118 insert: "foo! {$0}",
119 kind: Macro,
120 detail: "macro_rules! foo",
121 documentation: Documentation(
122 "Foo\n\nNot call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.\nCall as `let _=foo! { hello world };`",
123 ),
124 },
125 CompletionItem {
126 label: "main()",
127 source_range: [163; 163),
128 delete: [163; 163),
129 insert: "main()$0",
130 kind: Function,
131 lookup: "main",
132 detail: "fn main()",
133 },
134]
135 "###
136 );
137 }
80} 138}
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index e01197fe4..23dece73c 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -375,19 +375,22 @@ mod tests {
375 fn foo() { let _ = S::<|> } 375 fn foo() { let _ = S::<|> }
376 " 376 "
377 ), 377 ),
378 @r###"[ 378 @r###"
379 CompletionItem { 379 [
380 label: "m", 380 CompletionItem {
381 source_range: [100; 100), 381 label: "m()",
382 delete: [100; 100), 382 source_range: [100; 100),
383 insert: "m()$0", 383 delete: [100; 100),
384 kind: Function, 384 insert: "m()$0",
385 detail: "fn m()", 385 kind: Function,
386 documentation: Documentation( 386 lookup: "m",
387 "An associated method", 387 detail: "fn m()",
388 ), 388 documentation: Documentation(
389 }, 389 "An associated method",
390]"### 390 ),
391 },
392 ]
393 "###
391 ); 394 );
392 } 395 }
393 396
@@ -474,19 +477,22 @@ mod tests {
474 fn foo() { let _ = S::<|> } 477 fn foo() { let _ = S::<|> }
475 " 478 "
476 ), 479 ),
477 @r###"[ 480 @r###"
478 CompletionItem { 481 [
479 label: "m", 482 CompletionItem {
480 source_range: [100; 100), 483 label: "m()",
481 delete: [100; 100), 484 source_range: [100; 100),
482 insert: "m()$0", 485 delete: [100; 100),
483 kind: Function, 486 insert: "m()$0",
484 detail: "fn m()", 487 kind: Function,
485 documentation: Documentation( 488 lookup: "m",
486 "An associated method", 489 detail: "fn m()",
487 ), 490 documentation: Documentation(
488 }, 491 "An associated method",
489]"### 492 ),
493 },
494 ]
495 "###
490 ); 496 );
491 } 497 }
492 498
@@ -507,19 +513,22 @@ mod tests {
507 fn foo() { let _ = U::<|> } 513 fn foo() { let _ = U::<|> }
508 " 514 "
509 ), 515 ),
510 @r###"[ 516 @r###"
511 CompletionItem { 517 [
512 label: "m", 518 CompletionItem {
513 source_range: [101; 101), 519 label: "m()",
514 delete: [101; 101), 520 source_range: [101; 101),
515 insert: "m()$0", 521 delete: [101; 101),
516 kind: Function, 522 insert: "m()$0",
517 detail: "fn m()", 523 kind: Function,
518 documentation: Documentation( 524 lookup: "m",
519 "An associated method", 525 detail: "fn m()",
520 ), 526 documentation: Documentation(
521 }, 527 "An associated method",
522]"### 528 ),
529 },
530 ]
531 "###
523 ); 532 );
524 } 533 }
525 534
@@ -564,24 +573,28 @@ mod tests {
564 } 573 }
565 " 574 "
566 ), 575 ),
567 @r###"[ 576 @r###"
568 CompletionItem { 577 [
569 label: "bar", 578 CompletionItem {
570 source_range: [185; 185), 579 label: "bar()",
571 delete: [185; 185), 580 source_range: [185; 185),
572 insert: "bar()$0", 581 delete: [185; 185),
573 kind: Function, 582 insert: "bar()$0",
574 detail: "fn bar()", 583 kind: Function,
575 }, 584 lookup: "bar",
576 CompletionItem { 585 detail: "fn bar()",
577 label: "foo", 586 },
578 source_range: [185; 185), 587 CompletionItem {
579 delete: [185; 185), 588 label: "foo()",
580 insert: "foo()$0", 589 source_range: [185; 185),
581 kind: Function, 590 delete: [185; 185),
582 detail: "fn foo()", 591 insert: "foo()$0",
583 }, 592 kind: Function,
584]"### 593 lookup: "foo",
594 detail: "fn foo()",
595 },
596 ]
597 "###
585 ); 598 );
586 } 599 }
587 600
@@ -600,24 +613,27 @@ mod tests {
600 } 613 }
601 " 614 "
602 ), 615 ),
603 @r###"[ 616 @r###"
604 CompletionItem { 617 [
605 label: "foo!", 618 CompletionItem {
606 source_range: [179; 179), 619 label: "foo!",
607 delete: [179; 179), 620 source_range: [179; 179),
608 insert: "foo!($0)", 621 delete: [179; 179),
609 kind: Macro, 622 insert: "foo!($0)",
610 detail: "#[macro_export]\nmacro_rules! foo", 623 kind: Macro,
611 }, 624 detail: "#[macro_export]\nmacro_rules! foo",
612 CompletionItem { 625 },
613 label: "main", 626 CompletionItem {
614 source_range: [179; 179), 627 label: "main()",
615 delete: [179; 179), 628 source_range: [179; 179),
616 insert: "main()$0", 629 delete: [179; 179),
617 kind: Function, 630 insert: "main()$0",
618 detail: "fn main()", 631 kind: Function,
619 }, 632 lookup: "main",
620]"### 633 detail: "fn main()",
634 },
635 ]
636 "###
621 ); 637 );
622 } 638 }
623} 639}
diff --git a/crates/ra_ide_api/src/completion/complete_postfix.rs b/crates/ra_ide_api/src/completion/complete_postfix.rs
index 445a02676..555cecb73 100644
--- a/crates/ra_ide_api/src/completion/complete_postfix.rs
+++ b/crates/ra_ide_api/src/completion/complete_postfix.rs
@@ -8,7 +8,7 @@ use crate::{
8 CompletionItem, 8 CompletionItem,
9}; 9};
10use hir::{Ty, TypeCtor}; 10use hir::{Ty, TypeCtor};
11use ra_syntax::{ast::AstNode, TextRange}; 11use ra_syntax::{ast::AstNode, TextRange, TextUnit};
12use ra_text_edit::TextEditBuilder; 12use ra_text_edit::TextEditBuilder;
13 13
14fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder { 14fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder {
@@ -42,7 +42,13 @@ fn is_bool_or_unknown(ty: Option<Ty>) -> bool {
42 42
43pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { 43pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
44 if let Some(dot_receiver) = &ctx.dot_receiver { 44 if let Some(dot_receiver) = &ctx.dot_receiver {
45 let receiver_text = dot_receiver.syntax().text().to_string(); 45 let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal {
46 let text = dot_receiver.syntax().text();
47 let without_dot = ..text.len() - TextUnit::of_char('.');
48 text.slice(without_dot).to_string()
49 } else {
50 dot_receiver.syntax().text().to_string()
51 };
46 let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver); 52 let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver);
47 if is_bool_or_unknown(receiver_ty) { 53 if is_bool_or_unknown(receiver_ty) {
48 postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text)) 54 postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text))
@@ -209,4 +215,61 @@ mod tests {
209]"### 215]"###
210 ); 216 );
211 } 217 }
218
219 #[test]
220 fn postfix_completion_works_for_ambiguous_float_literal() {
221 assert_debug_snapshot!(
222 do_postfix_completion(
223 r#"
224 fn main() {
225 42.<|>
226 }
227 "#,
228 ),
229 @r###"[
230 CompletionItem {
231 label: "box",
232 source_range: [52; 52),
233 delete: [49; 52),
234 insert: "Box::new(42)",
235 detail: "Box::new(expr)",
236 },
237 CompletionItem {
238 label: "dbg",
239 source_range: [52; 52),
240 delete: [49; 52),
241 insert: "dbg!(42)",
242 detail: "dbg!(expr)",
243 },
244 CompletionItem {
245 label: "match",
246 source_range: [52; 52),
247 delete: [49; 52),
248 insert: "match 42 {\n ${1:_} => {$0\\},\n}",
249 detail: "match expr {}",
250 },
251 CompletionItem {
252 label: "not",
253 source_range: [52; 52),
254 delete: [49; 52),
255 insert: "!42",
256 detail: "!expr",
257 },
258 CompletionItem {
259 label: "ref",
260 source_range: [52; 52),
261 delete: [49; 52),
262 insert: "&42",
263 detail: "&expr",
264 },
265 CompletionItem {
266 label: "refm",
267 source_range: [52; 52),
268 delete: [49; 52),
269 insert: "&mut 42",
270 detail: "&mut expr",
271 },
272]"###
273 );
274 }
212} 275}
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index 515a6285c..4e56de3f5 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -145,32 +145,35 @@ mod tests {
145 } 145 }
146 " 146 "
147 ), 147 ),
148 @r###"[ 148 @r###"
149 CompletionItem { 149 [
150 label: "quux", 150 CompletionItem {
151 source_range: [91; 91), 151 label: "quux(…)",
152 delete: [91; 91), 152 source_range: [91; 91),
153 insert: "quux($0)", 153 delete: [91; 91),
154 kind: Function, 154 insert: "quux($0)",
155 detail: "fn quux(x: i32)", 155 kind: Function,
156 }, 156 lookup: "quux",
157 CompletionItem { 157 detail: "fn quux(x: i32)",
158 label: "x", 158 },
159 source_range: [91; 91), 159 CompletionItem {
160 delete: [91; 91), 160 label: "x",
161 insert: "x", 161 source_range: [91; 91),
162 kind: Binding, 162 delete: [91; 91),
163 detail: "i32", 163 insert: "x",
164 }, 164 kind: Binding,
165 CompletionItem { 165 detail: "i32",
166 label: "y", 166 },
167 source_range: [91; 91), 167 CompletionItem {
168 delete: [91; 91), 168 label: "y",
169 insert: "y", 169 source_range: [91; 91),
170 kind: Binding, 170 delete: [91; 91),
171 detail: "i32", 171 insert: "y",
172 }, 172 kind: Binding,
173]"### 173 detail: "i32",
174 },
175 ]
176 "###
174 ); 177 );
175 } 178 }
176 179
@@ -190,31 +193,34 @@ mod tests {
190 } 193 }
191 " 194 "
192 ), 195 ),
193 @r###"[ 196 @r###"
194 CompletionItem { 197 [
195 label: "a", 198 CompletionItem {
196 source_range: [242; 242), 199 label: "a",
197 delete: [242; 242), 200 source_range: [242; 242),
198 insert: "a", 201 delete: [242; 242),
199 kind: Binding, 202 insert: "a",
200 }, 203 kind: Binding,
201 CompletionItem { 204 },
202 label: "b", 205 CompletionItem {
203 source_range: [242; 242), 206 label: "b",
204 delete: [242; 242), 207 source_range: [242; 242),
205 insert: "b", 208 delete: [242; 242),
206 kind: Binding, 209 insert: "b",
207 detail: "i32", 210 kind: Binding,
208 }, 211 detail: "i32",
209 CompletionItem { 212 },
210 label: "quux", 213 CompletionItem {
211 source_range: [242; 242), 214 label: "quux()",
212 delete: [242; 242), 215 source_range: [242; 242),
213 insert: "quux()$0", 216 delete: [242; 242),
214 kind: Function, 217 insert: "quux()$0",
215 detail: "fn quux()", 218 kind: Function,
216 }, 219 lookup: "quux",
217]"### 220 detail: "fn quux()",
221 },
222 ]
223 "###
218 ); 224 );
219 } 225 }
220 226
@@ -230,23 +236,26 @@ mod tests {
230 } 236 }
231 " 237 "
232 ), 238 ),
233 @r###"[ 239 @r###"
234 CompletionItem { 240 [
235 label: "quux", 241 CompletionItem {
236 source_range: [95; 95), 242 label: "quux()",
237 delete: [95; 95), 243 source_range: [95; 95),
238 insert: "quux()$0", 244 delete: [95; 95),
239 kind: Function, 245 insert: "quux()$0",
240 detail: "fn quux()", 246 kind: Function,
241 }, 247 lookup: "quux",
242 CompletionItem { 248 detail: "fn quux()",
243 label: "x", 249 },
244 source_range: [95; 95), 250 CompletionItem {
245 delete: [95; 95), 251 label: "x",
246 insert: "x", 252 source_range: [95; 95),
247 kind: Binding, 253 delete: [95; 95),
248 }, 254 insert: "x",
249]"### 255 kind: Binding,
256 },
257 ]
258 "###
250 ); 259 );
251 } 260 }
252 261
@@ -260,23 +269,26 @@ mod tests {
260 } 269 }
261 " 270 "
262 ), 271 ),
263 @r###"[ 272 @r###"
264 CompletionItem { 273 [
265 label: "T", 274 CompletionItem {
266 source_range: [52; 52), 275 label: "T",
267 delete: [52; 52), 276 source_range: [52; 52),
268 insert: "T", 277 delete: [52; 52),
269 kind: TypeParam, 278 insert: "T",
270 }, 279 kind: TypeParam,
271 CompletionItem { 280 },
272 label: "quux", 281 CompletionItem {
273 source_range: [52; 52), 282 label: "quux()",
274 delete: [52; 52), 283 source_range: [52; 52),
275 insert: "quux()$0", 284 delete: [52; 52),
276 kind: Function, 285 insert: "quux()$0",
277 detail: "fn quux<T>()", 286 kind: Function,
278 }, 287 lookup: "quux",
279]"### 288 detail: "fn quux<T>()",
289 },
290 ]
291 "###
280 ); 292 );
281 } 293 }
282 294
@@ -290,22 +302,56 @@ mod tests {
290 } 302 }
291 " 303 "
292 ), 304 ),
293 @r###"[ 305 @r###"
294 CompletionItem { 306 [
295 label: "T", 307 CompletionItem {
296 source_range: [54; 54), 308 label: "T",
297 delete: [54; 54), 309 source_range: [54; 54),
298 insert: "T", 310 delete: [54; 54),
299 kind: TypeParam, 311 insert: "T",
300 }, 312 kind: TypeParam,
301 CompletionItem { 313 },
302 label: "X", 314 CompletionItem {
303 source_range: [54; 54), 315 label: "X<…>",
304 delete: [54; 54), 316 source_range: [54; 54),
305 insert: "X", 317 delete: [54; 54),
306 kind: Struct, 318 insert: "X<$0>",
307 }, 319 kind: Struct,
308]"### 320 lookup: "X",
321 },
322 ]
323 "###
324 );
325 }
326
327 #[test]
328 fn completes_self_in_enum() {
329 assert_debug_snapshot!(
330 do_reference_completion(
331 r"
332 enum X {
333 Y(<|>)
334 }
335 "
336 ),
337 @r###"
338 [
339 CompletionItem {
340 label: "Self",
341 source_range: [48; 48),
342 delete: [48; 48),
343 insert: "Self",
344 kind: TypeParam,
345 },
346 CompletionItem {
347 label: "X",
348 source_range: [48; 48),
349 delete: [48; 48),
350 insert: "X",
351 kind: Enum,
352 },
353 ]
354 "###
309 ); 355 );
310 } 356 }
311 357
@@ -321,30 +367,33 @@ mod tests {
321 } 367 }
322 " 368 "
323 ), 369 ),
324 @r###"[ 370 @r###"
325 CompletionItem { 371 [
326 label: "Baz", 372 CompletionItem {
327 source_range: [105; 105), 373 label: "Baz",
328 delete: [105; 105), 374 source_range: [105; 105),
329 insert: "Baz", 375 delete: [105; 105),
330 kind: Enum, 376 insert: "Baz",
331 }, 377 kind: Enum,
332 CompletionItem { 378 },
333 label: "Foo", 379 CompletionItem {
334 source_range: [105; 105), 380 label: "Foo",
335 delete: [105; 105), 381 source_range: [105; 105),
336 insert: "Foo", 382 delete: [105; 105),
337 kind: Struct, 383 insert: "Foo",
338 }, 384 kind: Struct,
339 CompletionItem { 385 },
340 label: "quux", 386 CompletionItem {
341 source_range: [105; 105), 387 label: "quux()",
342 delete: [105; 105), 388 source_range: [105; 105),
343 insert: "quux()$0", 389 delete: [105; 105),
344 kind: Function, 390 insert: "quux()$0",
345 detail: "fn quux()", 391 kind: Function,
346 }, 392 lookup: "quux",
347]"### 393 detail: "fn quux()",
394 },
395 ]
396 "###
348 ); 397 );
349 } 398 }
350 399
@@ -384,23 +433,26 @@ mod tests {
384 } 433 }
385 " 434 "
386 ), 435 ),
387 @r###"[ 436 @r###"
388 CompletionItem { 437 [
389 label: "Bar", 438 CompletionItem {
390 source_range: [117; 117), 439 label: "Bar",
391 delete: [117; 117), 440 source_range: [117; 117),
392 insert: "Bar", 441 delete: [117; 117),
393 kind: Struct, 442 insert: "Bar",
394 }, 443 kind: Struct,
395 CompletionItem { 444 },
396 label: "quux", 445 CompletionItem {
397 source_range: [117; 117), 446 label: "quux()",
398 delete: [117; 117), 447 source_range: [117; 117),
399 insert: "quux()$0", 448 delete: [117; 117),
400 kind: Function, 449 insert: "quux()$0",
401 detail: "fn quux()", 450 kind: Function,
402 }, 451 lookup: "quux",
403]"### 452 detail: "fn quux()",
453 },
454 ]
455 "###
404 ); 456 );
405 } 457 }
406 458
@@ -413,23 +465,26 @@ mod tests {
413 fn x() -> <|> 465 fn x() -> <|>
414 " 466 "
415 ), 467 ),
416 @r###"[ 468 @r###"
417 CompletionItem { 469 [
418 label: "Foo", 470 CompletionItem {
419 source_range: [55; 55), 471 label: "Foo",
420 delete: [55; 55), 472 source_range: [55; 55),
421 insert: "Foo", 473 delete: [55; 55),
422 kind: Struct, 474 insert: "Foo",
423 }, 475 kind: Struct,
424 CompletionItem { 476 },
425 label: "x", 477 CompletionItem {
426 source_range: [55; 55), 478 label: "x()",
427 delete: [55; 55), 479 source_range: [55; 55),
428 insert: "x()$0", 480 delete: [55; 55),
429 kind: Function, 481 insert: "x()$0",
430 detail: "fn x()", 482 kind: Function,
431 }, 483 lookup: "x",
432]"### 484 detail: "fn x()",
485 },
486 ]
487 "###
433 ); 488 );
434 } 489 }
435 490
@@ -447,24 +502,27 @@ mod tests {
447 } 502 }
448 " 503 "
449 ), 504 ),
450 @r###"[ 505 @r###"
451 CompletionItem { 506 [
452 label: "bar", 507 CompletionItem {
453 source_range: [146; 146), 508 label: "bar",
454 delete: [146; 146), 509 source_range: [146; 146),
455 insert: "bar", 510 delete: [146; 146),
456 kind: Binding, 511 insert: "bar",
457 detail: "i32", 512 kind: Binding,
458 }, 513 detail: "i32",
459 CompletionItem { 514 },
460 label: "foo", 515 CompletionItem {
461 source_range: [146; 146), 516 label: "foo()",
462 delete: [146; 146), 517 source_range: [146; 146),
463 insert: "foo()$0", 518 delete: [146; 146),
464 kind: Function, 519 insert: "foo()$0",
465 detail: "fn foo()", 520 kind: Function,
466 }, 521 lookup: "foo",
467]"### 522 detail: "fn foo()",
523 },
524 ]
525 "###
468 ); 526 );
469 } 527 }
470 528
@@ -509,30 +567,33 @@ mod tests {
509 } 567 }
510 " 568 "
511 ), 569 ),
512 @r#"[ 570 @r###"
513 CompletionItem { 571 [
514 label: "Option", 572 CompletionItem {
515 source_range: [18; 18), 573 label: "Option",
516 delete: [18; 18), 574 source_range: [18; 18),
517 insert: "Option", 575 delete: [18; 18),
518 kind: Struct, 576 insert: "Option",
519 }, 577 kind: Struct,
520 CompletionItem { 578 },
521 label: "foo", 579 CompletionItem {
522 source_range: [18; 18), 580 label: "foo()",
523 delete: [18; 18), 581 source_range: [18; 18),
524 insert: "foo()$0", 582 delete: [18; 18),
525 kind: Function, 583 insert: "foo()$0",
526 detail: "fn foo()", 584 kind: Function,
527 }, 585 lookup: "foo",
528 CompletionItem { 586 detail: "fn foo()",
529 label: "std", 587 },
530 source_range: [18; 18), 588 CompletionItem {
531 delete: [18; 18), 589 label: "std",
532 insert: "std", 590 source_range: [18; 18),
533 kind: Module, 591 delete: [18; 18),
534 }, 592 insert: "std",
535]"# 593 kind: Module,
594 },
595 ]
596 "###
536 ); 597 );
537 } 598 }
538 599
@@ -569,54 +630,57 @@ mod tests {
569 } 630 }
570 " 631 "
571 ), 632 ),
572 @r##"[ 633 @r###"
573 CompletionItem { 634 [
574 label: "bar!", 635 CompletionItem {
575 source_range: [252; 252), 636 label: "bar!",
576 delete: [252; 252), 637 source_range: [252; 252),
577 insert: "bar!($0)", 638 delete: [252; 252),
578 kind: Macro, 639 insert: "bar!($0)",
579 detail: "macro_rules! bar", 640 kind: Macro,
580 }, 641 detail: "macro_rules! bar",
581 CompletionItem { 642 },
582 label: "baz!", 643 CompletionItem {
583 source_range: [252; 252), 644 label: "baz!",
584 delete: [252; 252), 645 source_range: [252; 252),
585 insert: "baz!($0)", 646 delete: [252; 252),
586 kind: Macro, 647 insert: "baz!($0)",
587 detail: "#[macro_export]\nmacro_rules! baz", 648 kind: Macro,
588 }, 649 detail: "#[macro_export]\nmacro_rules! baz",
589 CompletionItem { 650 },
590 label: "foo!", 651 CompletionItem {
591 source_range: [252; 252), 652 label: "foo!",
592 delete: [252; 252), 653 source_range: [252; 252),
593 insert: "foo!($0)", 654 delete: [252; 252),
594 kind: Macro, 655 insert: "foo!($0)",
595 detail: "macro_rules! foo", 656 kind: Macro,
596 }, 657 detail: "macro_rules! foo",
597 CompletionItem { 658 },
598 label: "m1", 659 CompletionItem {
599 source_range: [252; 252), 660 label: "m1",
600 delete: [252; 252), 661 source_range: [252; 252),
601 insert: "m1", 662 delete: [252; 252),
602 kind: Module, 663 insert: "m1",
603 }, 664 kind: Module,
604 CompletionItem { 665 },
605 label: "m2", 666 CompletionItem {
606 source_range: [252; 252), 667 label: "m2",
607 delete: [252; 252), 668 source_range: [252; 252),
608 insert: "m2", 669 delete: [252; 252),
609 kind: Module, 670 insert: "m2",
610 }, 671 kind: Module,
611 CompletionItem { 672 },
612 label: "main", 673 CompletionItem {
613 source_range: [252; 252), 674 label: "main()",
614 delete: [252; 252), 675 source_range: [252; 252),
615 insert: "main()$0", 676 delete: [252; 252),
616 kind: Function, 677 insert: "main()$0",
617 detail: "fn main()", 678 kind: Function,
618 }, 679 lookup: "main",
619]"## 680 detail: "fn main()",
681 },
682 ]
683 "###
620 ); 684 );
621 } 685 }
622 686
@@ -635,24 +699,27 @@ mod tests {
635 } 699 }
636 " 700 "
637 ), 701 ),
638 @r##"[ 702 @r###"
639 CompletionItem { 703 [
640 label: "foo", 704 CompletionItem {
641 source_range: [49; 49), 705 label: "foo!",
642 delete: [49; 49), 706 source_range: [49; 49),
643 insert: "foo()$0", 707 delete: [49; 49),
644 kind: Function, 708 insert: "foo!($0)",
645 detail: "fn foo()", 709 kind: Macro,
646 }, 710 detail: "macro_rules! foo",
647 CompletionItem { 711 },
648 label: "foo!", 712 CompletionItem {
649 source_range: [49; 49), 713 label: "foo()",
650 delete: [49; 49), 714 source_range: [49; 49),
651 insert: "foo!($0)", 715 delete: [49; 49),
652 kind: Macro, 716 insert: "foo()$0",
653 detail: "macro_rules! foo", 717 kind: Function,
654 }, 718 lookup: "foo",
655]"## 719 detail: "fn foo()",
720 },
721 ]
722 "###
656 ); 723 );
657 } 724 }
658 725
@@ -671,24 +738,27 @@ mod tests {
671 } 738 }
672 " 739 "
673 ), 740 ),
674 @r##"[ 741 @r###"
675 CompletionItem { 742 [
676 label: "foo!", 743 CompletionItem {
677 source_range: [57; 57), 744 label: "foo!",
678 delete: [57; 57), 745 source_range: [57; 57),
679 insert: "foo!($0)", 746 delete: [57; 57),
680 kind: Macro, 747 insert: "foo!($0)",
681 detail: "macro_rules! foo", 748 kind: Macro,
682 }, 749 detail: "macro_rules! foo",
683 CompletionItem { 750 },
684 label: "main", 751 CompletionItem {
685 source_range: [57; 57), 752 label: "main()",
686 delete: [57; 57), 753 source_range: [57; 57),
687 insert: "main()$0", 754 delete: [57; 57),
688 kind: Function, 755 insert: "main()$0",
689 detail: "fn main()", 756 kind: Function,
690 }, 757 lookup: "main",
691]"## 758 detail: "fn main()",
759 },
760 ]
761 "###
692 ); 762 );
693 } 763 }
694 764
@@ -707,24 +777,27 @@ mod tests {
707 } 777 }
708 " 778 "
709 ), 779 ),
710 @r##"[ 780 @r###"
711 CompletionItem { 781 [
712 label: "foo!", 782 CompletionItem {
713 source_range: [50; 50), 783 label: "foo!",
714 delete: [50; 50), 784 source_range: [50; 50),
715 insert: "foo!($0)", 785 delete: [50; 50),
716 kind: Macro, 786 insert: "foo!($0)",
717 detail: "macro_rules! foo", 787 kind: Macro,
718 }, 788 detail: "macro_rules! foo",
719 CompletionItem { 789 },
720 label: "main", 790 CompletionItem {
721 source_range: [50; 50), 791 label: "main()",
722 delete: [50; 50), 792 source_range: [50; 50),
723 insert: "main()$0", 793 delete: [50; 50),
724 kind: Function, 794 insert: "main()$0",
725 detail: "fn main()", 795 kind: Function,
726 }, 796 lookup: "main",
727]"## 797 detail: "fn main()",
798 },
799 ]
800 "###
728 ); 801 );
729 } 802 }
730} 803}
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs
index e9ad06965..64cbc0f98 100644
--- a/crates/ra_ide_api/src/completion/completion_context.rs
+++ b/crates/ra_ide_api/src/completion/completion_context.rs
@@ -38,8 +38,11 @@ pub(crate) struct CompletionContext<'a> {
38 pub(super) is_new_item: bool, 38 pub(super) is_new_item: bool,
39 /// The receiver if this is a field or method access, i.e. writing something.<|> 39 /// The receiver if this is a field or method access, i.e. writing something.<|>
40 pub(super) dot_receiver: Option<ast::Expr>, 40 pub(super) dot_receiver: Option<ast::Expr>,
41 pub(super) dot_receiver_is_ambiguous_float_literal: bool,
41 /// If this is a call (method or function) in particular, i.e. the () are already there. 42 /// If this is a call (method or function) in particular, i.e. the () are already there.
42 pub(super) is_call: bool, 43 pub(super) is_call: bool,
44 pub(super) is_path_type: bool,
45 pub(super) has_type_args: bool,
43} 46}
44 47
45impl<'a> CompletionContext<'a> { 48impl<'a> CompletionContext<'a> {
@@ -76,6 +79,9 @@ impl<'a> CompletionContext<'a> {
76 is_new_item: false, 79 is_new_item: false,
77 dot_receiver: None, 80 dot_receiver: None,
78 is_call: false, 81 is_call: false,
82 is_path_type: false,
83 has_type_args: false,
84 dot_receiver_is_ambiguous_float_literal: false,
79 }; 85 };
80 ctx.fill(&original_parse, position.offset); 86 ctx.fill(&original_parse, position.offset);
81 Some(ctx) 87 Some(ctx)
@@ -176,6 +182,9 @@ impl<'a> CompletionContext<'a> {
176 .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast)) 182 .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast))
177 .is_some(); 183 .is_some();
178 184
185 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
186 self.has_type_args = segment.type_arg_list().is_some();
187
179 if let Some(mut path) = hir::Path::from_ast(path.clone()) { 188 if let Some(mut path) = hir::Path::from_ast(path.clone()) {
180 if !path.is_ident() { 189 if !path.is_ident() {
181 path.segments.pop().unwrap(); 190 path.segments.pop().unwrap();
@@ -228,6 +237,16 @@ impl<'a> CompletionContext<'a> {
228 .expr() 237 .expr()
229 .map(|e| e.syntax().text_range()) 238 .map(|e| e.syntax().text_range())
230 .and_then(|r| find_node_with_range(original_file.syntax(), r)); 239 .and_then(|r| find_node_with_range(original_file.syntax(), r));
240 self.dot_receiver_is_ambiguous_float_literal = if let Some(ast::Expr::Literal(l)) =
241 &self.dot_receiver
242 {
243 match l.kind() {
244 ast::LiteralKind::FloatNumber { suffix: _ } => l.token().text().ends_with('.'),
245 _ => false,
246 }
247 } else {
248 false
249 }
231 } 250 }
232 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { 251 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
233 // As above 252 // As above
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs
index b1f0390ec..3e6933bc1 100644
--- a/crates/ra_ide_api/src/completion/completion_item.rs
+++ b/crates/ra_ide_api/src/completion/completion_item.rs
@@ -216,6 +216,10 @@ impl Builder {
216 self.lookup = Some(lookup.into()); 216 self.lookup = Some(lookup.into());
217 self 217 self
218 } 218 }
219 pub(crate) fn label(mut self, label: impl Into<String>) -> Builder {
220 self.label = label.into();
221 self
222 }
219 pub(crate) fn insert_text(mut self, insert_text: impl Into<String>) -> Builder { 223 pub(crate) fn insert_text(mut self, insert_text: impl Into<String>) -> Builder {
220 self.insert_text = Some(insert_text.into()); 224 self.insert_text = Some(insert_text.into());
221 self 225 self
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index 48028a2f9..aed4ce6d4 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -1,12 +1,12 @@
1//! This modules takes care of rendering various definitions as completion items. 1//! This modules takes care of rendering various definitions as completion items.
2 2
3use hir::{Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; 3use hir::{db::HirDatabase, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk};
4use join_to_string::join; 4use join_to_string::join;
5use ra_syntax::ast::NameOwner; 5use ra_syntax::ast::NameOwner;
6use test_utils::tested_by; 6use test_utils::tested_by;
7 7
8use crate::completion::{ 8use crate::completion::{
9 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 9 db, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
10}; 10};
11 11
12use crate::display::{const_label, function_label, macro_label, type_label}; 12use crate::display::{const_label, function_label, macro_label, type_label};
@@ -44,54 +44,56 @@ impl Completions {
44 ) { 44 ) {
45 use hir::ModuleDef::*; 45 use hir::ModuleDef::*;
46 46
47 let mut completion_kind = CompletionKind::Reference; 47 let completion_kind = match resolution {
48 let (kind, docs) = match resolution { 48 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
49 ScopeDef::ModuleDef(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)), 49 _ => CompletionKind::Reference,
50 };
51
52 let kind = match resolution {
53 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module,
50 ScopeDef::ModuleDef(Function(func)) => { 54 ScopeDef::ModuleDef(Function(func)) => {
51 return self.add_function_with_name(ctx, Some(local_name), *func); 55 return self.add_function_with_name(ctx, Some(local_name), *func);
52 } 56 }
53 ScopeDef::ModuleDef(Adt(hir::Adt::Struct(it))) => { 57 ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct,
54 (CompletionItemKind::Struct, it.docs(ctx.db)) 58 // FIXME: add CompletionItemKind::Union
55 } 59 ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct,
56 ScopeDef::ModuleDef(Adt(hir::Adt::Union(it))) => { 60 ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum,
57 (CompletionItemKind::Struct, it.docs(ctx.db)) 61
58 } 62 ScopeDef::ModuleDef(EnumVariant(..)) => CompletionItemKind::EnumVariant,
59 ScopeDef::ModuleDef(Adt(hir::Adt::Enum(it))) => { 63 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const,
60 (CompletionItemKind::Enum, it.docs(ctx.db)) 64 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static,
61 } 65 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait,
62 ScopeDef::ModuleDef(EnumVariant(it)) => { 66 ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias,
63 (CompletionItemKind::EnumVariant, it.docs(ctx.db)) 67 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
64 } 68 ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam,
65 ScopeDef::ModuleDef(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)), 69 ScopeDef::LocalBinding(..) => CompletionItemKind::Binding,
66 ScopeDef::ModuleDef(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)), 70 // (does this need its own kind?)
67 ScopeDef::ModuleDef(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)), 71 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam,
68 ScopeDef::ModuleDef(TypeAlias(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)),
69 ScopeDef::ModuleDef(BuiltinType(..)) => {
70 completion_kind = CompletionKind::BuiltinType;
71 (CompletionItemKind::BuiltinType, None)
72 }
73 ScopeDef::GenericParam(..) => (CompletionItemKind::TypeParam, None),
74 ScopeDef::LocalBinding(..) => (CompletionItemKind::Binding, None),
75 ScopeDef::SelfType(..) => (
76 CompletionItemKind::TypeParam, // (does this need its own kind?)
77 None,
78 ),
79 ScopeDef::MacroDef(mac) => { 72 ScopeDef::MacroDef(mac) => {
80 self.add_macro(ctx, Some(local_name), *mac); 73 return self.add_macro(ctx, Some(local_name), *mac);
81 return;
82 } 74 }
83 ScopeDef::Unknown => { 75 ScopeDef::Unknown => {
84 self.add(CompletionItem::new( 76 return self.add(CompletionItem::new(
85 CompletionKind::Reference, 77 CompletionKind::Reference,
86 ctx.source_range(), 78 ctx.source_range(),
87 local_name, 79 local_name,
88 )); 80 ));
89 return;
90 } 81 }
91 }; 82 };
92 83
84 let docs = match resolution {
85 ScopeDef::ModuleDef(Module(it)) => it.docs(ctx.db),
86 ScopeDef::ModuleDef(Adt(it)) => it.docs(ctx.db),
87 ScopeDef::ModuleDef(EnumVariant(it)) => it.docs(ctx.db),
88 ScopeDef::ModuleDef(Const(it)) => it.docs(ctx.db),
89 ScopeDef::ModuleDef(Static(it)) => it.docs(ctx.db),
90 ScopeDef::ModuleDef(Trait(it)) => it.docs(ctx.db),
91 ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(ctx.db),
92 _ => None,
93 };
94
93 let mut completion_item = 95 let mut completion_item =
94 CompletionItem::new(completion_kind, ctx.source_range(), local_name); 96 CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
95 if let ScopeDef::LocalBinding(pat_id) = resolution { 97 if let ScopeDef::LocalBinding(pat_id) = resolution {
96 let ty = ctx 98 let ty = ctx
97 .analyzer 99 .analyzer
@@ -100,6 +102,28 @@ impl Completions {
100 .map(|t| t.display(ctx.db).to_string()); 102 .map(|t| t.display(ctx.db).to_string());
101 completion_item = completion_item.set_detail(ty); 103 completion_item = completion_item.set_detail(ty);
102 }; 104 };
105
106 // If not an import, add parenthesis automatically.
107 if ctx.is_path_type
108 && !ctx.has_type_args
109 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
110 {
111 let generic_def: Option<hir::GenericDef> = match resolution {
112 ScopeDef::ModuleDef(Adt(it)) => Some((*it).into()),
113 ScopeDef::ModuleDef(TypeAlias(it)) => Some((*it).into()),
114 _ => None,
115 };
116 if let Some(def) = generic_def {
117 if has_non_default_type_params(def, ctx.db) {
118 tested_by!(inserts_angle_brackets_for_generics);
119 completion_item = completion_item
120 .lookup_by(local_name.clone())
121 .label(format!("{}<…>", local_name))
122 .insert_snippet(format!("{}<$0>", local_name));
123 }
124 }
125 }
126
103 completion_item.kind(kind).set_documentation(docs).add_to(self) 127 completion_item.kind(kind).set_documentation(docs).add_to(self)
104 } 128 }
105 129
@@ -107,6 +131,33 @@ impl Completions {
107 self.add_function_with_name(ctx, None, func) 131 self.add_function_with_name(ctx, None, func)
108 } 132 }
109 133
134 fn guess_macro_braces(&self, macro_name: &str, docs: &str) -> &'static str {
135 let mut votes = [0, 0, 0];
136 for (idx, s) in docs.match_indices(&macro_name) {
137 let (before, after) = (&docs[..idx], &docs[idx + s.len()..]);
138 // Ensure to match the full word
139 if after.starts_with("!")
140 && before
141 .chars()
142 .rev()
143 .next()
144 .map_or(true, |c| c != '_' && !c.is_ascii_alphanumeric())
145 {
146 // It may have spaces before the braces like `foo! {}`
147 match after[1..].chars().find(|&c| !c.is_whitespace()) {
148 Some('{') => votes[0] += 1,
149 Some('[') => votes[1] += 1,
150 Some('(') => votes[2] += 1,
151 _ => {}
152 }
153 }
154 }
155
156 // Insert a space before `{}`.
157 // We prefer the last one when some votes equal.
158 *votes.iter().zip(&[" {$0}", "[$0]", "($0)"]).max_by_key(|&(&vote, _)| vote).unwrap().1
159 }
160
110 pub(crate) fn add_macro( 161 pub(crate) fn add_macro(
111 &mut self, 162 &mut self,
112 ctx: &CompletionContext, 163 ctx: &CompletionContext,
@@ -117,10 +168,9 @@ impl Completions {
117 if let Some(name) = name { 168 if let Some(name) = name {
118 let detail = macro_label(&ast_node); 169 let detail = macro_label(&ast_node);
119 170
120 let macro_braces_to_insert = match name.as_str() { 171 let docs = macro_.docs(ctx.db);
121 "vec" => "[$0]", 172 let macro_braces_to_insert =
122 _ => "($0)", 173 self.guess_macro_braces(&name, docs.as_ref().map_or("", |s| s.as_str()));
123 };
124 let macro_declaration = name + "!"; 174 let macro_declaration = name + "!";
125 175
126 let builder = CompletionItem::new( 176 let builder = CompletionItem::new(
@@ -129,7 +179,7 @@ impl Completions {
129 &macro_declaration, 179 &macro_declaration,
130 ) 180 )
131 .kind(CompletionItemKind::Macro) 181 .kind(CompletionItemKind::Macro)
132 .set_documentation(macro_.docs(ctx.db)) 182 .set_documentation(docs)
133 .detail(detail) 183 .detail(detail)
134 .insert_snippet(macro_declaration + macro_braces_to_insert); 184 .insert_snippet(macro_declaration + macro_braces_to_insert);
135 185
@@ -148,28 +198,31 @@ impl Completions {
148 let ast_node = func.source(ctx.db).ast; 198 let ast_node = func.source(ctx.db).ast;
149 let detail = function_label(&ast_node); 199 let detail = function_label(&ast_node);
150 200
151 let mut builder = CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name) 201 let mut builder =
152 .kind(if data.has_self_param() { 202 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone())
153 CompletionItemKind::Method 203 .kind(if data.has_self_param() {
154 } else { 204 CompletionItemKind::Method
155 CompletionItemKind::Function 205 } else {
156 }) 206 CompletionItemKind::Function
157 .set_documentation(func.docs(ctx.db)) 207 })
158 .detail(detail); 208 .set_documentation(func.docs(ctx.db))
159 // If not an import, add parenthesis automatically. 209 .detail(detail);
210
211 // Add `<>` for generic types
160 if ctx.use_item_syntax.is_none() 212 if ctx.use_item_syntax.is_none()
161 && !ctx.is_call 213 && !ctx.is_call
162 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") 214 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
163 { 215 {
164 tested_by!(inserts_parens_for_function_calls); 216 tested_by!(inserts_parens_for_function_calls);
165 let snippet = 217 let (snippet, label) =
166 if data.params().is_empty() || data.has_self_param() && data.params().len() == 1 { 218 if data.params().is_empty() || data.has_self_param() && data.params().len() == 1 {
167 format!("{}()$0", data.name()) 219 (format!("{}()$0", data.name()), format!("{}()", name))
168 } else { 220 } else {
169 format!("{}($0)", data.name()) 221 (format!("{}($0)", data.name()), format!("{}(…)", name))
170 }; 222 };
171 builder = builder.insert_snippet(snippet); 223 builder = builder.lookup_by(name.clone()).label(label).insert_snippet(snippet);
172 } 224 }
225
173 self.add(builder) 226 self.add(builder)
174 } 227 }
175 228
@@ -213,7 +266,6 @@ impl Completions {
213 .separator(", ") 266 .separator(", ")
214 .surround_with("(", ")") 267 .surround_with("(", ")")
215 .to_string(); 268 .to_string();
216
217 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) 269 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
218 .kind(CompletionItemKind::EnumVariant) 270 .kind(CompletionItemKind::EnumVariant)
219 .set_documentation(variant.docs(ctx.db)) 271 .set_documentation(variant.docs(ctx.db))
@@ -222,6 +274,11 @@ impl Completions {
222 } 274 }
223} 275}
224 276
277fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool {
278 let subst = db.generic_defaults(def);
279 subst.iter().any(|ty| ty == &Ty::Unknown)
280}
281
225#[cfg(test)] 282#[cfg(test)]
226mod tests { 283mod tests {
227 use crate::completion::{do_completion, CompletionItem, CompletionKind}; 284 use crate::completion::{do_completion, CompletionItem, CompletionKind};
@@ -242,24 +299,28 @@ mod tests {
242 fn main() { no_<|> } 299 fn main() { no_<|> }
243 " 300 "
244 ), 301 ),
245 @r###"[ 302 @r###"
246 CompletionItem { 303 [
247 label: "main", 304 CompletionItem {
248 source_range: [61; 64), 305 label: "main()",
249 delete: [61; 64), 306 source_range: [61; 64),
250 insert: "main()$0", 307 delete: [61; 64),
251 kind: Function, 308 insert: "main()$0",
252 detail: "fn main()", 309 kind: Function,
253 }, 310 lookup: "main",
254 CompletionItem { 311 detail: "fn main()",
255 label: "no_args", 312 },
256 source_range: [61; 64), 313 CompletionItem {
257 delete: [61; 64), 314 label: "no_args()",
258 insert: "no_args()$0", 315 source_range: [61; 64),
259 kind: Function, 316 delete: [61; 64),
260 detail: "fn no_args()", 317 insert: "no_args()$0",
261 }, 318 kind: Function,
262]"### 319 lookup: "no_args",
320 detail: "fn no_args()",
321 },
322 ]
323 "###
263 ); 324 );
264 assert_debug_snapshot!( 325 assert_debug_snapshot!(
265 do_reference_completion( 326 do_reference_completion(
@@ -268,24 +329,28 @@ mod tests {
268 fn main() { with_<|> } 329 fn main() { with_<|> }
269 " 330 "
270 ), 331 ),
271 @r###"[ 332 @r###"
272 CompletionItem { 333 [
273 label: "main", 334 CompletionItem {
274 source_range: [80; 85), 335 label: "main()",
275 delete: [80; 85), 336 source_range: [80; 85),
276 insert: "main()$0", 337 delete: [80; 85),
277 kind: Function, 338 insert: "main()$0",
278 detail: "fn main()", 339 kind: Function,
279 }, 340 lookup: "main",
280 CompletionItem { 341 detail: "fn main()",
281 label: "with_args", 342 },
282 source_range: [80; 85), 343 CompletionItem {
283 delete: [80; 85), 344 label: "with_args(…)",
284 insert: "with_args($0)", 345 source_range: [80; 85),
285 kind: Function, 346 delete: [80; 85),
286 detail: "fn with_args(x: i32, y: String)", 347 insert: "with_args($0)",
287 }, 348 kind: Function,
288]"### 349 lookup: "with_args",
350 detail: "fn with_args(x: i32, y: String)",
351 },
352 ]
353 "###
289 ); 354 );
290 assert_debug_snapshot!( 355 assert_debug_snapshot!(
291 do_reference_completion( 356 do_reference_completion(
@@ -299,16 +364,19 @@ mod tests {
299 } 364 }
300 " 365 "
301 ), 366 ),
302 @r###"[ 367 @r###"
303 CompletionItem { 368 [
304 label: "foo", 369 CompletionItem {
305 source_range: [163; 164), 370 label: "foo()",
306 delete: [163; 164), 371 source_range: [163; 164),
307 insert: "foo()$0", 372 delete: [163; 164),
308 kind: Method, 373 insert: "foo()$0",
309 detail: "fn foo(&self)", 374 kind: Method,
310 }, 375 lookup: "foo",
311]"### 376 detail: "fn foo(&self)",
377 },
378 ]
379 "###
312 ); 380 );
313 } 381 }
314 382
@@ -389,4 +457,123 @@ mod tests {
389]"# 457]"#
390 ); 458 );
391 } 459 }
460
461 #[test]
462 fn inserts_angle_brackets_for_generics() {
463 covers!(inserts_angle_brackets_for_generics);
464 assert_debug_snapshot!(
465 do_reference_completion(
466 r"
467 struct Vec<T> {}
468 fn foo(xs: Ve<|>)
469 "
470 ),
471 @r###"
472 [
473 CompletionItem {
474 label: "Vec<…>",
475 source_range: [61; 63),
476 delete: [61; 63),
477 insert: "Vec<$0>",
478 kind: Struct,
479 lookup: "Vec",
480 },
481 CompletionItem {
482 label: "foo(…)",
483 source_range: [61; 63),
484 delete: [61; 63),
485 insert: "foo($0)",
486 kind: Function,
487 lookup: "foo",
488 detail: "fn foo(xs: Ve)",
489 },
490 ]
491 "###
492 );
493 assert_debug_snapshot!(
494 do_reference_completion(
495 r"
496 type Vec<T> = (T,);
497 fn foo(xs: Ve<|>)
498 "
499 ),
500 @r###"
501 [
502 CompletionItem {
503 label: "Vec<…>",
504 source_range: [64; 66),
505 delete: [64; 66),
506 insert: "Vec<$0>",
507 kind: TypeAlias,
508 lookup: "Vec",
509 },
510 CompletionItem {
511 label: "foo(…)",
512 source_range: [64; 66),
513 delete: [64; 66),
514 insert: "foo($0)",
515 kind: Function,
516 lookup: "foo",
517 detail: "fn foo(xs: Ve)",
518 },
519 ]
520 "###
521 );
522 assert_debug_snapshot!(
523 do_reference_completion(
524 r"
525 struct Vec<T = i128> {}
526 fn foo(xs: Ve<|>)
527 "
528 ),
529 @r###"
530 [
531 CompletionItem {
532 label: "Vec",
533 source_range: [68; 70),
534 delete: [68; 70),
535 insert: "Vec",
536 kind: Struct,
537 },
538 CompletionItem {
539 label: "foo(…)",
540 source_range: [68; 70),
541 delete: [68; 70),
542 insert: "foo($0)",
543 kind: Function,
544 lookup: "foo",
545 detail: "fn foo(xs: Ve)",
546 },
547 ]
548 "###
549 );
550 assert_debug_snapshot!(
551 do_reference_completion(
552 r"
553 struct Vec<T> {}
554 fn foo(xs: Ve<|><i128>)
555 "
556 ),
557 @r###"
558 [
559 CompletionItem {
560 label: "Vec",
561 source_range: [61; 63),
562 delete: [61; 63),
563 insert: "Vec",
564 kind: Struct,
565 },
566 CompletionItem {
567 label: "foo(…)",
568 source_range: [61; 63),
569 delete: [61; 63),
570 insert: "foo($0)",
571 kind: Function,
572 lookup: "foo",
573 detail: "fn foo(xs: Ve<i128>)",
574 },
575 ]
576 "###
577 );
578 }
392} 579}