diff options
author | Lukas Wirth <[email protected]> | 2020-11-14 18:57:47 +0000 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2020-11-14 20:08:20 +0000 |
commit | cb60708274dc7c8cff281364507d23047cd482cd (patch) | |
tree | 31ebdff3546086e3d0c784535ceaad1ed945cb8b /crates | |
parent | 924eecf4af4d57c597c2e77c5e58c22b2a37bdb6 (diff) |
Use shorthand field syntax in destructures
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ide/src/references.rs | 4 | ||||
-rw-r--r-- | crates/ide/src/references/rename.rs | 77 | ||||
-rw-r--r-- | crates/ide_db/src/search.rs | 32 |
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 | ||
3 | use hir::{Module, ModuleDef, ModuleSource, Semantics}; | 3 | use hir::{Module, ModuleDef, ModuleSource, Semantics}; |
4 | use ide_db::base_db::SourceDatabaseExt; | 4 | use ide_db::base_db::{FileRange, SourceDatabaseExt}; |
5 | use ide_db::{ | 5 | use 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 | |||
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 | ||
151 | } | 171 | } |
152 | 172 | ||
153 | fn rename_mod( | 173 | fn 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#" | ||
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 | } | ||
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 | |||
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 | } | ||