aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorivan770 <[email protected]>2021-03-13 15:25:41 +0000
committerivan770 <[email protected]>2021-03-13 15:25:41 +0000
commit3bc5d81a33c98da2a5b450c817c09f5a41b03e98 (patch)
treef7cfc356e6f14673eaee0096bb1d63ab2a8298b5
parent75cb441fba111bed153f519f1f2906843360cfc7 (diff)
Make relevance tests display references, suggest derefs only when needed
-rw-r--r--crates/ide_completion/src/render.rs98
-rw-r--r--crates/rust-analyzer/src/to_proto.rs2
2 files changed, 84 insertions, 16 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> {
327fn compute_relevance(ctx: &RenderContext, ty: &Type, name: &str) -> Option<CompletionRelevance> { 329fn 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
335fn relevance_type_match(db: &dyn HirDatabase, ty: &Type, expected_type: Type) -> bool { 337fn 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: () };
911fn go(world: &WorldSnapshot) { go(w$0) } 925fn 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"]
1063trait Deref {
1064 type Target;
1065 fn deref(&self) -> &Self::Target;
1066}
1067
1068#[lang = "deref_mut"]
1069pub trait DerefMut: Deref {
1070 fn deref_mut(&mut self) -> &mut Self::Target;
1071}
1072
1073struct S;
1074struct T(S);
1075
1076impl Deref for T {
1077 type Target = S;
1078
1079 fn deref(&self) -> &Self::Target {
1080 &self.0
1081 }
1082}
1083
1084impl DerefMut for T {
1085 fn deref_mut(&self) -> &mut Self::Target {
1086 &mut self.0
1087 }
1088}
1089
1090fn foo(s: &mut S) {}
1091
1092fn 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(…) []
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index fecae1259..1a8cdadad 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -1123,7 +1123,7 @@ mod tests {
1123 ( 1123 (
1124 "arg", 1124 "arg",
1125 Some( 1125 Some(
1126 "fffffffd", 1126 "fffffffe",
1127 ), 1127 ),
1128 ), 1128 ),
1129 ] 1129 ]