Skip to content

Commit cb60708

Browse files
committed
Use shorthand field syntax in destructures
1 parent 924eecf commit cb60708

File tree

3 files changed

+84
-29
lines changed

3 files changed

+84
-29
lines changed

crates/ide/src/references.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,7 @@ fn foo() {
622622
expect![[r#"
623623
f RECORD_FIELD FileId(0) 15..21 15..16 Other
624624
625-
FileId(0) 55..56 Other Read
625+
FileId(0) 55..56 RecordFieldExprOrPat Read
626626
FileId(0) 68..69 Other Write
627627
"#]],
628628
);
@@ -757,7 +757,7 @@ fn f() -> m::En {
757757
expect![[r#"
758758
field RECORD_FIELD FileId(0) 56..65 56..61 Other
759759
760-
FileId(0) 125..130 Other Read
760+
FileId(0) 125..130 RecordFieldExprOrPat Read
761761
"#]],
762762
);
763763
}

crates/ide/src/references/rename.rs

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! FIXME: write short doc here
22
33
use hir::{Module, ModuleDef, ModuleSource, Semantics};
4-
use ide_db::base_db::SourceDatabaseExt;
4+
use ide_db::base_db::{FileRange, SourceDatabaseExt};
55
use ide_db::{
66
defs::{Definition, NameClass, NameRefClass},
77
RootDatabase,
@@ -112,7 +112,6 @@ fn source_edit_from_reference(
112112
new_name: &str,
113113
) -> SourceFileEdit {
114114
let mut replacement_text = String::new();
115-
let file_id = reference.file_range.file_id;
116115
let range = match reference.kind {
117116
ReferenceKind::FieldShorthandForField => {
118117
mark::hit!(test_rename_struct_field_for_shorthand);
@@ -126,28 +125,49 @@ fn source_edit_from_reference(
126125
replacement_text.push_str(new_name);
127126
TextRange::new(reference.file_range.range.end(), reference.file_range.range.end())
128127
}
129-
ReferenceKind::RecordExprField => {
128+
ReferenceKind::RecordFieldExprOrPat => {
130129
replacement_text.push_str(new_name);
131-
let mut range = reference.file_range.range;
132-
if let Some(field_expr) = syntax::algo::find_node_at_range::<ast::RecordExprField>(
133-
sema.parse(file_id).syntax(),
134-
reference.file_range.range,
135-
) {
136-
// use shorthand initializer if we were to write foo: foo
137-
if let Some(name) = field_expr.expr().and_then(|e| e.name_ref()) {
138-
if &name.to_string() == new_name {
139-
range = field_expr.syntax().text_range();
140-
}
141-
}
142-
}
143-
range
130+
edit_text_range_for_record_field_expr_or_pat(sema, reference.file_range, new_name)
144131
}
145132
_ => {
146133
replacement_text.push_str(new_name);
147134
reference.file_range.range
148135
}
149136
};
150-
SourceFileEdit { file_id, edit: TextEdit::replace(range, replacement_text) }
137+
SourceFileEdit {
138+
file_id: reference.file_range.file_id,
139+
edit: TextEdit::replace(range, replacement_text),
140+
}
141+
}
142+
143+
fn edit_text_range_for_record_field_expr_or_pat(
144+
sema: &Semantics<RootDatabase>,
145+
file_range: FileRange,
146+
new_name: &str,
147+
) -> TextRange {
148+
let mut range = file_range.range;
149+
let source_file = sema.parse(file_range.file_id);
150+
let file_syntax = source_file.syntax();
151+
if let Some(field_expr) =
152+
syntax::algo::find_node_at_range::<ast::RecordExprField>(file_syntax, range)
153+
{
154+
match field_expr.expr().and_then(|e| e.name_ref()) {
155+
Some(name) if &name.to_string() == new_name => range = field_expr.syntax().text_range(),
156+
_ => (),
157+
}
158+
} else if let Some(field_pat) =
159+
syntax::algo::find_node_at_range::<ast::RecordPatField>(file_syntax, range)
160+
{
161+
match field_pat.pat() {
162+
Some(ast::Pat::IdentPat(pat))
163+
if pat.name().map(|n| n.to_string()).as_deref() == Some(new_name) =>
164+
{
165+
range = field_pat.syntax().text_range()
166+
}
167+
_ => (),
168+
}
169+
}
170+
range
151171
}
152172

153173
fn rename_mod(
@@ -1189,6 +1209,29 @@ fn foo(foo: Foo) {
11891209
let Foo { i: bar } = foo;
11901210
let _ = bar;
11911211
}
1212+
"#,
1213+
);
1214+
}
1215+
1216+
#[test]
1217+
fn test_struct_field_destructure_into_shorthand() {
1218+
check(
1219+
"baz",
1220+
r#"
1221+
struct Foo { i<|>: i32 }
1222+
1223+
fn foo(foo: Foo) {
1224+
let Foo { i: baz } = foo;
1225+
let _ = baz;
1226+
}
1227+
"#,
1228+
r#"
1229+
struct Foo { baz: i32 }
1230+
1231+
fn foo(foo: Foo) {
1232+
let Foo { baz } = foo;
1233+
let _ = baz;
1234+
}
11921235
"#,
11931236
);
11941237
}

crates/ide_db/src/search.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub enum ReferenceKind {
3030
FieldShorthandForField,
3131
FieldShorthandForLocal,
3232
StructLiteral,
33-
RecordExprField,
33+
RecordFieldExprOrPat,
3434
Other,
3535
}
3636

@@ -279,15 +279,13 @@ impl<'a> FindUsages<'a> {
279279
) -> bool {
280280
match NameRefClass::classify(self.sema, &name_ref) {
281281
Some(NameRefClass::Definition(def)) if &def == self.def => {
282-
let kind =
283-
if name_ref.syntax().parent().and_then(ast::RecordExprField::cast).is_some() {
284-
ReferenceKind::RecordExprField
285-
} else if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref)
286-
{
287-
ReferenceKind::StructLiteral
288-
} else {
289-
ReferenceKind::Other
290-
};
282+
let kind = if is_record_field_expr_or_pat(&name_ref) {
283+
ReferenceKind::RecordFieldExprOrPat
284+
} else if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref) {
285+
ReferenceKind::StructLiteral
286+
} else {
287+
ReferenceKind::Other
288+
};
291289

292290
let reference = Reference {
293291
file_range: self.sema.original_range(name_ref.syntax()),
@@ -389,3 +387,17 @@ fn is_record_lit_name_ref(name_ref: &ast::NameRef) -> bool {
389387
.map(|p| p.name_ref().as_ref() == Some(name_ref))
390388
.unwrap_or(false)
391389
}
390+
391+
fn is_record_field_expr_or_pat(name_ref: &ast::NameRef) -> bool {
392+
if let Some(parent) = name_ref.syntax().parent() {
393+
match_ast! {
394+
match parent {
395+
ast::RecordExprField(it) => true,
396+
ast::RecordPatField(_it) => true,
397+
_ => false,
398+
}
399+
}
400+
} else {
401+
false
402+
}
403+
}

0 commit comments

Comments
 (0)