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.rs38
4 files changed, 103 insertions, 45 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index caf4c3395..638398e29 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1608,10 +1608,9 @@ impl Type {
1608 } 1608 }
1609 1609
1610 pub fn remove_ref(&self) -> Option<Type> { 1610 pub fn remove_ref(&self) -> Option<Type> {
1611 if let Ty::Ref(.., substs) = &self.ty.value { 1611 match &self.ty.value {
1612 Some(self.derived(substs[0].clone())) 1612 Ty::Ref(.., substs) => Some(self.derived(substs[0].clone())),
1613 } else { 1613 _ => None,
1614 None
1615 } 1614 }
1616 } 1615 }
1617 1616
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..2380e021a 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -175,12 +175,6 @@ pub(crate) fn completion_item(
175 line_index: &LineIndex, 175 line_index: &LineIndex,
176 item: CompletionItem, 176 item: CompletionItem,
177) -> Vec<lsp_types::CompletionItem> { 177) -> Vec<lsp_types::CompletionItem> {
178 fn set_score(lsp_item: &mut lsp_types::CompletionItem, label: &str) {
179 lsp_item.preselect = Some(true);
180 // HACK: sort preselect items first
181 lsp_item.sort_text = Some(format!(" {}", label));
182 }
183
184 let mut additional_text_edits = Vec::new(); 178 let mut additional_text_edits = Vec::new();
185 let mut text_edit = None; 179 let mut text_edit = None;
186 // LSP does not allow arbitrary edits in completion, so we have to do a 180 // LSP does not allow arbitrary edits in completion, so we have to do a
@@ -220,7 +214,9 @@ pub(crate) fn completion_item(
220 }; 214 };
221 215
222 if item.score().is_some() { 216 if item.score().is_some() {
223 set_score(&mut lsp_item, item.label()); 217 lsp_item.preselect = Some(true);
218 // HACK: sort preselect items first
219 lsp_item.sort_text = Some(format!(" {}", item.label()));
224 } 220 }
225 221
226 if item.deprecated() { 222 if item.deprecated() {
@@ -232,19 +228,23 @@ pub(crate) fn completion_item(
232 } 228 }
233 229
234 let mut res = match item.ref_match() { 230 let mut res = match item.ref_match() {
235 Some(ref_match) => { 231 Some(mutability) => {
236 let mut refed = lsp_item.clone(); 232 let mut lsp_item_with_ref = lsp_item.clone();
237 let (mutability, _score) = ref_match; 233 lsp_item.preselect = Some(true);
238 let label = format!("&{}{}", mutability.as_keyword_for_ref(), refed.label); 234 lsp_item.sort_text = Some(format!(" {}", item.label()));
239 set_score(&mut refed, &label); 235 lsp_item_with_ref.label =
240 refed.label = label; 236 format!("&{}{}", mutability.as_keyword_for_ref(), lsp_item_with_ref.label);
241 vec![lsp_item, refed] 237 if let Some(lsp_types::CompletionTextEdit::Edit(it)) = &mut lsp_item_with_ref.text_edit
238 {
239 it.new_text = format!("&{}{}", mutability.as_keyword_for_ref(), it.new_text);
240 }
241 vec![lsp_item_with_ref, lsp_item]
242 } 242 }
243 None => vec![lsp_item], 243 None => vec![lsp_item],
244 }; 244 };
245 245
246 for mut r in res.iter_mut() { 246 for lsp_item in res.iter_mut() {
247 r.insert_text_format = Some(insert_text_format(item.insert_text_format())); 247 lsp_item.insert_text_format = Some(insert_text_format(item.insert_text_format()));
248 } 248 }
249 res 249 res
250} 250}
@@ -1105,13 +1105,13 @@ mod tests {
1105 expect_test::expect![[r#" 1105 expect_test::expect![[r#"
1106 [ 1106 [
1107 ( 1107 (
1108 "arg", 1108 "&arg",
1109 None, 1109 None,
1110 ), 1110 ),
1111 ( 1111 (
1112 "&arg", 1112 "arg",
1113 Some( 1113 Some(
1114 " &arg", 1114 " arg",
1115 ), 1115 ),
1116 ), 1116 ),
1117 ] 1117 ]