diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-03-14 14:27:53 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-03-14 14:27:53 +0000 |
commit | f57e2f55984758a83644b852a4cc47e0b27945df (patch) | |
tree | 54d6221f672f343b848660434b653d269b7381ec /crates/ide_completion | |
parent | a32ca8ef796986b42536c3a14515db2cec1131b3 (diff) | |
parent | 8a9ebe62a114ef83d46771b28e483f6b8ea5478e (diff) |
Merge #7993
7993: Use auto-deref in completion scoring r=JoshMcguigan a=ivan770
Closes #7982
Co-authored-by: ivan770 <[email protected]>
Diffstat (limited to 'crates/ide_completion')
-rw-r--r-- | crates/ide_completion/src/render.rs | 158 |
1 files changed, 137 insertions, 21 deletions
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs index db31896e5..fcb8115fb 100644 --- a/crates/ide_completion/src/render.rs +++ b/crates/ide_completion/src/render.rs | |||
@@ -10,8 +10,10 @@ pub(crate) mod type_alias; | |||
10 | 10 | ||
11 | mod builder_ext; | 11 | mod builder_ext; |
12 | 12 | ||
13 | use base_db::Upcast; | ||
13 | use hir::{ | 14 | use hir::{ |
14 | AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, ScopeDef, Type, | 15 | db::HirDatabase, AsAssocItem, Documentation, HasAttrs, HirDisplay, ModuleDef, Mutability, |
16 | ScopeDef, Type, | ||
15 | }; | 17 | }; |
16 | use ide_db::{ | 18 | use ide_db::{ |
17 | helpers::{item_name, SnippetCap}, | 19 | helpers::{item_name, SnippetCap}, |
@@ -251,19 +253,23 @@ impl<'a> Render<'a> { | |||
251 | 253 | ||
252 | if let ScopeDef::Local(local) = resolution { | 254 | if let ScopeDef::Local(local) = resolution { |
253 | let ty = local.ty(self.ctx.db()); | 255 | let ty = local.ty(self.ctx.db()); |
256 | |||
254 | if let Some(relevance) = compute_relevance(&self.ctx, &ty, &local_name) { | 257 | if let Some(relevance) = compute_relevance(&self.ctx, &ty, &local_name) { |
255 | item.set_relevance(relevance); | 258 | item.set_relevance(relevance); |
256 | } | 259 | } |
260 | |||
257 | 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() { |
258 | if let Some(ty_without_ref) = expected_type.remove_ref() { | 262 | if ty != expected_type { |
259 | if ty_without_ref == ty { | 263 | if let Some(ty_without_ref) = expected_type.remove_ref() { |
260 | cov_mark::hit!(suggest_ref); | 264 | if relevance_type_match(self.ctx.db().upcast(), &ty, &ty_without_ref) { |
261 | let mutability = if expected_type.is_mutable_reference() { | 265 | cov_mark::hit!(suggest_ref); |
262 | Mutability::Mut | 266 | let mutability = if expected_type.is_mutable_reference() { |
263 | } else { | 267 | Mutability::Mut |
264 | Mutability::Shared | 268 | } else { |
265 | }; | 269 | Mutability::Shared |
266 | item.ref_match(mutability); | 270 | }; |
271 | item.ref_match(mutability); | ||
272 | } | ||
267 | } | 273 | } |
268 | } | 274 | } |
269 | } | 275 | } |
@@ -330,10 +336,12 @@ fn compute_relevance(ctx: &RenderContext, ty: &Type, name: &str) -> Option<Compl | |||
330 | Some(res) | 336 | Some(res) |
331 | } | 337 | } |
332 | 338 | ||
339 | fn relevance_type_match(db: &dyn HirDatabase, ty: &Type, expected_type: &Type) -> bool { | ||
340 | ty == expected_type || ty.autoderef(db).any(|deref_ty| &deref_ty == expected_type) | ||
341 | } | ||
342 | |||
333 | #[cfg(test)] | 343 | #[cfg(test)] |
334 | mod tests { | 344 | mod tests { |
335 | use std::cmp::Reverse; | ||
336 | |||
337 | use expect_test::{expect, Expect}; | 345 | use expect_test::{expect, Expect}; |
338 | 346 | ||
339 | use crate::{ | 347 | use crate::{ |
@@ -358,17 +366,27 @@ mod tests { | |||
358 | } | 366 | } |
359 | } | 367 | } |
360 | 368 | ||
361 | let mut completions = get_all_items(TEST_CONFIG, ra_fixture); | 369 | let actual = get_all_items(TEST_CONFIG, ra_fixture) |
362 | completions.sort_by_key(|it| (Reverse(it.relevance()), it.label().to_string())); | ||
363 | let actual = completions | ||
364 | .into_iter() | 370 | .into_iter() |
365 | .filter(|it| it.completion_kind == CompletionKind::Reference) | 371 | .filter(|it| it.completion_kind == CompletionKind::Reference) |
366 | .map(|it| { | 372 | .flat_map(|it| { |
373 | let mut items = vec![]; | ||
374 | |||
367 | let tag = it.kind().unwrap().tag(); | 375 | let tag = it.kind().unwrap().tag(); |
368 | let relevance = display_relevance(it.relevance()); | 376 | let relevance = display_relevance(it.relevance()); |
369 | format!("{} {} {}\n", tag, it.label(), relevance) | 377 | items.push(format!("{} {} {}\n", tag, it.label(), relevance)); |
378 | |||
379 | if let Some((mutability, relevance)) = it.ref_match() { | ||
380 | let label = format!("&{}{}", mutability.as_keyword_for_ref(), it.label()); | ||
381 | let relevance = display_relevance(relevance); | ||
382 | |||
383 | items.push(format!("{} {} {}\n", tag, label, relevance)); | ||
384 | } | ||
385 | |||
386 | items | ||
370 | }) | 387 | }) |
371 | .collect::<String>(); | 388 | .collect::<String>(); |
389 | |||
372 | expect.assert_eq(&actual); | 390 | expect.assert_eq(&actual); |
373 | } | 391 | } |
374 | 392 | ||
@@ -838,9 +856,9 @@ fn test(bar: u32) { } | |||
838 | fn foo(s: S) { test(s.$0) } | 856 | fn foo(s: S) { test(s.$0) } |
839 | "#, | 857 | "#, |
840 | expect![[r#" | 858 | expect![[r#" |
859 | fd foo [] | ||
841 | fd bar [type+name] | 860 | fd bar [type+name] |
842 | fd baz [type] | 861 | fd baz [type] |
843 | fd foo [] | ||
844 | "#]], | 862 | "#]], |
845 | ); | 863 | ); |
846 | } | 864 | } |
@@ -855,9 +873,9 @@ struct B { x: (), y: f32, bar: u32 } | |||
855 | fn foo(a: A) { B { bar: a.$0 }; } | 873 | fn foo(a: A) { B { bar: a.$0 }; } |
856 | "#, | 874 | "#, |
857 | expect![[r#" | 875 | expect![[r#" |
876 | fd foo [] | ||
858 | fd bar [type+name] | 877 | fd bar [type+name] |
859 | fd baz [type] | 878 | fd baz [type] |
860 | fd foo [] | ||
861 | "#]], | 879 | "#]], |
862 | ) | 880 | ) |
863 | } | 881 | } |
@@ -885,9 +903,9 @@ fn f(foo: i64) { } | |||
885 | fn foo(a: A) { f(B { bar: a.$0 }); } | 903 | fn foo(a: A) { f(B { bar: a.$0 }); } |
886 | "#, | 904 | "#, |
887 | expect![[r#" | 905 | expect![[r#" |
906 | fd foo [] | ||
888 | fd bar [type+name] | 907 | fd bar [type+name] |
889 | fd baz [type] | 908 | fd baz [type] |
890 | fd foo [] | ||
891 | "#]], | 909 | "#]], |
892 | ); | 910 | ); |
893 | } | 911 | } |
@@ -915,9 +933,9 @@ struct Foo; | |||
915 | fn f(foo: &Foo) { f(foo, w$0) } | 933 | fn f(foo: &Foo) { f(foo, w$0) } |
916 | "#, | 934 | "#, |
917 | expect![[r#" | 935 | expect![[r#" |
936 | lc foo [] | ||
918 | st Foo [] | 937 | st Foo [] |
919 | fn f(…) [] | 938 | fn f(…) [] |
920 | lc foo [] | ||
921 | "#]], | 939 | "#]], |
922 | ); | 940 | ); |
923 | } | 941 | } |
@@ -987,4 +1005,102 @@ fn main() { | |||
987 | "#]], | 1005 | "#]], |
988 | ) | 1006 | ) |
989 | } | 1007 | } |
1008 | |||
1009 | #[test] | ||
1010 | fn suggest_deref() { | ||
1011 | check_relevance( | ||
1012 | r#" | ||
1013 | #[lang = "deref"] | ||
1014 | trait Deref { | ||
1015 | type Target; | ||
1016 | fn deref(&self) -> &Self::Target; | ||
1017 | } | ||
1018 | |||
1019 | struct S; | ||
1020 | struct T(S); | ||
1021 | |||
1022 | impl Deref for T { | ||
1023 | type Target = S; | ||
1024 | |||
1025 | fn deref(&self) -> &Self::Target { | ||
1026 | &self.0 | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | fn foo(s: &S) {} | ||
1031 | |||
1032 | fn main() { | ||
1033 | let t = T(S); | ||
1034 | let m = 123; | ||
1035 | |||
1036 | foo($0); | ||
1037 | } | ||
1038 | "#, | ||
1039 | expect![[r#" | ||
1040 | lc m [] | ||
1041 | lc t [] | ||
1042 | lc &t [type] | ||
1043 | st T [] | ||
1044 | st S [] | ||
1045 | fn main() [] | ||
1046 | tt Deref [] | ||
1047 | fn foo(…) [] | ||
1048 | "#]], | ||
1049 | ) | ||
1050 | } | ||
1051 | |||
1052 | #[test] | ||
1053 | fn suggest_deref_mut() { | ||
1054 | check_relevance( | ||
1055 | r#" | ||
1056 | #[lang = "deref"] | ||
1057 | trait Deref { | ||
1058 | type Target; | ||
1059 | fn deref(&self) -> &Self::Target; | ||
1060 | } | ||
1061 | |||
1062 | #[lang = "deref_mut"] | ||
1063 | pub trait DerefMut: Deref { | ||
1064 | fn deref_mut(&mut self) -> &mut Self::Target; | ||
1065 | } | ||
1066 | |||
1067 | struct S; | ||
1068 | struct T(S); | ||
1069 | |||
1070 | impl Deref for T { | ||
1071 | type Target = S; | ||
1072 | |||
1073 | fn deref(&self) -> &Self::Target { | ||
1074 | &self.0 | ||
1075 | } | ||
1076 | } | ||
1077 | |||
1078 | impl DerefMut for T { | ||
1079 | fn deref_mut(&mut self) -> &mut Self::Target { | ||
1080 | &mut self.0 | ||
1081 | } | ||
1082 | } | ||
1083 | |||
1084 | fn foo(s: &mut S) {} | ||
1085 | |||
1086 | fn main() { | ||
1087 | let t = T(S); | ||
1088 | let m = 123; | ||
1089 | |||
1090 | foo($0); | ||
1091 | } | ||
1092 | "#, | ||
1093 | expect![[r#" | ||
1094 | lc m [] | ||
1095 | lc t [] | ||
1096 | lc &mut t [type] | ||
1097 | tt DerefMut [] | ||
1098 | tt Deref [] | ||
1099 | fn foo(…) [] | ||
1100 | st T [] | ||
1101 | st S [] | ||
1102 | fn main() [] | ||
1103 | "#]], | ||
1104 | ) | ||
1105 | } | ||
990 | } | 1106 | } |