aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs34
-rw-r--r--crates/ide_completion/src/item.rs41
-rw-r--r--crates/ide_completion/src/lib.rs7
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs99
4 files changed, 116 insertions, 65 deletions
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index c1e3f091f..c5b3c9e27 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -144,7 +144,7 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
144 .filter_map(|import| { 144 .filter_map(|import| {
145 render_resolution_with_import( 145 render_resolution_with_import(
146 RenderContext::new(ctx), 146 RenderContext::new(ctx),
147 ImportEdit { import, import_scope: import_scope.clone() }, 147 ImportEdit { import, scope: import_scope.clone() },
148 ) 148 )
149 }), 149 }),
150 ); 150 );
@@ -690,8 +690,8 @@ fn main() {
690} 690}
691"#, 691"#,
692 expect![[r#" 692 expect![[r#"
693 fn weird_function() (dep::test_mod::TestTrait) -> () DEPRECATED
694 ct SPECIAL_CONST (dep::test_mod::TestTrait) DEPRECATED 693 ct SPECIAL_CONST (dep::test_mod::TestTrait) DEPRECATED
694 fn weird_function() (dep::test_mod::TestTrait) -> () DEPRECATED
695 "#]], 695 "#]],
696 ); 696 );
697 } 697 }
@@ -807,7 +807,12 @@ fn main() {
807 bar::baz::Ite$0 807 bar::baz::Ite$0
808}"#; 808}"#;
809 809
810 check(fixture, expect![["st Item (foo::bar::baz::Item)"]]); 810 check(
811 fixture,
812 expect![[r#"
813 st foo::bar::baz::Item
814 "#]],
815 );
811 816
812 check_edit( 817 check_edit(
813 "Item", 818 "Item",
@@ -825,8 +830,7 @@ fn main() {
825 830
826 fn main() { 831 fn main() {
827 bar::baz::Item 832 bar::baz::Item
828 } 833 }"#,
829 "#,
830 ); 834 );
831 } 835 }
832 836
@@ -845,7 +849,12 @@ fn main() {
845 Item::TEST_A$0 849 Item::TEST_A$0
846}"#; 850}"#;
847 851
848 check(fixture, expect![["ct TEST_ASSOC (foo::bar::baz::Item)"]]); 852 check(
853 fixture,
854 expect![[r#"
855 ct TEST_ASSOC (foo::Item)
856 "#]],
857 );
849 858
850 check_edit( 859 check_edit(
851 "TEST_ASSOC", 860 "TEST_ASSOC",
@@ -863,8 +872,7 @@ mod foo {
863 872
864fn main() { 873fn main() {
865 Item::TEST_ASSOC 874 Item::TEST_ASSOC
866} 875}"#,
867"#,
868 ); 876 );
869 } 877 }
870 878
@@ -885,7 +893,12 @@ fn main() {
885 bar::Item::TEST_A$0 893 bar::Item::TEST_A$0
886}"#; 894}"#;
887 895
888 check(fixture, expect![["ct TEST_ASSOC (foo::bar::baz::Item)"]]); 896 check(
897 fixture,
898 expect![[r#"
899 ct TEST_ASSOC (foo::bar::Item)
900 "#]],
901 );
889 902
890 check_edit( 903 check_edit(
891 "TEST_ASSOC", 904 "TEST_ASSOC",
@@ -905,8 +918,7 @@ mod foo {
905 918
906fn main() { 919fn main() {
907 bar::Item::TEST_ASSOC 920 bar::Item::TEST_ASSOC
908} 921}"#,
909"#,
910 ); 922 );
911 } 923 }
912} 924}
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index d01620500..44e4a6dfd 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -11,7 +11,7 @@ use ide_db::{
11 }, 11 },
12 SymbolKind, 12 SymbolKind,
13}; 13};
14use stdx::{impl_from, never}; 14use stdx::{format_to, impl_from, never};
15use syntax::{algo, TextRange}; 15use syntax::{algo, TextRange};
16use text_edit::TextEdit; 16use text_edit::TextEdit;
17 17
@@ -274,7 +274,7 @@ impl CompletionItem {
274#[derive(Debug, Clone)] 274#[derive(Debug, Clone)]
275pub struct ImportEdit { 275pub struct ImportEdit {
276 pub import: LocatedImport, 276 pub import: LocatedImport,
277 pub import_scope: ImportScope, 277 pub scope: ImportScope,
278} 278}
279 279
280impl ImportEdit { 280impl ImportEdit {
@@ -284,7 +284,7 @@ impl ImportEdit {
284 let _p = profile::span("ImportEdit::to_text_edit"); 284 let _p = profile::span("ImportEdit::to_text_edit");
285 285
286 let rewriter = insert_use::insert_use( 286 let rewriter = insert_use::insert_use(
287 &self.import_scope, 287 &self.scope,
288 mod_path_to_ast(&self.import.import_path), 288 mod_path_to_ast(&self.import.import_path),
289 cfg, 289 cfg,
290 ); 290 );
@@ -302,7 +302,6 @@ impl ImportEdit {
302pub(crate) struct Builder { 302pub(crate) struct Builder {
303 source_range: TextRange, 303 source_range: TextRange,
304 completion_kind: CompletionKind, 304 completion_kind: CompletionKind,
305 // TODO kb also add a db here, to resolve the completion label?
306 import_to_add: Option<ImportEdit>, 305 import_to_add: Option<ImportEdit>,
307 label: String, 306 label: String,
308 insert_text: Option<String>, 307 insert_text: Option<String>,
@@ -322,22 +321,24 @@ impl Builder {
322 pub(crate) fn build(self) -> CompletionItem { 321 pub(crate) fn build(self) -> CompletionItem {
323 let _p = profile::span("item::Builder::build"); 322 let _p = profile::span("item::Builder::build");
324 323
325 let label = self.label; 324 let mut label = self.label;
326 let lookup = self.lookup; 325 let mut lookup = self.lookup;
327 let insert_text = self.insert_text; 326 let mut insert_text = self.insert_text;
328 327
329 if let Some(_import_to_add) = self.import_to_add.as_ref() { 328 if let Some(original_path) = self
330 todo!("todo kb") 329 .import_to_add
331 // let import = &import_to_add.import; 330 .as_ref()
332 // let item_to_import = import.item_to_import(); 331 .and_then(|import_edit| import_edit.import.original_path.as_ref())
333 // lookup = lookup.or_else(|| Some(label.clone())); 332 {
334 // insert_text = insert_text.or_else(|| Some(label.clone())); 333 lookup = lookup.or_else(|| Some(label.clone()));
335 // let display_path = import_to_add.import.display_path(); 334 insert_text = insert_text.or_else(|| Some(label.clone()));
336 // if import_to_add.import { 335
337 // label = format!("{} ({})", label, display_path); 336 let original_path_label = original_path.to_string();
338 // } else { 337 if original_path_label.ends_with(&label) {
339 // label = display_path.to_string(); 338 label = original_path_label;
340 // } 339 } else {
340 format_to!(label, " ({})", original_path)
341 }
341 } 342 }
342 343
343 let text_edit = match self.text_edit { 344 let text_edit = match self.text_edit {
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index d19368de0..5470914fb 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -144,7 +144,7 @@ pub fn resolve_completion_edits(
144) -> Option<Vec<TextEdit>> { 144) -> Option<Vec<TextEdit>> {
145 let ctx = CompletionContext::new(db, position, config)?; 145 let ctx = CompletionContext::new(db, position, config)?;
146 let position_for_import = position_for_import(&ctx, None)?; 146 let position_for_import = position_for_import(&ctx, None)?;
147 let import_scope = ImportScope::find_insert_use_container(position_for_import, &ctx.sema)?; 147 let scope = ImportScope::find_insert_use_container(position_for_import, &ctx.sema)?;
148 148
149 let current_module = ctx.sema.scope(position_for_import).module()?; 149 let current_module = ctx.sema.scope(position_for_import).module()?;
150 let current_crate = current_module.krate(); 150 let current_crate = current_module.krate();
@@ -158,9 +158,10 @@ pub fn resolve_completion_edits(
158 .zip(Some(candidate)) 158 .zip(Some(candidate))
159 }) 159 })
160 .find(|(mod_path, _)| mod_path.to_string() == full_import_path)?; 160 .find(|(mod_path, _)| mod_path.to_string() == full_import_path)?;
161 let import = LocatedImport::new(import_path, item_to_import, item_to_import); 161 let import =
162 LocatedImport::new(import_path.clone(), item_to_import, item_to_import, Some(import_path));
162 163
163 ImportEdit { import, import_scope }.to_text_edit(config.insert_use).map(|edit| vec![edit]) 164 ImportEdit { import, scope }.to_text_edit(config.insert_use).map(|edit| vec![edit])
164} 165}
165 166
166#[cfg(test)] 167#[cfg(test)]
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index 8d16c011e..b3e90717a 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -132,11 +132,17 @@ pub struct LocatedImport {
132 pub import_path: ModPath, 132 pub import_path: ModPath,
133 pub item_to_import: ItemInNs, 133 pub item_to_import: ItemInNs,
134 pub original_item: ItemInNs, 134 pub original_item: ItemInNs,
135 pub original_path: Option<ModPath>,
135} 136}
136 137
137impl LocatedImport { 138impl LocatedImport {
138 pub fn new(import_path: ModPath, item_to_import: ItemInNs, original_item: ItemInNs) -> Self { 139 pub fn new(
139 Self { import_path, item_to_import, original_item } 140 import_path: ModPath,
141 item_to_import: ItemInNs,
142 original_item: ItemInNs,
143 original_path: Option<ModPath>,
144 ) -> Self {
145 Self { import_path, item_to_import, original_item, original_path }
140 } 146 }
141 147
142 pub fn original_item_name(&self, db: &RootDatabase) -> Option<Name> { 148 pub fn original_item_name(&self, db: &RootDatabase) -> Option<Name> {
@@ -238,7 +244,9 @@ impl<'a> ImportAssets<'a> {
238 let _p = profile::span("import_assets::applicable_defs"); 244 let _p = profile::span("import_assets::applicable_defs");
239 let current_crate = self.module_with_candidate.krate(); 245 let current_crate = self.module_with_candidate.krate();
240 246
241 let mod_path = |item| get_mod_path(db, item, &self.module_with_candidate, prefixed); 247 let mod_path = |item| {
248 get_mod_path(db, item_for_path_search(db, item)?, &self.module_with_candidate, prefixed)
249 };
242 250
243 match &self.import_candidate { 251 match &self.import_candidate {
244 ImportCandidate::Path(path_candidate) => { 252 ImportCandidate::Path(path_candidate) => {
@@ -276,7 +284,9 @@ fn path_applicable_imports(
276 Qualifier::Absent => { 284 Qualifier::Absent => {
277 return items_with_candidate_name 285 return items_with_candidate_name
278 .into_iter() 286 .into_iter()
279 .filter_map(|item| Some(LocatedImport::new(mod_path(item)?, item, item))) 287 .filter_map(|item| {
288 Some(LocatedImport::new(mod_path(item)?, item, item, mod_path(item)))
289 })
280 .collect(); 290 .collect();
281 } 291 }
282 Qualifier::FirstSegmentUnresolved(first_segment, qualifier) => { 292 Qualifier::FirstSegmentUnresolved(first_segment, qualifier) => {
@@ -300,46 +310,69 @@ fn import_for_item(
300 original_item: ItemInNs, 310 original_item: ItemInNs,
301) -> Option<LocatedImport> { 311) -> Option<LocatedImport> {
302 let _p = profile::span("import_assets::import_for_item"); 312 let _p = profile::span("import_assets::import_for_item");
303 let (item_candidate, trait_to_import) = match original_item.as_module_def_id() {
304 Some(module_def_id) => {
305 match ModuleDef::from(module_def_id).as_assoc_item(db).map(|assoc| assoc.container(db))
306 {
307 Some(AssocItemContainer::Trait(trait_)) => {
308 let trait_item = ItemInNs::from(ModuleDef::from(trait_));
309 (trait_item, Some(trait_item))
310 }
311 Some(AssocItemContainer::Impl(impl_)) => {
312 (ItemInNs::from(ModuleDef::from(impl_.target_ty(db).as_adt()?)), None)
313 }
314 None => (original_item, None),
315 }
316 }
317 None => (original_item, None),
318 };
319 let import_path_candidate = mod_path(item_candidate)?;
320 313
314 let original_item_candidate = item_for_path_search(db, original_item)?;
315 let import_path_candidate = mod_path(original_item_candidate)?;
321 let import_path_string = import_path_candidate.to_string(); 316 let import_path_string = import_path_candidate.to_string();
317
322 if !import_path_string.contains(unresolved_first_segment) 318 if !import_path_string.contains(unresolved_first_segment)
323 || !import_path_string.contains(unresolved_qualifier) 319 || !import_path_string.contains(unresolved_qualifier)
324 { 320 {
325 return None; 321 return None;
326 } 322 }
327 323
328 let segment_import = find_import_for_segment(db, item_candidate, &unresolved_first_segment)?; 324 let segment_import =
329 Some(match (segment_import == item_candidate, trait_to_import) { 325 find_import_for_segment(db, original_item_candidate, &unresolved_first_segment)?;
326 let trait_item_to_import = original_item
327 .as_module_def_id()
328 .and_then(|module_def_id| {
329 ModuleDef::from(module_def_id).as_assoc_item(db)?.containing_trait(db)
330 })
331 .map(|trait_| ItemInNs::from(ModuleDef::from(trait_)));
332 Some(match (segment_import == original_item_candidate, trait_item_to_import) {
330 (true, Some(_)) => { 333 (true, Some(_)) => {
331 // FIXME we should be able to import both the trait and the segment, 334 // FIXME we should be able to import both the trait and the segment,
332 // but it's unclear what to do with overlapping edits (merge imports?) 335 // but it's unclear what to do with overlapping edits (merge imports?)
333 // especially in case of lazy completion edit resolutions. 336 // especially in case of lazy completion edit resolutions.
334 return None; 337 return None;
335 } 338 }
336 (false, Some(trait_to_import)) => { 339 (false, Some(trait_to_import)) => LocatedImport::new(
337 LocatedImport::new(mod_path(trait_to_import)?, trait_to_import, original_item) 340 mod_path(trait_to_import)?,
338 } 341 trait_to_import,
339 (true, None) => LocatedImport::new(import_path_candidate, item_candidate, original_item), 342 original_item,
340 (false, None) => { 343 mod_path(original_item),
341 LocatedImport::new(mod_path(segment_import)?, segment_import, original_item) 344 ),
345 (true, None) => LocatedImport::new(
346 import_path_candidate,
347 original_item_candidate,
348 original_item,
349 mod_path(original_item),
350 ),
351 (false, None) => LocatedImport::new(
352 mod_path(segment_import)?,
353 segment_import,
354 original_item,
355 mod_path(original_item),
356 ),
357 })
358}
359
360fn item_for_path_search(db: &RootDatabase, item: ItemInNs) -> Option<ItemInNs> {
361 Some(match item {
362 ItemInNs::Types(module_def_id) | ItemInNs::Values(module_def_id) => {
363 let module_def = ModuleDef::from(module_def_id);
364
365 match module_def.as_assoc_item(db) {
366 Some(assoc_item) => match assoc_item.container(db) {
367 AssocItemContainer::Trait(trait_) => ItemInNs::from(ModuleDef::from(trait_)),
368 AssocItemContainer::Impl(impl_) => {
369 ItemInNs::from(ModuleDef::from(impl_.target_ty(db).as_adt()?))
370 }
371 },
372 None => item,
373 }
342 } 374 }
375 ItemInNs::Macros(_) => item,
343 }) 376 })
344} 377}
345 378
@@ -420,10 +453,12 @@ fn trait_applicable_items(
420 } 453 }
421 454
422 let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); 455 let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?));
456 let original_item = assoc_to_item(assoc);
423 located_imports.insert(LocatedImport::new( 457 located_imports.insert(LocatedImport::new(
424 mod_path(item)?, 458 mod_path(item)?,
425 item, 459 item,
426 assoc_to_item(assoc), 460 original_item,
461 mod_path(original_item),
427 )); 462 ));
428 } 463 }
429 None::<()> 464 None::<()>
@@ -439,10 +474,12 @@ fn trait_applicable_items(
439 let assoc = function.as_assoc_item(db)?; 474 let assoc = function.as_assoc_item(db)?;
440 if required_assoc_items.contains(&assoc) { 475 if required_assoc_items.contains(&assoc) {
441 let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); 476 let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?));
477 let original_item = assoc_to_item(assoc);
442 located_imports.insert(LocatedImport::new( 478 located_imports.insert(LocatedImport::new(
443 mod_path(item)?, 479 mod_path(item)?,
444 item, 480 item,
445 assoc_to_item(assoc), 481 original_item,
482 mod_path(original_item),
446 )); 483 ));
447 } 484 }
448 None::<()> 485 None::<()>