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.rs99
1 files changed, 41 insertions, 58 deletions
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 0a1b0f95d..8c8b149a1 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -20,8 +20,8 @@ use ide_db::{
20use syntax::TextRange; 20use syntax::TextRange;
21 21
22use crate::{ 22use crate::{
23 item::ImportEdit, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, 23 item::{ImportEdit, Relevance},
24 CompletionScore, 24 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind,
25}; 25};
26 26
27use 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};
@@ -117,7 +117,7 @@ impl<'a> RenderContext<'a> {
117 node.docs(self.db()) 117 node.docs(self.db())
118 } 118 }
119 119
120 fn active_name_and_type(&self) -> Option<(String, Type)> { 120 fn expected_name_and_type(&self) -> Option<(String, Type)> {
121 if let Some(record_field) = &self.completion.record_field_syntax { 121 if let Some(record_field) = &self.completion.record_field_syntax {
122 cov_mark::hit!(record_field_type_match); 122 cov_mark::hit!(record_field_type_match);
123 let (struct_field, _local) = self.completion.sema.resolve_record_field(record_field)?; 123 let (struct_field, _local) = self.completion.sema.resolve_record_field(record_field)?;
@@ -155,8 +155,8 @@ impl<'a> Render<'a> {
155 .set_documentation(field.docs(self.ctx.db())) 155 .set_documentation(field.docs(self.ctx.db()))
156 .set_deprecated(is_deprecated); 156 .set_deprecated(is_deprecated);
157 157
158 if let Some(score) = compute_score(&self.ctx, &ty, &name.to_string()) { 158 if let Some(relevance) = compute_relevance(&self.ctx, &ty, &name.to_string()) {
159 item = item.set_score(score); 159 item = item.set_relevance(relevance);
160 } 160 }
161 161
162 item.build() 162 item.build()
@@ -247,18 +247,15 @@ impl<'a> Render<'a> {
247 }; 247 };
248 248
249 if let ScopeDef::Local(local) = resolution { 249 if let ScopeDef::Local(local) = resolution {
250 if let Some((active_name, active_type)) = self.ctx.active_name_and_type() { 250 let ty = local.ty(self.ctx.db());
251 let ty = local.ty(self.ctx.db()); 251 if let Some(relevance) = compute_relevance(&self.ctx, &ty, &local_name) {
252 if let Some(score) = 252 item = item.set_relevance(relevance)
253 compute_score_from_active(&active_type, &active_name, &ty, &local_name) 253 }
254 { 254 if let Some((_expected_name, expected_type)) = self.ctx.expected_name_and_type() {
255 item = item.set_score(score); 255 if let Some(ty_without_ref) = expected_type.remove_ref() {
256 }
257
258 if let Some(ty_without_ref) = active_type.remove_ref() {
259 if ty_without_ref == ty { 256 if ty_without_ref == ty {
260 cov_mark::hit!(suggest_ref); 257 cov_mark::hit!(suggest_ref);
261 let mutability = if active_type.is_mutable_reference() { 258 let mutability = if expected_type.is_mutable_reference() {
262 Mutability::Mut 259 Mutability::Mut
263 } else { 260 } else {
264 Mutability::Shared 261 Mutability::Shared
@@ -326,33 +323,14 @@ impl<'a> Render<'a> {
326 } 323 }
327} 324}
328 325
329fn compute_score_from_active( 326fn compute_relevance(ctx: &RenderContext, ty: &Type, name: &str) -> Option<Relevance> {
330 active_type: &Type, 327 let (expected_name, expected_type) = ctx.expected_name_and_type()?;
331 active_name: &str, 328 let mut res = Relevance::default();
332 ty: &Type, 329 res.exact_type_match = ty == &expected_type;
333 name: &str, 330 res.exact_name_match = name == &expected_name;
334) -> Option<CompletionScore> {
335 // Compute score
336 // For the same type
337 if active_type != ty {
338 return None;
339 }
340
341 let mut res = CompletionScore::TypeMatch;
342
343 // If same type + same name then go top position
344 if active_name == name {
345 res = CompletionScore::TypeAndNameMatch
346 }
347
348 Some(res) 331 Some(res)
349} 332}
350 333
351fn compute_score(ctx: &RenderContext, ty: &Type, name: &str) -> Option<CompletionScore> {
352 let (active_name, active_type) = ctx.active_name_and_type()?;
353 compute_score_from_active(&active_type, &active_name, ty, name)
354}
355
356#[cfg(test)] 334#[cfg(test)]
357mod tests { 335mod tests {
358 use std::cmp::Reverse; 336 use std::cmp::Reverse;
@@ -361,7 +339,7 @@ mod tests {
361 339
362 use crate::{ 340 use crate::{
363 test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, 341 test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG},
364 CompletionKind, CompletionScore, 342 CompletionKind, Relevance,
365 }; 343 };
366 344
367 fn check(ra_fixture: &str, expect: Expect) { 345 fn check(ra_fixture: &str, expect: Expect) {
@@ -369,24 +347,25 @@ mod tests {
369 expect.assert_debug_eq(&actual); 347 expect.assert_debug_eq(&actual);
370 } 348 }
371 349
372 fn check_scores(ra_fixture: &str, expect: Expect) { 350 fn check_relevance(ra_fixture: &str, expect: Expect) {
373 fn display_score(score: Option<CompletionScore>) -> &'static str { 351 fn display_relevance(relevance: Relevance) -> &'static str {
374 match score { 352 match relevance {
375 Some(CompletionScore::TypeMatch) => "[type]", 353 Relevance { exact_type_match: true, exact_name_match: true } => "[type+name]",
376 Some(CompletionScore::TypeAndNameMatch) => "[type+name]", 354 Relevance { exact_type_match: true, exact_name_match: false } => "[type]",
377 None => "[]".into(), 355 Relevance { exact_type_match: false, exact_name_match: true } => "[name]",
356 Relevance { exact_type_match: false, exact_name_match: false } => "[]",
378 } 357 }
379 } 358 }
380 359
381 let mut completions = get_all_items(TEST_CONFIG, ra_fixture); 360 let mut completions = get_all_items(TEST_CONFIG, ra_fixture);
382 completions.sort_by_key(|it| (Reverse(it.score()), it.label().to_string())); 361 completions.sort_by_key(|it| (Reverse(it.relevance()), it.label().to_string()));
383 let actual = completions 362 let actual = completions
384 .into_iter() 363 .into_iter()
385 .filter(|it| it.completion_kind == CompletionKind::Reference) 364 .filter(|it| it.completion_kind == CompletionKind::Reference)
386 .map(|it| { 365 .map(|it| {
387 let tag = it.kind().unwrap().tag(); 366 let tag = it.kind().unwrap().tag();
388 let score = display_score(it.score()); 367 let relevance = display_relevance(it.relevance());
389 format!("{} {} {}\n", tag, it.label(), score) 368 format!("{} {} {}\n", tag, it.label(), relevance)
390 }) 369 })
391 .collect::<String>(); 370 .collect::<String>();
392 expect.assert_eq(&actual); 371 expect.assert_eq(&actual);
@@ -849,9 +828,9 @@ fn foo(xs: Vec<i128>)
849 } 828 }
850 829
851 #[test] 830 #[test]
852 fn active_param_score() { 831 fn active_param_relevance() {
853 cov_mark::check!(active_param_type_match); 832 cov_mark::check!(active_param_type_match);
854 check_scores( 833 check_relevance(
855 r#" 834 r#"
856struct S { foo: i64, bar: u32, baz: u32 } 835struct S { foo: i64, bar: u32, baz: u32 }
857fn test(bar: u32) { } 836fn test(bar: u32) { }
@@ -866,9 +845,9 @@ fn foo(s: S) { test(s.$0) }
866 } 845 }
867 846
868 #[test] 847 #[test]
869 fn record_field_scores() { 848 fn record_field_relevances() {
870 cov_mark::check!(record_field_type_match); 849 cov_mark::check!(record_field_type_match);
871 check_scores( 850 check_relevance(
872 r#" 851 r#"
873struct A { foo: i64, bar: u32, baz: u32 } 852struct A { foo: i64, bar: u32, baz: u32 }
874struct B { x: (), y: f32, bar: u32 } 853struct B { x: (), y: f32, bar: u32 }
@@ -883,8 +862,8 @@ fn foo(a: A) { B { bar: a.$0 }; }
883 } 862 }
884 863
885 #[test] 864 #[test]
886 fn record_field_and_call_scores() { 865 fn record_field_and_call_relevances() {
887 check_scores( 866 check_relevance(
888 r#" 867 r#"
889struct A { foo: i64, bar: u32, baz: u32 } 868struct A { foo: i64, bar: u32, baz: u32 }
890struct B { x: (), y: f32, bar: u32 } 869struct B { x: (), y: f32, bar: u32 }
@@ -897,7 +876,7 @@ fn foo(a: A) { B { bar: f(a.$0) }; }
897 fd baz [] 876 fd baz []
898 "#]], 877 "#]],
899 ); 878 );
900 check_scores( 879 check_relevance(
901 r#" 880 r#"
902struct A { foo: i64, bar: u32, baz: u32 } 881struct A { foo: i64, bar: u32, baz: u32 }
903struct B { x: (), y: f32, bar: u32 } 882struct B { x: (), y: f32, bar: u32 }
@@ -914,7 +893,7 @@ fn foo(a: A) { f(B { bar: a.$0 }); }
914 893
915 #[test] 894 #[test]
916 fn prioritize_exact_ref_match() { 895 fn prioritize_exact_ref_match() {
917 check_scores( 896 check_relevance(
918 r#" 897 r#"
919struct WorldSnapshot { _f: () }; 898struct WorldSnapshot { _f: () };
920fn go(world: &WorldSnapshot) { go(w$0) } 899fn go(world: &WorldSnapshot) { go(w$0) }
@@ -929,7 +908,7 @@ fn go(world: &WorldSnapshot) { go(w$0) }
929 908
930 #[test] 909 #[test]
931 fn too_many_arguments() { 910 fn too_many_arguments() {
932 check_scores( 911 check_relevance(
933 r#" 912 r#"
934struct Foo; 913struct Foo;
935fn f(foo: &Foo) { f(foo, w$0) } 914fn f(foo: &Foo) { f(foo, w$0) }
@@ -997,6 +976,10 @@ fn main() {
997 Local, 976 Local,
998 ), 977 ),
999 detail: "S", 978 detail: "S",
979 relevance: Relevance {
980 exact_name_match: true,
981 exact_type_match: false,
982 },
1000 ref_match: "&mut ", 983 ref_match: "&mut ",
1001 }, 984 },
1002 ] 985 ]