Skip to content

Commit 2f0814e

Browse files
committed
Auto merge of rust-lang#12347 - feniljain:fix_extract_module, r=Veykril
fix(extract_module) resolving import panics and improve import resolution - Should solve rust-lang#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::x::Bar; use super::x::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
2 parents 6f7c558 + 8a1ef52 commit 2f0814e

File tree

1 file changed

+92
-6
lines changed

1 file changed

+92
-6
lines changed

crates/ide-assists/src/handlers/extract_module.rs

+92-6
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,10 @@ impl Module {
413413
ctx,
414414
)
415415
{
416-
import_paths_to_be_removed.push(import_path);
416+
check_intersection_and_push(
417+
&mut import_paths_to_be_removed,
418+
import_path,
419+
);
417420
}
418421
}
419422
}
@@ -439,7 +442,10 @@ impl Module {
439442
ctx,
440443
)
441444
{
442-
import_paths_to_be_removed.push(import_path);
445+
check_intersection_and_push(
446+
&mut import_paths_to_be_removed,
447+
import_path,
448+
);
443449
}
444450
}
445451
}
@@ -543,12 +549,25 @@ impl Module {
543549
} else if exists_inside_sel && !exists_outside_sel {
544550
//Changes to be made inside new module, and remove import from outside
545551

546-
if let Some((use_tree_str, text_range_opt)) =
552+
if let Some((mut use_tree_str, text_range_opt)) =
547553
self.process_use_stmt_for_import_resolve(use_stmt_opt, node_syntax)
548554
{
549555
if let Some(text_range) = text_range_opt {
550556
import_path_to_be_removed = Some(text_range);
551557
}
558+
559+
if source_exists_outside_sel_in_same_mod {
560+
if let Some(first_path_in_use_tree) = use_tree_str.last() {
561+
let first_path_in_use_tree_str = first_path_in_use_tree.to_string();
562+
if !first_path_in_use_tree_str.contains("super")
563+
&& !first_path_in_use_tree_str.contains("crate")
564+
{
565+
let super_path = make::ext::ident_path("super");
566+
use_tree_str.push(super_path);
567+
}
568+
}
569+
}
570+
552571
use_tree_str_opt = Some(use_tree_str);
553572
} else if source_exists_outside_sel_in_same_mod {
554573
self.make_use_stmt_of_node_with_super(node_syntax);
@@ -558,9 +577,16 @@ impl Module {
558577
if let Some(use_tree_str) = use_tree_str_opt {
559578
let mut use_tree_str = use_tree_str;
560579
use_tree_str.reverse();
561-
if use_tree_str[0].to_string().contains("super") {
562-
let super_path = make::ext::ident_path("super");
563-
use_tree_str.insert(0, super_path)
580+
581+
if !(!exists_outside_sel && exists_inside_sel && source_exists_outside_sel_in_same_mod)
582+
{
583+
if let Some(first_path_in_use_tree) = use_tree_str.first() {
584+
let first_path_in_use_tree_str = first_path_in_use_tree.to_string();
585+
if first_path_in_use_tree_str.contains("super") {
586+
let super_path = make::ext::ident_path("super");
587+
use_tree_str.insert(0, super_path)
588+
}
589+
}
564590
}
565591

566592
let use_ =
@@ -621,6 +647,32 @@ impl Module {
621647
}
622648
}
623649

650+
fn check_intersection_and_push(
651+
import_paths_to_be_removed: &mut Vec<TextRange>,
652+
import_path: TextRange,
653+
) {
654+
if import_paths_to_be_removed.len() > 0 {
655+
// Text ranges recieved here for imports are extended to the
656+
// next/previous comma which can cause intersections among them
657+
// and later deletion of these can cause panics similar
658+
// to reported in #11766. So to mitigate it, we
659+
// check for intersection between all current members
660+
// and if it exists we combine both text ranges into
661+
// one
662+
let r = import_paths_to_be_removed
663+
.into_iter()
664+
.position(|it| it.intersect(import_path).is_some());
665+
match r {
666+
Some(it) => {
667+
import_paths_to_be_removed[it] = import_paths_to_be_removed[it].cover(import_path)
668+
}
669+
None => import_paths_to_be_removed.push(import_path),
670+
}
671+
} else {
672+
import_paths_to_be_removed.push(import_path);
673+
}
674+
}
675+
624676
fn does_source_exists_outside_sel_in_same_mod(
625677
def: Definition,
626678
ctx: &AssistContext,
@@ -1495,4 +1547,38 @@ mod modname {
14951547
",
14961548
)
14971549
}
1550+
1551+
#[test]
1552+
fn test_issue_11766() {
1553+
//https://github.com/rust-lang/rust-analyzer/issues/11766
1554+
check_assist(
1555+
extract_module,
1556+
r"
1557+
mod x {
1558+
pub struct Foo;
1559+
pub struct Bar;
1560+
}
1561+
1562+
use x::{Bar, Foo};
1563+
1564+
$0type A = (Foo, Bar);$0
1565+
",
1566+
r"
1567+
mod x {
1568+
pub struct Foo;
1569+
pub struct Bar;
1570+
}
1571+
1572+
use x::{};
1573+
1574+
mod modname {
1575+
use super::x::Bar;
1576+
1577+
use super::x::Foo;
1578+
1579+
pub(crate) type A = (Foo, Bar);
1580+
}
1581+
",
1582+
)
1583+
}
14981584
}

0 commit comments

Comments
 (0)