Skip to content

Commit c235960

Browse files
bors[bot]matklad
andauthored
Merge #7944
7944: Selecting `&mut foo` completion now actually inserts `&mut` r=matklad a=matklad bors r+ 🤖 Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
2 parents 472641f + 73b9937 commit c235960

File tree

4 files changed

+103
-45
lines changed

4 files changed

+103
-45
lines changed

crates/hir/src/lib.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1614,10 +1614,9 @@ impl Type {
16141614
}
16151615

16161616
pub fn remove_ref(&self) -> Option<Type> {
1617-
if let Ty::Ref(.., substs) = &self.ty.value {
1618-
Some(self.derived(substs[0].clone()))
1619-
} else {
1620-
None
1617+
match &self.ty.value {
1618+
Ty::Ref(.., substs) => Some(self.derived(substs[0].clone())),
1619+
_ => None,
16211620
}
16221621
}
16231622

crates/ide_completion/src/item.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub struct CompletionItem {
6868

6969
/// Indicates that a reference or mutable reference to this variable is a
7070
/// possible match.
71-
ref_match: Option<(Mutability, CompletionScore)>,
71+
ref_match: Option<Mutability>,
7272

7373
/// The import data to add to completion's edits.
7474
import_to_add: Option<ImportEdit>,
@@ -104,6 +104,9 @@ impl fmt::Debug for CompletionItem {
104104
if let Some(score) = &self.score {
105105
s.field("score", score);
106106
}
107+
if let Some(mutability) = &self.ref_match {
108+
s.field("ref_match", &format!("&{}", mutability.as_keyword_for_ref()));
109+
}
107110
if self.trigger_call_info {
108111
s.field("trigger_call_info", &true);
109112
}
@@ -261,7 +264,7 @@ impl CompletionItem {
261264
self.trigger_call_info
262265
}
263266

264-
pub fn ref_match(&self) -> Option<(Mutability, CompletionScore)> {
267+
pub fn ref_match(&self) -> Option<Mutability> {
265268
self.ref_match
266269
}
267270

@@ -311,7 +314,7 @@ pub(crate) struct Builder {
311314
deprecated: bool,
312315
trigger_call_info: Option<bool>,
313316
score: Option<CompletionScore>,
314-
ref_match: Option<(Mutability, CompletionScore)>,
317+
ref_match: Option<Mutability>,
315318
}
316319

317320
impl Builder {
@@ -430,8 +433,8 @@ impl Builder {
430433
self.import_to_add = import_to_add;
431434
self
432435
}
433-
pub(crate) fn ref_match(mut self, ref_match: (Mutability, CompletionScore)) -> Builder {
434-
self.ref_match = Some(ref_match);
436+
pub(crate) fn ref_match(mut self, mutability: Mutability) -> Builder {
437+
self.ref_match = Some(mutability);
435438
self
436439
}
437440
}

crates/ide_completion/src/render.rs

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -254,10 +254,17 @@ impl<'a> Render<'a> {
254254
{
255255
item = item.set_score(score);
256256
}
257-
if let Some(ref_match) =
258-
refed_type_matches(&active_type, &active_name, &ty, &local_name)
259-
{
260-
item = item.ref_match(ref_match);
257+
258+
if let Some(ty_without_ref) = active_type.remove_ref() {
259+
if ty_without_ref == ty {
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+
}
261268
}
262269
}
263270
}
@@ -340,19 +347,6 @@ fn compute_score_from_active(
340347

341348
Some(res)
342349
}
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-
}
356350

357351
fn compute_score(ctx: &RenderContext, ty: &Type, name: &str) -> Option<CompletionScore> {
358352
let (active_name, active_type) = ctx.active_name_and_type()?;
@@ -947,4 +941,66 @@ fn f(foo: &Foo) { f(foo, w$0) }
947941
"#]],
948942
);
949943
}
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+
}
9501006
}

crates/rust-analyzer/src/to_proto.rs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,6 @@ pub(crate) fn completion_item(
175175
line_index: &LineIndex,
176176
item: CompletionItem,
177177
) -> 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-
184178
let mut additional_text_edits = Vec::new();
185179
let mut text_edit = None;
186180
// LSP does not allow arbitrary edits in completion, so we have to do a
@@ -220,7 +214,9 @@ pub(crate) fn completion_item(
220214
};
221215

222216
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()));
224220
}
225221

226222
if item.deprecated() {
@@ -232,19 +228,23 @@ pub(crate) fn completion_item(
232228
}
233229

234230
let mut res = match item.ref_match() {
235-
Some(ref_match) => {
236-
let mut refed = lsp_item.clone();
237-
let (mutability, _score) = ref_match;
238-
let label = format!("&{}{}", mutability.as_keyword_for_ref(), refed.label);
239-
set_score(&mut refed, &label);
240-
refed.label = label;
241-
vec![lsp_item, refed]
231+
Some(mutability) => {
232+
let mut lsp_item_with_ref = lsp_item.clone();
233+
lsp_item.preselect = Some(true);
234+
lsp_item.sort_text = Some(format!(" {}", item.label()));
235+
lsp_item_with_ref.label =
236+
format!("&{}{}", mutability.as_keyword_for_ref(), lsp_item_with_ref.label);
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]
242242
}
243243
None => vec![lsp_item],
244244
};
245245

246-
for mut r in res.iter_mut() {
247-
r.insert_text_format = Some(insert_text_format(item.insert_text_format()));
246+
for lsp_item in res.iter_mut() {
247+
lsp_item.insert_text_format = Some(insert_text_format(item.insert_text_format()));
248248
}
249249
res
250250
}
@@ -1105,13 +1105,13 @@ mod tests {
11051105
expect_test::expect![[r#"
11061106
[
11071107
(
1108-
"arg",
1108+
"&arg",
11091109
None,
11101110
),
11111111
(
1112-
"&arg",
1112+
"arg",
11131113
Some(
1114-
" &arg",
1114+
" arg",
11151115
),
11161116
),
11171117
]

0 commit comments

Comments
 (0)