mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-13 21:54:42 +00:00
Merge #6514
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:
commit
cf73b6851b
1 changed files with 92 additions and 28 deletions
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue