diff options
author | Seivan Heidari <[email protected]> | 2019-11-28 07:19:14 +0000 |
---|---|---|
committer | Seivan Heidari <[email protected]> | 2019-11-28 07:19:14 +0000 |
commit | 18a0937585b836ec5ed054b9ae48e0156ab6d9ef (patch) | |
tree | 9de2c0267ddcc00df717f90034d0843d751a851b /crates/ra_ide/src/completion/presentation.rs | |
parent | a7394b44c870f585eacfeb3036a33471aff49ff8 (diff) | |
parent | 484acc8a61d599662ed63a4cbda091d38a982551 (diff) |
Merge branch 'master' of https://github.com/rust-analyzer/rust-analyzer into feature/themes
Diffstat (limited to 'crates/ra_ide/src/completion/presentation.rs')
-rw-r--r-- | crates/ra_ide/src/completion/presentation.rs | 673 |
1 files changed, 673 insertions, 0 deletions
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs new file mode 100644 index 000000000..97475fc0b --- /dev/null +++ b/crates/ra_ide/src/completion/presentation.rs | |||
@@ -0,0 +1,673 @@ | |||
1 | //! This modules takes care of rendering various definitions as completion items. | ||
2 | |||
3 | use hir::{db::HirDatabase, Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, Type}; | ||
4 | use join_to_string::join; | ||
5 | use ra_syntax::ast::NameOwner; | ||
6 | use test_utils::tested_by; | ||
7 | |||
8 | use crate::completion::{ | ||
9 | CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, | ||
10 | }; | ||
11 | |||
12 | use crate::display::{const_label, function_label, macro_label, type_label}; | ||
13 | |||
14 | impl Completions { | ||
15 | pub(crate) fn add_field( | ||
16 | &mut self, | ||
17 | ctx: &CompletionContext, | ||
18 | field: hir::StructField, | ||
19 | ty: &Type, | ||
20 | ) { | ||
21 | let is_deprecated = is_deprecated(field, ctx.db); | ||
22 | CompletionItem::new( | ||
23 | CompletionKind::Reference, | ||
24 | ctx.source_range(), | ||
25 | field.name(ctx.db).to_string(), | ||
26 | ) | ||
27 | .kind(CompletionItemKind::Field) | ||
28 | .detail(ty.display(ctx.db).to_string()) | ||
29 | .set_documentation(field.docs(ctx.db)) | ||
30 | .set_deprecated(is_deprecated) | ||
31 | .add_to(self); | ||
32 | } | ||
33 | |||
34 | pub(crate) fn add_tuple_field(&mut self, ctx: &CompletionContext, field: usize, ty: &Type) { | ||
35 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), field.to_string()) | ||
36 | .kind(CompletionItemKind::Field) | ||
37 | .detail(ty.display(ctx.db).to_string()) | ||
38 | .add_to(self); | ||
39 | } | ||
40 | |||
41 | pub(crate) fn add_resolution( | ||
42 | &mut self, | ||
43 | ctx: &CompletionContext, | ||
44 | local_name: String, | ||
45 | resolution: &ScopeDef, | ||
46 | ) { | ||
47 | use hir::ModuleDef::*; | ||
48 | |||
49 | let completion_kind = match resolution { | ||
50 | ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType, | ||
51 | _ => CompletionKind::Reference, | ||
52 | }; | ||
53 | |||
54 | let kind = match resolution { | ||
55 | ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module, | ||
56 | ScopeDef::ModuleDef(Function(func)) => { | ||
57 | return self.add_function_with_name(ctx, Some(local_name), *func); | ||
58 | } | ||
59 | ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct, | ||
60 | // FIXME: add CompletionItemKind::Union | ||
61 | ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct, | ||
62 | ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum, | ||
63 | |||
64 | ScopeDef::ModuleDef(EnumVariant(..)) => CompletionItemKind::EnumVariant, | ||
65 | ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const, | ||
66 | ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static, | ||
67 | ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait, | ||
68 | ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias, | ||
69 | ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, | ||
70 | ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam, | ||
71 | ScopeDef::Local(..) => CompletionItemKind::Binding, | ||
72 | // (does this need its own kind?) | ||
73 | ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam, | ||
74 | ScopeDef::MacroDef(mac) => { | ||
75 | return self.add_macro(ctx, Some(local_name), *mac); | ||
76 | } | ||
77 | ScopeDef::Unknown => { | ||
78 | return self.add(CompletionItem::new( | ||
79 | CompletionKind::Reference, | ||
80 | ctx.source_range(), | ||
81 | local_name, | ||
82 | )); | ||
83 | } | ||
84 | }; | ||
85 | |||
86 | let docs = match resolution { | ||
87 | ScopeDef::ModuleDef(Module(it)) => it.docs(ctx.db), | ||
88 | ScopeDef::ModuleDef(Adt(it)) => it.docs(ctx.db), | ||
89 | ScopeDef::ModuleDef(EnumVariant(it)) => it.docs(ctx.db), | ||
90 | ScopeDef::ModuleDef(Const(it)) => it.docs(ctx.db), | ||
91 | ScopeDef::ModuleDef(Static(it)) => it.docs(ctx.db), | ||
92 | ScopeDef::ModuleDef(Trait(it)) => it.docs(ctx.db), | ||
93 | ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(ctx.db), | ||
94 | _ => None, | ||
95 | }; | ||
96 | |||
97 | let mut completion_item = | ||
98 | CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone()); | ||
99 | if let ScopeDef::Local(local) = resolution { | ||
100 | let ty = local.ty(ctx.db); | ||
101 | if !ty.is_unknown() { | ||
102 | completion_item = completion_item.detail(ty.display(ctx.db).to_string()); | ||
103 | } | ||
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 has_non_default_type_params = match resolution { | ||
112 | ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), | ||
113 | ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), | ||
114 | _ => false, | ||
115 | }; | ||
116 | if has_non_default_type_params { | ||
117 | tested_by!(inserts_angle_brackets_for_generics); | ||
118 | completion_item = completion_item | ||
119 | .lookup_by(local_name.clone()) | ||
120 | .label(format!("{}<…>", local_name)) | ||
121 | .insert_snippet(format!("{}<$0>", local_name)); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | completion_item.kind(kind).set_documentation(docs).add_to(self) | ||
126 | } | ||
127 | |||
128 | pub(crate) fn add_function(&mut self, ctx: &CompletionContext, func: hir::Function) { | ||
129 | self.add_function_with_name(ctx, None, func) | ||
130 | } | ||
131 | |||
132 | fn guess_macro_braces(&self, macro_name: &str, docs: &str) -> &'static str { | ||
133 | let mut votes = [0, 0, 0]; | ||
134 | for (idx, s) in docs.match_indices(¯o_name) { | ||
135 | let (before, after) = (&docs[..idx], &docs[idx + s.len()..]); | ||
136 | // Ensure to match the full word | ||
137 | if after.starts_with('!') | ||
138 | && before | ||
139 | .chars() | ||
140 | .rev() | ||
141 | .next() | ||
142 | .map_or(true, |c| c != '_' && !c.is_ascii_alphanumeric()) | ||
143 | { | ||
144 | // It may have spaces before the braces like `foo! {}` | ||
145 | match after[1..].chars().find(|&c| !c.is_whitespace()) { | ||
146 | Some('{') => votes[0] += 1, | ||
147 | Some('[') => votes[1] += 1, | ||
148 | Some('(') => votes[2] += 1, | ||
149 | _ => {} | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | |||
154 | // Insert a space before `{}`. | ||
155 | // We prefer the last one when some votes equal. | ||
156 | *votes.iter().zip(&[" {$0}", "[$0]", "($0)"]).max_by_key(|&(&vote, _)| vote).unwrap().1 | ||
157 | } | ||
158 | |||
159 | pub(crate) fn add_macro( | ||
160 | &mut self, | ||
161 | ctx: &CompletionContext, | ||
162 | name: Option<String>, | ||
163 | macro_: hir::MacroDef, | ||
164 | ) { | ||
165 | let name = match name { | ||
166 | Some(it) => it, | ||
167 | None => return, | ||
168 | }; | ||
169 | |||
170 | let ast_node = macro_.source(ctx.db).value; | ||
171 | let detail = macro_label(&ast_node); | ||
172 | |||
173 | let docs = macro_.docs(ctx.db); | ||
174 | let macro_declaration = format!("{}!", name); | ||
175 | |||
176 | let mut builder = | ||
177 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), ¯o_declaration) | ||
178 | .kind(CompletionItemKind::Macro) | ||
179 | .set_documentation(docs.clone()) | ||
180 | .set_deprecated(is_deprecated(macro_, ctx.db)) | ||
181 | .detail(detail); | ||
182 | |||
183 | builder = if ctx.use_item_syntax.is_some() { | ||
184 | builder.insert_text(name) | ||
185 | } else { | ||
186 | let macro_braces_to_insert = | ||
187 | self.guess_macro_braces(&name, docs.as_ref().map_or("", |s| s.as_str())); | ||
188 | builder.insert_snippet(macro_declaration + macro_braces_to_insert) | ||
189 | }; | ||
190 | |||
191 | self.add(builder); | ||
192 | } | ||
193 | |||
194 | fn add_function_with_name( | ||
195 | &mut self, | ||
196 | ctx: &CompletionContext, | ||
197 | name: Option<String>, | ||
198 | func: hir::Function, | ||
199 | ) { | ||
200 | let func_name = func.name(ctx.db); | ||
201 | let has_self_param = func.has_self_param(ctx.db); | ||
202 | let params = func.params(ctx.db); | ||
203 | |||
204 | let name = name.unwrap_or_else(|| func_name.to_string()); | ||
205 | let ast_node = func.source(ctx.db).value; | ||
206 | let detail = function_label(&ast_node); | ||
207 | |||
208 | let mut builder = | ||
209 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()) | ||
210 | .kind(if has_self_param { | ||
211 | CompletionItemKind::Method | ||
212 | } else { | ||
213 | CompletionItemKind::Function | ||
214 | }) | ||
215 | .set_documentation(func.docs(ctx.db)) | ||
216 | .set_deprecated(is_deprecated(func, ctx.db)) | ||
217 | .detail(detail); | ||
218 | |||
219 | // Add `<>` for generic types | ||
220 | if ctx.use_item_syntax.is_none() | ||
221 | && !ctx.is_call | ||
222 | && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") | ||
223 | { | ||
224 | tested_by!(inserts_parens_for_function_calls); | ||
225 | let (snippet, label) = if params.is_empty() || has_self_param && params.len() == 1 { | ||
226 | (format!("{}()$0", func_name), format!("{}()", name)) | ||
227 | } else { | ||
228 | (format!("{}($0)", func_name), format!("{}(…)", name)) | ||
229 | }; | ||
230 | builder = builder.lookup_by(name).label(label).insert_snippet(snippet); | ||
231 | } | ||
232 | |||
233 | self.add(builder) | ||
234 | } | ||
235 | |||
236 | pub(crate) fn add_const(&mut self, ctx: &CompletionContext, constant: hir::Const) { | ||
237 | let ast_node = constant.source(ctx.db).value; | ||
238 | let name = match ast_node.name() { | ||
239 | Some(name) => name, | ||
240 | _ => return, | ||
241 | }; | ||
242 | let detail = const_label(&ast_node); | ||
243 | |||
244 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) | ||
245 | .kind(CompletionItemKind::Const) | ||
246 | .set_documentation(constant.docs(ctx.db)) | ||
247 | .set_deprecated(is_deprecated(constant, ctx.db)) | ||
248 | .detail(detail) | ||
249 | .add_to(self); | ||
250 | } | ||
251 | |||
252 | pub(crate) fn add_type_alias(&mut self, ctx: &CompletionContext, type_alias: hir::TypeAlias) { | ||
253 | let type_def = type_alias.source(ctx.db).value; | ||
254 | let name = match type_def.name() { | ||
255 | Some(name) => name, | ||
256 | _ => return, | ||
257 | }; | ||
258 | let detail = type_label(&type_def); | ||
259 | |||
260 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) | ||
261 | .kind(CompletionItemKind::TypeAlias) | ||
262 | .set_documentation(type_alias.docs(ctx.db)) | ||
263 | .set_deprecated(is_deprecated(type_alias, ctx.db)) | ||
264 | .detail(detail) | ||
265 | .add_to(self); | ||
266 | } | ||
267 | |||
268 | pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { | ||
269 | let is_deprecated = is_deprecated(variant, ctx.db); | ||
270 | let name = variant.name(ctx.db); | ||
271 | let detail_types = variant.fields(ctx.db).into_iter().map(|field| field.ty(ctx.db)); | ||
272 | let detail = join(detail_types.map(|t| t.display(ctx.db).to_string())) | ||
273 | .separator(", ") | ||
274 | .surround_with("(", ")") | ||
275 | .to_string(); | ||
276 | CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) | ||
277 | .kind(CompletionItemKind::EnumVariant) | ||
278 | .set_documentation(variant.docs(ctx.db)) | ||
279 | .set_deprecated(is_deprecated) | ||
280 | .detail(detail) | ||
281 | .add_to(self); | ||
282 | } | ||
283 | } | ||
284 | |||
285 | fn is_deprecated(node: impl HasAttrs, db: &impl HirDatabase) -> bool { | ||
286 | node.attrs(db).by_key("deprecated").exists() | ||
287 | } | ||
288 | |||
289 | #[cfg(test)] | ||
290 | mod tests { | ||
291 | use insta::assert_debug_snapshot; | ||
292 | use test_utils::covers; | ||
293 | |||
294 | use crate::completion::{do_completion, CompletionItem, CompletionKind}; | ||
295 | |||
296 | fn do_reference_completion(code: &str) -> Vec<CompletionItem> { | ||
297 | do_completion(code, CompletionKind::Reference) | ||
298 | } | ||
299 | |||
300 | #[test] | ||
301 | fn sets_deprecated_flag_in_completion_items() { | ||
302 | assert_debug_snapshot!( | ||
303 | do_reference_completion( | ||
304 | r#" | ||
305 | #[deprecated] | ||
306 | fn something_deprecated() {} | ||
307 | |||
308 | #[deprecated(since = "1.0.0")] | ||
309 | fn something_else_deprecated() {} | ||
310 | |||
311 | fn main() { som<|> } | ||
312 | "#, | ||
313 | ), | ||
314 | @r###" | ||
315 | [ | ||
316 | CompletionItem { | ||
317 | label: "main()", | ||
318 | source_range: [203; 206), | ||
319 | delete: [203; 206), | ||
320 | insert: "main()$0", | ||
321 | kind: Function, | ||
322 | lookup: "main", | ||
323 | detail: "fn main()", | ||
324 | }, | ||
325 | CompletionItem { | ||
326 | label: "something_deprecated()", | ||
327 | source_range: [203; 206), | ||
328 | delete: [203; 206), | ||
329 | insert: "something_deprecated()$0", | ||
330 | kind: Function, | ||
331 | lookup: "something_deprecated", | ||
332 | detail: "fn something_deprecated()", | ||
333 | deprecated: true, | ||
334 | }, | ||
335 | CompletionItem { | ||
336 | label: "something_else_deprecated()", | ||
337 | source_range: [203; 206), | ||
338 | delete: [203; 206), | ||
339 | insert: "something_else_deprecated()$0", | ||
340 | kind: Function, | ||
341 | lookup: "something_else_deprecated", | ||
342 | detail: "fn something_else_deprecated()", | ||
343 | deprecated: true, | ||
344 | }, | ||
345 | ] | ||
346 | "### | ||
347 | ); | ||
348 | } | ||
349 | |||
350 | #[test] | ||
351 | fn inserts_parens_for_function_calls() { | ||
352 | covers!(inserts_parens_for_function_calls); | ||
353 | assert_debug_snapshot!( | ||
354 | do_reference_completion( | ||
355 | r" | ||
356 | fn no_args() {} | ||
357 | fn main() { no_<|> } | ||
358 | " | ||
359 | ), | ||
360 | @r###" | ||
361 | [ | ||
362 | CompletionItem { | ||
363 | label: "main()", | ||
364 | source_range: [61; 64), | ||
365 | delete: [61; 64), | ||
366 | insert: "main()$0", | ||
367 | kind: Function, | ||
368 | lookup: "main", | ||
369 | detail: "fn main()", | ||
370 | }, | ||
371 | CompletionItem { | ||
372 | label: "no_args()", | ||
373 | source_range: [61; 64), | ||
374 | delete: [61; 64), | ||
375 | insert: "no_args()$0", | ||
376 | kind: Function, | ||
377 | lookup: "no_args", | ||
378 | detail: "fn no_args()", | ||
379 | }, | ||
380 | ] | ||
381 | "### | ||
382 | ); | ||
383 | assert_debug_snapshot!( | ||
384 | do_reference_completion( | ||
385 | r" | ||
386 | fn with_args(x: i32, y: String) {} | ||
387 | fn main() { with_<|> } | ||
388 | " | ||
389 | ), | ||
390 | @r###" | ||
391 | [ | ||
392 | CompletionItem { | ||
393 | label: "main()", | ||
394 | source_range: [80; 85), | ||
395 | delete: [80; 85), | ||
396 | insert: "main()$0", | ||
397 | kind: Function, | ||
398 | lookup: "main", | ||
399 | detail: "fn main()", | ||
400 | }, | ||
401 | CompletionItem { | ||
402 | label: "with_args(…)", | ||
403 | source_range: [80; 85), | ||
404 | delete: [80; 85), | ||
405 | insert: "with_args($0)", | ||
406 | kind: Function, | ||
407 | lookup: "with_args", | ||
408 | detail: "fn with_args(x: i32, y: String)", | ||
409 | }, | ||
410 | ] | ||
411 | "### | ||
412 | ); | ||
413 | assert_debug_snapshot!( | ||
414 | do_reference_completion( | ||
415 | r" | ||
416 | struct S {} | ||
417 | impl S { | ||
418 | fn foo(&self) {} | ||
419 | } | ||
420 | fn bar(s: &S) { | ||
421 | s.f<|> | ||
422 | } | ||
423 | " | ||
424 | ), | ||
425 | @r###" | ||
426 | [ | ||
427 | CompletionItem { | ||
428 | label: "foo()", | ||
429 | source_range: [163; 164), | ||
430 | delete: [163; 164), | ||
431 | insert: "foo()$0", | ||
432 | kind: Method, | ||
433 | lookup: "foo", | ||
434 | detail: "fn foo(&self)", | ||
435 | }, | ||
436 | ] | ||
437 | "### | ||
438 | ); | ||
439 | } | ||
440 | |||
441 | #[test] | ||
442 | fn dont_render_function_parens_in_use_item() { | ||
443 | assert_debug_snapshot!( | ||
444 | do_reference_completion( | ||
445 | " | ||
446 | //- /lib.rs | ||
447 | mod m { pub fn foo() {} } | ||
448 | use crate::m::f<|>; | ||
449 | " | ||
450 | ), | ||
451 | @r###" | ||
452 | [ | ||
453 | CompletionItem { | ||
454 | label: "foo", | ||
455 | source_range: [40; 41), | ||
456 | delete: [40; 41), | ||
457 | insert: "foo", | ||
458 | kind: Function, | ||
459 | detail: "pub fn foo()", | ||
460 | }, | ||
461 | ] | ||
462 | "### | ||
463 | ); | ||
464 | } | ||
465 | |||
466 | #[test] | ||
467 | fn dont_render_function_parens_if_already_call() { | ||
468 | assert_debug_snapshot!( | ||
469 | do_reference_completion( | ||
470 | " | ||
471 | //- /lib.rs | ||
472 | fn frobnicate() {} | ||
473 | fn main() { | ||
474 | frob<|>(); | ||
475 | } | ||
476 | " | ||
477 | ), | ||
478 | @r###" | ||
479 | [ | ||
480 | CompletionItem { | ||
481 | label: "frobnicate", | ||
482 | source_range: [35; 39), | ||
483 | delete: [35; 39), | ||
484 | insert: "frobnicate", | ||
485 | kind: Function, | ||
486 | detail: "fn frobnicate()", | ||
487 | }, | ||
488 | CompletionItem { | ||
489 | label: "main", | ||
490 | source_range: [35; 39), | ||
491 | delete: [35; 39), | ||
492 | insert: "main", | ||
493 | kind: Function, | ||
494 | detail: "fn main()", | ||
495 | }, | ||
496 | ] | ||
497 | "### | ||
498 | ); | ||
499 | assert_debug_snapshot!( | ||
500 | do_reference_completion( | ||
501 | " | ||
502 | //- /lib.rs | ||
503 | struct Foo {} | ||
504 | impl Foo { fn new() -> Foo {} } | ||
505 | fn main() { | ||
506 | Foo::ne<|>(); | ||
507 | } | ||
508 | " | ||
509 | ), | ||
510 | @r###" | ||
511 | [ | ||
512 | CompletionItem { | ||
513 | label: "new", | ||
514 | source_range: [67; 69), | ||
515 | delete: [67; 69), | ||
516 | insert: "new", | ||
517 | kind: Function, | ||
518 | detail: "fn new() -> Foo", | ||
519 | }, | ||
520 | ] | ||
521 | "### | ||
522 | ); | ||
523 | } | ||
524 | |||
525 | #[test] | ||
526 | fn inserts_angle_brackets_for_generics() { | ||
527 | covers!(inserts_angle_brackets_for_generics); | ||
528 | assert_debug_snapshot!( | ||
529 | do_reference_completion( | ||
530 | r" | ||
531 | struct Vec<T> {} | ||
532 | fn foo(xs: Ve<|>) | ||
533 | " | ||
534 | ), | ||
535 | @r###" | ||
536 | [ | ||
537 | CompletionItem { | ||
538 | label: "Vec<…>", | ||
539 | source_range: [61; 63), | ||
540 | delete: [61; 63), | ||
541 | insert: "Vec<$0>", | ||
542 | kind: Struct, | ||
543 | lookup: "Vec", | ||
544 | }, | ||
545 | CompletionItem { | ||
546 | label: "foo(…)", | ||
547 | source_range: [61; 63), | ||
548 | delete: [61; 63), | ||
549 | insert: "foo($0)", | ||
550 | kind: Function, | ||
551 | lookup: "foo", | ||
552 | detail: "fn foo(xs: Ve)", | ||
553 | }, | ||
554 | ] | ||
555 | "### | ||
556 | ); | ||
557 | assert_debug_snapshot!( | ||
558 | do_reference_completion( | ||
559 | r" | ||
560 | type Vec<T> = (T,); | ||
561 | fn foo(xs: Ve<|>) | ||
562 | " | ||
563 | ), | ||
564 | @r###" | ||
565 | [ | ||
566 | CompletionItem { | ||
567 | label: "Vec<…>", | ||
568 | source_range: [64; 66), | ||
569 | delete: [64; 66), | ||
570 | insert: "Vec<$0>", | ||
571 | kind: TypeAlias, | ||
572 | lookup: "Vec", | ||
573 | }, | ||
574 | CompletionItem { | ||
575 | label: "foo(…)", | ||
576 | source_range: [64; 66), | ||
577 | delete: [64; 66), | ||
578 | insert: "foo($0)", | ||
579 | kind: Function, | ||
580 | lookup: "foo", | ||
581 | detail: "fn foo(xs: Ve)", | ||
582 | }, | ||
583 | ] | ||
584 | "### | ||
585 | ); | ||
586 | assert_debug_snapshot!( | ||
587 | do_reference_completion( | ||
588 | r" | ||
589 | struct Vec<T = i128> {} | ||
590 | fn foo(xs: Ve<|>) | ||
591 | " | ||
592 | ), | ||
593 | @r###" | ||
594 | [ | ||
595 | CompletionItem { | ||
596 | label: "Vec", | ||
597 | source_range: [68; 70), | ||
598 | delete: [68; 70), | ||
599 | insert: "Vec", | ||
600 | kind: Struct, | ||
601 | }, | ||
602 | CompletionItem { | ||
603 | label: "foo(…)", | ||
604 | source_range: [68; 70), | ||
605 | delete: [68; 70), | ||
606 | insert: "foo($0)", | ||
607 | kind: Function, | ||
608 | lookup: "foo", | ||
609 | detail: "fn foo(xs: Ve)", | ||
610 | }, | ||
611 | ] | ||
612 | "### | ||
613 | ); | ||
614 | assert_debug_snapshot!( | ||
615 | do_reference_completion( | ||
616 | r" | ||
617 | struct Vec<T> {} | ||
618 | fn foo(xs: Ve<|><i128>) | ||
619 | " | ||
620 | ), | ||
621 | @r###" | ||
622 | [ | ||
623 | CompletionItem { | ||
624 | label: "Vec", | ||
625 | source_range: [61; 63), | ||
626 | delete: [61; 63), | ||
627 | insert: "Vec", | ||
628 | kind: Struct, | ||
629 | }, | ||
630 | CompletionItem { | ||
631 | label: "foo(…)", | ||
632 | source_range: [61; 63), | ||
633 | delete: [61; 63), | ||
634 | insert: "foo($0)", | ||
635 | kind: Function, | ||
636 | lookup: "foo", | ||
637 | detail: "fn foo(xs: Ve<i128>)", | ||
638 | }, | ||
639 | ] | ||
640 | "### | ||
641 | ); | ||
642 | } | ||
643 | |||
644 | #[test] | ||
645 | fn dont_insert_macro_call_braces_in_use() { | ||
646 | assert_debug_snapshot!( | ||
647 | do_reference_completion( | ||
648 | r" | ||
649 | //- /main.rs | ||
650 | use foo::<|>; | ||
651 | |||
652 | //- /foo/lib.rs | ||
653 | #[macro_export] | ||
654 | macro_rules frobnicate { | ||
655 | () => () | ||
656 | } | ||
657 | " | ||
658 | ), | ||
659 | @r###" | ||
660 | [ | ||
661 | CompletionItem { | ||
662 | label: "frobnicate!", | ||
663 | source_range: [9; 9), | ||
664 | delete: [9; 9), | ||
665 | insert: "frobnicate", | ||
666 | kind: Macro, | ||
667 | detail: "#[macro_export]\nmacro_rules! frobnicate", | ||
668 | }, | ||
669 | ] | ||
670 | "### | ||
671 | ) | ||
672 | } | ||
673 | } | ||