Skip to content

Commit 02a3d89

Browse files
Merge #10076
10076: Use struct init shorthand when applicable in fill struct fields assist r=matklad a=nathanwhit This PR tweaks the fill struct fields assist to use the struct init shorthand when a local variable with a matching name and type is in scope. For example: ```rust struct Foo { a: usize, b: i32, c: char, } fn main() { let a = 1; let b = 2; let c = 3; let foo = Foo { <|> }; } ``` Before we would insert ```rust Foo { a: (), b: (), c: (), } ``` now we would insert ```rust Foo { a, b, c: () } ``` Co-authored-by: nathan.whitaker <[email protected]>
2 parents 5c704f1 + e1d86a4 commit 02a3d89

File tree

1 file changed

+110
-3
lines changed

1 file changed

+110
-3
lines changed

crates/ide_diagnostics/src/handlers/missing_fields.rs

Lines changed: 110 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use either::Either;
22
use hir::{db::AstDatabase, InFile};
33
use ide_db::{assists::Assist, source_change::SourceChange};
4+
use rustc_hash::FxHashMap;
45
use stdx::format_to;
56
use syntax::{algo, ast::make, AstNode, SyntaxNodePtr};
67
use text_edit::TextEdit;
@@ -54,9 +55,27 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
5455
};
5556
let old_field_list = field_list_parent.record_expr_field_list()?;
5657
let new_field_list = old_field_list.clone_for_update();
57-
for f in d.missed_fields.iter() {
58+
let mut locals = FxHashMap::default();
59+
ctx.sema.scope(field_list_parent.syntax()).process_all_names(&mut |name, def| {
60+
if let hir::ScopeDef::Local(local) = def {
61+
locals.insert(name.clone(), local);
62+
}
63+
});
64+
let missing_fields = ctx.sema.record_literal_missing_fields(&field_list_parent);
65+
for (f, ty) in missing_fields.iter() {
66+
let field_expr = if let Some(local_candidate) = locals.get(&f.name(ctx.sema.db)) {
67+
cov_mark::hit!(field_shorthand);
68+
let candidate_ty = local_candidate.ty(ctx.sema.db);
69+
if ty.could_unify_with(ctx.sema.db, &candidate_ty) {
70+
None
71+
} else {
72+
Some(make::expr_unit())
73+
}
74+
} else {
75+
Some(make::expr_unit())
76+
};
5877
let field =
59-
make::record_expr_field(make::name_ref(&f.to_string()), Some(make::expr_unit()))
78+
make::record_expr_field(make::name_ref(&f.name(ctx.sema.db).to_string()), field_expr)
6079
.clone_for_update();
6180
new_field_list.add_field(field);
6281
}
@@ -224,7 +243,7 @@ enum Expr {
224243
225244
impl Expr {
226245
fn new_bin(lhs: Box<Expr>, rhs: Box<Expr>) -> Expr {
227-
Expr::Bin { lhs: (), rhs: () }
246+
Expr::Bin { lhs, rhs }
228247
}
229248
}
230249
"#,
@@ -324,6 +343,94 @@ fn f() {
324343
);
325344
}
326345

346+
#[test]
347+
fn test_fill_struct_fields_shorthand() {
348+
cov_mark::check!(field_shorthand);
349+
check_fix(
350+
r#"
351+
struct S { a: &'static str, b: i32 }
352+
353+
fn f() {
354+
let a = "hello";
355+
let b = 1i32;
356+
S {
357+
$0
358+
};
359+
}
360+
"#,
361+
r#"
362+
struct S { a: &'static str, b: i32 }
363+
364+
fn f() {
365+
let a = "hello";
366+
let b = 1i32;
367+
S {
368+
a,
369+
b,
370+
};
371+
}
372+
"#,
373+
);
374+
}
375+
376+
#[test]
377+
fn test_fill_struct_fields_shorthand_ty_mismatch() {
378+
check_fix(
379+
r#"
380+
struct S { a: &'static str, b: i32 }
381+
382+
fn f() {
383+
let a = "hello";
384+
let b = 1usize;
385+
S {
386+
$0
387+
};
388+
}
389+
"#,
390+
r#"
391+
struct S { a: &'static str, b: i32 }
392+
393+
fn f() {
394+
let a = "hello";
395+
let b = 1usize;
396+
S {
397+
a,
398+
b: (),
399+
};
400+
}
401+
"#,
402+
);
403+
}
404+
405+
#[test]
406+
fn test_fill_struct_fields_shorthand_unifies() {
407+
check_fix(
408+
r#"
409+
struct S<T> { a: &'static str, b: T }
410+
411+
fn f() {
412+
let a = "hello";
413+
let b = 1i32;
414+
S {
415+
$0
416+
};
417+
}
418+
"#,
419+
r#"
420+
struct S<T> { a: &'static str, b: T }
421+
422+
fn f() {
423+
let a = "hello";
424+
let b = 1i32;
425+
S {
426+
a,
427+
b,
428+
};
429+
}
430+
"#,
431+
);
432+
}
433+
327434
#[test]
328435
fn import_extern_crate_clash_with_inner_item() {
329436
// This is more of a resolver test, but doesn't really work with the hir_def testsuite.

0 commit comments

Comments
 (0)