aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2020-11-14 18:57:47 +0000
committerLukas Wirth <[email protected]>2020-11-14 20:08:20 +0000
commitcb60708274dc7c8cff281364507d23047cd482cd (patch)
tree31ebdff3546086e3d0c784535ceaad1ed945cb8b /crates
parent924eecf4af4d57c597c2e77c5e58c22b2a37bdb6 (diff)
Use shorthand field syntax in destructures
Diffstat (limited to 'crates')
-rw-r--r--crates/ide/src/references.rs4
-rw-r--r--crates/ide/src/references/rename.rs77
-rw-r--r--crates/ide_db/src/search.rs32
3 files changed, 84 insertions, 29 deletions
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 10cd42032..5693dd400 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -622,7 +622,7 @@ fn foo() {
622 expect![[r#" 622 expect![[r#"
623 f RECORD_FIELD FileId(0) 15..21 15..16 Other 623 f RECORD_FIELD FileId(0) 15..21 15..16 Other
624 624
625 FileId(0) 55..56 Other Read 625 FileId(0) 55..56 RecordFieldExprOrPat Read
626 FileId(0) 68..69 Other Write 626 FileId(0) 68..69 Other Write
627 "#]], 627 "#]],
628 ); 628 );
@@ -757,7 +757,7 @@ fn f() -> m::En {
757 expect![[r#" 757 expect![[r#"
758 field RECORD_FIELD FileId(0) 56..65 56..61 Other 758 field RECORD_FIELD FileId(0) 56..65 56..61 Other
759 759
760 FileId(0) 125..130 Other Read 760 FileId(0) 125..130 RecordFieldExprOrPat Read
761 "#]], 761 "#]],
762 ); 762 );
763 } 763 }
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index bc4aa25bf..449cfa4ae 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -1,7 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{Module, ModuleDef, ModuleSource, Semantics}; 3use hir::{Module, ModuleDef, ModuleSource, Semantics};
4use ide_db::base_db::SourceDatabaseExt; 4use ide_db::base_db::{FileRange, SourceDatabaseExt};
5use ide_db::{ 5use ide_db::{
6 defs::{Definition, NameClass, NameRefClass}, 6 defs::{Definition, NameClass, NameRefClass},
7 RootDatabase, 7 RootDatabase,
@@ -112,7 +112,6 @@ fn source_edit_from_reference(
112 new_name: &str, 112 new_name: &str,
113) -> SourceFileEdit { 113) -> SourceFileEdit {
114 let mut replacement_text = String::new(); 114 let mut replacement_text = String::new();
115 let file_id = reference.file_range.file_id;
116 let range = match reference.kind { 115 let range = match reference.kind {
117 ReferenceKind::FieldShorthandForField => { 116 ReferenceKind::FieldShorthandForField => {
118 mark::hit!(test_rename_struct_field_for_shorthand); 117 mark::hit!(test_rename_struct_field_for_shorthand);
@@ -126,28 +125,49 @@ fn source_edit_from_reference(
126 replacement_text.push_str(new_name); 125 replacement_text.push_str(new_name);
127 TextRange::new(reference.file_range.range.end(), reference.file_range.range.end()) 126 TextRange::new(reference.file_range.range.end(), reference.file_range.range.end())
128 } 127 }
129 ReferenceKind::RecordExprField => { 128 ReferenceKind::RecordFieldExprOrPat => {
130 replacement_text.push_str(new_name); 129 replacement_text.push_str(new_name);
131 let mut range = reference.file_range.range; 130 edit_text_range_for_record_field_expr_or_pat(sema, reference.file_range, new_name)
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
144 } 131 }
145 _ => { 132 _ => {
146 replacement_text.push_str(new_name); 133 replacement_text.push_str(new_name);
147 reference.file_range.range 134 reference.file_range.range
148 } 135 }
149 }; 136 };
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
143fn 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
151} 171}
152 172
153fn rename_mod( 173fn rename_mod(
@@ -1192,4 +1212,27 @@ fn foo(foo: Foo) {
1192"#, 1212"#,
1193 ); 1213 );
1194 } 1214 }
1215
1216 #[test]
1217 fn test_struct_field_destructure_into_shorthand() {
1218 check(
1219 "baz",
1220 r#"
1221struct Foo { i<|>: i32 }
1222
1223fn foo(foo: Foo) {
1224 let Foo { i: baz } = foo;
1225 let _ = baz;
1226}
1227"#,
1228 r#"
1229struct Foo { baz: i32 }
1230
1231fn foo(foo: Foo) {
1232 let Foo { baz } = foo;
1233 let _ = baz;
1234}
1235"#,
1236 );
1237 }
1195} 1238}
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index 4248606c8..a3e765d05 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -30,7 +30,7 @@ pub enum ReferenceKind {
30 FieldShorthandForField, 30 FieldShorthandForField,
31 FieldShorthandForLocal, 31 FieldShorthandForLocal,
32 StructLiteral, 32 StructLiteral,
33 RecordExprField, 33 RecordFieldExprOrPat,
34 Other, 34 Other,
35} 35}
36 36
@@ -279,15 +279,13 @@ impl<'a> FindUsages<'a> {
279 ) -> bool { 279 ) -> bool {
280 match NameRefClass::classify(self.sema, &name_ref) { 280 match NameRefClass::classify(self.sema, &name_ref) {
281 Some(NameRefClass::Definition(def)) if &def == self.def => { 281 Some(NameRefClass::Definition(def)) if &def == self.def => {
282 let kind = 282 let kind = if is_record_field_expr_or_pat(&name_ref) {
283 if name_ref.syntax().parent().and_then(ast::RecordExprField::cast).is_some() { 283 ReferenceKind::RecordFieldExprOrPat
284 ReferenceKind::RecordExprField 284 } else if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref) {
285 } else if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref) 285 ReferenceKind::StructLiteral
286 { 286 } else {
287 ReferenceKind::StructLiteral 287 ReferenceKind::Other
288 } else { 288 };
289 ReferenceKind::Other
290 };
291 289
292 let reference = Reference { 290 let reference = Reference {
293 file_range: self.sema.original_range(name_ref.syntax()), 291 file_range: self.sema.original_range(name_ref.syntax()),
@@ -389,3 +387,17 @@ fn is_record_lit_name_ref(name_ref: &ast::NameRef) -> bool {
389 .map(|p| p.name_ref().as_ref() == Some(name_ref)) 387 .map(|p| p.name_ref().as_ref() == Some(name_ref))
390 .unwrap_or(false) 388 .unwrap_or(false)
391} 389}
390
391fn 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}