diff options
Diffstat (limited to 'crates/ide_completion/src/render.rs')
-rw-r--r-- | crates/ide_completion/src/render.rs | 98 |
1 files changed, 83 insertions, 15 deletions
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index e72f54ef4..1f4a8173a 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -253,12 +253,14 @@ impl<'a> Render<'a> { | |||
253 | 253 | ||
254 | if let ScopeDef::Local(local) = resolution { | 254 | if let ScopeDef::Local(local) = resolution { |
255 | let ty = local.ty(self.ctx.db()); | 255 | let ty = local.ty(self.ctx.db()); |
256 | |||
256 | if let Some(relevance) = compute_relevance(&self.ctx, &ty, &local_name) { | 257 | if let Some(relevance) = compute_relevance(&self.ctx, &ty, &local_name) { |
257 | item.set_relevance(relevance); | 258 | item.set_relevance(relevance); |
258 | } | 259 | } |
260 | |||
259 | if let Some((_expected_name, expected_type)) = self.ctx.expected_name_and_type() { | 261 | if let Some((_expected_name, expected_type)) = self.ctx.expected_name_and_type() { |
260 | if let Some(ty_without_ref) = expected_type.remove_ref() { | 262 | if let Some(ty_without_ref) = expected_type.remove_ref() { |
261 | if ty_without_ref == ty { | 263 | if relevance_type_match(self.ctx.db().upcast(), &ty, &ty_without_ref) { |
262 | cov_mark::hit!(suggest_ref); | 264 | cov_mark::hit!(suggest_ref); |
263 | let mutability = if expected_type.is_mutable_reference() { | 265 | let mutability = if expected_type.is_mutable_reference() { |
264 | Mutability::Mut | 266 | Mutability::Mut |
@@ -327,18 +329,13 @@ impl<'a> Render<'a> { | |||
327 | fn compute_relevance(ctx: &RenderContext, ty: &Type, name: &str) -> Option<CompletionRelevance> { | 329 | fn compute_relevance(ctx: &RenderContext, ty: &Type, name: &str) -> Option<CompletionRelevance> { |
328 | let (expected_name, expected_type) = ctx.expected_name_and_type()?; | 330 | let (expected_name, expected_type) = ctx.expected_name_and_type()?; |
329 | let mut res = CompletionRelevance::default(); | 331 | let mut res = CompletionRelevance::default(); |
330 | res.exact_type_match = relevance_type_match(ctx.db().upcast(), ty, expected_type); | 332 | res.exact_type_match = ty == &expected_type; |
331 | res.exact_name_match = name == &expected_name; | 333 | res.exact_name_match = name == &expected_name; |
332 | Some(res) | 334 | Some(res) |
333 | } | 335 | } |
334 | 336 | ||
335 | fn relevance_type_match(db: &dyn HirDatabase, ty: &Type, expected_type: Type) -> bool { | 337 | fn relevance_type_match(db: &dyn HirDatabase, ty: &Type, expected_type: &Type) -> bool { |
336 | if ty == &expected_type { | 338 | ty == expected_type || ty.autoderef(db).any(|deref_ty| &deref_ty == expected_type) |
337 | return true; | ||
338 | } | ||
339 | |||
340 | let ty_without_ref = expected_type.remove_ref().unwrap_or(expected_type); | ||
341 | ty.autoderef(db).any(|deref_ty| deref_ty == ty_without_ref) | ||
342 | } | 339 | } |
343 | 340 | ||
344 | #[cfg(test)] | 341 | #[cfg(test)] |
@@ -346,6 +343,7 @@ mod tests { | |||
346 | use std::cmp::Reverse; | 343 | use std::cmp::Reverse; |
347 | 344 | ||
348 | use expect_test::{expect, Expect}; | 345 | use expect_test::{expect, Expect}; |
346 | use hir::Mutability; | ||
349 | 347 | ||
350 | use crate::{ | 348 | use crate::{ |
351 | test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, | 349 | test_utils::{check_edit, do_completion, get_all_items, TEST_CONFIG}, |
@@ -369,15 +367,31 @@ mod tests { | |||
369 | } | 367 | } |
370 | } | 368 | } |
371 | 369 | ||
370 | fn display_label(label: &str, mutability: Option<Mutability>) -> String { | ||
371 | let mutability_label = match mutability { | ||
372 | Some(Mutability::Shared) => "&", | ||
373 | Some(Mutability::Mut) => "&mut ", | ||
374 | None => "", | ||
375 | }; | ||
376 | |||
377 | format!("{}{}", mutability_label, label) | ||
378 | } | ||
379 | |||
372 | let mut completions = get_all_items(TEST_CONFIG, ra_fixture); | 380 | let mut completions = get_all_items(TEST_CONFIG, ra_fixture); |
373 | completions.sort_by_key(|it| (Reverse(it.relevance()), it.label().to_string())); | 381 | completions.sort_by_key(|it| { |
382 | (Reverse(it.ref_match().map(|m| m.1).unwrap_or(it.relevance())), it.label().to_string()) | ||
383 | }); | ||
374 | let actual = completions | 384 | let actual = completions |
375 | .into_iter() | 385 | .into_iter() |
376 | .filter(|it| it.completion_kind == CompletionKind::Reference) | 386 | .filter(|it| it.completion_kind == CompletionKind::Reference) |
377 | .map(|it| { | 387 | .map(|it| { |
378 | let tag = it.kind().unwrap().tag(); | 388 | let tag = it.kind().unwrap().tag(); |
379 | let relevance = display_relevance(it.relevance()); | 389 | let (mutability, relevance) = it |
380 | format!("{} {} {}\n", tag, it.label(), relevance) | 390 | .ref_match() |
391 | .map(|(mutability, relevance)| (Some(mutability), relevance)) | ||
392 | .unwrap_or((None, it.relevance())); | ||
393 | let relevance = display_relevance(relevance); | ||
394 | format!("{} {} {}\n", tag, display_label(it.label(), mutability), relevance) | ||
381 | }) | 395 | }) |
382 | .collect::<String>(); | 396 | .collect::<String>(); |
383 | expect.assert_eq(&actual); | 397 | expect.assert_eq(&actual); |
@@ -911,7 +925,7 @@ struct WorldSnapshot { _f: () }; | |||
911 | fn go(world: &WorldSnapshot) { go(w$0) } | 925 | fn go(world: &WorldSnapshot) { go(w$0) } |
912 | "#, | 926 | "#, |
913 | expect![[r#" | 927 | expect![[r#" |
914 | lc world [type+name] | 928 | lc &world [type+name] |
915 | st WorldSnapshot [] | 929 | st WorldSnapshot [] |
916 | fn go(…) [] | 930 | fn go(…) [] |
917 | "#]], | 931 | "#]], |
@@ -990,7 +1004,7 @@ fn main() { | |||
990 | detail: "S", | 1004 | detail: "S", |
991 | relevance: CompletionRelevance { | 1005 | relevance: CompletionRelevance { |
992 | exact_name_match: true, | 1006 | exact_name_match: true, |
993 | exact_type_match: true, | 1007 | exact_type_match: false, |
994 | }, | 1008 | }, |
995 | ref_match: "&mut ", | 1009 | ref_match: "&mut ", |
996 | }, | 1010 | }, |
@@ -1030,8 +1044,62 @@ fn main() { | |||
1030 | } | 1044 | } |
1031 | "#, | 1045 | "#, |
1032 | expect![[r#" | 1046 | expect![[r#" |
1033 | lc t [type] | 1047 | lc &t [type] |
1048 | tt Deref [] | ||
1049 | st S [] | ||
1050 | st T [] | ||
1051 | fn foo(…) [] | ||
1052 | lc m [] | ||
1053 | fn main() [] | ||
1054 | "#]], | ||
1055 | ) | ||
1056 | } | ||
1057 | |||
1058 | #[test] | ||
1059 | fn suggest_deref_mut() { | ||
1060 | check_relevance( | ||
1061 | r#" | ||
1062 | #[lang = "deref"] | ||
1063 | trait Deref { | ||
1064 | type Target; | ||
1065 | fn deref(&self) -> &Self::Target; | ||
1066 | } | ||
1067 | |||
1068 | #[lang = "deref_mut"] | ||
1069 | pub trait DerefMut: Deref { | ||
1070 | fn deref_mut(&mut self) -> &mut Self::Target; | ||
1071 | } | ||
1072 | |||
1073 | struct S; | ||
1074 | struct T(S); | ||
1075 | |||
1076 | impl Deref for T { | ||
1077 | type Target = S; | ||
1078 | |||
1079 | fn deref(&self) -> &Self::Target { | ||
1080 | &self.0 | ||
1081 | } | ||
1082 | } | ||
1083 | |||
1084 | impl DerefMut for T { | ||
1085 | fn deref_mut(&self) -> &mut Self::Target { | ||
1086 | &mut self.0 | ||
1087 | } | ||
1088 | } | ||
1089 | |||
1090 | fn foo(s: &mut S) {} | ||
1091 | |||
1092 | fn main() { | ||
1093 | let t = T(S); | ||
1094 | let m = 123; | ||
1095 | |||
1096 | foo($0); | ||
1097 | } | ||
1098 | "#, | ||
1099 | expect![[r#" | ||
1100 | lc &mut t [type] | ||
1034 | tt Deref [] | 1101 | tt Deref [] |
1102 | tt DerefMut [] | ||
1035 | st S [] | 1103 | st S [] |
1036 | st T [] | 1104 | st T [] |
1037 | fn foo(…) [] | 1105 | fn foo(…) [] |