|
1 | 1 | use ast::make;
|
| 2 | +use either::Either; |
2 | 3 | use hir::{db::HirDatabase, HasSource, PathResolution, Semantics, TypeInfo};
|
3 | 4 | use ide_db::{
|
4 | 5 | base_db::{FileId, FileRange},
|
5 | 6 | defs::Definition,
|
| 7 | + helpers::insert_use::remove_path_if_in_use_stmt, |
6 | 8 | path_transform::PathTransform,
|
7 | 9 | search::{FileReference, SearchScope},
|
8 | 10 | RootDatabase,
|
9 | 11 | };
|
10 |
| -use itertools::izip; |
| 12 | +use itertools::{izip, Itertools}; |
11 | 13 | use syntax::{
|
12 | 14 | ast::{self, edit_in_place::Indent, ArgListOwner},
|
13 | 15 | ted, AstNode, SyntaxNode,
|
@@ -96,26 +98,45 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext) -> Opt
|
96 | 98 | let mut inline_refs_for_file = |file_id, refs: Vec<FileReference>| {
|
97 | 99 | builder.edit_file(file_id);
|
98 | 100 | let count = refs.len();
|
99 |
| - let name_refs = refs.into_iter().filter_map(|file_ref| match file_ref.name { |
100 |
| - ast::NameLike::NameRef(name_ref) => Some(name_ref), |
101 |
| - _ => None, |
102 |
| - }); |
103 |
| - let call_infos = name_refs.filter_map(CallInfo::from_name_ref); |
104 |
| - let replaced = call_infos |
| 101 | + // The collects are required as we are otherwise iterating while mutating 🙅♀️🙅♂️ |
| 102 | + let (name_refs, name_refs_use): (Vec<_>, Vec<_>) = refs |
| 103 | + .into_iter() |
| 104 | + .filter_map(|file_ref| match file_ref.name { |
| 105 | + ast::NameLike::NameRef(name_ref) => Some(name_ref), |
| 106 | + _ => None, |
| 107 | + }) |
| 108 | + .partition_map(|name_ref| { |
| 109 | + match name_ref.syntax().ancestors().find_map(ast::UseTree::cast) { |
| 110 | + Some(use_tree) => Either::Right(builder.make_mut(use_tree)), |
| 111 | + None => Either::Left(name_ref), |
| 112 | + } |
| 113 | + }); |
| 114 | + let call_infos: Vec<_> = name_refs |
| 115 | + .into_iter() |
| 116 | + .filter_map(CallInfo::from_name_ref) |
105 | 117 | .map(|call_info| {
|
| 118 | + let mut_node = builder.make_syntax_mut(call_info.node.syntax().clone()); |
| 119 | + (call_info, mut_node) |
| 120 | + }) |
| 121 | + .collect(); |
| 122 | + let replaced = call_infos |
| 123 | + .into_iter() |
| 124 | + .map(|(call_info, mut_node)| { |
106 | 125 | let replacement =
|
107 | 126 | inline(&ctx.sema, def_file, function, &func_body, ¶ms, &call_info);
|
108 |
| - |
109 |
| - builder.replace_ast( |
110 |
| - match call_info.node { |
111 |
| - CallExprNode::Call(it) => ast::Expr::CallExpr(it), |
112 |
| - CallExprNode::MethodCallExpr(it) => ast::Expr::MethodCallExpr(it), |
113 |
| - }, |
114 |
| - replacement, |
115 |
| - ); |
| 127 | + ted::replace(mut_node, replacement.syntax()); |
116 | 128 | })
|
117 | 129 | .count();
|
118 |
| - remove_def &= replaced == count; |
| 130 | + if replaced + name_refs_use.len() == count { |
| 131 | + // we replaced all usages in this file, so we can remove the imports |
| 132 | + name_refs_use.into_iter().for_each(|use_tree| { |
| 133 | + if let Some(path) = use_tree.path() { |
| 134 | + remove_path_if_in_use_stmt(&path); |
| 135 | + } |
| 136 | + }) |
| 137 | + } else { |
| 138 | + remove_def = false; |
| 139 | + } |
119 | 140 | };
|
120 | 141 | for (file_id, refs) in usages.into_iter() {
|
121 | 142 | inline_refs_for_file(file_id, refs);
|
@@ -915,7 +936,10 @@ fn foo() {
|
915 | 936 | }
|
916 | 937 | "#,
|
917 | 938 | r#"
|
918 |
| -use super::do_the_math; |
| 939 | +//- /lib.rs |
| 940 | +mod foo; |
| 941 | +
|
| 942 | +//- /foo.rs |
919 | 943 | fn foo() {
|
920 | 944 | {
|
921 | 945 | let foo = 10;
|
@@ -954,18 +978,14 @@ fn foo() {
|
954 | 978 | r#"
|
955 | 979 | //- /lib.rs
|
956 | 980 | mod foo;
|
957 |
| -fn do_the_math(b: u32) -> u32 { |
958 |
| - let foo = 10; |
959 |
| - foo * b + foo |
960 |
| -} |
| 981 | +
|
961 | 982 | fn bar(a: u32, b: u32) -> u32 {
|
962 | 983 | {
|
963 | 984 | let foo = 10;
|
964 | 985 | foo * 0 + foo
|
965 | 986 | };
|
966 | 987 | }
|
967 | 988 | //- /foo.rs
|
968 |
| -use super::do_the_math; |
969 | 989 | fn foo() {
|
970 | 990 | {
|
971 | 991 | let foo = 10;
|
|
0 commit comments