aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/lib.rs7
-rw-r--r--crates/ide_completion/src/item.rs13
-rw-r--r--crates/ide_completion/src/render.rs90
-rw-r--r--crates/rust-analyzer/src/to_proto.rs7
4 files changed, 87 insertions, 30 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index d5a3d9034..641ea4221 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1614,10 +1614,9 @@ impl Type {
1614 } 1614 }
1615 1615
1616 pub fn remove_ref(&self) -> Option<Type> { 1616 pub fn remove_ref(&self) -> Option<Type> {
1617 if let Ty::Ref(.., substs) = &self.ty.value { 1617 match &self.ty.value {
1618 Some(self.derived(substs[0].clone())) 1618 Ty::Ref(.., substs) => Some(self.derived(substs[0].clone())),
1619 } else { 1619 _ => None,
1620 None
1621 } 1620 }
1622 } 1621 }
1623 1622
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index b16f0775a..5e8ed75f1 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -68,7 +68,7 @@ pub struct CompletionItem {
68 68
69 /// Indicates that a reference or mutable reference to this variable is a 69 /// Indicates that a reference or mutable reference to this variable is a
70 /// possible match. 70 /// possible match.
71 ref_match: Option<(Mutability, CompletionScore)>, 71 ref_match: Option<Mutability>,
72 72
73 /// The import data to add to completion's edits. 73 /// The import data to add to completion's edits.
74 import_to_add: Option<ImportEdit>, 74 import_to_add: Option<ImportEdit>,
@@ -104,6 +104,9 @@ impl fmt::Debug for CompletionItem {
104 if let Some(score) = &self.score { 104 if let Some(score) = &self.score {
105 s.field("score", score); 105 s.field("score", score);
106 } 106 }
107 if let Some(mutability) = &self.ref_match {
108 s.field("ref_match", &format!("&{}", mutability.as_keyword_for_ref()));
109 }
107 if self.trigger_call_info { 110 if self.trigger_call_info {
108 s.field("trigger_call_info", &true); 111 s.field("trigger_call_info", &true);
109 } 112 }
@@ -261,7 +264,7 @@ impl CompletionItem {
261 self.trigger_call_info 264 self.trigger_call_info
262 } 265 }
263 266
264 pub fn ref_match(&self) -> Option<(Mutability, CompletionScore)> { 267 pub fn ref_match(&self) -> Option<Mutability> {
265 self.ref_match 268 self.ref_match
266 } 269 }
267 270
@@ -311,7 +314,7 @@ pub(crate) struct Builder {
311 deprecated: bool, 314 deprecated: bool,
312 trigger_call_info: Option<bool>, 315 trigger_call_info: Option<bool>,
313 score: Option<CompletionScore>, 316 score: Option<CompletionScore>,
314 ref_match: Option<(Mutability, CompletionScore)>, 317 ref_match: Option<Mutability>,
315} 318}
316 319
317impl Builder { 320impl Builder {
@@ -430,8 +433,8 @@ impl Builder {
430 self.import_to_add = import_to_add; 433 self.import_to_add = import_to_add;
431 self 434 self
432 } 435 }
433 pub(crate) fn ref_match(mut self, ref_match: (Mutability, CompletionScore)) -> Builder { 436 pub(crate) fn ref_match(mut self, mutability: Mutability) -> Builder {
434 self.ref_match = Some(ref_match); 437 self.ref_match = Some(mutability);
435 self 438 self
436 } 439 }
437} 440}
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 0a6ac8804..0a1b0f95d 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -254,10 +254,17 @@ impl<'a> Render<'a> {
254 { 254 {
255 item = item.set_score(score); 255 item = item.set_score(score);
256 } 256 }
257 if let Some(ref_match) = 257
258 refed_type_matches(&active_type, &active_name, &ty, &local_name) 258 if let Some(ty_without_ref) = active_type.remove_ref() {
259 { 259 if ty_without_ref == ty {
260 item = item.ref_match(ref_match); 260 cov_mark::hit!(suggest_ref);
261 let mutability = if active_type.is_mutable_reference() {
262 Mutability::Mut
263 } else {
264 Mutability::Shared
265 };
266 item = item.ref_match(mutability)
267 }
261 } 268 }
262 } 269 }
263 } 270 }
@@ -340,19 +347,6 @@ fn compute_score_from_active(
340 347
341 Some(res) 348 Some(res)
342} 349}
343fn refed_type_matches(
344 active_type: &Type,
345 active_name: &str,
346 ty: &Type,
347 name: &str,
348) -> Option<(Mutability, CompletionScore)> {
349 let derefed_active = active_type.remove_ref()?;
350 let score = compute_score_from_active(&derefed_active, &active_name, &ty, &name)?;
351 Some((
352 if active_type.is_mutable_reference() { Mutability::Mut } else { Mutability::Shared },
353 score,
354 ))
355}
356 350
357fn compute_score(ctx: &RenderContext, ty: &Type, name: &str) -> Option<CompletionScore> { 351fn compute_score(ctx: &RenderContext, ty: &Type, name: &str) -> Option<CompletionScore> {
358 let (active_name, active_type) = ctx.active_name_and_type()?; 352 let (active_name, active_type) = ctx.active_name_and_type()?;
@@ -947,4 +941,66 @@ fn f(foo: &Foo) { f(foo, w$0) }
947 "#]], 941 "#]],
948 ); 942 );
949 } 943 }
944
945 #[test]
946 fn suggest_ref_mut() {
947 cov_mark::check!(suggest_ref);
948 check(
949 r#"
950struct S;
951fn foo(s: &mut S) {}
952fn main() {
953 let mut s = S;
954 foo($0);
955}
956 "#,
957 expect![[r#"
958 [
959 CompletionItem {
960 label: "S",
961 source_range: 70..70,
962 delete: 70..70,
963 insert: "S",
964 kind: SymbolKind(
965 Struct,
966 ),
967 },
968 CompletionItem {
969 label: "foo(…)",
970 source_range: 70..70,
971 delete: 70..70,
972 insert: "foo(${1:&mut s})$0",
973 kind: SymbolKind(
974 Function,
975 ),
976 lookup: "foo",
977 detail: "-> ()",
978 trigger_call_info: true,
979 },
980 CompletionItem {
981 label: "main()",
982 source_range: 70..70,
983 delete: 70..70,
984 insert: "main()$0",
985 kind: SymbolKind(
986 Function,
987 ),
988 lookup: "main",
989 detail: "-> ()",
990 },
991 CompletionItem {
992 label: "s",
993 source_range: 70..70,
994 delete: 70..70,
995 insert: "s",
996 kind: SymbolKind(
997 Local,
998 ),
999 detail: "S",
1000 ref_match: "&mut ",
1001 },
1002 ]
1003 "#]],
1004 )
1005 }
950} 1006}
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 261d9fb18..a730fb448 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -232,9 +232,8 @@ pub(crate) fn completion_item(
232 } 232 }
233 233
234 let mut res = match item.ref_match() { 234 let mut res = match item.ref_match() {
235 Some(ref_match) => { 235 Some(mutability) => {
236 let mut refed = lsp_item.clone(); 236 let mut refed = lsp_item.clone();
237 let (mutability, _score) = ref_match;
238 let label = format!("&{}{}", mutability.as_keyword_for_ref(), refed.label); 237 let label = format!("&{}{}", mutability.as_keyword_for_ref(), refed.label);
239 set_score(&mut refed, &label); 238 set_score(&mut refed, &label);
240 refed.label = label; 239 refed.label = label;
@@ -243,8 +242,8 @@ pub(crate) fn completion_item(
243 None => vec![lsp_item], 242 None => vec![lsp_item],
244 }; 243 };
245 244
246 for mut r in res.iter_mut() { 245 for lsp_item in res.iter_mut() {
247 r.insert_text_format = Some(insert_text_format(item.insert_text_format())); 246 lsp_item.insert_text_format = Some(insert_text_format(item.insert_text_format()));
248 } 247 }
249 res 248 res
250} 249}