aboutsummaryrefslogtreecommitdiff
path: root/crates/completion
diff options
context:
space:
mode:
Diffstat (limited to 'crates/completion')
-rw-r--r--crates/completion/src/completions/attribute.rs9
-rw-r--r--crates/completion/src/completions/flyimport.rs452
-rw-r--r--crates/completion/src/completions/fn_param.rs4
-rw-r--r--crates/completion/src/completions/mod_.rs10
-rw-r--r--crates/completion/src/completions/record.rs8
-rw-r--r--crates/completion/src/completions/trait_impl.rs8
-rw-r--r--crates/completion/src/completions/unqualified_path.rs60
-rw-r--r--crates/completion/src/config.rs2
-rw-r--r--crates/completion/src/item.rs99
-rw-r--r--crates/completion/src/lib.rs11
-rw-r--r--crates/completion/src/render.rs191
-rw-r--r--crates/completion/src/render/const_.rs10
-rw-r--r--crates/completion/src/render/enum_variant.rs5
-rw-r--r--crates/completion/src/render/function.rs7
-rw-r--r--crates/completion/src/render/macro_.rs5
-rw-r--r--crates/completion/src/render/type_alias.rs10
-rw-r--r--crates/completion/src/test_utils.rs5
17 files changed, 695 insertions, 201 deletions
diff --git a/crates/completion/src/completions/attribute.rs b/crates/completion/src/completions/attribute.rs
index e5522980d..ab25a8c58 100644
--- a/crates/completion/src/completions/attribute.rs
+++ b/crates/completion/src/completions/attribute.rs
@@ -99,13 +99,14 @@ const ATTRIBUTES: &[AttrCompletion] = &[
99 Some("export_name"), 99 Some("export_name"),
100 Some(r#"export_name = "${0:exported_symbol_name}""#), 100 Some(r#"export_name = "${0:exported_symbol_name}""#),
101 ), 101 ),
102 attr(r#"doc(alias = "…")"#, Some("docalias"), Some(r#"doc(alias = "${0:docs}")"#)),
102 attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)), 103 attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)),
103 attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(), 104 attr("feature(…)", Some("feature"), Some("feature(${0:flag})")).prefer_inner(),
104 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")), 105 attr("forbid(…)", Some("forbid"), Some("forbid(${0:lint})")),
105 // FIXME: resolve through macro resolution? 106 // FIXME: resolve through macro resolution?
106 attr("global_allocator", None, None).prefer_inner(), 107 attr("global_allocator", None, None).prefer_inner(),
107 attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)), 108 attr(r#"ignore = "…""#, Some("ignore"), Some(r#"ignore = "${0:reason}""#)),
108 attr("inline(…)", Some("inline"), Some("inline(${0:lint})")), 109 attr("inline", Some("inline"), Some("inline")),
109 attr("link", None, None), 110 attr("link", None, None),
110 attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)), 111 attr(r#"link_name = "…""#, Some("link_name"), Some(r#"link_name = "${0:symbol_name}""#)),
111 attr( 112 attr(
@@ -468,10 +469,11 @@ struct Test {}
468 at deprecated 469 at deprecated
469 at derive(…) 470 at derive(…)
470 at export_name = "…" 471 at export_name = "…"
472 at doc(alias = "…")
471 at doc = "…" 473 at doc = "…"
472 at forbid(…) 474 at forbid(…)
473 at ignore = "…" 475 at ignore = "…"
474 at inline(…) 476 at inline
475 at link 477 at link
476 at link_name = "…" 478 at link_name = "…"
477 at link_section = "…" 479 at link_section = "…"
@@ -515,12 +517,13 @@ struct Test {}
515 at deprecated 517 at deprecated
516 at derive(…) 518 at derive(…)
517 at export_name = "…" 519 at export_name = "…"
520 at doc(alias = "…")
518 at doc = "…" 521 at doc = "…"
519 at feature(…) 522 at feature(…)
520 at forbid(…) 523 at forbid(…)
521 at global_allocator 524 at global_allocator
522 at ignore = "…" 525 at ignore = "…"
523 at inline(…) 526 at inline
524 at link 527 at link
525 at link_name = "…" 528 at link_name = "…"
526 at link_section = "…" 529 at link_section = "…"
diff --git a/crates/completion/src/completions/flyimport.rs b/crates/completion/src/completions/flyimport.rs
index 222809638..dc0b38a16 100644
--- a/crates/completion/src/completions/flyimport.rs
+++ b/crates/completion/src/completions/flyimport.rs
@@ -20,11 +20,14 @@
20//! # pub mod std { pub mod marker { pub struct PhantomData { } } } 20//! # pub mod std { pub mod marker { pub struct PhantomData { } } }
21//! ``` 21//! ```
22//! 22//!
23//! Also completes associated items, that require trait imports.
24//!
23//! .Fuzzy search details 25//! .Fuzzy search details
24//! 26//!
25//! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only 27//! To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
26//! (i.e. in `HashMap` in the `std::collections::HashMap` path). 28//! (i.e. in `HashMap` in the `std::collections::HashMap` path).
27//! For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols. 29//! For the same reasons, avoids searching for any path imports for inputs with their length less that 2 symbols
30//! (but shows all associated items for any input length).
28//! 31//!
29//! .Import configuration 32//! .Import configuration
30//! 33//!
@@ -45,10 +48,12 @@
45//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding 48//! Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding
46//! capability enabled. 49//! capability enabled.
47 50
48use either::Either; 51use hir::{AsAssocItem, ModPath, ScopeDef};
49use hir::{ModPath, ScopeDef}; 52use ide_db::helpers::{
50use ide_db::{helpers::insert_use::ImportScope, imports_locator}; 53 import_assets::{ImportAssets, ImportCandidate},
51use syntax::AstNode; 54 insert_use::ImportScope,
55};
56use syntax::{AstNode, SyntaxNode, T};
52use test_utils::mark; 57use test_utils::mark;
53 58
54use crate::{ 59use crate::{
@@ -60,58 +65,108 @@ use crate::{
60use super::Completions; 65use super::Completions;
61 66
62pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 67pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
63 if !ctx.config.enable_autoimport_completions { 68 if !ctx.config.enable_imports_on_the_fly {
64 return None; 69 return None;
65 } 70 }
66 if ctx.attribute_under_caret.is_some() || ctx.mod_declaration_under_caret.is_some() { 71 if ctx.attribute_under_caret.is_some() || ctx.mod_declaration_under_caret.is_some() {
67 return None; 72 return None;
68 } 73 }
69 let potential_import_name = ctx.token.to_string(); 74 let potential_import_name = {
70 if potential_import_name.len() < 2 { 75 let token_kind = ctx.token.kind();
71 return None; 76 if matches!(token_kind, T![.] | T![::]) {
72 } 77 String::new()
73 let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.to_string()); 78 } else {
79 ctx.token.to_string()
80 }
81 };
74 82
75 let current_module = ctx.scope.module()?; 83 let _p = profile::span("import_on_the_fly").detail(|| potential_import_name.to_string());
76 let anchor = ctx.name_ref_syntax.as_ref()?;
77 let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
78 84
79 let user_input_lowercased = potential_import_name.to_lowercase(); 85 let user_input_lowercased = potential_import_name.to_lowercase();
80 let mut all_mod_paths = imports_locator::find_similar_imports( 86 let import_assets = import_assets(ctx, potential_import_name)?;
87 let import_scope = ImportScope::find_insert_use_container(
88 position_for_import(ctx, Some(import_assets.import_candidate()))?,
81 &ctx.sema, 89 &ctx.sema,
82 ctx.krate?, 90 )?;
83 Some(40), 91 let mut all_mod_paths = import_assets
84 potential_import_name, 92 .search_for_relative_paths(&ctx.sema)
85 true, 93 .into_iter()
86 true, 94 .map(|(mod_path, item_in_ns)| {
87 ) 95 let scope_item = match item_in_ns {
88 .filter_map(|import_candidate| { 96 hir::ItemInNs::Types(id) => ScopeDef::ModuleDef(id.into()),
89 Some(match import_candidate { 97 hir::ItemInNs::Values(id) => ScopeDef::ModuleDef(id.into()),
90 Either::Left(module_def) => { 98 hir::ItemInNs::Macros(id) => ScopeDef::MacroDef(id.into()),
91 (current_module.find_use_path(ctx.db, module_def)?, ScopeDef::ModuleDef(module_def)) 99 };
92 } 100 (mod_path, scope_item)
93 Either::Right(macro_def) => {
94 (current_module.find_use_path(ctx.db, macro_def)?, ScopeDef::MacroDef(macro_def))
95 }
96 }) 101 })
97 }) 102 .collect::<Vec<_>>();
98 .filter(|(mod_path, _)| mod_path.len() > 1)
99 .collect::<Vec<_>>();
100
101 all_mod_paths.sort_by_cached_key(|(mod_path, _)| { 103 all_mod_paths.sort_by_cached_key(|(mod_path, _)| {
102 compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased) 104 compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased)
103 }); 105 });
104 106
105 acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| { 107 acc.add_all(all_mod_paths.into_iter().filter_map(|(import_path, definition)| {
106 render_resolution_with_import( 108 let import_for_trait_assoc_item = match definition {
107 RenderContext::new(ctx), 109 ScopeDef::ModuleDef(module_def) => module_def
108 ImportEdit { import_path, import_scope: import_scope.clone() }, 110 .as_assoc_item(ctx.db)
109 &definition, 111 .and_then(|assoc| assoc.containing_trait(ctx.db))
110 ) 112 .is_some(),
113 _ => false,
114 };
115 let import_edit = ImportEdit {
116 import_path,
117 import_scope: import_scope.clone(),
118 import_for_trait_assoc_item,
119 };
120 render_resolution_with_import(RenderContext::new(ctx), import_edit, &definition)
111 })); 121 }));
112 Some(()) 122 Some(())
113} 123}
114 124
125pub(crate) fn position_for_import<'a>(
126 ctx: &'a CompletionContext,
127 import_candidate: Option<&ImportCandidate>,
128) -> Option<&'a SyntaxNode> {
129 Some(match import_candidate {
130 Some(ImportCandidate::Path(_)) => ctx.name_ref_syntax.as_ref()?.syntax(),
131 Some(ImportCandidate::TraitAssocItem(_)) => ctx.path_qual.as_ref()?.syntax(),
132 Some(ImportCandidate::TraitMethod(_)) => ctx.dot_receiver.as_ref()?.syntax(),
133 None => ctx
134 .name_ref_syntax
135 .as_ref()
136 .map(|name_ref| name_ref.syntax())
137 .or_else(|| ctx.path_qual.as_ref().map(|path| path.syntax()))
138 .or_else(|| ctx.dot_receiver.as_ref().map(|expr| expr.syntax()))?,
139 })
140}
141
142fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAssets> {
143 let current_module = ctx.scope.module()?;
144 if let Some(dot_receiver) = &ctx.dot_receiver {
145 ImportAssets::for_fuzzy_method_call(
146 current_module,
147 ctx.sema.type_of_expr(dot_receiver)?,
148 fuzzy_name,
149 )
150 } else {
151 let fuzzy_name_length = fuzzy_name.len();
152 let assets_for_path = ImportAssets::for_fuzzy_path(
153 current_module,
154 ctx.path_qual.clone(),
155 fuzzy_name,
156 &ctx.sema,
157 );
158
159 if matches!(assets_for_path.as_ref()?.import_candidate(), ImportCandidate::Path(_))
160 && fuzzy_name_length < 2
161 {
162 mark::hit!(ignore_short_input_for_path);
163 None
164 } else {
165 assets_for_path
166 }
167 }
168}
169
115fn compute_fuzzy_completion_order_key( 170fn compute_fuzzy_completion_order_key(
116 proposed_mod_path: &ModPath, 171 proposed_mod_path: &ModPath,
117 user_input_lowercased: &str, 172 user_input_lowercased: &str,
@@ -224,6 +279,30 @@ fn main() {
224 } 279 }
225 280
226 #[test] 281 #[test]
282 fn short_paths_are_ignored() {
283 mark::check!(ignore_short_input_for_path);
284
285 check(
286 r#"
287//- /lib.rs crate:dep
288pub struct FirstStruct;
289pub mod some_module {
290 pub struct SecondStruct;
291 pub struct ThirdStruct;
292}
293
294//- /main.rs crate:main deps:dep
295use dep::{FirstStruct, some_module::SecondStruct};
296
297fn main() {
298 t$0
299}
300"#,
301 expect![[r#""#]],
302 );
303 }
304
305 #[test]
227 fn fuzzy_completions_come_in_specific_order() { 306 fn fuzzy_completions_come_in_specific_order() {
228 mark::check!(certain_fuzzy_order_test); 307 mark::check!(certain_fuzzy_order_test);
229 check( 308 check(
@@ -259,6 +338,176 @@ fn main() {
259 } 338 }
260 339
261 #[test] 340 #[test]
341 fn trait_function_fuzzy_completion() {
342 let fixture = r#"
343 //- /lib.rs crate:dep
344 pub mod test_mod {
345 pub trait TestTrait {
346 const SPECIAL_CONST: u8;
347 type HumbleType;
348 fn weird_function();
349 fn random_method(&self);
350 }
351 pub struct TestStruct {}
352 impl TestTrait for TestStruct {
353 const SPECIAL_CONST: u8 = 42;
354 type HumbleType = ();
355 fn weird_function() {}
356 fn random_method(&self) {}
357 }
358 }
359
360 //- /main.rs crate:main deps:dep
361 fn main() {
362 dep::test_mod::TestStruct::wei$0
363 }
364 "#;
365
366 check(
367 fixture,
368 expect![[r#"
369 fn weird_function() (dep::test_mod::TestTrait) fn weird_function()
370 "#]],
371 );
372
373 check_edit(
374 "weird_function",
375 fixture,
376 r#"
377use dep::test_mod::TestTrait;
378
379fn main() {
380 dep::test_mod::TestStruct::weird_function()$0
381}
382"#,
383 );
384 }
385
386 #[test]
387 fn trait_const_fuzzy_completion() {
388 let fixture = r#"
389 //- /lib.rs crate:dep
390 pub mod test_mod {
391 pub trait TestTrait {
392 const SPECIAL_CONST: u8;
393 type HumbleType;
394 fn weird_function();
395 fn random_method(&self);
396 }
397 pub struct TestStruct {}
398 impl TestTrait for TestStruct {
399 const SPECIAL_CONST: u8 = 42;
400 type HumbleType = ();
401 fn weird_function() {}
402 fn random_method(&self) {}
403 }
404 }
405
406 //- /main.rs crate:main deps:dep
407 fn main() {
408 dep::test_mod::TestStruct::spe$0
409 }
410 "#;
411
412 check(
413 fixture,
414 expect![[r#"
415 ct SPECIAL_CONST (dep::test_mod::TestTrait)
416 "#]],
417 );
418
419 check_edit(
420 "SPECIAL_CONST",
421 fixture,
422 r#"
423use dep::test_mod::TestTrait;
424
425fn main() {
426 dep::test_mod::TestStruct::SPECIAL_CONST
427}
428"#,
429 );
430 }
431
432 #[test]
433 fn trait_method_fuzzy_completion() {
434 let fixture = r#"
435 //- /lib.rs crate:dep
436 pub mod test_mod {
437 pub trait TestTrait {
438 const SPECIAL_CONST: u8;
439 type HumbleType;
440 fn weird_function();
441 fn random_method(&self);
442 }
443 pub struct TestStruct {}
444 impl TestTrait for TestStruct {
445 const SPECIAL_CONST: u8 = 42;
446 type HumbleType = ();
447 fn weird_function() {}
448 fn random_method(&self) {}
449 }
450 }
451
452 //- /main.rs crate:main deps:dep
453 fn main() {
454 let test_struct = dep::test_mod::TestStruct {};
455 test_struct.ran$0
456 }
457 "#;
458
459 check(
460 fixture,
461 expect![[r#"
462 me random_method() (dep::test_mod::TestTrait) fn random_method(&self)
463 "#]],
464 );
465
466 check_edit(
467 "random_method",
468 fixture,
469 r#"
470use dep::test_mod::TestTrait;
471
472fn main() {
473 let test_struct = dep::test_mod::TestStruct {};
474 test_struct.random_method()$0
475}
476"#,
477 );
478 }
479
480 #[test]
481 fn no_trait_type_fuzzy_completion() {
482 check(
483 r#"
484//- /lib.rs crate:dep
485pub mod test_mod {
486 pub trait TestTrait {
487 const SPECIAL_CONST: u8;
488 type HumbleType;
489 fn weird_function();
490 fn random_method(&self);
491 }
492 pub struct TestStruct {}
493 impl TestTrait for TestStruct {
494 const SPECIAL_CONST: u8 = 42;
495 type HumbleType = ();
496 fn weird_function() {}
497 fn random_method(&self) {}
498 }
499}
500
501//- /main.rs crate:main deps:dep
502fn main() {
503 dep::test_mod::TestStruct::hum$0
504}
505"#,
506 expect![[r#""#]],
507 );
508 }
509
510 #[test]
262 fn does_not_propose_names_in_scope() { 511 fn does_not_propose_names_in_scope() {
263 check( 512 check(
264 r#" 513 r#"
@@ -288,4 +537,131 @@ fn main() {
288 expect![[r#""#]], 537 expect![[r#""#]],
289 ); 538 );
290 } 539 }
540
541 #[test]
542 fn does_not_propose_traits_in_scope() {
543 check(
544 r#"
545//- /lib.rs crate:dep
546pub mod test_mod {
547 pub trait TestTrait {
548 const SPECIAL_CONST: u8;
549 type HumbleType;
550 fn weird_function();
551 fn random_method(&self);
552 }
553 pub struct TestStruct {}
554 impl TestTrait for TestStruct {
555 const SPECIAL_CONST: u8 = 42;
556 type HumbleType = ();
557 fn weird_function() {}
558 fn random_method(&self) {}
559 }
560}
561
562//- /main.rs crate:main deps:dep
563use dep::test_mod::{TestStruct, TestTrait};
564fn main() {
565 dep::test_mod::TestStruct::hum$0
566}
567"#,
568 expect![[r#""#]],
569 );
570 }
571
572 #[test]
573 fn blanket_trait_impl_import() {
574 check_edit(
575 "another_function",
576 r#"
577//- /lib.rs crate:dep
578pub mod test_mod {
579 pub struct TestStruct {}
580 pub trait TestTrait {
581 fn another_function();
582 }
583 impl<T> TestTrait for T {
584 fn another_function() {}
585 }
586}
587
588//- /main.rs crate:main deps:dep
589fn main() {
590 dep::test_mod::TestStruct::ano$0
591}
592"#,
593 r#"
594use dep::test_mod::TestTrait;
595
596fn main() {
597 dep::test_mod::TestStruct::another_function()$0
598}
599"#,
600 );
601 }
602
603 #[test]
604 fn zero_input_deprecated_assoc_item_completion() {
605 check(
606 r#"
607//- /lib.rs crate:dep
608pub mod test_mod {
609 #[deprecated]
610 pub trait TestTrait {
611 const SPECIAL_CONST: u8;
612 type HumbleType;
613 fn weird_function();
614 fn random_method(&self);
615 }
616 pub struct TestStruct {}
617 impl TestTrait for TestStruct {
618 const SPECIAL_CONST: u8 = 42;
619 type HumbleType = ();
620 fn weird_function() {}
621 fn random_method(&self) {}
622 }
623}
624
625//- /main.rs crate:main deps:dep
626fn main() {
627 let test_struct = dep::test_mod::TestStruct {};
628 test_struct.$0
629}
630 "#,
631 expect![[r#"
632 me random_method() (dep::test_mod::TestTrait) fn random_method(&self) DEPRECATED
633 "#]],
634 );
635
636 check(
637 r#"
638//- /lib.rs crate:dep
639pub mod test_mod {
640 #[deprecated]
641 pub trait TestTrait {
642 const SPECIAL_CONST: u8;
643 type HumbleType;
644 fn weird_function();
645 fn random_method(&self);
646 }
647 pub struct TestStruct {}
648 impl TestTrait for TestStruct {
649 const SPECIAL_CONST: u8 = 42;
650 type HumbleType = ();
651 fn weird_function() {}
652 fn random_method(&self) {}
653 }
654}
655
656//- /main.rs crate:main deps:dep
657fn main() {
658 dep::test_mod::TestStruct::$0
659}
660"#,
661 expect![[r#"
662 ct SPECIAL_CONST (dep::test_mod::TestTrait) DEPRECATED
663 fn weird_function() (dep::test_mod::TestTrait) fn weird_function() DEPRECATED
664 "#]],
665 );
666 }
291} 667}
diff --git a/crates/completion/src/completions/fn_param.rs b/crates/completion/src/completions/fn_param.rs
index 5505c3559..38e33a93e 100644
--- a/crates/completion/src/completions/fn_param.rs
+++ b/crates/completion/src/completions/fn_param.rs
@@ -6,7 +6,7 @@ use syntax::{
6 match_ast, AstNode, 6 match_ast, AstNode,
7}; 7};
8 8
9use crate::{CompletionContext, CompletionItem, CompletionKind, Completions}; 9use crate::{CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions};
10 10
11/// Complete repeated parameters, both name and type. For example, if all 11/// Complete repeated parameters, both name and type. For example, if all
12/// functions in a file have a `spam: &mut Spam` parameter, a completion with 12/// functions in a file have a `spam: &mut Spam` parameter, a completion with
@@ -58,7 +58,7 @@ pub(crate) fn complete_fn_param(acc: &mut Completions, ctx: &CompletionContext)
58 }) 58 })
59 .for_each(|(label, lookup)| { 59 .for_each(|(label, lookup)| {
60 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label) 60 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), label)
61 .kind(crate::CompletionItemKind::Binding) 61 .kind(CompletionItemKind::Binding)
62 .lookup_by(lookup) 62 .lookup_by(lookup)
63 .add_to(acc) 63 .add_to(acc)
64 }); 64 });
diff --git a/crates/completion/src/completions/mod_.rs b/crates/completion/src/completions/mod_.rs
index 00e951ca9..352fc7c77 100644
--- a/crates/completion/src/completions/mod_.rs
+++ b/crates/completion/src/completions/mod_.rs
@@ -3,11 +3,13 @@
3use std::iter; 3use std::iter;
4 4
5use hir::{Module, ModuleSource}; 5use hir::{Module, ModuleSource};
6use ide_db::base_db::{SourceDatabaseExt, VfsPath}; 6use ide_db::{
7use ide_db::RootDatabase; 7 base_db::{SourceDatabaseExt, VfsPath},
8 RootDatabase, SymbolKind,
9};
8use rustc_hash::FxHashSet; 10use rustc_hash::FxHashSet;
9 11
10use crate::{CompletionItem, CompletionItemKind}; 12use crate::CompletionItem;
11 13
12use crate::{context::CompletionContext, item::CompletionKind, Completions}; 14use crate::{context::CompletionContext, item::CompletionKind, Completions};
13 15
@@ -79,7 +81,7 @@ pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Op
79 label.push(';'); 81 label.push(';');
80 } 82 }
81 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), &label) 83 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), &label)
82 .kind(CompletionItemKind::Module) 84 .kind(SymbolKind::Module)
83 .add_to(acc) 85 .add_to(acc)
84 }); 86 });
85 87
diff --git a/crates/completion/src/completions/record.rs b/crates/completion/src/completions/record.rs
index bb6354ded..0a7927eb8 100644
--- a/crates/completion/src/completions/record.rs
+++ b/crates/completion/src/completions/record.rs
@@ -1,10 +1,8 @@
1//! Complete fields in record literals and patterns. 1//! Complete fields in record literals and patterns.
2use ide_db::helpers::FamousDefs; 2use ide_db::{helpers::FamousDefs, SymbolKind};
3use syntax::ast::Expr; 3use syntax::ast::Expr;
4 4
5use crate::{ 5use crate::{item::CompletionKind, CompletionContext, CompletionItem, Completions};
6 item::CompletionKind, CompletionContext, CompletionItem, CompletionItemKind, Completions,
7};
8 6
9pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 7pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
10 let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) { 8 let missing_fields = match (ctx.record_pat_syntax.as_ref(), ctx.record_lit_syntax.as_ref()) {
@@ -31,7 +29,7 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
31 "..Default::default()", 29 "..Default::default()",
32 ) 30 )
33 .insert_text(completion_text) 31 .insert_text(completion_text)
34 .kind(CompletionItemKind::Field) 32 .kind(SymbolKind::Field)
35 .build(), 33 .build(),
36 ); 34 );
37 } 35 }
diff --git a/crates/completion/src/completions/trait_impl.rs b/crates/completion/src/completions/trait_impl.rs
index 135ae49dc..f258ad9c3 100644
--- a/crates/completion/src/completions/trait_impl.rs
+++ b/crates/completion/src/completions/trait_impl.rs
@@ -32,7 +32,7 @@
32//! ``` 32//! ```
33 33
34use hir::{self, HasAttrs, HasSource}; 34use hir::{self, HasAttrs, HasSource};
35use ide_db::traits::get_missing_assoc_items; 35use ide_db::{traits::get_missing_assoc_items, SymbolKind};
36use syntax::{ 36use syntax::{
37 ast::{self, edit, Impl}, 37 ast::{self, edit, Impl},
38 display::function_declaration, 38 display::function_declaration,
@@ -152,7 +152,7 @@ fn add_function_impl(
152 let completion_kind = if func.self_param(ctx.db).is_some() { 152 let completion_kind = if func.self_param(ctx.db).is_some() {
153 CompletionItemKind::Method 153 CompletionItemKind::Method
154 } else { 154 } else {
155 CompletionItemKind::Function 155 CompletionItemKind::SymbolKind(SymbolKind::Function)
156 }; 156 };
157 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end()); 157 let range = TextRange::new(fn_def_node.text_range().start(), ctx.source_range().end());
158 158
@@ -188,7 +188,7 @@ fn add_type_alias_impl(
188 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) 188 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
189 .text_edit(TextEdit::replace(range, snippet)) 189 .text_edit(TextEdit::replace(range, snippet))
190 .lookup_by(alias_name) 190 .lookup_by(alias_name)
191 .kind(CompletionItemKind::TypeAlias) 191 .kind(SymbolKind::TypeAlias)
192 .set_documentation(type_alias.docs(ctx.db)) 192 .set_documentation(type_alias.docs(ctx.db))
193 .add_to(acc); 193 .add_to(acc);
194} 194}
@@ -211,7 +211,7 @@ fn add_const_impl(
211 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone()) 211 CompletionItem::new(CompletionKind::Magic, ctx.source_range(), snippet.clone())
212 .text_edit(TextEdit::replace(range, snippet)) 212 .text_edit(TextEdit::replace(range, snippet))
213 .lookup_by(const_name) 213 .lookup_by(const_name)
214 .kind(CompletionItemKind::Const) 214 .kind(SymbolKind::Const)
215 .set_documentation(const_.docs(ctx.db)) 215 .set_documentation(const_.docs(ctx.db))
216 .add_to(acc); 216 .add_to(acc);
217 } 217 }
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index ac5596ca4..a289efc34 100644
--- a/crates/completion/src/completions/unqualified_path.rs
+++ b/crates/completion/src/completions/unqualified_path.rs
@@ -29,6 +29,10 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
29 } 29 }
30 30
31 ctx.scope.process_all_names(&mut |name, res| { 31 ctx.scope.process_all_names(&mut |name, res| {
32 if let ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) = res {
33 mark::hit!(skip_lifetime_completion);
34 return;
35 }
32 if ctx.use_item_syntax.is_some() { 36 if ctx.use_item_syntax.is_some() {
33 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) { 37 if let (ScopeDef::Unknown, Some(name_ref)) = (&res, &ctx.name_ref_syntax) {
34 if name_ref.syntax().text() == name.to_string().as_str() { 38 if name_ref.syntax().text() == name.to_string().as_str() {
@@ -37,7 +41,7 @@ pub(crate) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionC
37 } 41 }
38 } 42 }
39 } 43 }
40 acc.add_resolution(ctx, name.to_string(), &res) 44 acc.add_resolution(ctx, name.to_string(), &res);
41 }); 45 });
42} 46}
43 47
@@ -161,8 +165,8 @@ fn quux(x: i32) {
161} 165}
162"#, 166"#,
163 expect![[r#" 167 expect![[r#"
164 bn y i32 168 lc y i32
165 bn x i32 169 lc x i32
166 fn quux(…) fn quux(x: i32) 170 fn quux(…) fn quux(x: i32)
167 "#]], 171 "#]],
168 ); 172 );
@@ -183,8 +187,8 @@ fn quux() {
183} 187}
184"#, 188"#,
185 expect![[r#" 189 expect![[r#"
186 bn b i32 190 lc b i32
187 bn a 191 lc a
188 fn quux() fn quux() 192 fn quux() fn quux()
189 "#]], 193 "#]],
190 ); 194 );
@@ -199,7 +203,7 @@ fn quux() {
199} 203}
200"#, 204"#,
201 expect![[r#" 205 expect![[r#"
202 bn x 206 lc x
203 fn quux() fn quux() 207 fn quux() fn quux()
204 "#]], 208 "#]],
205 ); 209 );
@@ -234,6 +238,24 @@ fn main() {
234 fn quux() fn quux<T>() 238 fn quux() fn quux<T>()
235 "#]], 239 "#]],
236 ); 240 );
241 check(
242 r#"fn quux<const C: usize>() { $0 }"#,
243 expect![[r#"
244 cp C
245 fn quux() fn quux<const C: usize>()
246 "#]],
247 );
248 }
249
250 #[test]
251 fn does_not_complete_lifetimes() {
252 mark::check!(skip_lifetime_completion);
253 check(
254 r#"fn quux<'a>() { $0 }"#,
255 expect![[r#"
256 fn quux() fn quux<'a>()
257 "#]],
258 );
237 } 259 }
238 260
239 #[test] 261 #[test]
@@ -241,7 +263,7 @@ fn main() {
241 check( 263 check(
242 r#"struct S<T> { x: $0}"#, 264 r#"struct S<T> { x: $0}"#,
243 expect![[r#" 265 expect![[r#"
244 tp Self 266 sp Self
245 tp T 267 tp T
246 st S<…> 268 st S<…>
247 "#]], 269 "#]],
@@ -253,7 +275,7 @@ fn main() {
253 check( 275 check(
254 r#"enum X { Y($0) }"#, 276 r#"enum X { Y($0) }"#,
255 expect![[r#" 277 expect![[r#"
256 tp Self 278 sp Self
257 en X 279 en X
258 "#]], 280 "#]],
259 ); 281 );
@@ -356,8 +378,8 @@ fn foo() {
356"#, 378"#,
357 // FIXME: should be only one bar here 379 // FIXME: should be only one bar here
358 expect![[r#" 380 expect![[r#"
359 bn bar i32 381 lc bar i32
360 bn bar i32 382 lc bar i32
361 fn foo() fn foo() 383 fn foo() fn foo()
362 "#]], 384 "#]],
363 ); 385 );
@@ -368,8 +390,8 @@ fn foo() {
368 check( 390 check(
369 r#"impl S { fn foo(&self) { $0 } }"#, 391 r#"impl S { fn foo(&self) { $0 } }"#,
370 expect![[r#" 392 expect![[r#"
371 bn self &{unknown} 393 lc self &{unknown}
372 tp Self 394 sp Self
373 "#]], 395 "#]],
374 ); 396 );
375 } 397 }
@@ -553,8 +575,8 @@ fn quux(x: i32) {
553} 575}
554"#, 576"#,
555 expect![[r#" 577 expect![[r#"
556 bn y i32 578 lc y i32
557 bn x i32 579 lc x i32
558 fn quux(…) fn quux(x: i32) 580 fn quux(…) fn quux(x: i32)
559 ma m!(…) macro_rules! m 581 ma m!(…) macro_rules! m
560 "#]], 582 "#]],
@@ -572,8 +594,8 @@ fn quux(x: i32) {
572} 594}
573", 595",
574 expect![[r#" 596 expect![[r#"
575 bn y i32 597 lc y i32
576 bn x i32 598 lc x i32
577 fn quux(…) fn quux(x: i32) 599 fn quux(…) fn quux(x: i32)
578 ma m!(…) macro_rules! m 600 ma m!(…) macro_rules! m
579 "#]], 601 "#]],
@@ -591,8 +613,8 @@ fn quux(x: i32) {
591} 613}
592"#, 614"#,
593 expect![[r#" 615 expect![[r#"
594 bn y i32 616 lc y i32
595 bn x i32 617 lc x i32
596 fn quux(…) fn quux(x: i32) 618 fn quux(…) fn quux(x: i32)
597 ma m!(…) macro_rules! m 619 ma m!(…) macro_rules! m
598 "#]], 620 "#]],
@@ -728,7 +750,7 @@ struct MyStruct {}
728impl My$0 750impl My$0
729"#, 751"#,
730 expect![[r#" 752 expect![[r#"
731 tp Self 753 sp Self
732 tt MyTrait 754 tt MyTrait
733 st MyStruct 755 st MyStruct
734 "#]], 756 "#]],
diff --git a/crates/completion/src/config.rs b/crates/completion/src/config.rs
index 58fc700f3..d70ed6c1c 100644
--- a/crates/completion/src/config.rs
+++ b/crates/completion/src/config.rs
@@ -9,7 +9,7 @@ use ide_db::helpers::{insert_use::InsertUseConfig, SnippetCap};
9#[derive(Clone, Debug, PartialEq, Eq)] 9#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct CompletionConfig { 10pub struct CompletionConfig {
11 pub enable_postfix_completions: bool, 11 pub enable_postfix_completions: bool,
12 pub enable_autoimport_completions: bool, 12 pub enable_imports_on_the_fly: bool,
13 pub add_call_parenthesis: bool, 13 pub add_call_parenthesis: bool,
14 pub add_call_argument_snippets: bool, 14 pub add_call_argument_snippets: bool,
15 pub snippet_cap: Option<SnippetCap>, 15 pub snippet_cap: Option<SnippetCap>,
diff --git a/crates/completion/src/item.rs b/crates/completion/src/item.rs
index 0134ff219..d2e6a6aeb 100644
--- a/crates/completion/src/item.rs
+++ b/crates/completion/src/item.rs
@@ -3,11 +3,14 @@
3use std::fmt; 3use std::fmt;
4 4
5use hir::{Documentation, ModPath, Mutability}; 5use hir::{Documentation, ModPath, Mutability};
6use ide_db::helpers::{ 6use ide_db::{
7 insert_use::{self, ImportScope, MergeBehavior}, 7 helpers::{
8 mod_path_to_ast, SnippetCap, 8 insert_use::{self, ImportScope, MergeBehavior},
9 mod_path_to_ast, SnippetCap,
10 },
11 SymbolKind,
9}; 12};
10use stdx::assert_never; 13use stdx::{assert_never, impl_from};
11use syntax::{algo, TextRange}; 14use syntax::{algo, TextRange};
12use text_edit::TextEdit; 15use text_edit::TextEdit;
13 16
@@ -117,49 +120,50 @@ pub enum CompletionScore {
117 120
118#[derive(Debug, Clone, Copy, PartialEq, Eq)] 121#[derive(Debug, Clone, Copy, PartialEq, Eq)]
119pub enum CompletionItemKind { 122pub enum CompletionItemKind {
120 Snippet, 123 SymbolKind(SymbolKind),
121 Keyword, 124 Attribute,
122 Module,
123 Function,
124 BuiltinType,
125 Struct,
126 Enum,
127 EnumVariant,
128 Binding, 125 Binding,
129 Field, 126 BuiltinType,
130 Static, 127 Keyword,
131 Const,
132 Trait,
133 TypeAlias,
134 Method, 128 Method,
135 TypeParam, 129 Snippet,
136 Macro,
137 Attribute,
138 UnresolvedReference, 130 UnresolvedReference,
139} 131}
140 132
133impl_from!(SymbolKind for CompletionItemKind);
134
141impl CompletionItemKind { 135impl CompletionItemKind {
142 #[cfg(test)] 136 #[cfg(test)]
143 pub(crate) fn tag(&self) -> &'static str { 137 pub(crate) fn tag(&self) -> &'static str {
144 match self { 138 match self {
139 CompletionItemKind::SymbolKind(kind) => match kind {
140 SymbolKind::Const => "ct",
141 SymbolKind::ConstParam => "cp",
142 SymbolKind::Enum => "en",
143 SymbolKind::Field => "fd",
144 SymbolKind::Function => "fn",
145 SymbolKind::Impl => "im",
146 SymbolKind::Label => "lb",
147 SymbolKind::LifetimeParam => "lt",
148 SymbolKind::Local => "lc",
149 SymbolKind::Macro => "ma",
150 SymbolKind::Module => "md",
151 SymbolKind::SelfParam => "sp",
152 SymbolKind::Static => "sc",
153 SymbolKind::Struct => "st",
154 SymbolKind::Trait => "tt",
155 SymbolKind::TypeAlias => "ta",
156 SymbolKind::TypeParam => "tp",
157 SymbolKind::Union => "un",
158 SymbolKind::ValueParam => "vp",
159 SymbolKind::Variant => "ev",
160 },
145 CompletionItemKind::Attribute => "at", 161 CompletionItemKind::Attribute => "at",
146 CompletionItemKind::Binding => "bn", 162 CompletionItemKind::Binding => "bn",
147 CompletionItemKind::BuiltinType => "bt", 163 CompletionItemKind::BuiltinType => "bt",
148 CompletionItemKind::Const => "ct",
149 CompletionItemKind::Enum => "en",
150 CompletionItemKind::EnumVariant => "ev",
151 CompletionItemKind::Field => "fd",
152 CompletionItemKind::Function => "fn",
153 CompletionItemKind::Keyword => "kw", 164 CompletionItemKind::Keyword => "kw",
154 CompletionItemKind::Macro => "ma",
155 CompletionItemKind::Method => "me", 165 CompletionItemKind::Method => "me",
156 CompletionItemKind::Module => "md",
157 CompletionItemKind::Snippet => "sn", 166 CompletionItemKind::Snippet => "sn",
158 CompletionItemKind::Static => "sc",
159 CompletionItemKind::Struct => "st",
160 CompletionItemKind::Trait => "tt",
161 CompletionItemKind::TypeAlias => "ta",
162 CompletionItemKind::TypeParam => "tp",
163 CompletionItemKind::UnresolvedReference => "??", 167 CompletionItemKind::UnresolvedReference => "??",
164 } 168 }
165 } 169 }
@@ -270,6 +274,7 @@ impl CompletionItem {
270pub struct ImportEdit { 274pub struct ImportEdit {
271 pub import_path: ModPath, 275 pub import_path: ModPath,
272 pub import_scope: ImportScope, 276 pub import_scope: ImportScope,
277 pub import_for_trait_assoc_item: bool,
273} 278}
274 279
275impl ImportEdit { 280impl ImportEdit {
@@ -321,17 +326,19 @@ impl Builder {
321 let mut insert_text = self.insert_text; 326 let mut insert_text = self.insert_text;
322 327
323 if let Some(import_to_add) = self.import_to_add.as_ref() { 328 if let Some(import_to_add) = self.import_to_add.as_ref() {
324 let mut import_path_without_last_segment = import_to_add.import_path.to_owned(); 329 if import_to_add.import_for_trait_assoc_item {
325 let _ = import_path_without_last_segment.segments.pop(); 330 lookup = lookup.or_else(|| Some(label.clone()));
326 331 insert_text = insert_text.or_else(|| Some(label.clone()));
327 if !import_path_without_last_segment.segments.is_empty() { 332 label = format!("{} ({})", label, import_to_add.import_path);
328 if lookup.is_none() { 333 } else {
329 lookup = Some(label.clone()); 334 let mut import_path_without_last_segment = import_to_add.import_path.to_owned();
330 } 335 let _ = import_path_without_last_segment.segments.pop();
331 if insert_text.is_none() { 336
332 insert_text = Some(label.clone()); 337 if !import_path_without_last_segment.segments.is_empty() {
338 lookup = lookup.or_else(|| Some(label.clone()));
339 insert_text = insert_text.or_else(|| Some(label.clone()));
340 label = format!("{}::{}", import_path_without_last_segment, label);
333 } 341 }
334 label = format!("{}::{}", import_path_without_last_segment, label);
335 } 342 }
336 } 343 }
337 344
@@ -379,8 +386,8 @@ impl Builder {
379 self.insert_text_format = InsertTextFormat::Snippet; 386 self.insert_text_format = InsertTextFormat::Snippet;
380 self.insert_text(snippet) 387 self.insert_text(snippet)
381 } 388 }
382 pub(crate) fn kind(mut self, kind: CompletionItemKind) -> Builder { 389 pub(crate) fn kind(mut self, kind: impl Into<CompletionItemKind>) -> Builder {
383 self.kind = Some(kind); 390 self.kind = Some(kind.into());
384 self 391 self
385 } 392 }
386 pub(crate) fn text_edit(mut self, edit: TextEdit) -> Builder { 393 pub(crate) fn text_edit(mut self, edit: TextEdit) -> Builder {
@@ -398,7 +405,9 @@ impl Builder {
398 pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder { 405 pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder {
399 self.detail = detail.map(Into::into); 406 self.detail = detail.map(Into::into);
400 if let Some(detail) = &self.detail { 407 if let Some(detail) = &self.detail {
401 assert_never!(detail.contains('\n'), "multiline detail: {}", detail); 408 if assert_never!(detail.contains('\n'), "multiline detail: {}", detail) {
409 self.detail = Some(detail.splitn(2, '\n').next().unwrap().to_string());
410 }
402 } 411 }
403 self 412 self
404 } 413 }
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs
index ee1b822e7..2c4e54524 100644
--- a/crates/completion/src/lib.rs
+++ b/crates/completion/src/lib.rs
@@ -11,10 +11,10 @@ mod render;
11 11
12mod completions; 12mod completions;
13 13
14use completions::flyimport::position_for_import;
14use ide_db::{ 15use ide_db::{
15 base_db::FilePosition, helpers::insert_use::ImportScope, imports_locator, RootDatabase, 16 base_db::FilePosition, helpers::insert_use::ImportScope, imports_locator, RootDatabase,
16}; 17};
17use syntax::AstNode;
18use text_edit::TextEdit; 18use text_edit::TextEdit;
19 19
20use crate::{completions::Completions, context::CompletionContext, item::CompletionKind}; 20use crate::{completions::Completions, context::CompletionContext, item::CompletionKind};
@@ -139,12 +139,13 @@ pub fn resolve_completion_edits(
139 position: FilePosition, 139 position: FilePosition,
140 full_import_path: &str, 140 full_import_path: &str,
141 imported_name: String, 141 imported_name: String,
142 import_for_trait_assoc_item: bool,
142) -> Option<Vec<TextEdit>> { 143) -> Option<Vec<TextEdit>> {
143 let ctx = CompletionContext::new(db, position, config)?; 144 let ctx = CompletionContext::new(db, position, config)?;
144 let anchor = ctx.name_ref_syntax.as_ref()?; 145 let position_for_import = position_for_import(&ctx, None)?;
145 let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?; 146 let import_scope = ImportScope::find_insert_use_container(position_for_import, &ctx.sema)?;
146 147
147 let current_module = ctx.sema.scope(anchor.syntax()).module()?; 148 let current_module = ctx.sema.scope(position_for_import).module()?;
148 let current_crate = current_module.krate(); 149 let current_crate = current_module.krate();
149 150
150 let import_path = imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name) 151 let import_path = imports_locator::find_exact_imports(&ctx.sema, current_crate, imported_name)
@@ -154,7 +155,7 @@ pub fn resolve_completion_edits(
154 }) 155 })
155 .find(|mod_path| mod_path.to_string() == full_import_path)?; 156 .find(|mod_path| mod_path.to_string() == full_import_path)?;
156 157
157 ImportEdit { import_path, import_scope } 158 ImportEdit { import_path, import_scope, import_for_trait_assoc_item }
158 .to_text_edit(config.insert_use.merge) 159 .to_text_edit(config.insert_use.merge)
159 .map(|edit| vec![edit]) 160 .map(|edit| vec![edit])
160} 161}
diff --git a/crates/completion/src/render.rs b/crates/completion/src/render.rs
index 820dd01d1..fa594b5e5 100644
--- a/crates/completion/src/render.rs
+++ b/crates/completion/src/render.rs
@@ -10,8 +10,10 @@ pub(crate) mod type_alias;
10 10
11mod builder_ext; 11mod builder_ext;
12 12
13use hir::{Documentation, HasAttrs, HirDisplay, Mutability, ScopeDef, Type}; 13use hir::{
14use ide_db::{helpers::SnippetCap, RootDatabase}; 14 AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type,
15};
16use ide_db::{helpers::SnippetCap, RootDatabase, SymbolKind};
15use syntax::TextRange; 17use syntax::TextRange;
16use test_utils::mark; 18use test_utils::mark;
17 19
@@ -51,16 +53,16 @@ pub(crate) fn render_resolution_with_import<'a>(
51 import_edit: ImportEdit, 53 import_edit: ImportEdit,
52 resolution: &ScopeDef, 54 resolution: &ScopeDef,
53) -> Option<CompletionItem> { 55) -> Option<CompletionItem> {
54 Render::new(ctx) 56 let local_name = match resolution {
55 .render_resolution( 57 ScopeDef::ModuleDef(ModuleDef::Function(f)) => f.name(ctx.completion.db).to_string(),
56 import_edit.import_path.segments.last()?.to_string(), 58 ScopeDef::ModuleDef(ModuleDef::Const(c)) => c.name(ctx.completion.db)?.to_string(),
57 Some(import_edit), 59 ScopeDef::ModuleDef(ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db).to_string(),
58 resolution, 60 _ => import_edit.import_path.segments.last()?.to_string(),
59 ) 61 };
60 .map(|mut item| { 62 Render::new(ctx).render_resolution(local_name, Some(import_edit), resolution).map(|mut item| {
61 item.completion_kind = CompletionKind::Magic; 63 item.completion_kind = CompletionKind::Magic;
62 item 64 item
63 }) 65 })
64} 66}
65 67
66/// Interface for data and methods required for items rendering. 68/// Interface for data and methods required for items rendering.
@@ -87,7 +89,24 @@ impl<'a> RenderContext<'a> {
87 } 89 }
88 90
89 fn is_deprecated(&self, node: impl HasAttrs) -> bool { 91 fn is_deprecated(&self, node: impl HasAttrs) -> bool {
90 node.attrs(self.db()).by_key("deprecated").exists() 92 let attrs = node.attrs(self.db());
93 attrs.by_key("deprecated").exists() || attrs.by_key("rustc_deprecated").exists()
94 }
95
96 fn is_deprecated_assoc_item(&self, as_assoc_item: impl AsAssocItem) -> bool {
97 let db = self.db();
98 let assoc = match as_assoc_item.as_assoc_item(db) {
99 Some(assoc) => assoc,
100 None => return false,
101 };
102
103 let is_assoc_deprecated = match assoc {
104 hir::AssocItem::Function(it) => self.is_deprecated(it),
105 hir::AssocItem::Const(it) => self.is_deprecated(it),
106 hir::AssocItem::TypeAlias(it) => self.is_deprecated(it),
107 };
108 is_assoc_deprecated
109 || assoc.containing_trait(db).map(|trait_| self.is_deprecated(trait_)).unwrap_or(false)
91 } 110 }
92 111
93 fn docs(&self, node: impl HasAttrs) -> Option<Documentation> { 112 fn docs(&self, node: impl HasAttrs) -> Option<Documentation> {
@@ -127,7 +146,7 @@ impl<'a> Render<'a> {
127 self.ctx.source_range(), 146 self.ctx.source_range(),
128 name.to_string(), 147 name.to_string(),
129 ) 148 )
130 .kind(CompletionItemKind::Field) 149 .kind(SymbolKind::Field)
131 .detail(ty.display(self.ctx.db()).to_string()) 150 .detail(ty.display(self.ctx.db()).to_string())
132 .set_documentation(field.docs(self.ctx.db())) 151 .set_documentation(field.docs(self.ctx.db()))
133 .set_deprecated(is_deprecated); 152 .set_deprecated(is_deprecated);
@@ -141,7 +160,7 @@ impl<'a> Render<'a> {
141 160
142 fn add_tuple_field(&mut self, field: usize, ty: &Type) -> CompletionItem { 161 fn add_tuple_field(&mut self, field: usize, ty: &Type) -> CompletionItem {
143 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), field.to_string()) 162 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), field.to_string())
144 .kind(CompletionItemKind::Field) 163 .kind(SymbolKind::Field)
145 .detail(ty.display(self.ctx.db()).to_string()) 164 .detail(ty.display(self.ctx.db()).to_string())
146 .build() 165 .build()
147 } 166 }
@@ -168,7 +187,7 @@ impl<'a> Render<'a> {
168 if self.ctx.completion.is_pat_binding_or_const 187 if self.ctx.completion.is_pat_binding_or_const
169 | self.ctx.completion.is_irrefutable_pat_binding => 188 | self.ctx.completion.is_irrefutable_pat_binding =>
170 { 189 {
171 CompletionItemKind::EnumVariant 190 CompletionItemKind::SymbolKind(SymbolKind::Variant)
172 } 191 }
173 ScopeDef::ModuleDef(Variant(var)) => { 192 ScopeDef::ModuleDef(Variant(var)) => {
174 let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None); 193 let item = render_variant(self.ctx, import_to_add, Some(local_name), *var, None);
@@ -179,20 +198,29 @@ impl<'a> Render<'a> {
179 return item; 198 return item;
180 } 199 }
181 200
182 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module, 201 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::SymbolKind(SymbolKind::Module),
183 ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct, 202 ScopeDef::ModuleDef(Adt(adt)) => CompletionItemKind::SymbolKind(match adt {
184 // FIXME: add CompletionItemKind::Union 203 hir::Adt::Struct(_) => SymbolKind::Struct,
185 ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct, 204 // FIXME: add CompletionItemKind::Union
186 ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum, 205 hir::Adt::Union(_) => SymbolKind::Struct,
187 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const, 206 hir::Adt::Enum(_) => SymbolKind::Enum,
188 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static, 207 }),
189 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait, 208 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::SymbolKind(SymbolKind::Const),
190 ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias, 209 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::SymbolKind(SymbolKind::Static),
210 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::SymbolKind(SymbolKind::Trait),
211 ScopeDef::ModuleDef(TypeAlias(..)) => {
212 CompletionItemKind::SymbolKind(SymbolKind::TypeAlias)
213 }
191 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType, 214 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
192 ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam, 215 ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
193 ScopeDef::Local(..) => CompletionItemKind::Binding, 216 hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
194 // (does this need its own kind?) 217 hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
195 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam, 218 hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
219 }),
220 ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
221 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => {
222 CompletionItemKind::SymbolKind(SymbolKind::SelfParam)
223 }
196 ScopeDef::Unknown => { 224 ScopeDef::Unknown => {
197 let item = CompletionItem::new( 225 let item = CompletionItem::new(
198 CompletionKind::Reference, 226 CompletionKind::Reference,
@@ -206,8 +234,6 @@ impl<'a> Render<'a> {
206 } 234 }
207 }; 235 };
208 236
209 let docs = self.docs(resolution);
210
211 let mut item = 237 let mut item =
212 CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone()); 238 CompletionItem::new(completion_kind, self.ctx.source_range(), local_name.clone());
213 if let ScopeDef::Local(local) = resolution { 239 if let ScopeDef::Local(local) = resolution {
@@ -253,13 +279,14 @@ impl<'a> Render<'a> {
253 } 279 }
254 } 280 }
255 281
256 let item = item 282 Some(
257 .kind(kind) 283 item.kind(kind)
258 .add_import(import_to_add) 284 .add_import(import_to_add)
259 .set_documentation(docs) 285 .set_ref_match(ref_match)
260 .set_ref_match(ref_match) 286 .set_documentation(self.docs(resolution))
261 .build(); 287 .set_deprecated(self.is_deprecated(resolution))
262 Some(item) 288 .build(),
289 )
263 } 290 }
264 291
265 fn docs(&self, resolution: &ScopeDef) -> Option<Documentation> { 292 fn docs(&self, resolution: &ScopeDef) -> Option<Documentation> {
@@ -275,6 +302,16 @@ impl<'a> Render<'a> {
275 _ => None, 302 _ => None,
276 } 303 }
277 } 304 }
305
306 fn is_deprecated(&self, resolution: &ScopeDef) -> bool {
307 match resolution {
308 ScopeDef::ModuleDef(it) => self.ctx.is_deprecated_assoc_item(*it),
309 ScopeDef::MacroDef(it) => self.ctx.is_deprecated(*it),
310 ScopeDef::GenericParam(it) => self.ctx.is_deprecated(*it),
311 ScopeDef::AdtSelfType(it) => self.ctx.is_deprecated(*it),
312 _ => false,
313 }
314 }
278} 315}
279 316
280fn compute_score_from_active( 317fn compute_score_from_active(
@@ -372,7 +409,9 @@ fn main() { Foo::Fo$0 }
372 source_range: 54..56, 409 source_range: 54..56,
373 delete: 54..56, 410 delete: 54..56,
374 insert: "Foo", 411 insert: "Foo",
375 kind: EnumVariant, 412 kind: SymbolKind(
413 Variant,
414 ),
376 detail: "{ x: i32, y: i32 }", 415 detail: "{ x: i32, y: i32 }",
377 }, 416 },
378 ] 417 ]
@@ -395,7 +434,9 @@ fn main() { Foo::Fo$0 }
395 source_range: 46..48, 434 source_range: 46..48,
396 delete: 46..48, 435 delete: 46..48,
397 insert: "Foo($0)", 436 insert: "Foo($0)",
398 kind: EnumVariant, 437 kind: SymbolKind(
438 Variant,
439 ),
399 lookup: "Foo", 440 lookup: "Foo",
400 detail: "(i32, i32)", 441 detail: "(i32, i32)",
401 trigger_call_info: true, 442 trigger_call_info: true,
@@ -420,7 +461,9 @@ fn main() { Foo::Fo$0 }
420 source_range: 35..37, 461 source_range: 35..37,
421 delete: 35..37, 462 delete: 35..37,
422 insert: "Foo", 463 insert: "Foo",
423 kind: EnumVariant, 464 kind: SymbolKind(
465 Variant,
466 ),
424 detail: "()", 467 detail: "()",
425 }, 468 },
426 ] 469 ]
@@ -444,7 +487,9 @@ fn main() { let _: m::Spam = S$0 }
444 source_range: 75..76, 487 source_range: 75..76,
445 delete: 75..76, 488 delete: 75..76,
446 insert: "Spam::Bar($0)", 489 insert: "Spam::Bar($0)",
447 kind: EnumVariant, 490 kind: SymbolKind(
491 Variant,
492 ),
448 lookup: "Spam::Bar", 493 lookup: "Spam::Bar",
449 detail: "(i32)", 494 detail: "(i32)",
450 trigger_call_info: true, 495 trigger_call_info: true,
@@ -454,14 +499,18 @@ fn main() { let _: m::Spam = S$0 }
454 source_range: 75..76, 499 source_range: 75..76,
455 delete: 75..76, 500 delete: 75..76,
456 insert: "m", 501 insert: "m",
457 kind: Module, 502 kind: SymbolKind(
503 Module,
504 ),
458 }, 505 },
459 CompletionItem { 506 CompletionItem {
460 label: "m::Spam::Foo", 507 label: "m::Spam::Foo",
461 source_range: 75..76, 508 source_range: 75..76,
462 delete: 75..76, 509 delete: 75..76,
463 insert: "m::Spam::Foo", 510 insert: "m::Spam::Foo",
464 kind: EnumVariant, 511 kind: SymbolKind(
512 Variant,
513 ),
465 lookup: "Spam::Foo", 514 lookup: "Spam::Foo",
466 detail: "()", 515 detail: "()",
467 }, 516 },
@@ -470,7 +519,9 @@ fn main() { let _: m::Spam = S$0 }
470 source_range: 75..76, 519 source_range: 75..76,
471 delete: 75..76, 520 delete: 75..76,
472 insert: "main()$0", 521 insert: "main()$0",
473 kind: Function, 522 kind: SymbolKind(
523 Function,
524 ),
474 lookup: "main", 525 lookup: "main",
475 detail: "fn main()", 526 detail: "fn main()",
476 }, 527 },
@@ -485,7 +536,7 @@ fn main() { let _: m::Spam = S$0 }
485 r#" 536 r#"
486#[deprecated] 537#[deprecated]
487fn something_deprecated() {} 538fn something_deprecated() {}
488#[deprecated(since = "1.0.0")] 539#[rustc_deprecated(since = "1.0.0")]
489fn something_else_deprecated() {} 540fn something_else_deprecated() {}
490 541
491fn main() { som$0 } 542fn main() { som$0 }
@@ -494,29 +545,35 @@ fn main() { som$0 }
494 [ 545 [
495 CompletionItem { 546 CompletionItem {
496 label: "main()", 547 label: "main()",
497 source_range: 121..124, 548 source_range: 127..130,
498 delete: 121..124, 549 delete: 127..130,
499 insert: "main()$0", 550 insert: "main()$0",
500 kind: Function, 551 kind: SymbolKind(
552 Function,
553 ),
501 lookup: "main", 554 lookup: "main",
502 detail: "fn main()", 555 detail: "fn main()",
503 }, 556 },
504 CompletionItem { 557 CompletionItem {
505 label: "something_deprecated()", 558 label: "something_deprecated()",
506 source_range: 121..124, 559 source_range: 127..130,
507 delete: 121..124, 560 delete: 127..130,
508 insert: "something_deprecated()$0", 561 insert: "something_deprecated()$0",
509 kind: Function, 562 kind: SymbolKind(
563 Function,
564 ),
510 lookup: "something_deprecated", 565 lookup: "something_deprecated",
511 detail: "fn something_deprecated()", 566 detail: "fn something_deprecated()",
512 deprecated: true, 567 deprecated: true,
513 }, 568 },
514 CompletionItem { 569 CompletionItem {
515 label: "something_else_deprecated()", 570 label: "something_else_deprecated()",
516 source_range: 121..124, 571 source_range: 127..130,
517 delete: 121..124, 572 delete: 127..130,
518 insert: "something_else_deprecated()$0", 573 insert: "something_else_deprecated()$0",
519 kind: Function, 574 kind: SymbolKind(
575 Function,
576 ),
520 lookup: "something_else_deprecated", 577 lookup: "something_else_deprecated",
521 detail: "fn something_else_deprecated()", 578 detail: "fn something_else_deprecated()",
522 deprecated: true, 579 deprecated: true,
@@ -537,7 +594,9 @@ fn foo() { A { the$0 } }
537 source_range: 57..60, 594 source_range: 57..60,
538 delete: 57..60, 595 delete: 57..60,
539 insert: "the_field", 596 insert: "the_field",
540 kind: Field, 597 kind: SymbolKind(
598 Field,
599 ),
541 detail: "u32", 600 detail: "u32",
542 deprecated: true, 601 deprecated: true,
543 }, 602 },
@@ -577,7 +636,9 @@ impl S {
577 source_range: 94..94, 636 source_range: 94..94,
578 delete: 94..94, 637 delete: 94..94,
579 insert: "foo", 638 insert: "foo",
580 kind: Field, 639 kind: SymbolKind(
640 Field,
641 ),
581 detail: "{unknown}", 642 detail: "{unknown}",
582 documentation: Documentation( 643 documentation: Documentation(
583 "Field docs", 644 "Field docs",
@@ -608,7 +669,9 @@ use self::E::*;
608 source_range: 10..12, 669 source_range: 10..12,
609 delete: 10..12, 670 delete: 10..12,
610 insert: "E", 671 insert: "E",
611 kind: Enum, 672 kind: SymbolKind(
673 Enum,
674 ),
612 documentation: Documentation( 675 documentation: Documentation(
613 "enum docs", 676 "enum docs",
614 ), 677 ),
@@ -618,7 +681,9 @@ use self::E::*;
618 source_range: 10..12, 681 source_range: 10..12,
619 delete: 10..12, 682 delete: 10..12,
620 insert: "V", 683 insert: "V",
621 kind: EnumVariant, 684 kind: SymbolKind(
685 Variant,
686 ),
622 detail: "()", 687 detail: "()",
623 documentation: Documentation( 688 documentation: Documentation(
624 "variant docs", 689 "variant docs",
@@ -629,7 +694,9 @@ use self::E::*;
629 source_range: 10..12, 694 source_range: 10..12,
630 delete: 10..12, 695 delete: 10..12,
631 insert: "my", 696 insert: "my",
632 kind: Module, 697 kind: SymbolKind(
698 Module,
699 ),
633 documentation: Documentation( 700 documentation: Documentation(
634 "mod docs", 701 "mod docs",
635 ), 702 ),
@@ -855,7 +922,7 @@ struct WorldSnapshot { _f: () };
855fn go(world: &WorldSnapshot) { go(w$0) } 922fn go(world: &WorldSnapshot) { go(w$0) }
856"#, 923"#,
857 expect![[r#" 924 expect![[r#"
858 bn world [type+name] 925 lc world [type+name]
859 st WorldSnapshot [] 926 st WorldSnapshot []
860 fn go(…) [] 927 fn go(…) []
861 "#]], 928 "#]],
@@ -872,7 +939,7 @@ fn f(foo: &Foo) { f(foo, w$0) }
872 expect![[r#" 939 expect![[r#"
873 st Foo [] 940 st Foo []
874 fn f(…) [] 941 fn f(…) []
875 bn foo [] 942 lc foo []
876 "#]], 943 "#]],
877 ); 944 );
878 } 945 }
diff --git a/crates/completion/src/render/const_.rs b/crates/completion/src/render/const_.rs
index ce924f309..5010b642a 100644
--- a/crates/completion/src/render/const_.rs
+++ b/crates/completion/src/render/const_.rs
@@ -1,13 +1,14 @@
1//! Renderer for `const` fields. 1//! Renderer for `const` fields.
2 2
3use hir::HasSource; 3use hir::HasSource;
4use ide_db::SymbolKind;
4use syntax::{ 5use syntax::{
5 ast::{Const, NameOwner}, 6 ast::{Const, NameOwner},
6 display::const_label, 7 display::const_label,
7}; 8};
8 9
9use crate::{ 10use crate::{
10 item::{CompletionItem, CompletionItemKind, CompletionKind}, 11 item::{CompletionItem, CompletionKind},
11 render::RenderContext, 12 render::RenderContext,
12}; 13};
13 14
@@ -36,9 +37,12 @@ impl<'a> ConstRender<'a> {
36 let detail = self.detail(); 37 let detail = self.detail();
37 38
38 let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) 39 let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name)
39 .kind(CompletionItemKind::Const) 40 .kind(SymbolKind::Const)
40 .set_documentation(self.ctx.docs(self.const_)) 41 .set_documentation(self.ctx.docs(self.const_))
41 .set_deprecated(self.ctx.is_deprecated(self.const_)) 42 .set_deprecated(
43 self.ctx.is_deprecated(self.const_)
44 || self.ctx.is_deprecated_assoc_item(self.const_),
45 )
42 .detail(detail) 46 .detail(detail)
43 .build(); 47 .build();
44 48
diff --git a/crates/completion/src/render/enum_variant.rs b/crates/completion/src/render/enum_variant.rs
index 89fb49773..adcddebd1 100644
--- a/crates/completion/src/render/enum_variant.rs
+++ b/crates/completion/src/render/enum_variant.rs
@@ -1,11 +1,12 @@
1//! Renderer for `enum` variants. 1//! Renderer for `enum` variants.
2 2
3use hir::{HasAttrs, HirDisplay, ModPath, StructKind}; 3use hir::{HasAttrs, HirDisplay, ModPath, StructKind};
4use ide_db::SymbolKind;
4use itertools::Itertools; 5use itertools::Itertools;
5use test_utils::mark; 6use test_utils::mark;
6 7
7use crate::{ 8use crate::{
8 item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit}, 9 item::{CompletionItem, CompletionKind, ImportEdit},
9 render::{builder_ext::Params, RenderContext}, 10 render::{builder_ext::Params, RenderContext},
10}; 11};
11 12
@@ -60,7 +61,7 @@ impl<'a> EnumRender<'a> {
60 self.ctx.source_range(), 61 self.ctx.source_range(),
61 self.qualified_name.clone(), 62 self.qualified_name.clone(),
62 ) 63 )
63 .kind(CompletionItemKind::EnumVariant) 64 .kind(SymbolKind::Variant)
64 .set_documentation(self.variant.docs(self.ctx.db())) 65 .set_documentation(self.variant.docs(self.ctx.db()))
65 .set_deprecated(self.ctx.is_deprecated(self.variant)) 66 .set_deprecated(self.ctx.is_deprecated(self.variant))
66 .add_import(import_to_add) 67 .add_import(import_to_add)
diff --git a/crates/completion/src/render/function.rs b/crates/completion/src/render/function.rs
index f5b0ce3e3..2d616b1fb 100644
--- a/crates/completion/src/render/function.rs
+++ b/crates/completion/src/render/function.rs
@@ -1,6 +1,7 @@
1//! Renderer for function calls. 1//! Renderer for function calls.
2 2
3use hir::{HasSource, Type}; 3use hir::{HasSource, Type};
4use ide_db::SymbolKind;
4use syntax::{ast::Fn, display::function_declaration}; 5use syntax::{ast::Fn, display::function_declaration};
5use test_utils::mark; 6use test_utils::mark;
6 7
@@ -44,7 +45,9 @@ impl<'a> FunctionRender<'a> {
44 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone()) 45 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), self.name.clone())
45 .kind(self.kind()) 46 .kind(self.kind())
46 .set_documentation(self.ctx.docs(self.func)) 47 .set_documentation(self.ctx.docs(self.func))
47 .set_deprecated(self.ctx.is_deprecated(self.func)) 48 .set_deprecated(
49 self.ctx.is_deprecated(self.func) || self.ctx.is_deprecated_assoc_item(self.func),
50 )
48 .detail(self.detail()) 51 .detail(self.detail())
49 .add_call_parens(self.ctx.completion, self.name, params) 52 .add_call_parens(self.ctx.completion, self.name, params)
50 .add_import(import_to_add) 53 .add_import(import_to_add)
@@ -103,7 +106,7 @@ impl<'a> FunctionRender<'a> {
103 if self.func.self_param(self.ctx.db()).is_some() { 106 if self.func.self_param(self.ctx.db()).is_some() {
104 CompletionItemKind::Method 107 CompletionItemKind::Method
105 } else { 108 } else {
106 CompletionItemKind::Function 109 SymbolKind::Function.into()
107 } 110 }
108 } 111 }
109} 112}
diff --git a/crates/completion/src/render/macro_.rs b/crates/completion/src/render/macro_.rs
index f893e420a..a4535786f 100644
--- a/crates/completion/src/render/macro_.rs
+++ b/crates/completion/src/render/macro_.rs
@@ -1,11 +1,12 @@
1//! Renderer for macro invocations. 1//! Renderer for macro invocations.
2 2
3use hir::{Documentation, HasSource}; 3use hir::{Documentation, HasSource};
4use ide_db::SymbolKind;
4use syntax::display::macro_label; 5use syntax::display::macro_label;
5use test_utils::mark; 6use test_utils::mark;
6 7
7use crate::{ 8use crate::{
8 item::{CompletionItem, CompletionItemKind, CompletionKind, ImportEdit}, 9 item::{CompletionItem, CompletionKind, ImportEdit},
9 render::RenderContext, 10 render::RenderContext,
10}; 11};
11 12
@@ -41,7 +42,7 @@ impl<'a> MacroRender<'a> {
41 fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> { 42 fn render(&self, import_to_add: Option<ImportEdit>) -> Option<CompletionItem> {
42 let mut builder = 43 let mut builder =
43 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label()) 44 CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), &self.label())
44 .kind(CompletionItemKind::Macro) 45 .kind(SymbolKind::Macro)
45 .set_documentation(self.docs.clone()) 46 .set_documentation(self.docs.clone())
46 .set_deprecated(self.ctx.is_deprecated(self.macro_)) 47 .set_deprecated(self.ctx.is_deprecated(self.macro_))
47 .add_import(import_to_add) 48 .add_import(import_to_add)
diff --git a/crates/completion/src/render/type_alias.rs b/crates/completion/src/render/type_alias.rs
index 69b445b9c..bd97c3692 100644
--- a/crates/completion/src/render/type_alias.rs
+++ b/crates/completion/src/render/type_alias.rs
@@ -1,13 +1,14 @@
1//! Renderer for type aliases. 1//! Renderer for type aliases.
2 2
3use hir::HasSource; 3use hir::HasSource;
4use ide_db::SymbolKind;
4use syntax::{ 5use syntax::{
5 ast::{NameOwner, TypeAlias}, 6 ast::{NameOwner, TypeAlias},
6 display::type_label, 7 display::type_label,
7}; 8};
8 9
9use crate::{ 10use crate::{
10 item::{CompletionItem, CompletionItemKind, CompletionKind}, 11 item::{CompletionItem, CompletionKind},
11 render::RenderContext, 12 render::RenderContext,
12}; 13};
13 14
@@ -36,9 +37,12 @@ impl<'a> TypeAliasRender<'a> {
36 let detail = self.detail(); 37 let detail = self.detail();
37 38
38 let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name) 39 let item = CompletionItem::new(CompletionKind::Reference, self.ctx.source_range(), name)
39 .kind(CompletionItemKind::TypeAlias) 40 .kind(SymbolKind::TypeAlias)
40 .set_documentation(self.ctx.docs(self.type_alias)) 41 .set_documentation(self.ctx.docs(self.type_alias))
41 .set_deprecated(self.ctx.is_deprecated(self.type_alias)) 42 .set_deprecated(
43 self.ctx.is_deprecated(self.type_alias)
44 || self.ctx.is_deprecated_assoc_item(self.type_alias),
45 )
42 .detail(detail) 46 .detail(detail)
43 .build(); 47 .build();
44 48
diff --git a/crates/completion/src/test_utils.rs b/crates/completion/src/test_utils.rs
index 6ea6da989..baff83305 100644
--- a/crates/completion/src/test_utils.rs
+++ b/crates/completion/src/test_utils.rs
@@ -18,7 +18,7 @@ use crate::{item::CompletionKind, CompletionConfig, CompletionItem};
18 18
19pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { 19pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
20 enable_postfix_completions: true, 20 enable_postfix_completions: true,
21 enable_autoimport_completions: true, 21 enable_imports_on_the_fly: true,
22 add_call_parenthesis: true, 22 add_call_parenthesis: true,
23 add_call_argument_snippets: true, 23 add_call_argument_snippets: true,
24 snippet_cap: SnippetCap::new(true), 24 snippet_cap: SnippetCap::new(true),
@@ -83,6 +83,9 @@ pub(crate) fn completion_list_with_config(
83 let width = label_width.saturating_sub(monospace_width(it.label())); 83 let width = label_width.saturating_sub(monospace_width(it.label()));
84 format_to!(buf, "{:width$} {}", "", detail, width = width); 84 format_to!(buf, "{:width$} {}", "", detail, width = width);
85 } 85 }
86 if it.deprecated() {
87 format_to!(buf, " DEPRECATED");
88 }
86 format_to!(buf, "\n"); 89 format_to!(buf, "\n");
87 buf 90 buf
88 }) 91 })