diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2021-03-09 16:05:23 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2021-03-09 16:05:23 +0000 |
commit | c2359608c926d4828f2b112e7069978449851d58 (patch) | |
tree | ccb62a1da7516ce170e6ddf8481154465c7abba5 | |
parent | 472641fc5beee1f998d46de70351bcb572d6226c (diff) | |
parent | 73b9937e4eea2633005e7d2814cb7990e5f20e8f (diff) |
Merge #7944
7944: Selecting `&mut foo` completion now actually inserts `&mut` r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r-- | crates/hir/src/lib.rs | 7 | ||||
-rw-r--r-- | crates/ide_completion/src/item.rs | 13 | ||||
-rw-r--r-- | crates/ide_completion/src/render.rs | 90 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 38 |
4 files changed, 103 insertions, 45 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 | ||
317 | impl Builder { | 320 | impl 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 | } |
343 | fn 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 | ||
357 | fn compute_score(ctx: &RenderContext, ty: &Type, name: &str) -> Option<CompletionScore> { | 351 | fn 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#" | ||
950 | struct S; | ||
951 | fn foo(s: &mut S) {} | ||
952 | fn 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 | ] |