6514: Fix extract_struct_from_enum_variant not updating record references r=Veykril a=Veykril

Related to #6510

Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
bors[bot] 2020-11-12 17:48:25 +00:00 committed by GitHub
commit cf73b6851b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -5,10 +5,9 @@ use hir::{AsName, EnumVariant, Module, ModuleDef, Name};
use ide_db::{defs::Definition, search::Reference, RootDatabase};
use rustc_hash::{FxHashMap, FxHashSet};
use syntax::{
algo::find_node_at_offset,
algo::SyntaxRewriter,
ast::{self, edit::IndentLevel, make, ArgListOwner, AstNode, NameOwner, VisibilityOwner},
SourceFile, SyntaxElement,
algo::{find_node_at_offset, SyntaxRewriter},
ast::{self, edit::IndentLevel, make, AstNode, NameOwner, VisibilityOwner},
SourceFile, SyntaxElement, SyntaxNode, T,
};
use crate::{
@ -130,17 +129,21 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &En
fn insert_import(
ctx: &AssistContext,
rewriter: &mut SyntaxRewriter,
path: &ast::PathExpr,
scope_node: &SyntaxNode,
module: &Module,
enum_module_def: &ModuleDef,
variant_hir_name: &Name,
) -> Option<()> {
let db = ctx.db();
let mod_path = module.find_use_path(db, enum_module_def.clone());
let mod_path = module.find_use_path_prefixed(
db,
enum_module_def.clone(),
ctx.config.insert_use.prefix_kind,
);
if let Some(mut mod_path) = mod_path {
mod_path.segments.pop();
mod_path.segments.push(variant_hir_name.clone());
let scope = ImportScope::find_insert_use_container(path.syntax(), ctx)?;
let scope = ImportScope::find_insert_use_container(scope_node, ctx)?;
*rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use.merge);
}
@ -204,27 +207,31 @@ fn update_reference(
variant_hir_name: &Name,
visited_modules_set: &mut FxHashSet<Module>,
) -> Option<()> {
let path_expr: ast::PathExpr = find_node_at_offset::<ast::PathExpr>(
source_file.syntax(),
reference.file_range.range.start(),
)?;
let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?;
let list = call.arg_list()?;
let segment = path_expr.path()?.segment()?;
let module = ctx.sema.scope(&path_expr.syntax()).module()?;
let offset = reference.file_range.range.start();
let (segment, expr) = if let Some(path_expr) =
find_node_at_offset::<ast::PathExpr>(source_file.syntax(), offset)
{
// tuple variant
(path_expr.path()?.segment()?, path_expr.syntax().parent()?.clone())
} else if let Some(record_expr) =
find_node_at_offset::<ast::RecordExpr>(source_file.syntax(), offset)
{
// record variant
(record_expr.path()?.segment()?, record_expr.syntax().clone())
} else {
return None;
};
let module = ctx.sema.scope(&expr).module()?;
if !visited_modules_set.contains(&module) {
if insert_import(ctx, rewriter, &path_expr, &module, enum_module_def, variant_hir_name)
.is_some()
if insert_import(ctx, rewriter, &expr, &module, enum_module_def, variant_hir_name).is_some()
{
visited_modules_set.insert(module);
}
}
let lparen = syntax::SyntaxElement::from(list.l_paren_token()?);
let rparen = syntax::SyntaxElement::from(list.r_paren_token()?);
rewriter.insert_after(&lparen, segment.syntax());
rewriter.insert_after(&lparen, &lparen);
rewriter.insert_before(&rparen, &rparen);
rewriter.insert_after(segment.syntax(), &make::token(T!['(']));
rewriter.insert_after(segment.syntax(), segment.syntax());
rewriter.insert_after(&expr, &make::token(T![')']));
Some(())
}
@ -320,7 +327,7 @@ fn another_fn() {
r#"use my_mod::my_other_mod::MyField;
mod my_mod {
use my_other_mod::MyField;
use self::my_other_mod::MyField;
fn another_fn() {
let m = my_other_mod::MyEnum::MyField(MyField(1, 1));
@ -345,6 +352,33 @@ fn another_fn() {
);
}
#[test]
fn extract_record_fix_references() {
check_assist(
extract_struct_from_enum_variant,
r#"
enum E {
<|>V { i: i32, j: i32 }
}
fn f() {
let e = E::V { i: 9, j: 2 };
}
"#,
r#"
struct V{ pub i: i32, pub j: i32 }
enum E {
V(V)
}
fn f() {
let e = E::V(V { i: 9, j: 2 });
}
"#,
)
}
#[test]
fn test_several_files() {
check_assist(
@ -372,9 +406,7 @@ enum E {
mod foo;
//- /foo.rs
use V;
use crate::E;
use crate::{E, V};
fn f() {
let e = E::V(V(9, 2));
}
@ -384,7 +416,6 @@ fn f() {
#[test]
fn test_several_files_record() {
// FIXME: this should fix the usage as well!
check_assist(
extract_struct_from_enum_variant,
r#"
@ -401,6 +432,7 @@ fn f() {
}
"#,
r#"
//- /main.rs
struct V{ pub i: i32, pub j: i32 }
enum E {
@ -408,10 +440,42 @@ enum E {
}
mod foo;
//- /foo.rs
use crate::{E, V};
fn f() {
let e = E::V(V { i: 9, j: 2 });
}
"#,
)
}
#[test]
fn test_extract_struct_record_nested_call_exp() {
check_assist(
extract_struct_from_enum_variant,
r#"
enum A { <|>One { a: u32, b: u32 } }
struct B(A);
fn foo() {
let _ = B(A::One { a: 1, b: 2 });
}
"#,
r#"
struct One{ pub a: u32, pub b: u32 }
enum A { One(One) }
struct B(A);
fn foo() {
let _ = B(A::One(One { a: 1, b: 2 }));
}
"#,
);
}
fn check_not_applicable(ra_fixture: &str) {
let fixture =
format!("//- /main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);