aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/src/handlers/extract_struct_from_enum_variant.rs85
1 files changed, 59 insertions, 26 deletions
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
index 84662d832..38ecf5065 100644
--- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -5,10 +5,9 @@ use hir::{AsName, EnumVariant, Module, ModuleDef, Name};
5use ide_db::{defs::Definition, search::Reference, RootDatabase}; 5use ide_db::{defs::Definition, search::Reference, RootDatabase};
6use rustc_hash::{FxHashMap, FxHashSet}; 6use rustc_hash::{FxHashMap, FxHashSet};
7use syntax::{ 7use syntax::{
8 algo::find_node_at_offset, 8 algo::{find_node_at_offset, SyntaxRewriter},
9 algo::SyntaxRewriter, 9 ast::{self, edit::IndentLevel, make, AstNode, NameOwner, VisibilityOwner},
10 ast::{self, edit::IndentLevel, make, ArgListOwner, AstNode, NameOwner, VisibilityOwner}, 10 SourceFile, SyntaxElement, SyntaxNode, T,
11 SourceFile, SyntaxElement,
12}; 11};
13 12
14use crate::{ 13use crate::{
@@ -130,17 +129,17 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &En
130fn insert_import( 129fn insert_import(
131 ctx: &AssistContext, 130 ctx: &AssistContext,
132 rewriter: &mut SyntaxRewriter, 131 rewriter: &mut SyntaxRewriter,
133 path: &ast::PathExpr, 132 scope_node: &SyntaxNode,
134 module: &Module, 133 module: &Module,
135 enum_module_def: &ModuleDef, 134 enum_module_def: &ModuleDef,
136 variant_hir_name: &Name, 135 variant_hir_name: &Name,
137) -> Option<()> { 136) -> Option<()> {
138 let db = ctx.db(); 137 let db = ctx.db();
139 let mod_path = module.find_use_path(db, enum_module_def.clone()); 138 let mod_path = module.find_use_path(db, enum_module_def.clone());
140 if let Some(mut mod_path) = mod_path { 139 if let Some(mut mod_path) = mod_path.filter(|path| path.len() > 1) {
141 mod_path.segments.pop(); 140 mod_path.segments.pop();
142 mod_path.segments.push(variant_hir_name.clone()); 141 mod_path.segments.push(variant_hir_name.clone());
143 let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?; 142 let scope = ImportScope::find_insert_use_container(scope_node, ctx)?;
144 143
145 *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use.merge); 144 *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use.merge);
146 } 145 }
@@ -204,27 +203,31 @@ fn update_reference(
204 variant_hir_name: &Name, 203 variant_hir_name: &Name,
205 visited_modules_set: &mut FxHashSet<Module>, 204 visited_modules_set: &mut FxHashSet<Module>,
206) -> Option<()> { 205) -> Option<()> {
207 let path_expr: ast::PathExpr = find_node_at_offset::<ast::PathExpr>( 206 let offset = reference.file_range.range.start();
208 source_file.syntax(), 207 let (segment, expr) = if let Some(path_expr) =
209 reference.file_range.range.start(), 208 find_node_at_offset::<ast::PathExpr>(source_file.syntax(), offset)
210 )?; 209 {
211 let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; 210 // tuple variant
212 let list = call.arg_list()?; 211 (path_expr.path()?.segment()?, path_expr.syntax().parent()?.clone())
213 let segment = path_expr.path()?.segment()?; 212 } else if let Some(record_expr) =
214 let module = ctx.sema.scope(&path_expr.syntax()).module()?; 213 find_node_at_offset::<ast::RecordExpr>(source_file.syntax(), offset)
214 {
215 // record variant
216 (record_expr.path()?.segment()?, record_expr.syntax().clone())
217 } else {
218 return None;
219 };
220
221 let module = ctx.sema.scope(&expr).module()?;
215 if !visited_modules_set.contains(&module) { 222 if !visited_modules_set.contains(&module) {
216 if insert_import(ctx, rewriter, &path_expr, &module, enum_module_def, variant_hir_name) 223 if insert_import(ctx, rewriter, &expr, &module, enum_module_def, variant_hir_name).is_some()
217 .is_some()
218 { 224 {
219 visited_modules_set.insert(module); 225 visited_modules_set.insert(module);
220 } 226 }
221 } 227 }
222 228 rewriter.insert_after(segment.syntax(), &make::token(T!['(']));
223 let lparen = syntax::SyntaxElement::from(list.l_paren_token()?); 229 rewriter.insert_after(segment.syntax(), segment.syntax());
224 let rparen = syntax::SyntaxElement::from(list.r_paren_token()?); 230 rewriter.insert_after(&expr, &make::token(T![')']));
225 rewriter.insert_after(&lparen, segment.syntax());
226 rewriter.insert_after(&lparen, &lparen);
227 rewriter.insert_before(&rparen, &rparen);
228 Some(()) 231 Some(())
229} 232}
230 233
@@ -346,6 +349,33 @@ fn another_fn() {
346 } 349 }
347 350
348 #[test] 351 #[test]
352 fn extract_record_fix_references() {
353 check_assist(
354 extract_struct_from_enum_variant,
355 r#"
356enum E {
357 <|>V { i: i32, j: i32 }
358}
359
360fn f() {
361 let e = E::V { i: 9, j: 2 };
362}
363"#,
364 r#"
365struct V{ pub i: i32, pub j: i32 }
366
367enum E {
368 V(V)
369}
370
371fn f() {
372 let e = E::V(V { i: 9, j: 2 });
373}
374"#,
375 )
376 }
377
378 #[test]
349 fn test_several_files() { 379 fn test_several_files() {
350 check_assist( 380 check_assist(
351 extract_struct_from_enum_variant, 381 extract_struct_from_enum_variant,
@@ -372,8 +402,6 @@ enum E {
372mod foo; 402mod foo;
373 403
374//- /foo.rs 404//- /foo.rs
375use V;
376
377use crate::E; 405use crate::E;
378fn f() { 406fn f() {
379 let e = E::V(V(9, 2)); 407 let e = E::V(V(9, 2));
@@ -384,7 +412,6 @@ fn f() {
384 412
385 #[test] 413 #[test]
386 fn test_several_files_record() { 414 fn test_several_files_record() {
387 // FIXME: this should fix the usage as well!
388 check_assist( 415 check_assist(
389 extract_struct_from_enum_variant, 416 extract_struct_from_enum_variant,
390 r#" 417 r#"
@@ -401,6 +428,7 @@ fn f() {
401} 428}
402"#, 429"#,
403 r#" 430 r#"
431//- /main.rs
404struct V{ pub i: i32, pub j: i32 } 432struct V{ pub i: i32, pub j: i32 }
405 433
406enum E { 434enum E {
@@ -408,6 +436,11 @@ enum E {
408} 436}
409mod foo; 437mod foo;
410 438
439//- /foo.rs
440use crate::E;
441fn f() {
442 let e = E::V(V { i: 9, j: 2 });
443}
411"#, 444"#,
412 ) 445 )
413 } 446 }