aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src/render.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src/render.rs')
-rw-r--r--crates/ide_completion/src/render.rs230
1 files changed, 187 insertions, 43 deletions
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 2514dda7c..4e4923e0d 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -10,10 +10,8 @@ pub(crate) mod type_alias;
10 10
11mod builder_ext; 11mod builder_ext;
12 12
13use base_db::Upcast;
14use hir::{ 13use hir::{
15 db::HirDatabase, AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, 14 AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type,
16 ScopeDef, Type,
17}; 15};
18use ide_db::{ 16use ide_db::{
19 helpers::{item_name, SnippetCap}, 17 helpers::{item_name, SnippetCap},
@@ -22,8 +20,8 @@ use ide_db::{
22use syntax::TextRange; 20use syntax::TextRange;
23 21
24use crate::{ 22use crate::{
25 item::{CompletionRelevance, ImportEdit}, 23 item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind,
26 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, 24 CompletionRelevance,
27}; 25};
28 26
29use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro}; 27use crate::render::{enum_variant::render_variant, function::render_fn, macro_::render_macro};
@@ -144,7 +142,15 @@ impl<'a> Render<'a> {
144 .set_documentation(field.docs(self.ctx.db())) 142 .set_documentation(field.docs(self.ctx.db()))
145 .set_deprecated(is_deprecated); 143 .set_deprecated(is_deprecated);
146 144
147 item.set_relevance(compute_relevance(&self.ctx, &ty, &name.to_string())); 145 item.set_relevance(CompletionRelevance {
146 exact_type_match: compute_exact_type_match(self.ctx.completion, ty),
147 exact_name_match: compute_exact_name_match(self.ctx.completion, name.to_string()),
148 ..CompletionRelevance::default()
149 });
150
151 if let Some(ref_match) = compute_ref_match(self.ctx.completion, ty) {
152 item.ref_match(ref_match);
153 }
148 154
149 item.build() 155 item.build()
150 } 156 }
@@ -234,31 +240,18 @@ impl<'a> Render<'a> {
234 if !ty.is_unknown() { 240 if !ty.is_unknown() {
235 item.detail(ty.display(self.ctx.db()).to_string()); 241 item.detail(ty.display(self.ctx.db()).to_string());
236 } 242 }
237 };
238 243
239 if let ScopeDef::Local(local) = resolution { 244 item.set_relevance(CompletionRelevance {
240 let ty = local.ty(self.ctx.db()); 245 exact_type_match: compute_exact_type_match(self.ctx.completion, &ty),
246 exact_name_match: compute_exact_name_match(self.ctx.completion, local_name.clone()),
247 is_local: true,
248 ..CompletionRelevance::default()
249 });
241 250
242 let mut relevance = compute_relevance(&self.ctx, &ty, &local_name); 251 if let Some(ref_match) = compute_ref_match(self.ctx.completion, &ty) {
243 relevance.is_local = true; 252 item.ref_match(ref_match);
244 item.set_relevance(relevance);
245
246 if let Some(expected_type) = self.ctx.completion.expected_type.as_ref() {
247 if &ty != expected_type {
248 if let Some(ty_without_ref) = expected_type.remove_ref() {
249 if relevance_type_match(self.ctx.db().upcast(), &ty, &ty_without_ref) {
250 cov_mark::hit!(suggest_ref);
251 let mutability = if expected_type.is_mutable_reference() {
252 Mutability::Mut
253 } else {
254 Mutability::Shared
255 };
256 item.ref_match(mutability);
257 }
258 }
259 }
260 } 253 }
261 } 254 };
262 255
263 // Add `<>` for generic types 256 // Add `<>` for generic types
264 if self.ctx.completion.is_path_type 257 if self.ctx.completion.is_path_type
@@ -313,17 +306,38 @@ impl<'a> Render<'a> {
313 } 306 }
314} 307}
315 308
316fn compute_relevance(ctx: &RenderContext, ty: &Type, name: &str) -> CompletionRelevance { 309fn compute_exact_type_match(ctx: &CompletionContext, completion_ty: &hir::Type) -> bool {
317 let mut res = CompletionRelevance::default(); 310 match ctx.expected_type.as_ref() {
311 Some(expected_type) => {
312 // We don't ever consider unit type to be an exact type match, since
313 // nearly always this is not meaningful to the user.
314 completion_ty == expected_type && !expected_type.is_unit()
315 }
316 None => false,
317 }
318}
318 319
319 res.exact_type_match = Some(ty) == ctx.completion.expected_type.as_ref(); 320fn compute_exact_name_match(ctx: &CompletionContext, completion_name: impl Into<String>) -> bool {
320 res.exact_name_match = Some(name) == ctx.completion.expected_name.as_deref(); 321 let completion_name = completion_name.into();
321 322
322 res 323 Some(&completion_name) == ctx.expected_name.as_ref()
323} 324}
324 325
325fn relevance_type_match(db: &dyn HirDatabase, ty: &Type, expected_type: &Type) -> bool { 326fn compute_ref_match(ctx: &CompletionContext, completion_ty: &hir::Type) -> Option<Mutability> {
326 ty == expected_type || ty.autoderef(db).any(|deref_ty| &deref_ty == expected_type) 327 let expected_type = ctx.expected_type.as_ref()?;
328 if completion_ty != expected_type {
329 let expected_type_without_ref = expected_type.remove_ref()?;
330 if completion_ty.autoderef(ctx.db).any(|deref_ty| deref_ty == expected_type_without_ref) {
331 cov_mark::hit!(suggest_ref);
332 let mutability = if expected_type.is_mutable_reference() {
333 Mutability::Mut
334 } else {
335 Mutability::Shared
336 };
337 return Some(mutability);
338 };
339 }
340 None
327} 341}
328 342
329#[cfg(test)] 343#[cfg(test)]
@@ -432,6 +446,44 @@ fn main() { Foo::Fo$0 }
432 } 446 }
433 447
434 #[test] 448 #[test]
449 fn fn_detail_includes_args_and_return_type() {
450 check(
451 r#"
452fn foo<T>(a: u32, b: u32, t: T) -> (u32, T) { (a, t) }
453
454fn main() { fo$0 }
455"#,
456 expect![[r#"
457 [
458 CompletionItem {
459 label: "foo(…)",
460 source_range: 68..70,
461 delete: 68..70,
462 insert: "foo(${1:a}, ${2:b}, ${3:t})$0",
463 kind: SymbolKind(
464 Function,
465 ),
466 lookup: "foo",
467 detail: "fn(u32, u32, T) -> (u32, T)",
468 trigger_call_info: true,
469 },
470 CompletionItem {
471 label: "main()",
472 source_range: 68..70,
473 delete: 68..70,
474 insert: "main()$0",
475 kind: SymbolKind(
476 Function,
477 ),
478 lookup: "main",
479 detail: "fn()",
480 },
481 ]
482 "#]],
483 );
484 }
485
486 #[test]
435 fn enum_detail_just_parentheses_for_unit() { 487 fn enum_detail_just_parentheses_for_unit() {
436 check( 488 check(
437 r#" 489 r#"
@@ -477,6 +529,11 @@ fn main() { let _: m::Spam = S$0 }
477 ), 529 ),
478 lookup: "Spam::Bar", 530 lookup: "Spam::Bar",
479 detail: "(i32)", 531 detail: "(i32)",
532 relevance: CompletionRelevance {
533 exact_name_match: false,
534 exact_type_match: true,
535 is_local: false,
536 },
480 trigger_call_info: true, 537 trigger_call_info: true,
481 }, 538 },
482 CompletionItem { 539 CompletionItem {
@@ -498,6 +555,11 @@ fn main() { let _: m::Spam = S$0 }
498 ), 555 ),
499 lookup: "Spam::Foo", 556 lookup: "Spam::Foo",
500 detail: "()", 557 detail: "()",
558 relevance: CompletionRelevance {
559 exact_name_match: false,
560 exact_type_match: true,
561 is_local: false,
562 },
501 }, 563 },
502 CompletionItem { 564 CompletionItem {
503 label: "main()", 565 label: "main()",
@@ -508,7 +570,7 @@ fn main() { let _: m::Spam = S$0 }
508 Function, 570 Function,
509 ), 571 ),
510 lookup: "main", 572 lookup: "main",
511 detail: "-> ()", 573 detail: "fn()",
512 }, 574 },
513 ] 575 ]
514 "#]], 576 "#]],
@@ -537,7 +599,7 @@ fn main() { som$0 }
537 Function, 599 Function,
538 ), 600 ),
539 lookup: "main", 601 lookup: "main",
540 detail: "-> ()", 602 detail: "fn()",
541 }, 603 },
542 CompletionItem { 604 CompletionItem {
543 label: "something_deprecated()", 605 label: "something_deprecated()",
@@ -548,7 +610,7 @@ fn main() { som$0 }
548 Function, 610 Function,
549 ), 611 ),
550 lookup: "something_deprecated", 612 lookup: "something_deprecated",
551 detail: "-> ()", 613 detail: "fn()",
552 deprecated: true, 614 deprecated: true,
553 }, 615 },
554 CompletionItem { 616 CompletionItem {
@@ -560,7 +622,7 @@ fn main() { som$0 }
560 Function, 622 Function,
561 ), 623 ),
562 lookup: "something_else_deprecated", 624 lookup: "something_else_deprecated",
563 detail: "-> ()", 625 detail: "fn()",
564 deprecated: true, 626 deprecated: true,
565 }, 627 },
566 ] 628 ]
@@ -611,7 +673,7 @@ impl S {
611 insert: "bar()$0", 673 insert: "bar()$0",
612 kind: Method, 674 kind: Method,
613 lookup: "bar", 675 lookup: "bar",
614 detail: "-> ()", 676 detail: "fn(self)",
615 documentation: Documentation( 677 documentation: Documentation(
616 "Method docs", 678 "Method docs",
617 ), 679 ),
@@ -711,7 +773,7 @@ fn foo(s: S) { s.$0 }
711 insert: "the_method()$0", 773 insert: "the_method()$0",
712 kind: Method, 774 kind: Method,
713 lookup: "the_method", 775 lookup: "the_method",
714 detail: "-> ()", 776 detail: "fn(&self)",
715 }, 777 },
716 ] 778 ]
717 "#]], 779 "#]],
@@ -1019,7 +1081,7 @@ fn main() {
1019 Function, 1081 Function,
1020 ), 1082 ),
1021 lookup: "foo", 1083 lookup: "foo",
1022 detail: "-> ()", 1084 detail: "fn(&mut S)",
1023 trigger_call_info: true, 1085 trigger_call_info: true,
1024 }, 1086 },
1025 CompletionItem { 1087 CompletionItem {
@@ -1031,7 +1093,7 @@ fn main() {
1031 Function, 1093 Function,
1032 ), 1094 ),
1033 lookup: "main", 1095 lookup: "main",
1034 detail: "-> ()", 1096 detail: "fn()",
1035 }, 1097 },
1036 CompletionItem { 1098 CompletionItem {
1037 label: "s", 1099 label: "s",
@@ -1169,4 +1231,86 @@ fn foo(bar: u32) {
1169 "#]], 1231 "#]],
1170 ); 1232 );
1171 } 1233 }
1234
1235 #[test]
1236 fn enum_owned() {
1237 check_relevance(
1238 r#"
1239enum Foo { A, B }
1240fn foo() {
1241 bar($0);
1242}
1243fn bar(t: Foo) {}
1244"#,
1245 expect![[r#"
1246 ev Foo::A [type]
1247 ev Foo::B [type]
1248 en Foo []
1249 fn bar(…) []
1250 fn foo() []
1251 "#]],
1252 );
1253 }
1254
1255 #[test]
1256 fn enum_ref() {
1257 check_relevance(
1258 r#"
1259enum Foo { A, B }
1260fn foo() {
1261 bar($0);
1262}
1263fn bar(t: &Foo) {}
1264"#,
1265 expect![[r#"
1266 ev Foo::A []
1267 ev &Foo::A [type]
1268 ev Foo::B []
1269 ev &Foo::B [type]
1270 en Foo []
1271 fn bar(…) []
1272 fn foo() []
1273 "#]],
1274 );
1275 }
1276
1277 #[test]
1278 fn suggest_deref_fn_ret() {
1279 check_relevance(
1280 r#"
1281#[lang = "deref"]
1282trait Deref {
1283 type Target;
1284 fn deref(&self) -> &Self::Target;
1285}
1286
1287struct S;
1288struct T(S);
1289
1290impl Deref for T {
1291 type Target = S;
1292
1293 fn deref(&self) -> &Self::Target {
1294 &self.0
1295 }
1296}
1297
1298fn foo(s: &S) {}
1299fn bar() -> T {}
1300
1301fn main() {
1302 foo($0);
1303}
1304 "#,
1305 expect![[r#"
1306 tt Deref []
1307 fn bar() []
1308 fn &bar() [type]
1309 fn foo(…) []
1310 st T []
1311 st S []
1312 fn main() []
1313 "#]],
1314 )
1315 }
1172} 1316}