Skip to content

Commit 215a077

Browse files
committed
Remove imports when inlining all calls in a file
1 parent 79c70d0 commit 215a077

File tree

2 files changed

+59
-22
lines changed

2 files changed

+59
-22
lines changed

crates/ide_assists/src/handlers/inline_call.rs

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
use ast::make;
2+
use either::Either;
23
use hir::{db::HirDatabase, HasSource, PathResolution, Semantics, TypeInfo};
34
use ide_db::{
45
base_db::{FileId, FileRange},
56
defs::Definition,
7+
helpers::insert_use::remove_path_if_in_use_stmt,
68
path_transform::PathTransform,
79
search::{FileReference, SearchScope},
810
RootDatabase,
911
};
10-
use itertools::izip;
12+
use itertools::{izip, Itertools};
1113
use syntax::{
1214
ast::{self, edit_in_place::Indent, ArgListOwner},
1315
ted, AstNode, SyntaxNode,
@@ -96,26 +98,45 @@ pub(crate) fn inline_into_callers(acc: &mut Assists, ctx: &AssistContext) -> Opt
9698
let mut inline_refs_for_file = |file_id, refs: Vec<FileReference>| {
9799
builder.edit_file(file_id);
98100
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)
105117
.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)| {
106125
let replacement =
107126
inline(&ctx.sema, def_file, function, &func_body, &params, &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());
116128
})
117129
.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+
}
119140
};
120141
for (file_id, refs) in usages.into_iter() {
121142
inline_refs_for_file(file_id, refs);
@@ -915,7 +936,10 @@ fn foo() {
915936
}
916937
"#,
917938
r#"
918-
use super::do_the_math;
939+
//- /lib.rs
940+
mod foo;
941+
942+
//- /foo.rs
919943
fn foo() {
920944
{
921945
let foo = 10;
@@ -954,18 +978,14 @@ fn foo() {
954978
r#"
955979
//- /lib.rs
956980
mod foo;
957-
fn do_the_math(b: u32) -> u32 {
958-
let foo = 10;
959-
foo * b + foo
960-
}
981+
961982
fn bar(a: u32, b: u32) -> u32 {
962983
{
963984
let foo = 10;
964985
foo * 0 + foo
965986
};
966987
}
967988
//- /foo.rs
968-
use super::do_the_math;
969989
fn foo() {
970990
{
971991
let foo = 10;

crates/ide_db/src/helpers/insert_use.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,23 @@ pub fn insert_use(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) {
220220
insert_use_(scope, &path, cfg.group, use_item);
221221
}
222222

223+
pub fn remove_path_if_in_use_stmt(path: &ast::Path) {
224+
// FIXME: improve this
225+
if path.parent_path().is_some() {
226+
return;
227+
}
228+
if let Some(use_tree) = path.syntax().parent().and_then(ast::UseTree::cast) {
229+
if use_tree.use_tree_list().is_some() || use_tree.star_token().is_some() {
230+
return;
231+
}
232+
if let Some(use_) = use_tree.syntax().parent().and_then(ast::Use::cast) {
233+
use_.remove();
234+
return;
235+
}
236+
use_tree.remove();
237+
}
238+
}
239+
223240
#[derive(Eq, PartialEq, PartialOrd, Ord)]
224241
enum ImportGroup {
225242
// the order here defines the order of new group inserts

0 commit comments

Comments
 (0)