|
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