diff options
Diffstat (limited to 'crates/assists/src/handlers')
-rw-r--r-- | crates/assists/src/handlers/extract_struct_from_enum_variant.rs | 85 |
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}; | |||
5 | use ide_db::{defs::Definition, search::Reference, RootDatabase}; | 5 | use ide_db::{defs::Definition, search::Reference, RootDatabase}; |
6 | use rustc_hash::{FxHashMap, FxHashSet}; | 6 | use rustc_hash::{FxHashMap, FxHashSet}; |
7 | use syntax::{ | 7 | use 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 | ||
14 | use crate::{ | 13 | use crate::{ |
@@ -130,17 +129,17 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &En | |||
130 | fn insert_import( | 129 | fn 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#" | ||
356 | enum E { | ||
357 | <|>V { i: i32, j: i32 } | ||
358 | } | ||
359 | |||
360 | fn f() { | ||
361 | let e = E::V { i: 9, j: 2 }; | ||
362 | } | ||
363 | "#, | ||
364 | r#" | ||
365 | struct V{ pub i: i32, pub j: i32 } | ||
366 | |||
367 | enum E { | ||
368 | V(V) | ||
369 | } | ||
370 | |||
371 | fn 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 { | |||
372 | mod foo; | 402 | mod foo; |
373 | 403 | ||
374 | //- /foo.rs | 404 | //- /foo.rs |
375 | use V; | ||
376 | |||
377 | use crate::E; | 405 | use crate::E; |
378 | fn f() { | 406 | fn 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 | ||
404 | struct V{ pub i: i32, pub j: i32 } | 432 | struct V{ pub i: i32, pub j: i32 } |
405 | 433 | ||
406 | enum E { | 434 | enum E { |
@@ -408,6 +436,11 @@ enum E { | |||
408 | } | 436 | } |
409 | mod foo; | 437 | mod foo; |
410 | 438 | ||
439 | //- /foo.rs | ||
440 | use crate::E; | ||
441 | fn f() { | ||
442 | let e = E::V(V { i: 9, j: 2 }); | ||
443 | } | ||
411 | "#, | 444 | "#, |
412 | ) | 445 | ) |
413 | } | 446 | } |