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