aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs')
-rw-r--r--crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs85
1 files changed, 45 insertions, 40 deletions
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
index a8d6355bd..26e1c66ab 100644
--- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -13,9 +13,9 @@ use ide_db::{
13}; 13};
14use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
15use syntax::{ 15use syntax::{
16 algo::{find_node_at_offset, SyntaxRewriter}, 16 algo::find_node_at_offset,
17 ast::{self, edit::IndentLevel, make, AstNode, NameOwner, VisibilityOwner}, 17 ast::{self, make, AstNode, NameOwner, VisibilityOwner},
18 SourceFile, SyntaxElement, SyntaxNode, T, 18 ted, SourceFile, SyntaxElement, SyntaxNode, T,
19}; 19};
20 20
21use crate::{AssistContext, AssistId, AssistKind, Assists}; 21use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -62,14 +62,17 @@ pub(crate) fn extract_struct_from_enum_variant(
62 let mut visited_modules_set = FxHashSet::default(); 62 let mut visited_modules_set = FxHashSet::default();
63 let current_module = enum_hir.module(ctx.db()); 63 let current_module = enum_hir.module(ctx.db());
64 visited_modules_set.insert(current_module); 64 visited_modules_set.insert(current_module);
65 let mut def_rewriter = None; 65 let mut def_file_references = None;
66 for (file_id, references) in usages { 66 for (file_id, references) in usages {
67 let mut rewriter = SyntaxRewriter::default(); 67 if file_id == ctx.frange.file_id {
68 let source_file = ctx.sema.parse(file_id); 68 def_file_references = Some(references);
69 continue;
70 }
71 builder.edit_file(file_id);
72 let source_file = builder.make_ast_mut(ctx.sema.parse(file_id));
69 for reference in references { 73 for reference in references {
70 update_reference( 74 update_reference(
71 ctx, 75 ctx,
72 &mut rewriter,
73 reference, 76 reference,
74 &source_file, 77 &source_file,
75 &enum_module_def, 78 &enum_module_def,
@@ -77,25 +80,27 @@ pub(crate) fn extract_struct_from_enum_variant(
77 &mut visited_modules_set, 80 &mut visited_modules_set,
78 ); 81 );
79 } 82 }
80 if file_id == ctx.frange.file_id {
81 def_rewriter = Some(rewriter);
82 continue;
83 }
84 builder.edit_file(file_id);
85 builder.rewrite(rewriter);
86 } 83 }
87 let mut rewriter = def_rewriter.unwrap_or_default(); 84 builder.edit_file(ctx.frange.file_id);
88 update_variant(&mut rewriter, &variant); 85 let variant = builder.make_ast_mut(variant.clone());
86 let source_file = builder.make_ast_mut(ctx.sema.parse(ctx.frange.file_id));
87 for reference in def_file_references.into_iter().flatten() {
88 update_reference(
89 ctx,
90 reference,
91 &source_file,
92 &enum_module_def,
93 &variant_hir_name,
94 &mut visited_modules_set,
95 );
96 }
89 extract_struct_def( 97 extract_struct_def(
90 &mut rewriter,
91 &enum_ast,
92 variant_name.clone(), 98 variant_name.clone(),
93 &field_list, 99 &field_list,
94 &variant.parent_enum().syntax().clone().into(), 100 &variant.parent_enum().syntax().clone().into(),
95 enum_ast.visibility(), 101 enum_ast.visibility(),
96 ); 102 );
97 builder.edit_file(ctx.frange.file_id); 103 update_variant(&variant);
98 builder.rewrite(rewriter);
99 }, 104 },
100 ) 105 )
101} 106}
@@ -138,7 +143,6 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va
138 143
139fn insert_import( 144fn insert_import(
140 ctx: &AssistContext, 145 ctx: &AssistContext,
141 rewriter: &mut SyntaxRewriter,
142 scope_node: &SyntaxNode, 146 scope_node: &SyntaxNode,
143 module: &Module, 147 module: &Module,
144 enum_module_def: &ModuleDef, 148 enum_module_def: &ModuleDef,
@@ -151,14 +155,12 @@ fn insert_import(
151 mod_path.pop_segment(); 155 mod_path.pop_segment();
152 mod_path.push_segment(variant_hir_name.clone()); 156 mod_path.push_segment(variant_hir_name.clone());
153 let scope = ImportScope::find_insert_use_container(scope_node, &ctx.sema)?; 157 let scope = ImportScope::find_insert_use_container(scope_node, &ctx.sema)?;
154 *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use); 158 insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use);
155 } 159 }
156 Some(()) 160 Some(())
157} 161}
158 162
159fn extract_struct_def( 163fn extract_struct_def(
160 rewriter: &mut SyntaxRewriter,
161 enum_: &ast::Enum,
162 variant_name: ast::Name, 164 variant_name: ast::Name,
163 field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>, 165 field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
164 start_offset: &SyntaxElement, 166 start_offset: &SyntaxElement,
@@ -180,33 +182,34 @@ fn extract_struct_def(
180 .into(), 182 .into(),
181 }; 183 };
182 184
183 rewriter.insert_before( 185 ted::insert_raw(
184 start_offset, 186 ted::Position::before(start_offset),
185 make::struct_(visibility, variant_name, None, field_list).syntax(), 187 make::struct_(visibility, variant_name, None, field_list).clone_for_update().syntax(),
186 ); 188 );
187 rewriter.insert_before(start_offset, &make::tokens::blank_line()); 189 ted::insert_raw(ted::Position::before(start_offset), &make::tokens::blank_line());
188 190
189 if let indent_level @ 1..=usize::MAX = IndentLevel::from_node(enum_.syntax()).0 as usize { 191 // if let indent_level @ 1..=usize::MAX = IndentLevel::from_node(enum_.syntax()).0 as usize {
190 rewriter 192 // ted::insert(ted::Position::before(start_offset), &make::tokens::blank_line());
191 .insert_before(start_offset, &make::tokens::whitespace(&" ".repeat(4 * indent_level))); 193 // rewriter
192 } 194 // .insert_before(start_offset, &make::tokens::whitespace(&" ".repeat(4 * indent_level)));
195 // }
193 Some(()) 196 Some(())
194} 197}
195 198
196fn update_variant(rewriter: &mut SyntaxRewriter, variant: &ast::Variant) -> Option<()> { 199fn update_variant(variant: &ast::Variant) -> Option<()> {
197 let name = variant.name()?; 200 let name = variant.name()?;
198 let tuple_field = make::tuple_field(None, make::ty(&name.text())); 201 let tuple_field = make::tuple_field(None, make::ty(&name.text()));
199 let replacement = make::variant( 202 let replacement = make::variant(
200 name, 203 name,
201 Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))), 204 Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))),
202 ); 205 )
203 rewriter.replace(variant.syntax(), replacement.syntax()); 206 .clone_for_update();
207 ted::replace(variant.syntax(), replacement.syntax());
204 Some(()) 208 Some(())
205} 209}
206 210
207fn update_reference( 211fn update_reference(
208 ctx: &AssistContext, 212 ctx: &AssistContext,
209 rewriter: &mut SyntaxRewriter,
210 reference: FileReference, 213 reference: FileReference,
211 source_file: &SourceFile, 214 source_file: &SourceFile,
212 enum_module_def: &ModuleDef, 215 enum_module_def: &ModuleDef,
@@ -230,14 +233,16 @@ fn update_reference(
230 233
231 let module = ctx.sema.scope(&expr).module()?; 234 let module = ctx.sema.scope(&expr).module()?;
232 if !visited_modules_set.contains(&module) { 235 if !visited_modules_set.contains(&module) {
233 if insert_import(ctx, rewriter, &expr, &module, enum_module_def, variant_hir_name).is_some() 236 if insert_import(ctx, &expr, &module, enum_module_def, variant_hir_name).is_some() {
234 {
235 visited_modules_set.insert(module); 237 visited_modules_set.insert(module);
236 } 238 }
237 } 239 }
238 rewriter.insert_after(segment.syntax(), &make::token(T!['('])); 240 ted::insert_raw(
239 rewriter.insert_after(segment.syntax(), segment.syntax()); 241 ted::Position::before(segment.syntax()),
240 rewriter.insert_after(&expr, &make::token(T![')'])); 242 make::path_from_text(&format!("{}", segment)).clone_for_update().syntax(),
243 );
244 ted::insert_raw(ted::Position::before(segment.syntax()), make::token(T!['(']));
245 ted::insert_raw(ted::Position::after(&expr), make::token(T![')']));
241 Some(()) 246 Some(())
242} 247}
243 248