diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-02-22 20:28:17 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-02-22 20:28:17 +0000 |
commit | 27ed1ebf8997cea55fb446ce249b390607b84105 (patch) | |
tree | a49a763fee848041fd607f449ad13a0b1040636e /crates/ide_assists/src/handlers/qualify_path.rs | |
parent | 8687053b118f47ce1a4962d0baa19b22d40d2758 (diff) | |
parent | eb6cfa7f157690480fca5d55c69dba3fae87ad4f (diff) |
Merge #7759
7759: 7526: Rename ide related crates r=Veykril a=chetankhilosiya
renamed assists -> ide_assists and ssr -> ide_ssr.
the completion crate is already renamed.
Co-authored-by: Chetan Khilosiya <[email protected]>
Diffstat (limited to 'crates/ide_assists/src/handlers/qualify_path.rs')
-rw-r--r-- | crates/ide_assists/src/handlers/qualify_path.rs | 1205 |
1 files changed, 1205 insertions, 0 deletions
diff --git a/crates/ide_assists/src/handlers/qualify_path.rs b/crates/ide_assists/src/handlers/qualify_path.rs new file mode 100644 index 000000000..b0b0d31b4 --- /dev/null +++ b/crates/ide_assists/src/handlers/qualify_path.rs | |||
@@ -0,0 +1,1205 @@ | |||
1 | use std::iter; | ||
2 | |||
3 | use hir::{AsAssocItem, AsName}; | ||
4 | use ide_db::helpers::{import_assets::ImportCandidate, mod_path_to_ast}; | ||
5 | use ide_db::RootDatabase; | ||
6 | use syntax::{ | ||
7 | ast, | ||
8 | ast::{make, ArgListOwner}, | ||
9 | AstNode, | ||
10 | }; | ||
11 | use test_utils::mark; | ||
12 | |||
13 | use crate::{ | ||
14 | assist_context::{AssistContext, Assists}, | ||
15 | AssistId, AssistKind, GroupLabel, | ||
16 | }; | ||
17 | |||
18 | use super::auto_import::find_importable_node; | ||
19 | |||
20 | // Assist: qualify_path | ||
21 | // | ||
22 | // If the name is unresolved, provides all possible qualified paths for it. | ||
23 | // | ||
24 | // ``` | ||
25 | // fn main() { | ||
26 | // let map = HashMap$0::new(); | ||
27 | // } | ||
28 | // # pub mod std { pub mod collections { pub struct HashMap { } } } | ||
29 | // ``` | ||
30 | // -> | ||
31 | // ``` | ||
32 | // fn main() { | ||
33 | // let map = std::collections::HashMap::new(); | ||
34 | // } | ||
35 | // # pub mod std { pub mod collections { pub struct HashMap { } } } | ||
36 | // ``` | ||
37 | pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
38 | let (import_assets, syntax_under_caret) = find_importable_node(ctx)?; | ||
39 | let proposed_imports = import_assets.search_for_relative_paths(&ctx.sema); | ||
40 | if proposed_imports.is_empty() { | ||
41 | return None; | ||
42 | } | ||
43 | |||
44 | let candidate = import_assets.import_candidate(); | ||
45 | let range = ctx.sema.original_range(&syntax_under_caret).range; | ||
46 | |||
47 | let qualify_candidate = match candidate { | ||
48 | ImportCandidate::Path(candidate) => { | ||
49 | if candidate.qualifier.is_some() { | ||
50 | mark::hit!(qualify_path_qualifier_start); | ||
51 | let path = ast::Path::cast(syntax_under_caret)?; | ||
52 | let (prev_segment, segment) = (path.qualifier()?.segment()?, path.segment()?); | ||
53 | QualifyCandidate::QualifierStart(segment, prev_segment.generic_arg_list()) | ||
54 | } else { | ||
55 | mark::hit!(qualify_path_unqualified_name); | ||
56 | let path = ast::Path::cast(syntax_under_caret)?; | ||
57 | let generics = path.segment()?.generic_arg_list(); | ||
58 | QualifyCandidate::UnqualifiedName(generics) | ||
59 | } | ||
60 | } | ||
61 | ImportCandidate::TraitAssocItem(_) => { | ||
62 | mark::hit!(qualify_path_trait_assoc_item); | ||
63 | let path = ast::Path::cast(syntax_under_caret)?; | ||
64 | let (qualifier, segment) = (path.qualifier()?, path.segment()?); | ||
65 | QualifyCandidate::TraitAssocItem(qualifier, segment) | ||
66 | } | ||
67 | ImportCandidate::TraitMethod(_) => { | ||
68 | mark::hit!(qualify_path_trait_method); | ||
69 | let mcall_expr = ast::MethodCallExpr::cast(syntax_under_caret)?; | ||
70 | QualifyCandidate::TraitMethod(ctx.sema.db, mcall_expr) | ||
71 | } | ||
72 | }; | ||
73 | |||
74 | let group_label = group_label(candidate); | ||
75 | for (import, item) in proposed_imports { | ||
76 | acc.add_group( | ||
77 | &group_label, | ||
78 | AssistId("qualify_path", AssistKind::QuickFix), | ||
79 | label(candidate, &import), | ||
80 | range, | ||
81 | |builder| { | ||
82 | qualify_candidate.qualify( | ||
83 | |replace_with: String| builder.replace(range, replace_with), | ||
84 | import, | ||
85 | item, | ||
86 | ) | ||
87 | }, | ||
88 | ); | ||
89 | } | ||
90 | Some(()) | ||
91 | } | ||
92 | |||
93 | enum QualifyCandidate<'db> { | ||
94 | QualifierStart(ast::PathSegment, Option<ast::GenericArgList>), | ||
95 | UnqualifiedName(Option<ast::GenericArgList>), | ||
96 | TraitAssocItem(ast::Path, ast::PathSegment), | ||
97 | TraitMethod(&'db RootDatabase, ast::MethodCallExpr), | ||
98 | } | ||
99 | |||
100 | impl QualifyCandidate<'_> { | ||
101 | fn qualify(&self, mut replacer: impl FnMut(String), import: hir::ModPath, item: hir::ItemInNs) { | ||
102 | let import = mod_path_to_ast(&import); | ||
103 | match self { | ||
104 | QualifyCandidate::QualifierStart(segment, generics) => { | ||
105 | let generics = generics.as_ref().map_or_else(String::new, ToString::to_string); | ||
106 | replacer(format!("{}{}::{}", import, generics, segment)); | ||
107 | } | ||
108 | QualifyCandidate::UnqualifiedName(generics) => { | ||
109 | let generics = generics.as_ref().map_or_else(String::new, ToString::to_string); | ||
110 | replacer(format!("{}{}", import.to_string(), generics)); | ||
111 | } | ||
112 | QualifyCandidate::TraitAssocItem(qualifier, segment) => { | ||
113 | replacer(format!("<{} as {}>::{}", qualifier, import, segment)); | ||
114 | } | ||
115 | &QualifyCandidate::TraitMethod(db, ref mcall_expr) => { | ||
116 | Self::qualify_trait_method(db, mcall_expr, replacer, import, item); | ||
117 | } | ||
118 | } | ||
119 | } | ||
120 | |||
121 | fn qualify_trait_method( | ||
122 | db: &RootDatabase, | ||
123 | mcall_expr: &ast::MethodCallExpr, | ||
124 | mut replacer: impl FnMut(String), | ||
125 | import: ast::Path, | ||
126 | item: hir::ItemInNs, | ||
127 | ) -> Option<()> { | ||
128 | let receiver = mcall_expr.receiver()?; | ||
129 | let trait_method_name = mcall_expr.name_ref()?; | ||
130 | let generics = | ||
131 | mcall_expr.generic_arg_list().as_ref().map_or_else(String::new, ToString::to_string); | ||
132 | let arg_list = mcall_expr.arg_list().map(|arg_list| arg_list.args()); | ||
133 | let trait_ = item_as_trait(db, item)?; | ||
134 | let method = find_trait_method(db, trait_, &trait_method_name)?; | ||
135 | if let Some(self_access) = method.self_param(db).map(|sp| sp.access(db)) { | ||
136 | let receiver = match self_access { | ||
137 | hir::Access::Shared => make::expr_ref(receiver, false), | ||
138 | hir::Access::Exclusive => make::expr_ref(receiver, true), | ||
139 | hir::Access::Owned => receiver, | ||
140 | }; | ||
141 | replacer(format!( | ||
142 | "{}::{}{}{}", | ||
143 | import, | ||
144 | trait_method_name, | ||
145 | generics, | ||
146 | match arg_list { | ||
147 | Some(args) => make::arg_list(iter::once(receiver).chain(args)), | ||
148 | None => make::arg_list(iter::once(receiver)), | ||
149 | } | ||
150 | )); | ||
151 | } | ||
152 | Some(()) | ||
153 | } | ||
154 | } | ||
155 | |||
156 | fn find_trait_method( | ||
157 | db: &RootDatabase, | ||
158 | trait_: hir::Trait, | ||
159 | trait_method_name: &ast::NameRef, | ||
160 | ) -> Option<hir::Function> { | ||
161 | if let Some(hir::AssocItem::Function(method)) = | ||
162 | trait_.items(db).into_iter().find(|item: &hir::AssocItem| { | ||
163 | item.name(db).map(|name| name == trait_method_name.as_name()).unwrap_or(false) | ||
164 | }) | ||
165 | { | ||
166 | Some(method) | ||
167 | } else { | ||
168 | None | ||
169 | } | ||
170 | } | ||
171 | |||
172 | fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option<hir::Trait> { | ||
173 | let item_module_def = hir::ModuleDef::from(item.as_module_def_id()?); | ||
174 | |||
175 | if let hir::ModuleDef::Trait(trait_) = item_module_def { | ||
176 | Some(trait_) | ||
177 | } else { | ||
178 | item_module_def.as_assoc_item(db)?.containing_trait(db) | ||
179 | } | ||
180 | } | ||
181 | |||
182 | fn group_label(candidate: &ImportCandidate) -> GroupLabel { | ||
183 | let name = match candidate { | ||
184 | ImportCandidate::Path(it) => &it.name, | ||
185 | ImportCandidate::TraitAssocItem(it) | ImportCandidate::TraitMethod(it) => &it.name, | ||
186 | } | ||
187 | .text(); | ||
188 | GroupLabel(format!("Qualify {}", name)) | ||
189 | } | ||
190 | |||
191 | fn label(candidate: &ImportCandidate, import: &hir::ModPath) -> String { | ||
192 | match candidate { | ||
193 | ImportCandidate::Path(candidate) => { | ||
194 | if candidate.qualifier.is_some() { | ||
195 | format!("Qualify with `{}`", &import) | ||
196 | } else { | ||
197 | format!("Qualify as `{}`", &import) | ||
198 | } | ||
199 | } | ||
200 | ImportCandidate::TraitAssocItem(_) => format!("Qualify `{}`", &import), | ||
201 | ImportCandidate::TraitMethod(_) => format!("Qualify with cast as `{}`", &import), | ||
202 | } | ||
203 | } | ||
204 | |||
205 | #[cfg(test)] | ||
206 | mod tests { | ||
207 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; | ||
208 | |||
209 | use super::*; | ||
210 | |||
211 | #[test] | ||
212 | fn applicable_when_found_an_import_partial() { | ||
213 | mark::check!(qualify_path_unqualified_name); | ||
214 | check_assist( | ||
215 | qualify_path, | ||
216 | r" | ||
217 | mod std { | ||
218 | pub mod fmt { | ||
219 | pub struct Formatter; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | use std::fmt; | ||
224 | |||
225 | $0Formatter | ||
226 | ", | ||
227 | r" | ||
228 | mod std { | ||
229 | pub mod fmt { | ||
230 | pub struct Formatter; | ||
231 | } | ||
232 | } | ||
233 | |||
234 | use std::fmt; | ||
235 | |||
236 | fmt::Formatter | ||
237 | ", | ||
238 | ); | ||
239 | } | ||
240 | |||
241 | #[test] | ||
242 | fn applicable_when_found_an_import() { | ||
243 | check_assist( | ||
244 | qualify_path, | ||
245 | r" | ||
246 | $0PubStruct | ||
247 | |||
248 | pub mod PubMod { | ||
249 | pub struct PubStruct; | ||
250 | } | ||
251 | ", | ||
252 | r" | ||
253 | PubMod::PubStruct | ||
254 | |||
255 | pub mod PubMod { | ||
256 | pub struct PubStruct; | ||
257 | } | ||
258 | ", | ||
259 | ); | ||
260 | } | ||
261 | |||
262 | #[test] | ||
263 | fn applicable_in_macros() { | ||
264 | check_assist( | ||
265 | qualify_path, | ||
266 | r" | ||
267 | macro_rules! foo { | ||
268 | ($i:ident) => { fn foo(a: $i) {} } | ||
269 | } | ||
270 | foo!(Pub$0Struct); | ||
271 | |||
272 | pub mod PubMod { | ||
273 | pub struct PubStruct; | ||
274 | } | ||
275 | ", | ||
276 | r" | ||
277 | macro_rules! foo { | ||
278 | ($i:ident) => { fn foo(a: $i) {} } | ||
279 | } | ||
280 | foo!(PubMod::PubStruct); | ||
281 | |||
282 | pub mod PubMod { | ||
283 | pub struct PubStruct; | ||
284 | } | ||
285 | ", | ||
286 | ); | ||
287 | } | ||
288 | |||
289 | #[test] | ||
290 | fn applicable_when_found_multiple_imports() { | ||
291 | check_assist( | ||
292 | qualify_path, | ||
293 | r" | ||
294 | PubSt$0ruct | ||
295 | |||
296 | pub mod PubMod1 { | ||
297 | pub struct PubStruct; | ||
298 | } | ||
299 | pub mod PubMod2 { | ||
300 | pub struct PubStruct; | ||
301 | } | ||
302 | pub mod PubMod3 { | ||
303 | pub struct PubStruct; | ||
304 | } | ||
305 | ", | ||
306 | r" | ||
307 | PubMod3::PubStruct | ||
308 | |||
309 | pub mod PubMod1 { | ||
310 | pub struct PubStruct; | ||
311 | } | ||
312 | pub mod PubMod2 { | ||
313 | pub struct PubStruct; | ||
314 | } | ||
315 | pub mod PubMod3 { | ||
316 | pub struct PubStruct; | ||
317 | } | ||
318 | ", | ||
319 | ); | ||
320 | } | ||
321 | |||
322 | #[test] | ||
323 | fn not_applicable_for_already_imported_types() { | ||
324 | check_assist_not_applicable( | ||
325 | qualify_path, | ||
326 | r" | ||
327 | use PubMod::PubStruct; | ||
328 | |||
329 | PubStruct$0 | ||
330 | |||
331 | pub mod PubMod { | ||
332 | pub struct PubStruct; | ||
333 | } | ||
334 | ", | ||
335 | ); | ||
336 | } | ||
337 | |||
338 | #[test] | ||
339 | fn not_applicable_for_types_with_private_paths() { | ||
340 | check_assist_not_applicable( | ||
341 | qualify_path, | ||
342 | r" | ||
343 | PrivateStruct$0 | ||
344 | |||
345 | pub mod PubMod { | ||
346 | struct PrivateStruct; | ||
347 | } | ||
348 | ", | ||
349 | ); | ||
350 | } | ||
351 | |||
352 | #[test] | ||
353 | fn not_applicable_when_no_imports_found() { | ||
354 | check_assist_not_applicable( | ||
355 | qualify_path, | ||
356 | " | ||
357 | PubStruct$0", | ||
358 | ); | ||
359 | } | ||
360 | |||
361 | #[test] | ||
362 | fn not_applicable_in_import_statements() { | ||
363 | check_assist_not_applicable( | ||
364 | qualify_path, | ||
365 | r" | ||
366 | use PubStruct$0; | ||
367 | |||
368 | pub mod PubMod { | ||
369 | pub struct PubStruct; | ||
370 | }", | ||
371 | ); | ||
372 | } | ||
373 | |||
374 | #[test] | ||
375 | fn qualify_function() { | ||
376 | check_assist( | ||
377 | qualify_path, | ||
378 | r" | ||
379 | test_function$0 | ||
380 | |||
381 | pub mod PubMod { | ||
382 | pub fn test_function() {}; | ||
383 | } | ||
384 | ", | ||
385 | r" | ||
386 | PubMod::test_function | ||
387 | |||
388 | pub mod PubMod { | ||
389 | pub fn test_function() {}; | ||
390 | } | ||
391 | ", | ||
392 | ); | ||
393 | } | ||
394 | |||
395 | #[test] | ||
396 | fn qualify_macro() { | ||
397 | check_assist( | ||
398 | qualify_path, | ||
399 | r" | ||
400 | //- /lib.rs crate:crate_with_macro | ||
401 | #[macro_export] | ||
402 | macro_rules! foo { | ||
403 | () => () | ||
404 | } | ||
405 | |||
406 | //- /main.rs crate:main deps:crate_with_macro | ||
407 | fn main() { | ||
408 | foo$0 | ||
409 | } | ||
410 | ", | ||
411 | r" | ||
412 | fn main() { | ||
413 | crate_with_macro::foo | ||
414 | } | ||
415 | ", | ||
416 | ); | ||
417 | } | ||
418 | |||
419 | #[test] | ||
420 | fn qualify_path_target() { | ||
421 | check_assist_target( | ||
422 | qualify_path, | ||
423 | r" | ||
424 | struct AssistInfo { | ||
425 | group_label: Option<$0GroupLabel>, | ||
426 | } | ||
427 | |||
428 | mod m { pub struct GroupLabel; } | ||
429 | ", | ||
430 | "GroupLabel", | ||
431 | ) | ||
432 | } | ||
433 | |||
434 | #[test] | ||
435 | fn not_applicable_when_path_start_is_imported() { | ||
436 | check_assist_not_applicable( | ||
437 | qualify_path, | ||
438 | r" | ||
439 | pub mod mod1 { | ||
440 | pub mod mod2 { | ||
441 | pub mod mod3 { | ||
442 | pub struct TestStruct; | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | |||
447 | use mod1::mod2; | ||
448 | fn main() { | ||
449 | mod2::mod3::TestStruct$0 | ||
450 | } | ||
451 | ", | ||
452 | ); | ||
453 | } | ||
454 | |||
455 | #[test] | ||
456 | fn not_applicable_for_imported_function() { | ||
457 | check_assist_not_applicable( | ||
458 | qualify_path, | ||
459 | r" | ||
460 | pub mod test_mod { | ||
461 | pub fn test_function() {} | ||
462 | } | ||
463 | |||
464 | use test_mod::test_function; | ||
465 | fn main() { | ||
466 | test_function$0 | ||
467 | } | ||
468 | ", | ||
469 | ); | ||
470 | } | ||
471 | |||
472 | #[test] | ||
473 | fn associated_struct_function() { | ||
474 | check_assist( | ||
475 | qualify_path, | ||
476 | r" | ||
477 | mod test_mod { | ||
478 | pub struct TestStruct {} | ||
479 | impl TestStruct { | ||
480 | pub fn test_function() {} | ||
481 | } | ||
482 | } | ||
483 | |||
484 | fn main() { | ||
485 | TestStruct::test_function$0 | ||
486 | } | ||
487 | ", | ||
488 | r" | ||
489 | mod test_mod { | ||
490 | pub struct TestStruct {} | ||
491 | impl TestStruct { | ||
492 | pub fn test_function() {} | ||
493 | } | ||
494 | } | ||
495 | |||
496 | fn main() { | ||
497 | test_mod::TestStruct::test_function | ||
498 | } | ||
499 | ", | ||
500 | ); | ||
501 | } | ||
502 | |||
503 | #[test] | ||
504 | fn associated_struct_const() { | ||
505 | mark::check!(qualify_path_qualifier_start); | ||
506 | check_assist( | ||
507 | qualify_path, | ||
508 | r" | ||
509 | mod test_mod { | ||
510 | pub struct TestStruct {} | ||
511 | impl TestStruct { | ||
512 | const TEST_CONST: u8 = 42; | ||
513 | } | ||
514 | } | ||
515 | |||
516 | fn main() { | ||
517 | TestStruct::TEST_CONST$0 | ||
518 | } | ||
519 | ", | ||
520 | r" | ||
521 | mod test_mod { | ||
522 | pub struct TestStruct {} | ||
523 | impl TestStruct { | ||
524 | const TEST_CONST: u8 = 42; | ||
525 | } | ||
526 | } | ||
527 | |||
528 | fn main() { | ||
529 | test_mod::TestStruct::TEST_CONST | ||
530 | } | ||
531 | ", | ||
532 | ); | ||
533 | } | ||
534 | |||
535 | #[test] | ||
536 | fn associated_trait_function() { | ||
537 | check_assist( | ||
538 | qualify_path, | ||
539 | r" | ||
540 | mod test_mod { | ||
541 | pub trait TestTrait { | ||
542 | fn test_function(); | ||
543 | } | ||
544 | pub struct TestStruct {} | ||
545 | impl TestTrait for TestStruct { | ||
546 | fn test_function() {} | ||
547 | } | ||
548 | } | ||
549 | |||
550 | fn main() { | ||
551 | test_mod::TestStruct::test_function$0 | ||
552 | } | ||
553 | ", | ||
554 | r" | ||
555 | mod test_mod { | ||
556 | pub trait TestTrait { | ||
557 | fn test_function(); | ||
558 | } | ||
559 | pub struct TestStruct {} | ||
560 | impl TestTrait for TestStruct { | ||
561 | fn test_function() {} | ||
562 | } | ||
563 | } | ||
564 | |||
565 | fn main() { | ||
566 | <test_mod::TestStruct as test_mod::TestTrait>::test_function | ||
567 | } | ||
568 | ", | ||
569 | ); | ||
570 | } | ||
571 | |||
572 | #[test] | ||
573 | fn not_applicable_for_imported_trait_for_function() { | ||
574 | check_assist_not_applicable( | ||
575 | qualify_path, | ||
576 | r" | ||
577 | mod test_mod { | ||
578 | pub trait TestTrait { | ||
579 | fn test_function(); | ||
580 | } | ||
581 | pub trait TestTrait2 { | ||
582 | fn test_function(); | ||
583 | } | ||
584 | pub enum TestEnum { | ||
585 | One, | ||
586 | Two, | ||
587 | } | ||
588 | impl TestTrait2 for TestEnum { | ||
589 | fn test_function() {} | ||
590 | } | ||
591 | impl TestTrait for TestEnum { | ||
592 | fn test_function() {} | ||
593 | } | ||
594 | } | ||
595 | |||
596 | use test_mod::TestTrait2; | ||
597 | fn main() { | ||
598 | test_mod::TestEnum::test_function$0; | ||
599 | } | ||
600 | ", | ||
601 | ) | ||
602 | } | ||
603 | |||
604 | #[test] | ||
605 | fn associated_trait_const() { | ||
606 | mark::check!(qualify_path_trait_assoc_item); | ||
607 | check_assist( | ||
608 | qualify_path, | ||
609 | r" | ||
610 | mod test_mod { | ||
611 | pub trait TestTrait { | ||
612 | const TEST_CONST: u8; | ||
613 | } | ||
614 | pub struct TestStruct {} | ||
615 | impl TestTrait for TestStruct { | ||
616 | const TEST_CONST: u8 = 42; | ||
617 | } | ||
618 | } | ||
619 | |||
620 | fn main() { | ||
621 | test_mod::TestStruct::TEST_CONST$0 | ||
622 | } | ||
623 | ", | ||
624 | r" | ||
625 | mod test_mod { | ||
626 | pub trait TestTrait { | ||
627 | const TEST_CONST: u8; | ||
628 | } | ||
629 | pub struct TestStruct {} | ||
630 | impl TestTrait for TestStruct { | ||
631 | const TEST_CONST: u8 = 42; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | fn main() { | ||
636 | <test_mod::TestStruct as test_mod::TestTrait>::TEST_CONST | ||
637 | } | ||
638 | ", | ||
639 | ); | ||
640 | } | ||
641 | |||
642 | #[test] | ||
643 | fn not_applicable_for_imported_trait_for_const() { | ||
644 | check_assist_not_applicable( | ||
645 | qualify_path, | ||
646 | r" | ||
647 | mod test_mod { | ||
648 | pub trait TestTrait { | ||
649 | const TEST_CONST: u8; | ||
650 | } | ||
651 | pub trait TestTrait2 { | ||
652 | const TEST_CONST: f64; | ||
653 | } | ||
654 | pub enum TestEnum { | ||
655 | One, | ||
656 | Two, | ||
657 | } | ||
658 | impl TestTrait2 for TestEnum { | ||
659 | const TEST_CONST: f64 = 42.0; | ||
660 | } | ||
661 | impl TestTrait for TestEnum { | ||
662 | const TEST_CONST: u8 = 42; | ||
663 | } | ||
664 | } | ||
665 | |||
666 | use test_mod::TestTrait2; | ||
667 | fn main() { | ||
668 | test_mod::TestEnum::TEST_CONST$0; | ||
669 | } | ||
670 | ", | ||
671 | ) | ||
672 | } | ||
673 | |||
674 | #[test] | ||
675 | fn trait_method() { | ||
676 | mark::check!(qualify_path_trait_method); | ||
677 | check_assist( | ||
678 | qualify_path, | ||
679 | r" | ||
680 | mod test_mod { | ||
681 | pub trait TestTrait { | ||
682 | fn test_method(&self); | ||
683 | } | ||
684 | pub struct TestStruct {} | ||
685 | impl TestTrait for TestStruct { | ||
686 | fn test_method(&self) {} | ||
687 | } | ||
688 | } | ||
689 | |||
690 | fn main() { | ||
691 | let test_struct = test_mod::TestStruct {}; | ||
692 | test_struct.test_meth$0od() | ||
693 | } | ||
694 | ", | ||
695 | r" | ||
696 | mod test_mod { | ||
697 | pub trait TestTrait { | ||
698 | fn test_method(&self); | ||
699 | } | ||
700 | pub struct TestStruct {} | ||
701 | impl TestTrait for TestStruct { | ||
702 | fn test_method(&self) {} | ||
703 | } | ||
704 | } | ||
705 | |||
706 | fn main() { | ||
707 | let test_struct = test_mod::TestStruct {}; | ||
708 | test_mod::TestTrait::test_method(&test_struct) | ||
709 | } | ||
710 | ", | ||
711 | ); | ||
712 | } | ||
713 | |||
714 | #[test] | ||
715 | fn trait_method_multi_params() { | ||
716 | check_assist( | ||
717 | qualify_path, | ||
718 | r" | ||
719 | mod test_mod { | ||
720 | pub trait TestTrait { | ||
721 | fn test_method(&self, test: i32); | ||
722 | } | ||
723 | pub struct TestStruct {} | ||
724 | impl TestTrait for TestStruct { | ||
725 | fn test_method(&self, test: i32) {} | ||
726 | } | ||
727 | } | ||
728 | |||
729 | fn main() { | ||
730 | let test_struct = test_mod::TestStruct {}; | ||
731 | test_struct.test_meth$0od(42) | ||
732 | } | ||
733 | ", | ||
734 | r" | ||
735 | mod test_mod { | ||
736 | pub trait TestTrait { | ||
737 | fn test_method(&self, test: i32); | ||
738 | } | ||
739 | pub struct TestStruct {} | ||
740 | impl TestTrait for TestStruct { | ||
741 | fn test_method(&self, test: i32) {} | ||
742 | } | ||
743 | } | ||
744 | |||
745 | fn main() { | ||
746 | let test_struct = test_mod::TestStruct {}; | ||
747 | test_mod::TestTrait::test_method(&test_struct, 42) | ||
748 | } | ||
749 | ", | ||
750 | ); | ||
751 | } | ||
752 | |||
753 | #[test] | ||
754 | fn trait_method_consume() { | ||
755 | check_assist( | ||
756 | qualify_path, | ||
757 | r" | ||
758 | mod test_mod { | ||
759 | pub trait TestTrait { | ||
760 | fn test_method(self); | ||
761 | } | ||
762 | pub struct TestStruct {} | ||
763 | impl TestTrait for TestStruct { | ||
764 | fn test_method(self) {} | ||
765 | } | ||
766 | } | ||
767 | |||
768 | fn main() { | ||
769 | let test_struct = test_mod::TestStruct {}; | ||
770 | test_struct.test_meth$0od() | ||
771 | } | ||
772 | ", | ||
773 | r" | ||
774 | mod test_mod { | ||
775 | pub trait TestTrait { | ||
776 | fn test_method(self); | ||
777 | } | ||
778 | pub struct TestStruct {} | ||
779 | impl TestTrait for TestStruct { | ||
780 | fn test_method(self) {} | ||
781 | } | ||
782 | } | ||
783 | |||
784 | fn main() { | ||
785 | let test_struct = test_mod::TestStruct {}; | ||
786 | test_mod::TestTrait::test_method(test_struct) | ||
787 | } | ||
788 | ", | ||
789 | ); | ||
790 | } | ||
791 | |||
792 | #[test] | ||
793 | fn trait_method_cross_crate() { | ||
794 | check_assist( | ||
795 | qualify_path, | ||
796 | r" | ||
797 | //- /main.rs crate:main deps:dep | ||
798 | fn main() { | ||
799 | let test_struct = dep::test_mod::TestStruct {}; | ||
800 | test_struct.test_meth$0od() | ||
801 | } | ||
802 | //- /dep.rs crate:dep | ||
803 | pub mod test_mod { | ||
804 | pub trait TestTrait { | ||
805 | fn test_method(&self); | ||
806 | } | ||
807 | pub struct TestStruct {} | ||
808 | impl TestTrait for TestStruct { | ||
809 | fn test_method(&self) {} | ||
810 | } | ||
811 | } | ||
812 | ", | ||
813 | r" | ||
814 | fn main() { | ||
815 | let test_struct = dep::test_mod::TestStruct {}; | ||
816 | dep::test_mod::TestTrait::test_method(&test_struct) | ||
817 | } | ||
818 | ", | ||
819 | ); | ||
820 | } | ||
821 | |||
822 | #[test] | ||
823 | fn assoc_fn_cross_crate() { | ||
824 | check_assist( | ||
825 | qualify_path, | ||
826 | r" | ||
827 | //- /main.rs crate:main deps:dep | ||
828 | fn main() { | ||
829 | dep::test_mod::TestStruct::test_func$0tion | ||
830 | } | ||
831 | //- /dep.rs crate:dep | ||
832 | pub mod test_mod { | ||
833 | pub trait TestTrait { | ||
834 | fn test_function(); | ||
835 | } | ||
836 | pub struct TestStruct {} | ||
837 | impl TestTrait for TestStruct { | ||
838 | fn test_function() {} | ||
839 | } | ||
840 | } | ||
841 | ", | ||
842 | r" | ||
843 | fn main() { | ||
844 | <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::test_function | ||
845 | } | ||
846 | ", | ||
847 | ); | ||
848 | } | ||
849 | |||
850 | #[test] | ||
851 | fn assoc_const_cross_crate() { | ||
852 | check_assist( | ||
853 | qualify_path, | ||
854 | r" | ||
855 | //- /main.rs crate:main deps:dep | ||
856 | fn main() { | ||
857 | dep::test_mod::TestStruct::CONST$0 | ||
858 | } | ||
859 | //- /dep.rs crate:dep | ||
860 | pub mod test_mod { | ||
861 | pub trait TestTrait { | ||
862 | const CONST: bool; | ||
863 | } | ||
864 | pub struct TestStruct {} | ||
865 | impl TestTrait for TestStruct { | ||
866 | const CONST: bool = true; | ||
867 | } | ||
868 | } | ||
869 | ", | ||
870 | r" | ||
871 | fn main() { | ||
872 | <dep::test_mod::TestStruct as dep::test_mod::TestTrait>::CONST | ||
873 | } | ||
874 | ", | ||
875 | ); | ||
876 | } | ||
877 | |||
878 | #[test] | ||
879 | fn assoc_fn_as_method_cross_crate() { | ||
880 | check_assist_not_applicable( | ||
881 | qualify_path, | ||
882 | r" | ||
883 | //- /main.rs crate:main deps:dep | ||
884 | fn main() { | ||
885 | let test_struct = dep::test_mod::TestStruct {}; | ||
886 | test_struct.test_func$0tion() | ||
887 | } | ||
888 | //- /dep.rs crate:dep | ||
889 | pub mod test_mod { | ||
890 | pub trait TestTrait { | ||
891 | fn test_function(); | ||
892 | } | ||
893 | pub struct TestStruct {} | ||
894 | impl TestTrait for TestStruct { | ||
895 | fn test_function() {} | ||
896 | } | ||
897 | } | ||
898 | ", | ||
899 | ); | ||
900 | } | ||
901 | |||
902 | #[test] | ||
903 | fn private_trait_cross_crate() { | ||
904 | check_assist_not_applicable( | ||
905 | qualify_path, | ||
906 | r" | ||
907 | //- /main.rs crate:main deps:dep | ||
908 | fn main() { | ||
909 | let test_struct = dep::test_mod::TestStruct {}; | ||
910 | test_struct.test_meth$0od() | ||
911 | } | ||
912 | //- /dep.rs crate:dep | ||
913 | pub mod test_mod { | ||
914 | trait TestTrait { | ||
915 | fn test_method(&self); | ||
916 | } | ||
917 | pub struct TestStruct {} | ||
918 | impl TestTrait for TestStruct { | ||
919 | fn test_method(&self) {} | ||
920 | } | ||
921 | } | ||
922 | ", | ||
923 | ); | ||
924 | } | ||
925 | |||
926 | #[test] | ||
927 | fn not_applicable_for_imported_trait_for_method() { | ||
928 | check_assist_not_applicable( | ||
929 | qualify_path, | ||
930 | r" | ||
931 | mod test_mod { | ||
932 | pub trait TestTrait { | ||
933 | fn test_method(&self); | ||
934 | } | ||
935 | pub trait TestTrait2 { | ||
936 | fn test_method(&self); | ||
937 | } | ||
938 | pub enum TestEnum { | ||
939 | One, | ||
940 | Two, | ||
941 | } | ||
942 | impl TestTrait2 for TestEnum { | ||
943 | fn test_method(&self) {} | ||
944 | } | ||
945 | impl TestTrait for TestEnum { | ||
946 | fn test_method(&self) {} | ||
947 | } | ||
948 | } | ||
949 | |||
950 | use test_mod::TestTrait2; | ||
951 | fn main() { | ||
952 | let one = test_mod::TestEnum::One; | ||
953 | one.test$0_method(); | ||
954 | } | ||
955 | ", | ||
956 | ) | ||
957 | } | ||
958 | |||
959 | #[test] | ||
960 | fn dep_import() { | ||
961 | check_assist( | ||
962 | qualify_path, | ||
963 | r" | ||
964 | //- /lib.rs crate:dep | ||
965 | pub struct Struct; | ||
966 | |||
967 | //- /main.rs crate:main deps:dep | ||
968 | fn main() { | ||
969 | Struct$0 | ||
970 | } | ||
971 | ", | ||
972 | r" | ||
973 | fn main() { | ||
974 | dep::Struct | ||
975 | } | ||
976 | ", | ||
977 | ); | ||
978 | } | ||
979 | |||
980 | #[test] | ||
981 | fn whole_segment() { | ||
982 | // Tests that only imports whose last segment matches the identifier get suggested. | ||
983 | check_assist( | ||
984 | qualify_path, | ||
985 | r" | ||
986 | //- /lib.rs crate:dep | ||
987 | pub mod fmt { | ||
988 | pub trait Display {} | ||
989 | } | ||
990 | |||
991 | pub fn panic_fmt() {} | ||
992 | |||
993 | //- /main.rs crate:main deps:dep | ||
994 | struct S; | ||
995 | |||
996 | impl f$0mt::Display for S {} | ||
997 | ", | ||
998 | r" | ||
999 | struct S; | ||
1000 | |||
1001 | impl dep::fmt::Display for S {} | ||
1002 | ", | ||
1003 | ); | ||
1004 | } | ||
1005 | |||
1006 | #[test] | ||
1007 | fn macro_generated() { | ||
1008 | // Tests that macro-generated items are suggested from external crates. | ||
1009 | check_assist( | ||
1010 | qualify_path, | ||
1011 | r" | ||
1012 | //- /lib.rs crate:dep | ||
1013 | macro_rules! mac { | ||
1014 | () => { | ||
1015 | pub struct Cheese; | ||
1016 | }; | ||
1017 | } | ||
1018 | |||
1019 | mac!(); | ||
1020 | |||
1021 | //- /main.rs crate:main deps:dep | ||
1022 | fn main() { | ||
1023 | Cheese$0; | ||
1024 | } | ||
1025 | ", | ||
1026 | r" | ||
1027 | fn main() { | ||
1028 | dep::Cheese; | ||
1029 | } | ||
1030 | ", | ||
1031 | ); | ||
1032 | } | ||
1033 | |||
1034 | #[test] | ||
1035 | fn casing() { | ||
1036 | // Tests that differently cased names don't interfere and we only suggest the matching one. | ||
1037 | check_assist( | ||
1038 | qualify_path, | ||
1039 | r" | ||
1040 | //- /lib.rs crate:dep | ||
1041 | pub struct FMT; | ||
1042 | pub struct fmt; | ||
1043 | |||
1044 | //- /main.rs crate:main deps:dep | ||
1045 | fn main() { | ||
1046 | FMT$0; | ||
1047 | } | ||
1048 | ", | ||
1049 | r" | ||
1050 | fn main() { | ||
1051 | dep::FMT; | ||
1052 | } | ||
1053 | ", | ||
1054 | ); | ||
1055 | } | ||
1056 | |||
1057 | #[test] | ||
1058 | fn keep_generic_annotations() { | ||
1059 | check_assist( | ||
1060 | qualify_path, | ||
1061 | r" | ||
1062 | //- /lib.rs crate:dep | ||
1063 | pub mod generic { pub struct Thing<'a, T>(&'a T); } | ||
1064 | |||
1065 | //- /main.rs crate:main deps:dep | ||
1066 | fn foo() -> Thin$0g<'static, ()> {} | ||
1067 | |||
1068 | fn main() {} | ||
1069 | ", | ||
1070 | r" | ||
1071 | fn foo() -> dep::generic::Thing<'static, ()> {} | ||
1072 | |||
1073 | fn main() {} | ||
1074 | ", | ||
1075 | ); | ||
1076 | } | ||
1077 | |||
1078 | #[test] | ||
1079 | fn keep_generic_annotations_leading_colon() { | ||
1080 | check_assist( | ||
1081 | qualify_path, | ||
1082 | r" | ||
1083 | //- /lib.rs crate:dep | ||
1084 | pub mod generic { pub struct Thing<'a, T>(&'a T); } | ||
1085 | |||
1086 | //- /main.rs crate:main deps:dep | ||
1087 | fn foo() -> Thin$0g::<'static, ()> {} | ||
1088 | |||
1089 | fn main() {} | ||
1090 | ", | ||
1091 | r" | ||
1092 | fn foo() -> dep::generic::Thing::<'static, ()> {} | ||
1093 | |||
1094 | fn main() {} | ||
1095 | ", | ||
1096 | ); | ||
1097 | } | ||
1098 | |||
1099 | #[test] | ||
1100 | fn associated_struct_const_generic() { | ||
1101 | check_assist( | ||
1102 | qualify_path, | ||
1103 | r" | ||
1104 | mod test_mod { | ||
1105 | pub struct TestStruct<T> {} | ||
1106 | impl<T> TestStruct<T> { | ||
1107 | const TEST_CONST: u8 = 42; | ||
1108 | } | ||
1109 | } | ||
1110 | |||
1111 | fn main() { | ||
1112 | TestStruct::<()>::TEST_CONST$0 | ||
1113 | } | ||
1114 | ", | ||
1115 | r" | ||
1116 | mod test_mod { | ||
1117 | pub struct TestStruct<T> {} | ||
1118 | impl<T> TestStruct<T> { | ||
1119 | const TEST_CONST: u8 = 42; | ||
1120 | } | ||
1121 | } | ||
1122 | |||
1123 | fn main() { | ||
1124 | test_mod::TestStruct::<()>::TEST_CONST | ||
1125 | } | ||
1126 | ", | ||
1127 | ); | ||
1128 | } | ||
1129 | |||
1130 | #[test] | ||
1131 | fn associated_trait_const_generic() { | ||
1132 | check_assist( | ||
1133 | qualify_path, | ||
1134 | r" | ||
1135 | mod test_mod { | ||
1136 | pub trait TestTrait { | ||
1137 | const TEST_CONST: u8; | ||
1138 | } | ||
1139 | pub struct TestStruct<T> {} | ||
1140 | impl<T> TestTrait for TestStruct<T> { | ||
1141 | const TEST_CONST: u8 = 42; | ||
1142 | } | ||
1143 | } | ||
1144 | |||
1145 | fn main() { | ||
1146 | test_mod::TestStruct::<()>::TEST_CONST$0 | ||
1147 | } | ||
1148 | ", | ||
1149 | r" | ||
1150 | mod test_mod { | ||
1151 | pub trait TestTrait { | ||
1152 | const TEST_CONST: u8; | ||
1153 | } | ||
1154 | pub struct TestStruct<T> {} | ||
1155 | impl<T> TestTrait for TestStruct<T> { | ||
1156 | const TEST_CONST: u8 = 42; | ||
1157 | } | ||
1158 | } | ||
1159 | |||
1160 | fn main() { | ||
1161 | <test_mod::TestStruct::<()> as test_mod::TestTrait>::TEST_CONST | ||
1162 | } | ||
1163 | ", | ||
1164 | ); | ||
1165 | } | ||
1166 | |||
1167 | #[test] | ||
1168 | fn trait_method_generic() { | ||
1169 | check_assist( | ||
1170 | qualify_path, | ||
1171 | r" | ||
1172 | mod test_mod { | ||
1173 | pub trait TestTrait { | ||
1174 | fn test_method<T>(&self); | ||
1175 | } | ||
1176 | pub struct TestStruct {} | ||
1177 | impl TestTrait for TestStruct { | ||
1178 | fn test_method<T>(&self) {} | ||
1179 | } | ||
1180 | } | ||
1181 | |||
1182 | fn main() { | ||
1183 | let test_struct = test_mod::TestStruct {}; | ||
1184 | test_struct.test_meth$0od::<()>() | ||
1185 | } | ||
1186 | ", | ||
1187 | r" | ||
1188 | mod test_mod { | ||
1189 | pub trait TestTrait { | ||
1190 | fn test_method<T>(&self); | ||
1191 | } | ||
1192 | pub struct TestStruct {} | ||
1193 | impl TestTrait for TestStruct { | ||
1194 | fn test_method<T>(&self) {} | ||
1195 | } | ||
1196 | } | ||
1197 | |||
1198 | fn main() { | ||
1199 | let test_struct = test_mod::TestStruct {}; | ||
1200 | test_mod::TestTrait::test_method::<()>(&test_struct) | ||
1201 | } | ||
1202 | ", | ||
1203 | ); | ||
1204 | } | ||
1205 | } | ||