aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2020-11-14 16:49:36 +0000
committerLukas Wirth <[email protected]>2020-11-14 16:51:09 +0000
commite55a44a831477e2fc8e11340c3d91db883b97c8e (patch)
treedb334060759bcc4252689e305a466ec3dd2b5d8b
parent99fa139beab0c03583c676554c3d807525f602af (diff)
Use shorthand record syntax when renaming struct initializer field
-rw-r--r--crates/ide/src/references/rename.rs49
-rw-r--r--crates/ide_db/src/search.rs16
-rw-r--r--crates/syntax/src/ast/expr_ext.rs12
-rw-r--r--crates/syntax/src/ast/node_ext.rs10
4 files changed, 68 insertions, 19 deletions
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 26ac2371a..b3ade20ef 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -106,7 +106,11 @@ fn find_module_at_offset(
106 Some(module) 106 Some(module)
107} 107}
108 108
109fn source_edit_from_reference(reference: Reference, new_name: &str) -> SourceFileEdit { 109fn source_edit_from_reference(
110 sema: &Semantics<RootDatabase>,
111 reference: Reference,
112 new_name: &str,
113) -> SourceFileEdit {
110 let mut replacement_text = String::new(); 114 let mut replacement_text = String::new();
111 let file_id = reference.file_range.file_id; 115 let file_id = reference.file_range.file_id;
112 let range = match reference.kind { 116 let range = match reference.kind {
@@ -122,6 +126,22 @@ fn source_edit_from_reference(reference: Reference, new_name: &str) -> SourceFil
122 replacement_text.push_str(new_name); 126 replacement_text.push_str(new_name);
123 TextRange::new(reference.file_range.range.end(), reference.file_range.range.end()) 127 TextRange::new(reference.file_range.range.end(), reference.file_range.range.end())
124 } 128 }
129 ReferenceKind::RecordExprField => {
130 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
144 }
125 _ => { 145 _ => {
126 replacement_text.push_str(new_name); 146 replacement_text.push_str(new_name);
127 reference.file_range.range 147 reference.file_range.range
@@ -170,7 +190,7 @@ fn rename_mod(
170 let ref_edits = refs 190 let ref_edits = refs
171 .references 191 .references
172 .into_iter() 192 .into_iter()
173 .map(|reference| source_edit_from_reference(reference, new_name)); 193 .map(|reference| source_edit_from_reference(sema, reference, new_name));
174 source_file_edits.extend(ref_edits); 194 source_file_edits.extend(ref_edits);
175 195
176 Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits))) 196 Ok(RangeInfo::new(range, SourceChange::from_edits(source_file_edits, file_system_edits)))
@@ -211,7 +231,7 @@ fn rename_to_self(
211 231
212 let mut edits = usages 232 let mut edits = usages
213 .into_iter() 233 .into_iter()
214 .map(|reference| source_edit_from_reference(reference, "self")) 234 .map(|reference| source_edit_from_reference(sema, reference, "self"))
215 .collect::<Vec<_>>(); 235 .collect::<Vec<_>>();
216 236
217 edits.push(SourceFileEdit { 237 edits.push(SourceFileEdit {
@@ -300,7 +320,7 @@ fn rename_reference(
300 320
301 let edit = refs 321 let edit = refs
302 .into_iter() 322 .into_iter()
303 .map(|reference| source_edit_from_reference(reference, new_name)) 323 .map(|reference| source_edit_from_reference(sema, reference, new_name))
304 .collect::<Vec<_>>(); 324 .collect::<Vec<_>>();
305 325
306 if edit.is_empty() { 326 if edit.is_empty() {
@@ -1097,4 +1117,25 @@ impl Foo {
1097"#, 1117"#,
1098 ); 1118 );
1099 } 1119 }
1120
1121 #[test]
1122 fn test_initializer_use_field_init_shorthand() {
1123 check(
1124 "bar",
1125 r#"
1126struct Foo { i<|>: i32 }
1127
1128fn foo(bar: i32) -> Foo {
1129 Foo { i: bar }
1130}
1131"#,
1132 r#"
1133struct Foo { bar: i32 }
1134
1135fn foo(bar: i32) -> Foo {
1136 Foo { bar }
1137}
1138"#,
1139 );
1140 }
1100} 1141}
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index a24335240..4248606c8 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -30,6 +30,7 @@ pub enum ReferenceKind {
30 FieldShorthandForField, 30 FieldShorthandForField,
31 FieldShorthandForLocal, 31 FieldShorthandForLocal,
32 StructLiteral, 32 StructLiteral,
33 RecordExprField,
33 Other, 34 Other,
34} 35}
35 36
@@ -278,12 +279,15 @@ impl<'a> FindUsages<'a> {
278 ) -> bool { 279 ) -> bool {
279 match NameRefClass::classify(self.sema, &name_ref) { 280 match NameRefClass::classify(self.sema, &name_ref) {
280 Some(NameRefClass::Definition(def)) if &def == self.def => { 281 Some(NameRefClass::Definition(def)) if &def == self.def => {
281 let kind = if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref) 282 let kind =
282 { 283 if name_ref.syntax().parent().and_then(ast::RecordExprField::cast).is_some() {
283 ReferenceKind::StructLiteral 284 ReferenceKind::RecordExprField
284 } else { 285 } else if is_record_lit_name_ref(&name_ref) || is_call_expr_name_ref(&name_ref)
285 ReferenceKind::Other 286 {
286 }; 287 ReferenceKind::StructLiteral
288 } else {
289 ReferenceKind::Other
290 };
287 291
288 let reference = Reference { 292 let reference = Reference {
289 file_range: self.sema.original_range(name_ref.syntax()), 293 file_range: self.sema.original_range(name_ref.syntax()),
diff --git a/crates/syntax/src/ast/expr_ext.rs b/crates/syntax/src/ast/expr_ext.rs
index 9253c97d0..e4a9b945c 100644
--- a/crates/syntax/src/ast/expr_ext.rs
+++ b/crates/syntax/src/ast/expr_ext.rs
@@ -22,6 +22,18 @@ impl ast::Expr {
22 _ => false, 22 _ => false,
23 } 23 }
24 } 24 }
25
26 pub fn name_ref(&self) -> Option<ast::NameRef> {
27 if let ast::Expr::PathExpr(expr) = self {
28 let path = expr.path()?;
29 let segment = path.segment()?;
30 let name_ref = segment.name_ref()?;
31 if path.qualifier().is_none() {
32 return Some(name_ref);
33 }
34 }
35 None
36 }
25} 37}
26 38
27#[derive(Debug, Clone, PartialEq, Eq)] 39#[derive(Debug, Clone, PartialEq, Eq)]
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index ce35ac01a..b70b840b8 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -203,15 +203,7 @@ impl ast::RecordExprField {
203 if let Some(name_ref) = self.name_ref() { 203 if let Some(name_ref) = self.name_ref() {
204 return Some(name_ref); 204 return Some(name_ref);
205 } 205 }
206 if let Some(ast::Expr::PathExpr(expr)) = self.expr() { 206 self.expr()?.name_ref()
207 let path = expr.path()?;
208 let segment = path.segment()?;
209 let name_ref = segment.name_ref()?;
210 if path.qualifier().is_none() {
211 return Some(name_ref);
212 }
213 }
214 None
215 } 207 }
216} 208}
217 209