diff options
author | Galilée 'Bill' Enguehard <[email protected]> | 2020-05-21 22:27:38 +0100 |
---|---|---|
committer | Galilée 'Bill' Enguehard <[email protected]> | 2020-05-21 22:27:38 +0100 |
commit | 7fece3bdd2450c0807f7dd742239cae95f0cc65e (patch) | |
tree | 866c4db826c959e79c63a6727bdb9f2c61e6fc4f /crates/ra_assists/src/handlers/auto_import.rs | |
parent | db926218b2082077750291f8426ddd28b284cd08 (diff) | |
parent | 59732df8d40dfadc6dcf5951265416576399712a (diff) |
Merge branch 'master' of github.com:rust-analyzer/rust-analyzer into modname_spacing
Diffstat (limited to 'crates/ra_assists/src/handlers/auto_import.rs')
-rw-r--r-- | crates/ra_assists/src/handlers/auto_import.rs | 109 |
1 files changed, 71 insertions, 38 deletions
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index 99682e023..edf96d50e 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -1,5 +1,6 @@ | |||
1 | use std::collections::BTreeSet; | 1 | use std::collections::BTreeSet; |
2 | 2 | ||
3 | use either::Either; | ||
3 | use hir::{ | 4 | use hir::{ |
4 | AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait, | 5 | AsAssocItem, AssocItemContainer, ModPath, Module, ModuleDef, PathResolution, Semantics, Trait, |
5 | Type, | 6 | Type, |
@@ -12,12 +13,7 @@ use ra_syntax::{ | |||
12 | }; | 13 | }; |
13 | use rustc_hash::FxHashSet; | 14 | use rustc_hash::FxHashSet; |
14 | 15 | ||
15 | use crate::{ | 16 | use crate::{utils::insert_use_statement, AssistContext, AssistId, Assists, GroupLabel}; |
16 | assist_ctx::{Assist, AssistCtx}, | ||
17 | utils::insert_use_statement, | ||
18 | AssistId, | ||
19 | }; | ||
20 | use either::Either; | ||
21 | 17 | ||
22 | // Assist: auto_import | 18 | // Assist: auto_import |
23 | // | 19 | // |
@@ -38,25 +34,32 @@ use either::Either; | |||
38 | // } | 34 | // } |
39 | // # pub mod std { pub mod collections { pub struct HashMap { } } } | 35 | // # pub mod std { pub mod collections { pub struct HashMap { } } } |
40 | // ``` | 36 | // ``` |
41 | pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> { | 37 | pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
42 | let auto_import_assets = AutoImportAssets::new(&ctx)?; | 38 | let auto_import_assets = AutoImportAssets::new(&ctx)?; |
43 | let proposed_imports = auto_import_assets.search_for_imports(ctx.db); | 39 | let proposed_imports = auto_import_assets.search_for_imports(ctx.db); |
44 | if proposed_imports.is_empty() { | 40 | if proposed_imports.is_empty() { |
45 | return None; | 41 | return None; |
46 | } | 42 | } |
47 | 43 | ||
48 | let mut group = ctx.add_assist_group(auto_import_assets.get_import_group_message()); | 44 | let range = ctx.sema.original_range(&auto_import_assets.syntax_under_caret).range; |
45 | let group = auto_import_assets.get_import_group_message(); | ||
49 | for import in proposed_imports { | 46 | for import in proposed_imports { |
50 | group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| { | 47 | acc.add_group( |
51 | edit.target(auto_import_assets.syntax_under_caret.text_range()); | 48 | &group, |
52 | insert_use_statement( | 49 | AssistId("auto_import"), |
53 | &auto_import_assets.syntax_under_caret, | 50 | format!("Import `{}`", &import), |
54 | &import, | 51 | range, |
55 | edit.text_edit_builder(), | 52 | |builder| { |
56 | ); | 53 | insert_use_statement( |
57 | }); | 54 | &auto_import_assets.syntax_under_caret, |
58 | } | 55 | &import, |
59 | group.finish() | 56 | ctx, |
57 | builder.text_edit_builder(), | ||
58 | ); | ||
59 | }, | ||
60 | ); | ||
61 | } | ||
62 | Some(()) | ||
60 | } | 63 | } |
61 | 64 | ||
62 | #[derive(Debug)] | 65 | #[derive(Debug)] |
@@ -67,15 +70,15 @@ struct AutoImportAssets { | |||
67 | } | 70 | } |
68 | 71 | ||
69 | impl AutoImportAssets { | 72 | impl AutoImportAssets { |
70 | fn new(ctx: &AssistCtx) -> Option<Self> { | 73 | fn new(ctx: &AssistContext) -> Option<Self> { |
71 | if let Some(path_under_caret) = ctx.find_node_at_offset::<ast::Path>() { | 74 | if let Some(path_under_caret) = ctx.find_node_at_offset_with_descend::<ast::Path>() { |
72 | Self::for_regular_path(path_under_caret, &ctx) | 75 | Self::for_regular_path(path_under_caret, &ctx) |
73 | } else { | 76 | } else { |
74 | Self::for_method_call(ctx.find_node_at_offset()?, &ctx) | 77 | Self::for_method_call(ctx.find_node_at_offset_with_descend()?, &ctx) |
75 | } | 78 | } |
76 | } | 79 | } |
77 | 80 | ||
78 | fn for_method_call(method_call: ast::MethodCallExpr, ctx: &AssistCtx) -> Option<Self> { | 81 | fn for_method_call(method_call: ast::MethodCallExpr, ctx: &AssistContext) -> Option<Self> { |
79 | let syntax_under_caret = method_call.syntax().to_owned(); | 82 | let syntax_under_caret = method_call.syntax().to_owned(); |
80 | let module_with_name_to_import = ctx.sema.scope(&syntax_under_caret).module()?; | 83 | let module_with_name_to_import = ctx.sema.scope(&syntax_under_caret).module()?; |
81 | Some(Self { | 84 | Some(Self { |
@@ -85,7 +88,7 @@ impl AutoImportAssets { | |||
85 | }) | 88 | }) |
86 | } | 89 | } |
87 | 90 | ||
88 | fn for_regular_path(path_under_caret: ast::Path, ctx: &AssistCtx) -> Option<Self> { | 91 | fn for_regular_path(path_under_caret: ast::Path, ctx: &AssistContext) -> Option<Self> { |
89 | let syntax_under_caret = path_under_caret.syntax().to_owned(); | 92 | let syntax_under_caret = path_under_caret.syntax().to_owned(); |
90 | if syntax_under_caret.ancestors().find_map(ast::UseItem::cast).is_some() { | 93 | if syntax_under_caret.ancestors().find_map(ast::UseItem::cast).is_some() { |
91 | return None; | 94 | return None; |
@@ -108,8 +111,8 @@ impl AutoImportAssets { | |||
108 | } | 111 | } |
109 | } | 112 | } |
110 | 113 | ||
111 | fn get_import_group_message(&self) -> String { | 114 | fn get_import_group_message(&self) -> GroupLabel { |
112 | match &self.import_candidate { | 115 | let name = match &self.import_candidate { |
113 | ImportCandidate::UnqualifiedName(name) => format!("Import {}", name), | 116 | ImportCandidate::UnqualifiedName(name) => format!("Import {}", name), |
114 | ImportCandidate::QualifierStart(qualifier_start) => { | 117 | ImportCandidate::QualifierStart(qualifier_start) => { |
115 | format!("Import {}", qualifier_start) | 118 | format!("Import {}", qualifier_start) |
@@ -120,7 +123,8 @@ impl AutoImportAssets { | |||
120 | ImportCandidate::TraitMethod(_, trait_method_name) => { | 123 | ImportCandidate::TraitMethod(_, trait_method_name) => { |
121 | format!("Import a trait for method {}", trait_method_name) | 124 | format!("Import a trait for method {}", trait_method_name) |
122 | } | 125 | } |
123 | } | 126 | }; |
127 | GroupLabel(name) | ||
124 | } | 128 | } |
125 | 129 | ||
126 | fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet<ModPath> { | 130 | fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet<ModPath> { |
@@ -280,7 +284,7 @@ impl ImportCandidate { | |||
280 | #[cfg(test)] | 284 | #[cfg(test)] |
281 | mod tests { | 285 | mod tests { |
282 | use super::*; | 286 | use super::*; |
283 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 287 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
284 | 288 | ||
285 | #[test] | 289 | #[test] |
286 | fn applicable_when_found_an_import() { | 290 | fn applicable_when_found_an_import() { |
@@ -294,7 +298,7 @@ mod tests { | |||
294 | } | 298 | } |
295 | ", | 299 | ", |
296 | r" | 300 | r" |
297 | <|>use PubMod::PubStruct; | 301 | use PubMod::PubStruct; |
298 | 302 | ||
299 | PubStruct | 303 | PubStruct |
300 | 304 | ||
@@ -306,6 +310,35 @@ mod tests { | |||
306 | } | 310 | } |
307 | 311 | ||
308 | #[test] | 312 | #[test] |
313 | fn applicable_when_found_an_import_in_macros() { | ||
314 | check_assist( | ||
315 | auto_import, | ||
316 | r" | ||
317 | macro_rules! foo { | ||
318 | ($i:ident) => { fn foo(a: $i) {} } | ||
319 | } | ||
320 | foo!(Pub<|>Struct); | ||
321 | |||
322 | pub mod PubMod { | ||
323 | pub struct PubStruct; | ||
324 | } | ||
325 | ", | ||
326 | r" | ||
327 | use PubMod::PubStruct; | ||
328 | |||
329 | macro_rules! foo { | ||
330 | ($i:ident) => { fn foo(a: $i) {} } | ||
331 | } | ||
332 | foo!(PubStruct); | ||
333 | |||
334 | pub mod PubMod { | ||
335 | pub struct PubStruct; | ||
336 | } | ||
337 | ", | ||
338 | ); | ||
339 | } | ||
340 | |||
341 | #[test] | ||
309 | fn auto_imports_are_merged() { | 342 | fn auto_imports_are_merged() { |
310 | check_assist( | 343 | check_assist( |
311 | auto_import, | 344 | auto_import, |
@@ -327,7 +360,7 @@ mod tests { | |||
327 | use PubMod::{PubStruct2, PubStruct1}; | 360 | use PubMod::{PubStruct2, PubStruct1}; |
328 | 361 | ||
329 | struct Test { | 362 | struct Test { |
330 | test: Pub<|>Struct2<u8>, | 363 | test: PubStruct2<u8>, |
331 | } | 364 | } |
332 | 365 | ||
333 | pub mod PubMod { | 366 | pub mod PubMod { |
@@ -358,9 +391,9 @@ mod tests { | |||
358 | } | 391 | } |
359 | ", | 392 | ", |
360 | r" | 393 | r" |
361 | use PubMod1::PubStruct; | 394 | use PubMod3::PubStruct; |
362 | 395 | ||
363 | PubSt<|>ruct | 396 | PubStruct |
364 | 397 | ||
365 | pub mod PubMod1 { | 398 | pub mod PubMod1 { |
366 | pub struct PubStruct; | 399 | pub struct PubStruct; |
@@ -441,7 +474,7 @@ mod tests { | |||
441 | r" | 474 | r" |
442 | use PubMod::test_function; | 475 | use PubMod::test_function; |
443 | 476 | ||
444 | test_function<|> | 477 | test_function |
445 | 478 | ||
446 | pub mod PubMod { | 479 | pub mod PubMod { |
447 | pub fn test_function() {}; | 480 | pub fn test_function() {}; |
@@ -468,7 +501,7 @@ mod tests { | |||
468 | r"use crate_with_macro::foo; | 501 | r"use crate_with_macro::foo; |
469 | 502 | ||
470 | fn main() { | 503 | fn main() { |
471 | foo<|> | 504 | foo |
472 | } | 505 | } |
473 | ", | 506 | ", |
474 | ); | 507 | ); |
@@ -554,7 +587,7 @@ fn main() { | |||
554 | } | 587 | } |
555 | 588 | ||
556 | fn main() { | 589 | fn main() { |
557 | TestStruct::test_function<|> | 590 | TestStruct::test_function |
558 | } | 591 | } |
559 | ", | 592 | ", |
560 | ); | 593 | ); |
@@ -587,7 +620,7 @@ fn main() { | |||
587 | } | 620 | } |
588 | 621 | ||
589 | fn main() { | 622 | fn main() { |
590 | TestStruct::TEST_CONST<|> | 623 | TestStruct::TEST_CONST |
591 | } | 624 | } |
592 | ", | 625 | ", |
593 | ); | 626 | ); |
@@ -626,7 +659,7 @@ fn main() { | |||
626 | } | 659 | } |
627 | 660 | ||
628 | fn main() { | 661 | fn main() { |
629 | test_mod::TestStruct::test_function<|> | 662 | test_mod::TestStruct::test_function |
630 | } | 663 | } |
631 | ", | 664 | ", |
632 | ); | 665 | ); |
@@ -697,7 +730,7 @@ fn main() { | |||
697 | } | 730 | } |
698 | 731 | ||
699 | fn main() { | 732 | fn main() { |
700 | test_mod::TestStruct::TEST_CONST<|> | 733 | test_mod::TestStruct::TEST_CONST |
701 | } | 734 | } |
702 | ", | 735 | ", |
703 | ); | 736 | ); |
@@ -770,7 +803,7 @@ fn main() { | |||
770 | 803 | ||
771 | fn main() { | 804 | fn main() { |
772 | let test_struct = test_mod::TestStruct {}; | 805 | let test_struct = test_mod::TestStruct {}; |
773 | test_struct.test_meth<|>od() | 806 | test_struct.test_method() |
774 | } | 807 | } |
775 | ", | 808 | ", |
776 | ); | 809 | ); |