aboutsummaryrefslogtreecommitdiff
path: root/crates/assists/src/handlers/remove_unused_param.rs
diff options
context:
space:
mode:
authorZac Pullar-Strecker <[email protected]>2020-08-24 10:19:53 +0100
committerZac Pullar-Strecker <[email protected]>2020-08-24 10:20:13 +0100
commit7bbca7a1b3f9293d2f5cc5745199bc5f8396f2f0 (patch)
treebdb47765991cb973b2cd5481a088fac636bd326c /crates/assists/src/handlers/remove_unused_param.rs
parentca464650eeaca6195891199a93f4f76cf3e7e697 (diff)
parente65d48d1fb3d4d91d9dc1148a7a836ff5c9a3c87 (diff)
Merge remote-tracking branch 'upstream/master' into 503-hover-doc-links
Diffstat (limited to 'crates/assists/src/handlers/remove_unused_param.rs')
-rw-r--r--crates/assists/src/handlers/remove_unused_param.rs131
1 files changed, 131 insertions, 0 deletions
diff --git a/crates/assists/src/handlers/remove_unused_param.rs b/crates/assists/src/handlers/remove_unused_param.rs
new file mode 100644
index 000000000..5fccca54b
--- /dev/null
+++ b/crates/assists/src/handlers/remove_unused_param.rs
@@ -0,0 +1,131 @@
1use ide_db::{defs::Definition, search::Reference};
2use syntax::{
3 algo::find_node_at_range,
4 ast::{self, ArgListOwner},
5 AstNode, SyntaxNode, TextRange, T,
6};
7use test_utils::mark;
8
9use crate::{
10 assist_context::AssistBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, Assists,
11};
12
13// Assist: remove_unused_param
14//
15// Removes unused function parameter.
16//
17// ```
18// fn frobnicate(x: i32<|>) {}
19//
20// fn main() {
21// frobnicate(92);
22// }
23// ```
24// ->
25// ```
26// fn frobnicate() {}
27//
28// fn main() {
29// frobnicate();
30// }
31// ```
32pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
33 let param: ast::Param = ctx.find_node_at_offset()?;
34 let ident_pat = match param.pat()? {
35 ast::Pat::IdentPat(it) => it,
36 _ => return None,
37 };
38 let func = param.syntax().ancestors().find_map(ast::Fn::cast)?;
39 let param_position = func.param_list()?.params().position(|it| it == param)?;
40
41 let fn_def = {
42 let func = ctx.sema.to_def(&func)?;
43 Definition::ModuleDef(func.into())
44 };
45
46 let param_def = {
47 let local = ctx.sema.to_def(&ident_pat)?;
48 Definition::Local(local)
49 };
50 if param_def.usages(&ctx.sema).at_least_one() {
51 mark::hit!(keep_used);
52 return None;
53 }
54 acc.add(
55 AssistId("remove_unused_param", AssistKind::Refactor),
56 "Remove unused parameter",
57 param.syntax().text_range(),
58 |builder| {
59 builder.delete(range_with_coma(param.syntax()));
60 for usage in fn_def.usages(&ctx.sema).all() {
61 process_usage(ctx, builder, usage, param_position);
62 }
63 },
64 )
65}
66
67fn process_usage(
68 ctx: &AssistContext,
69 builder: &mut AssistBuilder,
70 usage: Reference,
71 arg_to_remove: usize,
72) -> Option<()> {
73 let source_file = ctx.sema.parse(usage.file_range.file_id);
74 let call_expr: ast::CallExpr =
75 find_node_at_range(source_file.syntax(), usage.file_range.range)?;
76 if call_expr.expr()?.syntax().text_range() != usage.file_range.range {
77 return None;
78 }
79 let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?;
80
81 builder.edit_file(usage.file_range.file_id);
82 builder.delete(range_with_coma(arg.syntax()));
83
84 Some(())
85}
86
87fn range_with_coma(node: &SyntaxNode) -> TextRange {
88 let up_to = next_prev().find_map(|dir| {
89 node.siblings_with_tokens(dir)
90 .filter_map(|it| it.into_token())
91 .find(|it| it.kind() == T![,])
92 });
93 let up_to = up_to.map_or(node.text_range(), |it| it.text_range());
94 node.text_range().cover(up_to)
95}
96
97#[cfg(test)]
98mod tests {
99 use crate::tests::{check_assist, check_assist_not_applicable};
100
101 use super::*;
102
103 #[test]
104 fn remove_unused() {
105 check_assist(
106 remove_unused_param,
107 r#"
108fn a() { foo(9, 2) }
109fn foo(x: i32, <|>y: i32) { x; }
110fn b() { foo(9, 2,) }
111"#,
112 r#"
113fn a() { foo(9) }
114fn foo(x: i32) { x; }
115fn b() { foo(9, ) }
116"#,
117 );
118 }
119
120 #[test]
121 fn keep_used() {
122 mark::check!(keep_used);
123 check_assist_not_applicable(
124 remove_unused_param,
125 r#"
126fn foo(x: i32, <|>y: i32) { y; }
127fn main() { foo(9, 2) }
128"#,
129 );
130 }
131}