Auto merge of #12347 - feniljain:fix_extract_module, r=Veykril
fix(extract_module) resolving import panics and improve import resolution - Should solve #11766 - While adding a test case for this issue, I observed another issue: For this test case: ```rust mod x { pub struct Foo; pub struct Bar; } use x::{Bar, Foo}; $0type A = (Foo, Bar);$0 ``` extract module should yield this: ```rust mod x { pub struct Foo; pub struct Bar; } use x::{}; mod modname { use super:❌:Bar; use super:❌:Foo; pub(crate) type A = (Foo, Bar); } ``` instead it gave: ```rust mod x { pub struct Foo; pub struct Bar; } use x::{}; mod modname { use x::Bar; use x::Foo; pub(crate) type A = (Foo, Bar); } ``` So fixed this problem with second commit
This commit is contained in:
commit
2f0814ea35
@ -413,7 +413,10 @@ fn resolve_imports(
|
|||||||
ctx,
|
ctx,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
import_paths_to_be_removed.push(import_path);
|
check_intersection_and_push(
|
||||||
|
&mut import_paths_to_be_removed,
|
||||||
|
import_path,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -439,7 +442,10 @@ fn resolve_imports(
|
|||||||
ctx,
|
ctx,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
import_paths_to_be_removed.push(import_path);
|
check_intersection_and_push(
|
||||||
|
&mut import_paths_to_be_removed,
|
||||||
|
import_path,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -543,12 +549,25 @@ fn process_names_and_namerefs_for_import_resolve(
|
|||||||
} else if exists_inside_sel && !exists_outside_sel {
|
} else if exists_inside_sel && !exists_outside_sel {
|
||||||
//Changes to be made inside new module, and remove import from outside
|
//Changes to be made inside new module, and remove import from outside
|
||||||
|
|
||||||
if let Some((use_tree_str, text_range_opt)) =
|
if let Some((mut use_tree_str, text_range_opt)) =
|
||||||
self.process_use_stmt_for_import_resolve(use_stmt_opt, node_syntax)
|
self.process_use_stmt_for_import_resolve(use_stmt_opt, node_syntax)
|
||||||
{
|
{
|
||||||
if let Some(text_range) = text_range_opt {
|
if let Some(text_range) = text_range_opt {
|
||||||
import_path_to_be_removed = Some(text_range);
|
import_path_to_be_removed = Some(text_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if source_exists_outside_sel_in_same_mod {
|
||||||
|
if let Some(first_path_in_use_tree) = use_tree_str.last() {
|
||||||
|
let first_path_in_use_tree_str = first_path_in_use_tree.to_string();
|
||||||
|
if !first_path_in_use_tree_str.contains("super")
|
||||||
|
&& !first_path_in_use_tree_str.contains("crate")
|
||||||
|
{
|
||||||
|
let super_path = make::ext::ident_path("super");
|
||||||
|
use_tree_str.push(super_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
use_tree_str_opt = Some(use_tree_str);
|
use_tree_str_opt = Some(use_tree_str);
|
||||||
} else if source_exists_outside_sel_in_same_mod {
|
} else if source_exists_outside_sel_in_same_mod {
|
||||||
self.make_use_stmt_of_node_with_super(node_syntax);
|
self.make_use_stmt_of_node_with_super(node_syntax);
|
||||||
@ -558,10 +577,17 @@ fn process_names_and_namerefs_for_import_resolve(
|
|||||||
if let Some(use_tree_str) = use_tree_str_opt {
|
if let Some(use_tree_str) = use_tree_str_opt {
|
||||||
let mut use_tree_str = use_tree_str;
|
let mut use_tree_str = use_tree_str;
|
||||||
use_tree_str.reverse();
|
use_tree_str.reverse();
|
||||||
if use_tree_str[0].to_string().contains("super") {
|
|
||||||
|
if !(!exists_outside_sel && exists_inside_sel && source_exists_outside_sel_in_same_mod)
|
||||||
|
{
|
||||||
|
if let Some(first_path_in_use_tree) = use_tree_str.first() {
|
||||||
|
let first_path_in_use_tree_str = first_path_in_use_tree.to_string();
|
||||||
|
if first_path_in_use_tree_str.contains("super") {
|
||||||
let super_path = make::ext::ident_path("super");
|
let super_path = make::ext::ident_path("super");
|
||||||
use_tree_str.insert(0, super_path)
|
use_tree_str.insert(0, super_path)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let use_ =
|
let use_ =
|
||||||
make::use_(None, make::use_tree(make::join_paths(use_tree_str), None, None, false));
|
make::use_(None, make::use_tree(make::join_paths(use_tree_str), None, None, false));
|
||||||
@ -621,6 +647,32 @@ fn process_use_stmt_for_import_resolve(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_intersection_and_push(
|
||||||
|
import_paths_to_be_removed: &mut Vec<TextRange>,
|
||||||
|
import_path: TextRange,
|
||||||
|
) {
|
||||||
|
if import_paths_to_be_removed.len() > 0 {
|
||||||
|
// Text ranges recieved here for imports are extended to the
|
||||||
|
// next/previous comma which can cause intersections among them
|
||||||
|
// and later deletion of these can cause panics similar
|
||||||
|
// to reported in #11766. So to mitigate it, we
|
||||||
|
// check for intersection between all current members
|
||||||
|
// and if it exists we combine both text ranges into
|
||||||
|
// one
|
||||||
|
let r = import_paths_to_be_removed
|
||||||
|
.into_iter()
|
||||||
|
.position(|it| it.intersect(import_path).is_some());
|
||||||
|
match r {
|
||||||
|
Some(it) => {
|
||||||
|
import_paths_to_be_removed[it] = import_paths_to_be_removed[it].cover(import_path)
|
||||||
|
}
|
||||||
|
None => import_paths_to_be_removed.push(import_path),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
import_paths_to_be_removed.push(import_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn does_source_exists_outside_sel_in_same_mod(
|
fn does_source_exists_outside_sel_in_same_mod(
|
||||||
def: Definition,
|
def: Definition,
|
||||||
ctx: &AssistContext,
|
ctx: &AssistContext,
|
||||||
@ -1495,4 +1547,38 @@ pub(crate) fn foo(x: B) {}
|
|||||||
",
|
",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_issue_11766() {
|
||||||
|
//https://github.com/rust-lang/rust-analyzer/issues/11766
|
||||||
|
check_assist(
|
||||||
|
extract_module,
|
||||||
|
r"
|
||||||
|
mod x {
|
||||||
|
pub struct Foo;
|
||||||
|
pub struct Bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
use x::{Bar, Foo};
|
||||||
|
|
||||||
|
$0type A = (Foo, Bar);$0
|
||||||
|
",
|
||||||
|
r"
|
||||||
|
mod x {
|
||||||
|
pub struct Foo;
|
||||||
|
pub struct Bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
use x::{};
|
||||||
|
|
||||||
|
mod modname {
|
||||||
|
use super::x::Bar;
|
||||||
|
|
||||||
|
use super::x::Foo;
|
||||||
|
|
||||||
|
pub(crate) type A = (Foo, Bar);
|
||||||
|
}
|
||||||
|
",
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user