Merge #5821
5821: **Remove Unused Parameter** refactoring
r=matklad a=matklad
bors r+
🤖
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
bb07e6bdee
@ -8,6 +8,7 @@
|
||||
|
||||
use crate::{
|
||||
assist_context::{AssistContext, Assists},
|
||||
utils::next_prev,
|
||||
AssistId, AssistKind,
|
||||
};
|
||||
|
||||
@ -66,10 +67,6 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<()
|
||||
)
|
||||
}
|
||||
|
||||
fn next_prev() -> impl Iterator<Item = Direction> {
|
||||
[Direction::Next, Direction::Prev].iter().copied()
|
||||
}
|
||||
|
||||
fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option<ast::UseTree> {
|
||||
let lhs_path = old.path()?;
|
||||
let rhs_path = new.path()?;
|
||||
|
@ -82,9 +82,10 @@ fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<b
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_remove_dbg() {
|
||||
check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1");
|
||||
|
131
crates/assists/src/handlers/remove_unused_param.rs
Normal file
131
crates/assists/src/handlers/remove_unused_param.rs
Normal file
@ -0,0 +1,131 @@
|
||||
use ide_db::{defs::Definition, search::Reference};
|
||||
use syntax::{
|
||||
algo::find_node_at_range,
|
||||
ast::{self, ArgListOwner},
|
||||
AstNode, SyntaxNode, TextRange, T,
|
||||
};
|
||||
use test_utils::mark;
|
||||
|
||||
use crate::{
|
||||
assist_context::AssistBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, Assists,
|
||||
};
|
||||
|
||||
// Assist: remove_unused_param
|
||||
//
|
||||
// Removes unused function parameter.
|
||||
//
|
||||
// ```
|
||||
// fn frobnicate(x: i32<|>) {}
|
||||
//
|
||||
// fn main() {
|
||||
// frobnicate(92);
|
||||
// }
|
||||
// ```
|
||||
// ->
|
||||
// ```
|
||||
// fn frobnicate() {}
|
||||
//
|
||||
// fn main() {
|
||||
// frobnicate();
|
||||
// }
|
||||
// ```
|
||||
pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
|
||||
let param: ast::Param = ctx.find_node_at_offset()?;
|
||||
let ident_pat = match param.pat()? {
|
||||
ast::Pat::IdentPat(it) => it,
|
||||
_ => return None,
|
||||
};
|
||||
let func = param.syntax().ancestors().find_map(ast::Fn::cast)?;
|
||||
let param_position = func.param_list()?.params().position(|it| it == param)?;
|
||||
|
||||
let fn_def = {
|
||||
let func = ctx.sema.to_def(&func)?;
|
||||
Definition::ModuleDef(func.into())
|
||||
};
|
||||
|
||||
let param_def = {
|
||||
let local = ctx.sema.to_def(&ident_pat)?;
|
||||
Definition::Local(local)
|
||||
};
|
||||
if param_def.usages(&ctx.sema).at_least_one() {
|
||||
mark::hit!(keep_used);
|
||||
return None;
|
||||
}
|
||||
acc.add(
|
||||
AssistId("remove_unused_param", AssistKind::Refactor),
|
||||
"Remove unused parameter",
|
||||
param.syntax().text_range(),
|
||||
|builder| {
|
||||
builder.delete(range_with_coma(param.syntax()));
|
||||
for usage in fn_def.usages(&ctx.sema).all() {
|
||||
process_usage(ctx, builder, usage, param_position);
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn process_usage(
|
||||
ctx: &AssistContext,
|
||||
builder: &mut AssistBuilder,
|
||||
usage: Reference,
|
||||
arg_to_remove: usize,
|
||||
) -> Option<()> {
|
||||
let source_file = ctx.sema.parse(usage.file_range.file_id);
|
||||
let call_expr: ast::CallExpr =
|
||||
find_node_at_range(source_file.syntax(), usage.file_range.range)?;
|
||||
if call_expr.expr()?.syntax().text_range() != usage.file_range.range {
|
||||
return None;
|
||||
}
|
||||
let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?;
|
||||
|
||||
builder.edit_file(usage.file_range.file_id);
|
||||
builder.delete(range_with_coma(arg.syntax()));
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn range_with_coma(node: &SyntaxNode) -> TextRange {
|
||||
let up_to = next_prev().find_map(|dir| {
|
||||
node.siblings_with_tokens(dir)
|
||||
.filter_map(|it| it.into_token())
|
||||
.find(|it| it.kind() == T![,])
|
||||
});
|
||||
let up_to = up_to.map_or(node.text_range(), |it| it.text_range());
|
||||
node.text_range().cover(up_to)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::tests::{check_assist, check_assist_not_applicable};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn remove_unused() {
|
||||
check_assist(
|
||||
remove_unused_param,
|
||||
r#"
|
||||
fn a() { foo(9, 2) }
|
||||
fn foo(x: i32, <|>y: i32) { x; }
|
||||
fn b() { foo(9, 2,) }
|
||||
"#,
|
||||
r#"
|
||||
fn a() { foo(9) }
|
||||
fn foo(x: i32) { x; }
|
||||
fn b() { foo(9, ) }
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keep_used() {
|
||||
mark::check!(keep_used);
|
||||
check_assist_not_applicable(
|
||||
remove_unused_param,
|
||||
r#"
|
||||
fn foo(x: i32, <|>y: i32) { y; }
|
||||
fn main() { foo(9, 2) }
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
@ -152,6 +152,7 @@ mod handlers {
|
||||
mod raw_string;
|
||||
mod remove_dbg;
|
||||
mod remove_mut;
|
||||
mod remove_unused_param;
|
||||
mod reorder_fields;
|
||||
mod replace_if_let_with_match;
|
||||
mod replace_let_with_if_let;
|
||||
@ -198,6 +199,7 @@ pub(crate) fn all() -> &'static [Handler] {
|
||||
raw_string::remove_hash,
|
||||
remove_dbg::remove_dbg,
|
||||
remove_mut::remove_mut,
|
||||
remove_unused_param::remove_unused_param,
|
||||
reorder_fields::reorder_fields,
|
||||
replace_if_let_with_match::replace_if_let_with_match,
|
||||
replace_let_with_if_let::replace_let_with_if_let,
|
||||
|
@ -750,6 +750,27 @@ fn feed(&self, amount: u32) {}
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_remove_unused_param() {
|
||||
check_doc_test(
|
||||
"remove_unused_param",
|
||||
r#####"
|
||||
fn frobnicate(x: i32<|>) {}
|
||||
|
||||
fn main() {
|
||||
frobnicate(92);
|
||||
}
|
||||
"#####,
|
||||
r#####"
|
||||
fn frobnicate() {}
|
||||
|
||||
fn main() {
|
||||
frobnicate();
|
||||
}
|
||||
"#####,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_reorder_fields() {
|
||||
check_doc_test(
|
||||
|
@ -9,7 +9,7 @@
|
||||
use rustc_hash::FxHashSet;
|
||||
use syntax::{
|
||||
ast::{self, make, NameOwner},
|
||||
AstNode,
|
||||
AstNode, Direction,
|
||||
SyntaxKind::*,
|
||||
SyntaxNode, TextSize, T,
|
||||
};
|
||||
@ -311,3 +311,7 @@ fn find_def(&self, path: &str) -> Option<ScopeDef> {
|
||||
Some(def)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn next_prev() -> impl Iterator<Item = Direction> {
|
||||
[Direction::Next, Direction::Prev].iter().copied()
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ pub fn set_scope(mut self, scope: Option<SearchScope>) -> FindUsages<'a> {
|
||||
}
|
||||
|
||||
pub fn at_least_one(self) -> bool {
|
||||
self.all().is_empty()
|
||||
!self.all().is_empty()
|
||||
}
|
||||
|
||||
pub fn all(self) -> Vec<Reference> {
|
||||
|
Loading…
Reference in New Issue
Block a user