aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs77
1 files changed, 51 insertions, 26 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 6ce417086..d3ff7b65c 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
@@ -14,16 +14,16 @@ use ide_db::{
14use itertools::Itertools; 14use itertools::Itertools;
15use rustc_hash::FxHashSet; 15use rustc_hash::FxHashSet;
16use syntax::{ 16use syntax::{
17 algo::find_node_at_offset,
18 ast::{ 17 ast::{
19 self, make, AstNode, AttrsOwner, GenericParamsOwner, NameOwner, TypeBoundsOwner, 18 self, make, AstNode, AttrsOwner, GenericParamsOwner, NameOwner, TypeBoundsOwner,
20 VisibilityOwner, 19 VisibilityOwner,
21 }, 20 },
21 match_ast,
22 ted::{self, Position}, 22 ted::{self, Position},
23 SyntaxNode, T, 23 SyntaxNode, T,
24}; 24};
25 25
26use crate::{AssistContext, AssistId, AssistKind, Assists}; 26use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists};
27 27
28// Assist: extract_struct_from_enum_variant 28// Assist: extract_struct_from_enum_variant
29// 29//
@@ -75,11 +75,10 @@ pub(crate) fn extract_struct_from_enum_variant(
75 continue; 75 continue;
76 } 76 }
77 builder.edit_file(file_id); 77 builder.edit_file(file_id);
78 let source_file = builder.make_mut(ctx.sema.parse(file_id));
79 let processed = process_references( 78 let processed = process_references(
80 ctx, 79 ctx,
80 builder,
81 &mut visited_modules_set, 81 &mut visited_modules_set,
82 source_file.syntax(),
83 &enum_module_def, 82 &enum_module_def,
84 &variant_hir_name, 83 &variant_hir_name,
85 references, 84 references,
@@ -89,13 +88,12 @@ pub(crate) fn extract_struct_from_enum_variant(
89 }); 88 });
90 } 89 }
91 builder.edit_file(ctx.frange.file_id); 90 builder.edit_file(ctx.frange.file_id);
92 let source_file = builder.make_mut(ctx.sema.parse(ctx.frange.file_id));
93 let variant = builder.make_mut(variant.clone()); 91 let variant = builder.make_mut(variant.clone());
94 if let Some(references) = def_file_references { 92 if let Some(references) = def_file_references {
95 let processed = process_references( 93 let processed = process_references(
96 ctx, 94 ctx,
95 builder,
97 &mut visited_modules_set, 96 &mut visited_modules_set,
98 source_file.syntax(),
99 &enum_module_def, 97 &enum_module_def,
100 &variant_hir_name, 98 &variant_hir_name,
101 references, 99 references,
@@ -248,8 +246,8 @@ fn apply_references(
248 246
249fn process_references( 247fn process_references(
250 ctx: &AssistContext, 248 ctx: &AssistContext,
249 builder: &mut AssistBuilder,
251 visited_modules: &mut FxHashSet<Module>, 250 visited_modules: &mut FxHashSet<Module>,
252 source_file: &SyntaxNode,
253 enum_module_def: &ModuleDef, 251 enum_module_def: &ModuleDef,
254 variant_hir_name: &Name, 252 variant_hir_name: &Name,
255 refs: Vec<FileReference>, 253 refs: Vec<FileReference>,
@@ -258,8 +256,9 @@ fn process_references(
258 // and corresponding nodes up front 256 // and corresponding nodes up front
259 refs.into_iter() 257 refs.into_iter()
260 .flat_map(|reference| { 258 .flat_map(|reference| {
261 let (segment, scope_node, module) = 259 let (segment, scope_node, module) = reference_to_node(&ctx.sema, reference)?;
262 reference_to_node(&ctx.sema, source_file, reference)?; 260 let segment = builder.make_mut(segment);
261 let scope_node = builder.make_syntax_mut(scope_node);
263 if !visited_modules.contains(&module) { 262 if !visited_modules.contains(&module) {
264 let mod_path = module.find_use_path_prefixed( 263 let mod_path = module.find_use_path_prefixed(
265 ctx.sema.db, 264 ctx.sema.db,
@@ -281,23 +280,22 @@ fn process_references(
281 280
282fn reference_to_node( 281fn reference_to_node(
283 sema: &hir::Semantics<RootDatabase>, 282 sema: &hir::Semantics<RootDatabase>,
284 source_file: &SyntaxNode,
285 reference: FileReference, 283 reference: FileReference,
286) -> Option<(ast::PathSegment, SyntaxNode, hir::Module)> { 284) -> Option<(ast::PathSegment, SyntaxNode, hir::Module)> {
287 let offset = reference.range.start(); 285 let segment =
288 if let Some(path_expr) = find_node_at_offset::<ast::PathExpr>(source_file, offset) { 286 reference.name.as_name_ref()?.syntax().parent().and_then(ast::PathSegment::cast)?;
289 // tuple variant 287 let parent = segment.parent_path().syntax().parent()?;
290 Some((path_expr.path()?.segment()?, path_expr.syntax().parent()?)) 288 let expr_or_pat = match_ast! {
291 } else if let Some(record_expr) = find_node_at_offset::<ast::RecordExpr>(source_file, offset) { 289 match parent {
292 // record variant 290 ast::PathExpr(_it) => parent.parent()?,
293 Some((record_expr.path()?.segment()?, record_expr.syntax().clone())) 291 ast::RecordExpr(_it) => parent,
294 } else { 292 ast::TupleStructPat(_it) => parent,
295 None 293 ast::RecordPat(_it) => parent,
296 } 294 _ => return None,
297 .and_then(|(segment, expr)| { 295 }
298 let module = sema.scope(&expr).module()?; 296 };
299 Some((segment, expr, module)) 297 let module = sema.scope(&expr_or_pat).module()?;
300 }) 298 Some((segment, expr_or_pat, module))
301} 299}
302 300
303#[cfg(test)] 301#[cfg(test)]
@@ -558,7 +556,7 @@ enum E {
558} 556}
559 557
560fn f() { 558fn f() {
561 let e = E::V { i: 9, j: 2 }; 559 let E::V { i, j } = E::V { i: 9, j: 2 };
562} 560}
563"#, 561"#,
564 r#" 562 r#"
@@ -569,7 +567,34 @@ enum E {
569} 567}
570 568
571fn f() { 569fn f() {
572 let e = E::V(V { i: 9, j: 2 }); 570 let E::V(V { i, j }) = E::V(V { i: 9, j: 2 });
571}
572"#,
573 )
574 }
575
576 #[test]
577 fn extract_record_fix_references2() {
578 check_assist(
579 extract_struct_from_enum_variant,
580 r#"
581enum E {
582 $0V(i32, i32)
583}
584
585fn f() {
586 let E::V(i, j) = E::V(9, 2);
587}
588"#,
589 r#"
590struct V(pub i32, pub i32);
591
592enum E {
593 V(V)
594}
595
596fn f() {
597 let E::V(V(i, j)) = E::V(V(9, 2));
573} 598}
574"#, 599"#,
575 ) 600 )