diff options
author | Lukas Wirth <[email protected]> | 2020-10-14 18:56:20 +0100 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2020-10-14 18:56:20 +0100 |
commit | 9f41f074be3a600a40b398dd3f4e57a0d69db256 (patch) | |
tree | 6e5f06f49c8aa34e1705500b028734811742d9d0 /crates/assists | |
parent | 84d6cdef86dfe1054ecafaedfddbf90a2b3a469d (diff) |
Add qualify path assist
Diffstat (limited to 'crates/assists')
-rw-r--r-- | crates/assists/src/handlers/qualify_path.rs | 1020 | ||||
-rw-r--r-- | crates/assists/src/lib.rs | 2 |
2 files changed, 1022 insertions, 0 deletions
diff --git a/crates/assists/src/handlers/qualify_path.rs b/crates/assists/src/handlers/qualify_path.rs new file mode 100644 index 000000000..cff207889 --- /dev/null +++ b/crates/assists/src/handlers/qualify_path.rs | |||
@@ -0,0 +1,1020 @@ | |||
1 | use std::collections::BTreeSet; | ||
2 | |||
3 | use syntax::{ast, AstNode, TextRange}; | ||
4 | |||
5 | use crate::{ | ||
6 | assist_context::{AssistContext, Assists}, | ||
7 | utils::import_assets::{ImportAssets, ImportCandidate}, | ||
8 | utils::mod_path_to_ast, | ||
9 | AssistId, AssistKind, GroupLabel, | ||
10 | }; | ||
11 | |||
12 | // Assist: qualify_path | ||
13 | // | ||
14 | // If the name is unresolved, provides all possible qualified paths for it. | ||
15 | // | ||
16 | // ``` | ||
17 | // fn main() { | ||
18 | // let map = HashMap<|>::new(); | ||
19 | // } | ||
20 | // # pub mod std { pub mod collections { pub struct HashMap { } } } | ||
21 | // ``` | ||
22 | // -> | ||
23 | // ``` | ||
24 | // fn main() { | ||
25 | // let map = std::collections::HashMap::new(); | ||
26 | // } | ||
27 | // # pub mod std { pub mod collections { pub struct HashMap { } } } | ||
28 | // ``` | ||
29 | pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
30 | let import_assets = | ||
31 | if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() { | ||
32 | ImportAssets::for_regular_path(path_under_caret, &ctx.sema) | ||
33 | } else if let Some(method_under_caret) = | ||
34 | ctx.find_node_at_offset_with_descend::<ast::MethodCallExpr>() | ||
35 | { | ||
36 | ImportAssets::for_method_call(method_under_caret, &ctx.sema) | ||
37 | } else { | ||
38 | None | ||
39 | }?; | ||
40 | let proposed_imports = import_assets.search_for_relative_paths(&ctx.sema); | ||
41 | if proposed_imports.is_empty() { | ||
42 | return None; | ||
43 | } | ||
44 | |||
45 | let range = ctx.sema.original_range(import_assets.syntax_under_caret()).range; | ||
46 | match import_assets.import_candidate() { | ||
47 | ImportCandidate::QualifierStart(candidate) => { | ||
48 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; | ||
49 | let segment = path.segment()?; | ||
50 | qualify_path_qualifier_start(acc, proposed_imports, range, segment, &candidate.name) | ||
51 | } | ||
52 | ImportCandidate::UnqualifiedName(candidate) => { | ||
53 | qualify_path_unqualified_name(acc, proposed_imports, range, &candidate.name) | ||
54 | } | ||
55 | ImportCandidate::TraitAssocItem(candidate) => { | ||
56 | let path = ast::Path::cast(import_assets.syntax_under_caret().clone())?; | ||
57 | let (qualifier, segment) = (path.qualifier()?, path.segment()?); | ||
58 | qualify_path_trait_assoc_item( | ||
59 | acc, | ||
60 | proposed_imports, | ||
61 | range, | ||
62 | qualifier, | ||
63 | segment, | ||
64 | &candidate.name, | ||
65 | ) | ||
66 | } | ||
67 | ImportCandidate::TraitMethod(candidate) => { | ||
68 | let mcall_expr = ast::MethodCallExpr::cast(import_assets.syntax_under_caret().clone())?; | ||
69 | let receiver = mcall_expr.receiver()?; | ||
70 | let name_ref = mcall_expr.name_ref()?; | ||
71 | qualify_path_trait_method( | ||
72 | acc, | ||
73 | proposed_imports, | ||
74 | range, | ||
75 | receiver, | ||
76 | name_ref, | ||
77 | &candidate.name, | ||
78 | ) | ||
79 | } | ||
80 | }; | ||
81 | Some(()) | ||
82 | } | ||
83 | |||
84 | // a test that covers this -> `associated_struct_const` | ||
85 | fn qualify_path_qualifier_start( | ||
86 | acc: &mut Assists, | ||
87 | proposed_imports: BTreeSet<hir::ModPath>, | ||
88 | range: TextRange, | ||
89 | segment: ast::PathSegment, | ||
90 | qualifier_start: &str, | ||
91 | ) { | ||
92 | let group_label = GroupLabel(format!("Qualify {}", qualifier_start)); | ||
93 | for import in proposed_imports { | ||
94 | acc.add_group( | ||
95 | &group_label, | ||
96 | AssistId("qualify_path", AssistKind::QuickFix), | ||
97 | format!("Qualify with `{}`", &import), | ||
98 | range, | ||
99 | |builder| { | ||
100 | let import = mod_path_to_ast(&import); | ||
101 | builder.replace(range, format!("{}::{}", import, segment)); | ||
102 | }, | ||
103 | ); | ||
104 | } | ||
105 | } | ||
106 | |||
107 | // a test that covers this -> `applicable_when_found_an_import_partial` | ||
108 | fn qualify_path_unqualified_name( | ||
109 | acc: &mut Assists, | ||
110 | proposed_imports: BTreeSet<hir::ModPath>, | ||
111 | range: TextRange, | ||
112 | name: &str, | ||
113 | ) { | ||
114 | let group_label = GroupLabel(format!("Qualify {}", name)); | ||
115 | for import in proposed_imports { | ||
116 | acc.add_group( | ||
117 | &group_label, | ||
118 | AssistId("qualify_path", AssistKind::QuickFix), | ||
119 | format!("Qualify as `{}`", &import), | ||
120 | range, | ||
121 | |builder| builder.replace(range, mod_path_to_ast(&import).to_string()), | ||
122 | ); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | // a test that covers this -> `associated_trait_const` | ||
127 | fn qualify_path_trait_assoc_item( | ||
128 | acc: &mut Assists, | ||
129 | proposed_imports: BTreeSet<hir::ModPath>, | ||
130 | range: TextRange, | ||
131 | qualifier: ast::Path, | ||
132 | segment: ast::PathSegment, | ||
133 | trait_assoc_item_name: &str, | ||
134 | ) { | ||
135 | let group_label = GroupLabel(format!("Qualify {}", trait_assoc_item_name)); | ||
136 | for import in proposed_imports { | ||
137 | acc.add_group( | ||
138 | &group_label, | ||
139 | AssistId("qualify_path", AssistKind::QuickFix), | ||
140 | format!("Qualify with cast as `{}`", &import), | ||
141 | range, | ||
142 | |builder| { | ||
143 | let import = mod_path_to_ast(&import); | ||
144 | builder.replace(range, format!("<{} as {}>::{}", qualifier, import, segment)); | ||
145 | }, | ||
146 | ); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | // a test that covers this -> `trait_method` | ||
151 | fn qualify_path_trait_method( | ||
152 | acc: &mut Assists, | ||
153 | proposed_imports: BTreeSet<hir::ModPath>, | ||
154 | range: TextRange, | ||
155 | receiver: ast::Expr, | ||
156 | name_ref: ast::NameRef, | ||
157 | trait_method_name: &str, | ||
158 | ) { | ||
159 | let group_label = GroupLabel(format!("Qualify {}", trait_method_name)); | ||
160 | for import in proposed_imports { | ||
161 | acc.add_group( | ||
162 | &group_label, | ||
163 | AssistId("qualify_path", AssistKind::QuickFix), // < Does this still count as quickfix? | ||
164 | format!("Qualify `{}`", &import), | ||
165 | range, | ||
166 | |builder| { | ||
167 | let import = mod_path_to_ast(&import); | ||
168 | // TODO: check the receiver self type and emit refs accordingly, don't discard other function parameters | ||
169 | builder.replace(range, format!("{}::{}(&{})", import, name_ref, receiver)); | ||
170 | }, | ||
171 | ); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | #[cfg(test)] | ||
176 | mod tests { | ||
177 | use super::*; | ||
178 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; | ||
179 | #[test] | ||
180 | fn applicable_when_found_an_import_partial() { | ||
181 | check_assist( | ||
182 | qualify_path, | ||
183 | r" | ||
184 | mod std { | ||
185 | pub mod fmt { | ||
186 | pub struct Formatter; | ||
187 | } | ||
188 | } | ||
189 | |||
190 | use std::fmt; | ||
191 | |||
192 | <|>Formatter | ||
193 | ", | ||
194 | r" | ||
195 | mod std { | ||
196 | pub mod fmt { | ||
197 | pub struct Formatter; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | use std::fmt; | ||
202 | |||
203 | fmt::Formatter | ||
204 | ", | ||
205 | ); | ||
206 | } | ||
207 | |||
208 | #[test] | ||
209 | fn applicable_when_found_an_import() { | ||
210 | check_assist( | ||
211 | qualify_path, | ||
212 | r" | ||
213 | <|>PubStruct | ||
214 | |||
215 | pub mod PubMod { | ||
216 | pub struct PubStruct; | ||
217 | } | ||
218 | ", | ||
219 | r" | ||
220 | PubMod::PubStruct | ||
221 | |||
222 | pub mod PubMod { | ||
223 | pub struct PubStruct; | ||
224 | } | ||
225 | ", | ||
226 | ); | ||
227 | } | ||
228 | |||
229 | #[test] | ||
230 | fn applicable_in_macros() { | ||
231 | check_assist( | ||
232 | qualify_path, | ||
233 | r" | ||
234 | macro_rules! foo { | ||
235 | ($i:ident) => { fn foo(a: $i) {} } | ||
236 | } | ||
237 | foo!(Pub<|>Struct); | ||
238 | |||
239 | pub mod PubMod { | ||
240 | pub struct PubStruct; | ||
241 | } | ||
242 | ", | ||
243 | r" | ||
244 | macro_rules! foo { | ||
245 | ($i:ident) => { fn foo(a: $i) {} } | ||
246 | } | ||
247 | foo!(PubMod::PubStruct); | ||
248 | |||
249 | pub mod PubMod { | ||
250 | pub struct PubStruct; | ||
251 | } | ||
252 | ", | ||
253 | ); | ||
254 | } | ||
255 | |||
256 | #[test] | ||
257 | fn applicable_when_found_multiple_imports() { | ||
258 | check_assist( | ||
259 | qualify_path, | ||
260 | r" | ||
261 | PubSt<|>ruct | ||
262 | |||
263 | pub mod PubMod1 { | ||
264 | pub struct PubStruct; | ||
265 | } | ||
266 | pub mod PubMod2 { | ||
267 | pub struct PubStruct; | ||
268 | } | ||
269 | pub mod PubMod3 { | ||
270 | pub struct PubStruct; | ||
271 | } | ||
272 | ", | ||
273 | r" | ||
274 | PubMod3::PubStruct | ||
275 | |||
276 | pub mod PubMod1 { | ||
277 | pub struct PubStruct; | ||
278 | } | ||
279 | pub mod PubMod2 { | ||
280 | pub struct PubStruct; | ||
281 | } | ||
282 | pub mod PubMod3 { | ||
283 | pub struct PubStruct; | ||
284 | } | ||
285 | ", | ||
286 | ); | ||
287 | } | ||
288 | |||
289 | #[test] | ||
290 | fn not_applicable_for_already_imported_types() { | ||
291 | check_assist_not_applicable( | ||
292 | qualify_path, | ||
293 | r" | ||
294 | use PubMod::PubStruct; | ||
295 | |||
296 | PubStruct<|> | ||
297 | |||
298 | pub mod PubMod { | ||
299 | pub struct PubStruct; | ||
300 | } | ||
301 | ", | ||
302 | ); | ||
303 | } | ||
304 | |||
305 | #[test] | ||
306 | fn not_applicable_for_types_with_private_paths() { | ||
307 | check_assist_not_applicable( | ||
308 | qualify_path, | ||
309 | r" | ||
310 | PrivateStruct<|> | ||
311 | |||
312 | pub mod PubMod { | ||
313 | struct PrivateStruct; | ||
314 | } | ||
315 | ", | ||
316 | ); | ||
317 | } | ||
318 | |||
319 | #[test] | ||
320 | fn not_applicable_when_no_imports_found() { | ||
321 | check_assist_not_applicable( | ||
322 | qualify_path, | ||
323 | " | ||
324 | PubStruct<|>", | ||
325 | ); | ||
326 | } | ||
327 | |||
328 | #[test] | ||
329 | fn not_applicable_in_import_statements() { | ||
330 | check_assist_not_applicable( | ||
331 | qualify_path, | ||
332 | r" | ||
333 | use PubStruct<|>; | ||
334 | |||
335 | pub mod PubMod { | ||
336 | pub struct PubStruct; | ||
337 | }", | ||
338 | ); | ||
339 | } | ||
340 | |||
341 | #[test] | ||
342 | fn qualify_function() { | ||
343 | check_assist( | ||
344 | qualify_path, | ||
345 | r" | ||
346 | test_function<|> | ||
347 | |||
348 | pub mod PubMod { | ||
349 | pub fn test_function() {}; | ||
350 | } | ||
351 | ", | ||
352 | r" | ||
353 | PubMod::test_function | ||
354 | |||
355 | pub mod PubMod { | ||
356 | pub fn test_function() {}; | ||
357 | } | ||
358 | ", | ||
359 | ); | ||
360 | } | ||
361 | |||
362 | #[test] | ||
363 | fn qualify_macro() { | ||
364 | check_assist( | ||
365 | qualify_path, | ||
366 | r" | ||
367 | //- /lib.rs crate:crate_with_macro | ||
368 | #[macro_export] | ||
369 | macro_rules! foo { | ||
370 | () => () | ||
371 | } | ||
372 | |||
373 | //- /main.rs crate:main deps:crate_with_macro | ||
374 | fn main() { | ||
375 | foo<|> | ||
376 | } | ||
377 | ", | ||
378 | r" | ||
379 | fn main() { | ||
380 | crate_with_macro::foo | ||
381 | } | ||
382 | ", | ||
383 | ); | ||
384 | } | ||
385 | |||
386 | #[test] | ||
387 | fn qualify_path_target() { | ||
388 | check_assist_target( | ||
389 | qualify_path, | ||
390 | r" | ||
391 | struct AssistInfo { | ||
392 | group_label: Option<<|>GroupLabel>, | ||
393 | } | ||
394 | |||
395 | mod m { pub struct GroupLabel; } | ||
396 | ", | ||
397 | "GroupLabel", | ||
398 | ) | ||
399 | } | ||
400 | |||
401 | #[test] | ||
402 | fn not_applicable_when_path_start_is_imported() { | ||
403 | check_assist_not_applicable( | ||
404 | qualify_path, | ||
405 | r" | ||
406 | pub mod mod1 { | ||
407 | pub mod mod2 { | ||
408 | pub mod mod3 { | ||
409 | pub struct TestStruct; | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | |||
414 | use mod1::mod2; | ||
415 | fn main() { | ||
416 | mod2::mod3::TestStruct<|> | ||
417 | } | ||
418 | ", | ||
419 | ); | ||
420 | } | ||
421 | |||
422 | #[test] | ||
423 | fn not_applicable_for_imported_function() { | ||
424 | check_assist_not_applicable( | ||
425 | qualify_path, | ||
426 | r" | ||
427 | pub mod test_mod { | ||
428 | pub fn test_function() {} | ||
429 | } | ||
430 | |||
431 | use test_mod::test_function; | ||
432 | fn main() { | ||
433 | test_function<|> | ||
434 | } | ||
435 | ", | ||
436 | ); | ||
437 | } | ||
438 | |||
439 | #[test] | ||
440 | fn associated_struct_function() { | ||
441 | check_assist( | ||
442 | qualify_path, | ||
443 | r" | ||
444 | mod test_mod { | ||
445 | pub struct TestStruct {} | ||
446 | impl TestStruct { | ||
447 | pub fn test_function() {} | ||
448 | } | ||
449 | } | ||
450 | |||
451 | fn main() { | ||
452 | TestStruct::test_function<|> | ||
453 | } | ||
454 | ", | ||
455 | r" | ||
456 | mod test_mod { | ||
457 | pub struct TestStruct {} | ||
458 | impl TestStruct { | ||
459 | pub fn test_function() {} | ||
460 | } | ||
461 | } | ||
462 | |||
463 | fn main() { | ||
464 | test_mod::TestStruct::test_function | ||
465 | } | ||
466 | ", | ||
467 | ); | ||
468 | } | ||
469 | |||
470 | #[test] | ||
471 | fn associated_struct_const() { | ||
472 | check_assist( | ||
473 | qualify_path, | ||
474 | r" | ||
475 | mod test_mod { | ||
476 | pub struct TestStruct {} | ||
477 | impl TestStruct { | ||
478 | const TEST_CONST: u8 = 42; | ||
479 | } | ||
480 | } | ||
481 | |||
482 | fn main() { | ||
483 | TestStruct::TEST_CONST<|> | ||
484 | } | ||
485 | ", | ||
486 | r" | ||
487 | mod test_mod { | ||
488 | pub struct TestStruct {} | ||
489 | impl TestStruct { | ||
490 | const TEST_CONST: u8 = 42; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | fn main() { | ||
495 | test_mod::TestStruct::TEST_CONST | ||
496 | } | ||
497 | ", | ||
498 | ); | ||
499 | } | ||
500 | |||
501 | #[test] | ||
502 | fn associated_trait_function() { | ||
503 | check_assist( | ||
504 | qualify_path, | ||
505 | r" | ||
506 | mod test_mod { | ||
507 | pub trait TestTrait { | ||
508 | fn test_function(); | ||
509 | } | ||
510 | pub struct TestStruct {} | ||
511 | impl TestTrait for TestStruct { | ||
512 | fn test_function() {} | ||
513 | } | ||
514 | } | ||
515 | |||
516 | fn main() { | ||
517 | test_mod::TestStruct::test_function<|> | ||
518 | } | ||
519 | ", | ||
520 | r" | ||
521 | mod test_mod { | ||
522 | pub trait TestTrait { | ||
523 | fn test_function(); | ||
524 | } | ||
525 | pub struct TestStruct {} | ||
526 | impl TestTrait for TestStruct { | ||
527 | fn test_function() {} | ||
528 | } | ||
529 | } | ||
530 | |||
531 | fn main() { | ||
532 | <test_mod::TestStruct as test_mod::TestTrait>::test_function | ||
533 | } | ||
534 | ", | ||
535 | ); | ||
536 | } | ||
537 | |||
538 | #[test] | ||
539 | fn not_applicable_for_imported_trait_for_function() { | ||
540 | check_assist_not_applicable( | ||
541 | qualify_path, | ||
542 | r" | ||
543 | mod test_mod { | ||
544 | pub trait TestTrait { | ||
545 | fn test_function(); | ||
546 | } | ||
547 | pub trait TestTrait2 { | ||
548 | fn test_function(); | ||
549 | } | ||
550 | pub enum TestEnum { | ||
551 | One, | ||
552 | Two, | ||
553 | } | ||
554 | impl TestTrait2 for TestEnum { | ||
555 | fn test_function() {} | ||
556 | } | ||
557 | impl TestTrait for TestEnum { | ||
558 | fn test_function() {} | ||
559 | } | ||
560 | } | ||
561 | |||
562 | use test_mod::TestTrait2; | ||
563 | fn main() { | ||
564 | test_mod::TestEnum::test_function<|>; | ||
565 | } | ||
566 | ", | ||
567 | ) | ||
568 | } | ||
569 | |||
570 | #[test] | ||
571 | fn associated_trait_const() { | ||
572 | check_assist( | ||
573 | qualify_path, | ||
574 | r" | ||
575 | mod test_mod { | ||
576 | pub trait TestTrait { | ||
577 | const TEST_CONST: u8; | ||
578 | } | ||
579 | pub struct TestStruct {} | ||
580 | impl TestTrait for TestStruct { | ||
581 | const TEST_CONST: u8 = 42; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | fn main() { | ||
586 | test_mod::TestStruct::TEST_CONST<|> | ||
587 | } | ||
588 | ", | ||
589 | r" | ||
590 | mod test_mod { | ||
591 | pub trait TestTrait { | ||
592 | const TEST_CONST: u8; | ||
593 | } | ||
594 | pub struct TestStruct {} | ||
595 | impl TestTrait for TestStruct { | ||
596 | const TEST_CONST: u8 = 42; | ||
597 | } | ||
598 | } | ||
599 | |||
600 | fn main() { | ||
601 | <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST | ||
602 | } | ||
603 | ", | ||
604 | ); | ||
605 | } | ||
606 | |||
607 | #[test] | ||
608 | fn not_applicable_for_imported_trait_for_const() { | ||
609 | check_assist_not_applicable( | ||
610 | qualify_path, | ||
611 | r" | ||
612 | mod test_mod { | ||
613 | pub trait TestTrait { | ||
614 | const TEST_CONST: u8; | ||
615 | } | ||
616 | pub trait TestTrait2 { | ||
617 | const TEST_CONST: f64; | ||
618 | } | ||
619 | pub enum TestEnum { | ||
620 | One, | ||
621 | Two, | ||
622 | } | ||
623 | impl TestTrait2 for TestEnum { | ||
624 | const TEST_CONST: f64 = 42.0; | ||
625 | } | ||
626 | impl TestTrait for TestEnum { | ||
627 | const TEST_CONST: u8 = 42; | ||
628 | } | ||
629 | } | ||
630 | |||
631 | use test_mod::TestTrait2; | ||
632 | fn main() { | ||
633 | test_mod::TestEnum::TEST_CONST<|>; | ||
634 | } | ||
635 | ", | ||
636 | ) | ||
637 | } | ||
638 | |||
639 | #[test] | ||
640 | fn trait_method() { | ||
641 | check_assist( | ||
642 | qualify_path, | ||
643 | r" | ||
644 | mod test_mod { | ||
645 | pub trait TestTrait { | ||
646 | fn test_method(&self); | ||
647 | } | ||
648 | pub struct TestStruct {} | ||
649 | impl TestTrait for TestStruct { | ||
650 | fn test_method(&self) {} | ||
651 | } | ||
652 | } | ||
653 | |||
654 | fn main() { | ||
655 | let test_struct = test_mod::TestStruct {}; | ||
656 | test_struct.test_meth<|>od() | ||
657 | } | ||
658 | ", | ||
659 | r" | ||
660 | mod test_mod { | ||
661 | pub trait TestTrait { | ||
662 | fn test_method(&self); | ||
663 | } | ||
664 | pub struct TestStruct {} | ||
665 | impl TestTrait for TestStruct { | ||
666 | fn test_method(&self) {} | ||
667 | } | ||
668 | } | ||
669 | |||
670 | fn main() { | ||
671 | let test_struct = test_mod::TestStruct {}; | ||
672 | test_mod::TestTrait::test_method(&test_struct) | ||
673 | } | ||
674 | ", | ||
675 | ); | ||
676 | } | ||
677 | |||
678 | #[test] | ||
679 | fn trait_method_multi_params() { | ||
680 | check_assist( | ||
681 | qualify_path, | ||
682 | r" | ||
683 | mod test_mod { | ||
684 | pub trait TestTrait { | ||
685 | fn test_method(&self, test: i32); | ||
686 | } | ||
687 | pub struct TestStruct {} | ||
688 | impl TestTrait for TestStruct { | ||
689 | fn test_method(&self, test: i32) {} | ||
690 | } | ||
691 | } | ||
692 | |||
693 | fn main() { | ||
694 | let test_struct = test_mod::TestStruct {}; | ||
695 | test_struct.test_meth<|>od(42) | ||
696 | } | ||
697 | ", | ||
698 | r" | ||
699 | mod test_mod { | ||
700 | pub trait TestTrait { | ||
701 | fn test_method(&self, test: i32); | ||
702 | } | ||
703 | pub struct TestStruct {} | ||
704 | impl TestTrait for TestStruct { | ||
705 | fn test_method(&self, test: i32) {} | ||
706 | } | ||
707 | } | ||
708 | |||
709 | fn main() { | ||
710 | let test_struct = test_mod::TestStruct {}; | ||
711 | test_mod::TestTrait::test_method(&test_struct, 42) | ||
712 | } | ||
713 | ", | ||
714 | ); | ||
715 | } | ||
716 | |||
717 | #[test] | ||
718 | fn trait_method_consume() { | ||
719 | check_assist( | ||
720 | qualify_path, | ||
721 | r" | ||
722 | mod test_mod { | ||
723 | pub trait TestTrait { | ||
724 | fn test_method(self); | ||
725 | } | ||
726 | pub struct TestStruct {} | ||
727 | impl TestTrait for TestStruct { | ||
728 | fn test_method(self) {} | ||
729 | } | ||
730 | } | ||
731 | |||
732 | fn main() { | ||
733 | let test_struct = test_mod::TestStruct {}; | ||
734 | test_struct.test_meth<|>od() | ||
735 | } | ||
736 | ", | ||
737 | r" | ||
738 | mod test_mod { | ||
739 | pub trait TestTrait { | ||
740 | fn test_method(self); | ||
741 | } | ||
742 | pub struct TestStruct {} | ||
743 | impl TestTrait for TestStruct { | ||
744 | fn test_method(self) {} | ||
745 | } | ||
746 | } | ||
747 | |||
748 | fn main() { | ||
749 | let test_struct = test_mod::TestStruct {}; | ||
750 | test_mod::TestTrait::test_method(test_struct) | ||
751 | } | ||
752 | ", | ||
753 | ); | ||
754 | } | ||
755 | |||
756 | #[test] | ||
757 | fn trait_method_cross_crate() { | ||
758 | check_assist( | ||
759 | qualify_path, | ||
760 | r" | ||
761 | //- /main.rs crate:main deps:dep | ||
762 | fn main() { | ||
763 | let test_struct = dep::test_mod::TestStruct {}; | ||
764 | test_struct.test_meth<|>od() | ||
765 | } | ||
766 | //- /dep.rs crate:dep | ||
767 | pub mod test_mod { | ||
768 | pub trait TestTrait { | ||
769 | fn test_method(&self); | ||
770 | } | ||
771 | pub struct TestStruct {} | ||
772 | impl TestTrait for TestStruct { | ||
773 | fn test_method(&self) {} | ||
774 | } | ||
775 | } | ||
776 | ", | ||
777 | r" | ||
778 | fn main() { | ||
779 | let test_struct = dep::test_mod::TestStruct {}; | ||
780 | dep::test_mod::TestTrait::test_method(&test_struct) | ||
781 | } | ||
782 | ", | ||
783 | ); | ||
784 | } | ||
785 | |||
786 | #[test] | ||
787 | fn assoc_fn_cross_crate() { | ||
788 | check_assist( | ||
789 | qualify_path, | ||
790 | r" | ||
791 | //- /main.rs crate:main deps:dep | ||
792 | fn main() { | ||
793 | dep::test_mod::TestStruct::test_func<|>tion | ||
794 | } | ||
795 | //- /dep.rs crate:dep | ||
796 | pub mod test_mod { | ||
797 | pub trait TestTrait { | ||
798 | fn test_function(); | ||
799 | } | ||
800 | pub struct TestStruct {} | ||
801 | impl TestTrait for TestStruct { | ||
802 | fn test_function() {} | ||
803 | } | ||
804 | } | ||
805 | ", | ||
806 | r" | ||
807 | fn main() { | ||
808 | <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function | ||
809 | } | ||
810 | ", | ||
811 | ); | ||
812 | } | ||
813 | |||
814 | #[test] | ||
815 | fn assoc_const_cross_crate() { | ||
816 | check_assist( | ||
817 | qualify_path, | ||
818 | r" | ||
819 | //- /main.rs crate:main deps:dep | ||
820 | fn main() { | ||
821 | dep::test_mod::TestStruct::CONST<|> | ||
822 | } | ||
823 | //- /dep.rs crate:dep | ||
824 | pub mod test_mod { | ||
825 | pub trait TestTrait { | ||
826 | const CONST: bool; | ||
827 | } | ||
828 | pub struct TestStruct {} | ||
829 | impl TestTrait for TestStruct { | ||
830 | const CONST: bool = true; | ||
831 | } | ||
832 | } | ||
833 | ", | ||
834 | r" | ||
835 | fn main() { | ||
836 | <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST | ||
837 | } | ||
838 | ", | ||
839 | ); | ||
840 | } | ||
841 | |||
842 | #[test] | ||
843 | fn assoc_fn_as_method_cross_crate() { | ||
844 | check_assist_not_applicable( | ||
845 | qualify_path, | ||
846 | r" | ||
847 | //- /main.rs crate:main deps:dep | ||
848 | fn main() { | ||
849 | let test_struct = dep::test_mod::TestStruct {}; | ||
850 | test_struct.test_func<|>tion() | ||
851 | } | ||
852 | //- /dep.rs crate:dep | ||
853 | pub mod test_mod { | ||
854 | pub trait TestTrait { | ||
855 | fn test_function(); | ||
856 | } | ||
857 | pub struct TestStruct {} | ||
858 | impl TestTrait for TestStruct { | ||
859 | fn test_function() {} | ||
860 | } | ||
861 | } | ||
862 | ", | ||
863 | ); | ||
864 | } | ||
865 | |||
866 | #[test] | ||
867 | fn private_trait_cross_crate() { | ||
868 | check_assist_not_applicable( | ||
869 | qualify_path, | ||
870 | r" | ||
871 | //- /main.rs crate:main deps:dep | ||
872 | fn main() { | ||
873 | let test_struct = dep::test_mod::TestStruct {}; | ||
874 | test_struct.test_meth<|>od() | ||
875 | } | ||
876 | //- /dep.rs crate:dep | ||
877 | pub mod test_mod { | ||
878 | trait TestTrait { | ||
879 | fn test_method(&self); | ||
880 | } | ||
881 | pub struct TestStruct {} | ||
882 | impl TestTrait for TestStruct { | ||
883 | fn test_method(&self) {} | ||
884 | } | ||
885 | } | ||
886 | ", | ||
887 | ); | ||
888 | } | ||
889 | |||
890 | #[test] | ||
891 | fn not_applicable_for_imported_trait_for_method() { | ||
892 | check_assist_not_applicable( | ||
893 | qualify_path, | ||
894 | r" | ||
895 | mod test_mod { | ||
896 | pub trait TestTrait { | ||
897 | fn test_method(&self); | ||
898 | } | ||
899 | pub trait TestTrait2 { | ||
900 | fn test_method(&self); | ||
901 | } | ||
902 | pub enum TestEnum { | ||
903 | One, | ||
904 | Two, | ||
905 | } | ||
906 | impl TestTrait2 for TestEnum { | ||
907 | fn test_method(&self) {} | ||
908 | } | ||
909 | impl TestTrait for TestEnum { | ||
910 | fn test_method(&self) {} | ||
911 | } | ||
912 | } | ||
913 | |||
914 | use test_mod::TestTrait2; | ||
915 | fn main() { | ||
916 | let one = test_mod::TestEnum::One; | ||
917 | one.test<|>_method(); | ||
918 | } | ||
919 | ", | ||
920 | ) | ||
921 | } | ||
922 | |||
923 | #[test] | ||
924 | fn dep_import() { | ||
925 | check_assist( | ||
926 | qualify_path, | ||
927 | r" | ||
928 | //- /lib.rs crate:dep | ||
929 | pub struct Struct; | ||
930 | |||
931 | //- /main.rs crate:main deps:dep | ||
932 | fn main() { | ||
933 | Struct<|> | ||
934 | } | ||
935 | ", | ||
936 | r" | ||
937 | fn main() { | ||
938 | dep::Struct | ||
939 | } | ||
940 | ", | ||
941 | ); | ||
942 | } | ||
943 | |||
944 | #[test] | ||
945 | fn whole_segment() { | ||
946 | // Tests that only imports whose last segment matches the identifier get suggested. | ||
947 | check_assist( | ||
948 | qualify_path, | ||
949 | r" | ||
950 | //- /lib.rs crate:dep | ||
951 | pub mod fmt { | ||
952 | pub trait Display {} | ||
953 | } | ||
954 | |||
955 | pub fn panic_fmt() {} | ||
956 | |||
957 | //- /main.rs crate:main deps:dep | ||
958 | struct S; | ||
959 | |||
960 | impl f<|>mt::Display for S {} | ||
961 | ", | ||
962 | r" | ||
963 | struct S; | ||
964 | |||
965 | impl dep::fmt::Display for S {} | ||
966 | ", | ||
967 | ); | ||
968 | } | ||
969 | |||
970 | #[test] | ||
971 | fn macro_generated() { | ||
972 | // Tests that macro-generated items are suggested from external crates. | ||
973 | check_assist( | ||
974 | qualify_path, | ||
975 | r" | ||
976 | //- /lib.rs crate:dep | ||
977 | macro_rules! mac { | ||
978 | () => { | ||
979 | pub struct Cheese; | ||
980 | }; | ||
981 | } | ||
982 | |||
983 | mac!(); | ||
984 | |||
985 | //- /main.rs crate:main deps:dep | ||
986 | fn main() { | ||
987 | Cheese<|>; | ||
988 | } | ||
989 | ", | ||
990 | r" | ||
991 | fn main() { | ||
992 | dep::Cheese; | ||
993 | } | ||
994 | ", | ||
995 | ); | ||
996 | } | ||
997 | |||
998 | #[test] | ||
999 | fn casing() { | ||
1000 | // Tests that differently cased names don't interfere and we only suggest the matching one. | ||
1001 | check_assist( | ||
1002 | qualify_path, | ||
1003 | r" | ||
1004 | //- /lib.rs crate:dep | ||
1005 | pub struct FMT; | ||
1006 | pub struct fmt; | ||
1007 | |||
1008 | //- /main.rs crate:main deps:dep | ||
1009 | fn main() { | ||
1010 | FMT<|>; | ||
1011 | } | ||
1012 | ", | ||
1013 | r" | ||
1014 | fn main() { | ||
1015 | dep::FMT; | ||
1016 | } | ||
1017 | ", | ||
1018 | ); | ||
1019 | } | ||
1020 | } | ||
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs index a2bec818c..f29b8212f 100644 --- a/crates/assists/src/lib.rs +++ b/crates/assists/src/lib.rs | |||
@@ -150,6 +150,7 @@ mod handlers { | |||
150 | mod merge_match_arms; | 150 | mod merge_match_arms; |
151 | mod move_bounds; | 151 | mod move_bounds; |
152 | mod move_guard; | 152 | mod move_guard; |
153 | mod qualify_path; | ||
153 | mod raw_string; | 154 | mod raw_string; |
154 | mod remove_dbg; | 155 | mod remove_dbg; |
155 | mod remove_mut; | 156 | mod remove_mut; |
@@ -196,6 +197,7 @@ mod handlers { | |||
196 | move_bounds::move_bounds_to_where_clause, | 197 | move_bounds::move_bounds_to_where_clause, |
197 | move_guard::move_arm_cond_to_match_guard, | 198 | move_guard::move_arm_cond_to_match_guard, |
198 | move_guard::move_guard_to_arm_body, | 199 | move_guard::move_guard_to_arm_body, |
200 | qualify_path::qualify_path, | ||
199 | raw_string::add_hash, | 201 | raw_string::add_hash, |
200 | raw_string::make_raw_string, | 202 | raw_string::make_raw_string, |
201 | raw_string::make_usual_string, | 203 | raw_string::make_usual_string, |