diff options
Diffstat (limited to 'crates/completion/src/completions/qualified_path.rs')
-rw-r--r-- | crates/completion/src/completions/qualified_path.rs | 755 |
1 files changed, 755 insertions, 0 deletions
diff --git a/crates/completion/src/completions/qualified_path.rs b/crates/completion/src/completions/qualified_path.rs new file mode 100644 index 000000000..d9387054d --- /dev/null +++ b/crates/completion/src/completions/qualified_path.rs | |||
@@ -0,0 +1,755 @@ | |||
1 | //! Completion of paths, i.e. `some::prefix::<|>`. | ||
2 | |||
3 | use hir::{Adt, HasVisibility, PathResolution, ScopeDef}; | ||
4 | use rustc_hash::FxHashSet; | ||
5 | use syntax::AstNode; | ||
6 | use test_utils::mark; | ||
7 | |||
8 | use crate::{CompletionContext, Completions}; | ||
9 | |||
10 | pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionContext) { | ||
11 | let path = match &ctx.path_qual { | ||
12 | Some(path) => path.clone(), | ||
13 | None => return, | ||
14 | }; | ||
15 | |||
16 | if ctx.attribute_under_caret.is_some() || ctx.mod_declaration_under_caret.is_some() { | ||
17 | return; | ||
18 | } | ||
19 | |||
20 | let context_module = ctx.scope.module(); | ||
21 | |||
22 | let resolution = match ctx.sema.resolve_path(&path) { | ||
23 | Some(res) => res, | ||
24 | None => return, | ||
25 | }; | ||
26 | |||
27 | // Add associated types on type parameters and `Self`. | ||
28 | resolution.assoc_type_shorthand_candidates(ctx.db, |alias| { | ||
29 | acc.add_type_alias(ctx, alias); | ||
30 | None::<()> | ||
31 | }); | ||
32 | |||
33 | match resolution { | ||
34 | PathResolution::Def(hir::ModuleDef::Module(module)) => { | ||
35 | let module_scope = module.scope(ctx.db, context_module); | ||
36 | for (name, def) in module_scope { | ||
37 | if ctx.use_item_syntax.is_some() { | ||
38 | if let ScopeDef::Unknown = def { | ||
39 | if let Some(name_ref) = ctx.name_ref_syntax.as_ref() { | ||
40 | if name_ref.syntax().text() == name.to_string().as_str() { | ||
41 | // for `use self::foo<|>`, don't suggest `foo` as a completion | ||
42 | mark::hit!(dont_complete_current_use); | ||
43 | continue; | ||
44 | } | ||
45 | } | ||
46 | } | ||
47 | } | ||
48 | |||
49 | acc.add_resolution(ctx, name.to_string(), &def); | ||
50 | } | ||
51 | } | ||
52 | PathResolution::Def(def @ hir::ModuleDef::Adt(_)) | ||
53 | | PathResolution::Def(def @ hir::ModuleDef::TypeAlias(_)) => { | ||
54 | if let hir::ModuleDef::Adt(Adt::Enum(e)) = def { | ||
55 | for variant in e.variants(ctx.db) { | ||
56 | acc.add_enum_variant(ctx, variant, None); | ||
57 | } | ||
58 | } | ||
59 | let ty = match def { | ||
60 | hir::ModuleDef::Adt(adt) => adt.ty(ctx.db), | ||
61 | hir::ModuleDef::TypeAlias(a) => a.ty(ctx.db), | ||
62 | _ => unreachable!(), | ||
63 | }; | ||
64 | |||
65 | // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType. | ||
66 | // (where AssocType is defined on a trait, not an inherent impl) | ||
67 | |||
68 | let krate = ctx.krate; | ||
69 | if let Some(krate) = krate { | ||
70 | let traits_in_scope = ctx.scope.traits_in_scope(); | ||
71 | ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { | ||
72 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | ||
73 | return None; | ||
74 | } | ||
75 | match item { | ||
76 | hir::AssocItem::Function(func) => { | ||
77 | acc.add_function(ctx, func, None); | ||
78 | } | ||
79 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
80 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
81 | } | ||
82 | None::<()> | ||
83 | }); | ||
84 | |||
85 | // Iterate assoc types separately | ||
86 | ty.iterate_assoc_items(ctx.db, krate, |item| { | ||
87 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | ||
88 | return None; | ||
89 | } | ||
90 | match item { | ||
91 | hir::AssocItem::Function(_) | hir::AssocItem::Const(_) => {} | ||
92 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
93 | } | ||
94 | None::<()> | ||
95 | }); | ||
96 | } | ||
97 | } | ||
98 | PathResolution::Def(hir::ModuleDef::Trait(t)) => { | ||
99 | // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`. | ||
100 | for item in t.items(ctx.db) { | ||
101 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | ||
102 | continue; | ||
103 | } | ||
104 | match item { | ||
105 | hir::AssocItem::Function(func) => { | ||
106 | acc.add_function(ctx, func, None); | ||
107 | } | ||
108 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
109 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | PathResolution::TypeParam(_) | PathResolution::SelfType(_) => { | ||
114 | if let Some(krate) = ctx.krate { | ||
115 | let ty = match resolution { | ||
116 | PathResolution::TypeParam(param) => param.ty(ctx.db), | ||
117 | PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db), | ||
118 | _ => return, | ||
119 | }; | ||
120 | |||
121 | let traits_in_scope = ctx.scope.traits_in_scope(); | ||
122 | let mut seen = FxHashSet::default(); | ||
123 | ty.iterate_path_candidates(ctx.db, krate, &traits_in_scope, None, |_ty, item| { | ||
124 | if context_module.map_or(false, |m| !item.is_visible_from(ctx.db, m)) { | ||
125 | return None; | ||
126 | } | ||
127 | |||
128 | // We might iterate candidates of a trait multiple times here, so deduplicate | ||
129 | // them. | ||
130 | if seen.insert(item) { | ||
131 | match item { | ||
132 | hir::AssocItem::Function(func) => { | ||
133 | acc.add_function(ctx, func, None); | ||
134 | } | ||
135 | hir::AssocItem::Const(ct) => acc.add_const(ctx, ct), | ||
136 | hir::AssocItem::TypeAlias(ty) => acc.add_type_alias(ctx, ty), | ||
137 | } | ||
138 | } | ||
139 | None::<()> | ||
140 | }); | ||
141 | } | ||
142 | } | ||
143 | _ => {} | ||
144 | } | ||
145 | } | ||
146 | |||
147 | #[cfg(test)] | ||
148 | mod tests { | ||
149 | use expect_test::{expect, Expect}; | ||
150 | use test_utils::mark; | ||
151 | |||
152 | use crate::{ | ||
153 | test_utils::{check_edit, completion_list}, | ||
154 | CompletionKind, | ||
155 | }; | ||
156 | |||
157 | fn check(ra_fixture: &str, expect: Expect) { | ||
158 | let actual = completion_list(ra_fixture, CompletionKind::Reference); | ||
159 | expect.assert_eq(&actual); | ||
160 | } | ||
161 | |||
162 | fn check_builtin(ra_fixture: &str, expect: Expect) { | ||
163 | let actual = completion_list(ra_fixture, CompletionKind::BuiltinType); | ||
164 | expect.assert_eq(&actual); | ||
165 | } | ||
166 | |||
167 | #[test] | ||
168 | fn dont_complete_current_use() { | ||
169 | mark::check!(dont_complete_current_use); | ||
170 | check(r#"use self::foo<|>;"#, expect![[""]]); | ||
171 | } | ||
172 | |||
173 | #[test] | ||
174 | fn dont_complete_current_use_in_braces_with_glob() { | ||
175 | check( | ||
176 | r#" | ||
177 | mod foo { pub struct S; } | ||
178 | use self::{foo::*, bar<|>}; | ||
179 | "#, | ||
180 | expect![[r#" | ||
181 | st S | ||
182 | md foo | ||
183 | "#]], | ||
184 | ); | ||
185 | } | ||
186 | |||
187 | #[test] | ||
188 | fn dont_complete_primitive_in_use() { | ||
189 | check_builtin(r#"use self::<|>;"#, expect![[""]]); | ||
190 | } | ||
191 | |||
192 | #[test] | ||
193 | fn dont_complete_primitive_in_module_scope() { | ||
194 | check_builtin(r#"fn foo() { self::<|> }"#, expect![[""]]); | ||
195 | } | ||
196 | |||
197 | #[test] | ||
198 | fn completes_primitives() { | ||
199 | check_builtin( | ||
200 | r#"fn main() { let _: <|> = 92; }"#, | ||
201 | expect![[r#" | ||
202 | bt bool | ||
203 | bt char | ||
204 | bt f32 | ||
205 | bt f64 | ||
206 | bt i128 | ||
207 | bt i16 | ||
208 | bt i32 | ||
209 | bt i64 | ||
210 | bt i8 | ||
211 | bt isize | ||
212 | bt str | ||
213 | bt u128 | ||
214 | bt u16 | ||
215 | bt u32 | ||
216 | bt u64 | ||
217 | bt u8 | ||
218 | bt usize | ||
219 | "#]], | ||
220 | ); | ||
221 | } | ||
222 | |||
223 | #[test] | ||
224 | fn completes_mod_with_same_name_as_function() { | ||
225 | check( | ||
226 | r#" | ||
227 | use self::my::<|>; | ||
228 | |||
229 | mod my { pub struct Bar; } | ||
230 | fn my() {} | ||
231 | "#, | ||
232 | expect![[r#" | ||
233 | st Bar | ||
234 | "#]], | ||
235 | ); | ||
236 | } | ||
237 | |||
238 | #[test] | ||
239 | fn filters_visibility() { | ||
240 | check( | ||
241 | r#" | ||
242 | use self::my::<|>; | ||
243 | |||
244 | mod my { | ||
245 | struct Bar; | ||
246 | pub struct Foo; | ||
247 | pub use Bar as PublicBar; | ||
248 | } | ||
249 | "#, | ||
250 | expect![[r#" | ||
251 | st Foo | ||
252 | st PublicBar | ||
253 | "#]], | ||
254 | ); | ||
255 | } | ||
256 | |||
257 | #[test] | ||
258 | fn completes_use_item_starting_with_self() { | ||
259 | check( | ||
260 | r#" | ||
261 | use self::m::<|>; | ||
262 | |||
263 | mod m { pub struct Bar; } | ||
264 | "#, | ||
265 | expect![[r#" | ||
266 | st Bar | ||
267 | "#]], | ||
268 | ); | ||
269 | } | ||
270 | |||
271 | #[test] | ||
272 | fn completes_use_item_starting_with_crate() { | ||
273 | check( | ||
274 | r#" | ||
275 | //- /lib.rs | ||
276 | mod foo; | ||
277 | struct Spam; | ||
278 | //- /foo.rs | ||
279 | use crate::Sp<|> | ||
280 | "#, | ||
281 | expect![[r#" | ||
282 | st Spam | ||
283 | md foo | ||
284 | "#]], | ||
285 | ); | ||
286 | } | ||
287 | |||
288 | #[test] | ||
289 | fn completes_nested_use_tree() { | ||
290 | check( | ||
291 | r#" | ||
292 | //- /lib.rs | ||
293 | mod foo; | ||
294 | struct Spam; | ||
295 | //- /foo.rs | ||
296 | use crate::{Sp<|>}; | ||
297 | "#, | ||
298 | expect![[r#" | ||
299 | st Spam | ||
300 | md foo | ||
301 | "#]], | ||
302 | ); | ||
303 | } | ||
304 | |||
305 | #[test] | ||
306 | fn completes_deeply_nested_use_tree() { | ||
307 | check( | ||
308 | r#" | ||
309 | //- /lib.rs | ||
310 | mod foo; | ||
311 | pub mod bar { | ||
312 | pub mod baz { | ||
313 | pub struct Spam; | ||
314 | } | ||
315 | } | ||
316 | //- /foo.rs | ||
317 | use crate::{bar::{baz::Sp<|>}}; | ||
318 | "#, | ||
319 | expect![[r#" | ||
320 | st Spam | ||
321 | "#]], | ||
322 | ); | ||
323 | } | ||
324 | |||
325 | #[test] | ||
326 | fn completes_enum_variant() { | ||
327 | check( | ||
328 | r#" | ||
329 | enum E { Foo, Bar(i32) } | ||
330 | fn foo() { let _ = E::<|> } | ||
331 | "#, | ||
332 | expect![[r#" | ||
333 | ev Bar(…) (i32) | ||
334 | ev Foo () | ||
335 | "#]], | ||
336 | ); | ||
337 | } | ||
338 | |||
339 | #[test] | ||
340 | fn completes_struct_associated_items() { | ||
341 | check( | ||
342 | r#" | ||
343 | //- /lib.rs | ||
344 | struct S; | ||
345 | |||
346 | impl S { | ||
347 | fn a() {} | ||
348 | fn b(&self) {} | ||
349 | const C: i32 = 42; | ||
350 | type T = i32; | ||
351 | } | ||
352 | |||
353 | fn foo() { let _ = S::<|> } | ||
354 | "#, | ||
355 | expect![[r#" | ||
356 | ct C const C: i32 = 42; | ||
357 | ta T type T = i32; | ||
358 | fn a() fn a() | ||
359 | me b() fn b(&self) | ||
360 | "#]], | ||
361 | ); | ||
362 | } | ||
363 | |||
364 | #[test] | ||
365 | fn associated_item_visibility() { | ||
366 | check( | ||
367 | r#" | ||
368 | struct S; | ||
369 | |||
370 | mod m { | ||
371 | impl super::S { | ||
372 | pub(crate) fn public_method() { } | ||
373 | fn private_method() { } | ||
374 | pub(crate) type PublicType = u32; | ||
375 | type PrivateType = u32; | ||
376 | pub(crate) const PUBLIC_CONST: u32 = 1; | ||
377 | const PRIVATE_CONST: u32 = 1; | ||
378 | } | ||
379 | } | ||
380 | |||
381 | fn foo() { let _ = S::<|> } | ||
382 | "#, | ||
383 | expect![[r#" | ||
384 | ct PUBLIC_CONST pub(crate) const PUBLIC_CONST: u32 = 1; | ||
385 | ta PublicType pub(crate) type PublicType = u32; | ||
386 | fn public_method() pub(crate) fn public_method() | ||
387 | "#]], | ||
388 | ); | ||
389 | } | ||
390 | |||
391 | #[test] | ||
392 | fn completes_enum_associated_method() { | ||
393 | check( | ||
394 | r#" | ||
395 | enum E {}; | ||
396 | impl E { fn m() { } } | ||
397 | |||
398 | fn foo() { let _ = E::<|> } | ||
399 | "#, | ||
400 | expect![[r#" | ||
401 | fn m() fn m() | ||
402 | "#]], | ||
403 | ); | ||
404 | } | ||
405 | |||
406 | #[test] | ||
407 | fn completes_union_associated_method() { | ||
408 | check( | ||
409 | r#" | ||
410 | union U {}; | ||
411 | impl U { fn m() { } } | ||
412 | |||
413 | fn foo() { let _ = U::<|> } | ||
414 | "#, | ||
415 | expect![[r#" | ||
416 | fn m() fn m() | ||
417 | "#]], | ||
418 | ); | ||
419 | } | ||
420 | |||
421 | #[test] | ||
422 | fn completes_use_paths_across_crates() { | ||
423 | check( | ||
424 | r#" | ||
425 | //- /main.rs crate:main deps:foo | ||
426 | use foo::<|>; | ||
427 | |||
428 | //- /foo/lib.rs crate:foo | ||
429 | pub mod bar { pub struct S; } | ||
430 | "#, | ||
431 | expect![[r#" | ||
432 | md bar | ||
433 | "#]], | ||
434 | ); | ||
435 | } | ||
436 | |||
437 | #[test] | ||
438 | fn completes_trait_associated_method_1() { | ||
439 | check( | ||
440 | r#" | ||
441 | trait Trait { fn m(); } | ||
442 | |||
443 | fn foo() { let _ = Trait::<|> } | ||
444 | "#, | ||
445 | expect![[r#" | ||
446 | fn m() fn m() | ||
447 | "#]], | ||
448 | ); | ||
449 | } | ||
450 | |||
451 | #[test] | ||
452 | fn completes_trait_associated_method_2() { | ||
453 | check( | ||
454 | r#" | ||
455 | trait Trait { fn m(); } | ||
456 | |||
457 | struct S; | ||
458 | impl Trait for S {} | ||
459 | |||
460 | fn foo() { let _ = S::<|> } | ||
461 | "#, | ||
462 | expect![[r#" | ||
463 | fn m() fn m() | ||
464 | "#]], | ||
465 | ); | ||
466 | } | ||
467 | |||
468 | #[test] | ||
469 | fn completes_trait_associated_method_3() { | ||
470 | check( | ||
471 | r#" | ||
472 | trait Trait { fn m(); } | ||
473 | |||
474 | struct S; | ||
475 | impl Trait for S {} | ||
476 | |||
477 | fn foo() { let _ = <S as Trait>::<|> } | ||
478 | "#, | ||
479 | expect![[r#" | ||
480 | fn m() fn m() | ||
481 | "#]], | ||
482 | ); | ||
483 | } | ||
484 | |||
485 | #[test] | ||
486 | fn completes_ty_param_assoc_ty() { | ||
487 | check( | ||
488 | r#" | ||
489 | trait Super { | ||
490 | type Ty; | ||
491 | const CONST: u8; | ||
492 | fn func() {} | ||
493 | fn method(&self) {} | ||
494 | } | ||
495 | |||
496 | trait Sub: Super { | ||
497 | type SubTy; | ||
498 | const C2: (); | ||
499 | fn subfunc() {} | ||
500 | fn submethod(&self) {} | ||
501 | } | ||
502 | |||
503 | fn foo<T: Sub>() { T::<|> } | ||
504 | "#, | ||
505 | expect![[r#" | ||
506 | ct C2 const C2: (); | ||
507 | ct CONST const CONST: u8; | ||
508 | ta SubTy type SubTy; | ||
509 | ta Ty type Ty; | ||
510 | fn func() fn func() | ||
511 | me method() fn method(&self) | ||
512 | fn subfunc() fn subfunc() | ||
513 | me submethod() fn submethod(&self) | ||
514 | "#]], | ||
515 | ); | ||
516 | } | ||
517 | |||
518 | #[test] | ||
519 | fn completes_self_param_assoc_ty() { | ||
520 | check( | ||
521 | r#" | ||
522 | trait Super { | ||
523 | type Ty; | ||
524 | const CONST: u8 = 0; | ||
525 | fn func() {} | ||
526 | fn method(&self) {} | ||
527 | } | ||
528 | |||
529 | trait Sub: Super { | ||
530 | type SubTy; | ||
531 | const C2: () = (); | ||
532 | fn subfunc() {} | ||
533 | fn submethod(&self) {} | ||
534 | } | ||
535 | |||
536 | struct Wrap<T>(T); | ||
537 | impl<T> Super for Wrap<T> {} | ||
538 | impl<T> Sub for Wrap<T> { | ||
539 | fn subfunc() { | ||
540 | // Should be able to assume `Self: Sub + Super` | ||
541 | Self::<|> | ||
542 | } | ||
543 | } | ||
544 | "#, | ||
545 | expect![[r#" | ||
546 | ct C2 const C2: () = (); | ||
547 | ct CONST const CONST: u8 = 0; | ||
548 | ta SubTy type SubTy; | ||
549 | ta Ty type Ty; | ||
550 | fn func() fn func() | ||
551 | me method() fn method(&self) | ||
552 | fn subfunc() fn subfunc() | ||
553 | me submethod() fn submethod(&self) | ||
554 | "#]], | ||
555 | ); | ||
556 | } | ||
557 | |||
558 | #[test] | ||
559 | fn completes_type_alias() { | ||
560 | check( | ||
561 | r#" | ||
562 | struct S; | ||
563 | impl S { fn foo() {} } | ||
564 | type T = S; | ||
565 | impl T { fn bar() {} } | ||
566 | |||
567 | fn main() { T::<|>; } | ||
568 | "#, | ||
569 | expect![[r#" | ||
570 | fn bar() fn bar() | ||
571 | fn foo() fn foo() | ||
572 | "#]], | ||
573 | ); | ||
574 | } | ||
575 | |||
576 | #[test] | ||
577 | fn completes_qualified_macros() { | ||
578 | check( | ||
579 | r#" | ||
580 | #[macro_export] | ||
581 | macro_rules! foo { () => {} } | ||
582 | |||
583 | fn main() { let _ = crate::<|> } | ||
584 | "#, | ||
585 | expect![[r##" | ||
586 | ma foo!(…) #[macro_export] | ||
587 | macro_rules! foo | ||
588 | fn main() fn main() | ||
589 | "##]], | ||
590 | ); | ||
591 | } | ||
592 | |||
593 | #[test] | ||
594 | fn test_super_super_completion() { | ||
595 | check( | ||
596 | r#" | ||
597 | mod a { | ||
598 | const A: usize = 0; | ||
599 | mod b { | ||
600 | const B: usize = 0; | ||
601 | mod c { use super::super::<|> } | ||
602 | } | ||
603 | } | ||
604 | "#, | ||
605 | expect![[r#" | ||
606 | ct A | ||
607 | md b | ||
608 | "#]], | ||
609 | ); | ||
610 | } | ||
611 | |||
612 | #[test] | ||
613 | fn completes_reexported_items_under_correct_name() { | ||
614 | check( | ||
615 | r#" | ||
616 | fn foo() { self::m::<|> } | ||
617 | |||
618 | mod m { | ||
619 | pub use super::p::wrong_fn as right_fn; | ||
620 | pub use super::p::WRONG_CONST as RIGHT_CONST; | ||
621 | pub use super::p::WrongType as RightType; | ||
622 | } | ||
623 | mod p { | ||
624 | fn wrong_fn() {} | ||
625 | const WRONG_CONST: u32 = 1; | ||
626 | struct WrongType {}; | ||
627 | } | ||
628 | "#, | ||
629 | expect![[r#" | ||
630 | ct RIGHT_CONST | ||
631 | st RightType | ||
632 | fn right_fn() fn wrong_fn() | ||
633 | "#]], | ||
634 | ); | ||
635 | |||
636 | check_edit( | ||
637 | "RightType", | ||
638 | r#" | ||
639 | fn foo() { self::m::<|> } | ||
640 | |||
641 | mod m { | ||
642 | pub use super::p::wrong_fn as right_fn; | ||
643 | pub use super::p::WRONG_CONST as RIGHT_CONST; | ||
644 | pub use super::p::WrongType as RightType; | ||
645 | } | ||
646 | mod p { | ||
647 | fn wrong_fn() {} | ||
648 | const WRONG_CONST: u32 = 1; | ||
649 | struct WrongType {}; | ||
650 | } | ||
651 | "#, | ||
652 | r#" | ||
653 | fn foo() { self::m::RightType } | ||
654 | |||
655 | mod m { | ||
656 | pub use super::p::wrong_fn as right_fn; | ||
657 | pub use super::p::WRONG_CONST as RIGHT_CONST; | ||
658 | pub use super::p::WrongType as RightType; | ||
659 | } | ||
660 | mod p { | ||
661 | fn wrong_fn() {} | ||
662 | const WRONG_CONST: u32 = 1; | ||
663 | struct WrongType {}; | ||
664 | } | ||
665 | "#, | ||
666 | ); | ||
667 | } | ||
668 | |||
669 | #[test] | ||
670 | fn completes_in_simple_macro_call() { | ||
671 | check( | ||
672 | r#" | ||
673 | macro_rules! m { ($e:expr) => { $e } } | ||
674 | fn main() { m!(self::f<|>); } | ||
675 | fn foo() {} | ||
676 | "#, | ||
677 | expect![[r#" | ||
678 | fn foo() fn foo() | ||
679 | fn main() fn main() | ||
680 | "#]], | ||
681 | ); | ||
682 | } | ||
683 | |||
684 | #[test] | ||
685 | fn function_mod_share_name() { | ||
686 | check( | ||
687 | r#" | ||
688 | fn foo() { self::m::<|> } | ||
689 | |||
690 | mod m { | ||
691 | pub mod z {} | ||
692 | pub fn z() {} | ||
693 | } | ||
694 | "#, | ||
695 | expect![[r#" | ||
696 | md z | ||
697 | fn z() pub fn z() | ||
698 | "#]], | ||
699 | ); | ||
700 | } | ||
701 | |||
702 | #[test] | ||
703 | fn completes_hashmap_new() { | ||
704 | check( | ||
705 | r#" | ||
706 | struct RandomState; | ||
707 | struct HashMap<K, V, S = RandomState> {} | ||
708 | |||
709 | impl<K, V> HashMap<K, V, RandomState> { | ||
710 | pub fn new() -> HashMap<K, V, RandomState> { } | ||
711 | } | ||
712 | fn foo() { | ||
713 | HashMap::<|> | ||
714 | } | ||
715 | "#, | ||
716 | expect![[r#" | ||
717 | fn new() pub fn new() -> HashMap<K, V, RandomState> | ||
718 | "#]], | ||
719 | ); | ||
720 | } | ||
721 | |||
722 | #[test] | ||
723 | fn dont_complete_attr() { | ||
724 | check( | ||
725 | r#" | ||
726 | mod foo { pub struct Foo; } | ||
727 | #[foo::<|>] | ||
728 | fn f() {} | ||
729 | "#, | ||
730 | expect![[""]], | ||
731 | ); | ||
732 | } | ||
733 | |||
734 | #[test] | ||
735 | fn completes_function() { | ||
736 | check( | ||
737 | r#" | ||
738 | fn foo( | ||
739 | a: i32, | ||
740 | b: i32 | ||
741 | ) { | ||
742 | |||
743 | } | ||
744 | |||
745 | fn main() { | ||
746 | fo<|> | ||
747 | } | ||
748 | "#, | ||
749 | expect![[r#" | ||
750 | fn foo(…) fn foo(a: i32, b: i32) | ||
751 | fn main() fn main() | ||
752 | "#]], | ||
753 | ); | ||
754 | } | ||
755 | } | ||