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