aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs129
1 files changed, 61 insertions, 68 deletions
diff --git a/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs
index 0df96be03..994e1a01a 100644
--- a/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs
+++ b/crates/ide_assists/src/handlers/convert_tuple_struct_to_named_struct.rs
@@ -1,8 +1,7 @@
1use hir::{Adt, ModuleDef, Struct};
2use ide_db::defs::{Definition, NameRefClass}; 1use ide_db::defs::{Definition, NameRefClass};
3use syntax::{ 2use syntax::{
4 ast::{self, AstNode, GenericParamsOwner, VisibilityOwner}, 3 ast::{self, AstNode, GenericParamsOwner, VisibilityOwner},
5 match_ast, 4 match_ast, SyntaxNode,
6}; 5};
7 6
8use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists}; 7use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists};
@@ -104,80 +103,74 @@ fn edit_struct_def(
104fn edit_struct_references( 103fn edit_struct_references(
105 ctx: &AssistContext, 104 ctx: &AssistContext,
106 edit: &mut AssistBuilder, 105 edit: &mut AssistBuilder,
107 strukt: Struct, 106 strukt: hir::Struct,
108 names: &[ast::Name], 107 names: &[ast::Name],
109) { 108) {
110 let strukt_def = Definition::ModuleDef(ModuleDef::Adt(Adt::Struct(strukt))); 109 let strukt_def = Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(strukt)));
111 let usages = strukt_def.usages(&ctx.sema).include_self_kw_refs(true).all(); 110 let usages = strukt_def.usages(&ctx.sema).include_self_kw_refs(true).all();
112 111
112 let edit_node = |edit: &mut AssistBuilder, node: SyntaxNode| -> Option<()> {
113 match_ast! {
114 match node {
115 ast::TupleStructPat(tuple_struct_pat) => {
116 edit.replace(
117 tuple_struct_pat.syntax().text_range(),
118 ast::make::record_pat_with_fields(
119 tuple_struct_pat.path()?,
120 ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
121 |(pat, name)| {
122 ast::make::record_pat_field(
123 ast::make::name_ref(&name.to_string()),
124 pat,
125 )
126 },
127 )),
128 )
129 .to_string(),
130 );
131 },
132 // for tuple struct creations like Foo(42)
133 ast::CallExpr(call_expr) => {
134 let path = call_expr.syntax().descendants().find_map(ast::PathExpr::cast).and_then(|expr| expr.path())?;
135
136 // this also includes method calls like Foo::new(42), we should skip them
137 if let Some(name_ref) = path.segment().and_then(|s| s.name_ref()) {
138 match NameRefClass::classify(&ctx.sema, &name_ref) {
139 Some(NameRefClass::Definition(Definition::SelfType(_))) => {},
140 Some(NameRefClass::Definition(def)) if def == strukt_def => {},
141 _ => return None,
142 };
143 }
144
145 let arg_list = call_expr.syntax().descendants().find_map(ast::ArgList::cast)?;
146
147 edit.replace(
148 call_expr.syntax().text_range(),
149 ast::make::record_expr(
150 path,
151 ast::make::record_expr_field_list(arg_list.args().zip(names).map(
152 |(expr, name)| {
153 ast::make::record_expr_field(
154 ast::make::name_ref(&name.to_string()),
155 Some(expr),
156 )
157 },
158 )),
159 )
160 .to_string(),
161 );
162 },
163 _ => ()
164 }
165 }
166 Some(())
167 };
168
113 for (file_id, refs) in usages { 169 for (file_id, refs) in usages {
114 edit.edit_file(file_id); 170 edit.edit_file(file_id);
115 for r in refs { 171 for r in refs {
116 for node in r.name.syntax().ancestors() { 172 for node in r.name.syntax().ancestors() {
117 match_ast! { 173 edit_node(edit, node);
118 match node {
119 ast::TupleStructPat(tuple_struct_pat) => {
120 let path = match tuple_struct_pat.path() {
121 Some(it) => it,
122 None => continue,
123 };
124
125 edit.replace(
126 tuple_struct_pat.syntax().text_range(),
127 ast::make::record_pat_with_fields(
128 path,
129 ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
130 |(pat, name)| {
131 ast::make::record_pat_field(
132 ast::make::name_ref(&name.to_string()),
133 pat,
134 )
135 },
136 )),
137 )
138 .to_string(),
139 );
140 },
141 // for tuple struct creations like Foo(42)
142 ast::CallExpr(call_expr) => {
143 let path = match call_expr.syntax().descendants().find_map(ast::PathExpr::cast).map(|expr| expr.path()) {
144 Some(Some(it)) => it,
145 _ => continue,
146 };
147
148 // this also includes method calls like Foo::new(42), we should skip them
149 if let Some(Some(name_ref)) = path.segment().map(|s| s.name_ref()) {
150 match NameRefClass::classify(&ctx.sema, &name_ref) {
151 Some(NameRefClass::Definition(Definition::SelfType(_))) => {},
152 Some(NameRefClass::Definition(def)) if def == strukt_def => {},
153 _ => continue,
154 };
155 }
156
157 let arg_list = match call_expr.syntax().descendants().find_map(ast::ArgList::cast) {
158 Some(it) => it,
159 None => continue,
160 };
161
162 edit.replace(
163 call_expr.syntax().text_range(),
164 ast::make::record_expr(
165 path,
166 ast::make::record_expr_field_list(arg_list.args().zip(names).map(
167 |(expr, name)| {
168 ast::make::record_expr_field(
169 ast::make::name_ref(&name.to_string()),
170 Some(expr),
171 )
172 },
173 )),
174 )
175 .to_string(),
176 );
177 },
178 _ => ()
179 }
180 }
181 } 174 }
182 } 175 }
183 } 176 }