diff options
Diffstat (limited to 'crates/assists/src/handlers')
-rw-r--r-- | crates/assists/src/handlers/merge_imports.rs | 5 | ||||
-rw-r--r-- | crates/assists/src/handlers/remove_dbg.rs | 3 | ||||
-rw-r--r-- | crates/assists/src/handlers/remove_unused_param.rs | 131 |
3 files changed, 134 insertions, 5 deletions
diff --git a/crates/assists/src/handlers/merge_imports.rs b/crates/assists/src/handlers/merge_imports.rs index 47d465404..35b884206 100644 --- a/crates/assists/src/handlers/merge_imports.rs +++ b/crates/assists/src/handlers/merge_imports.rs | |||
@@ -8,6 +8,7 @@ use syntax::{ | |||
8 | 8 | ||
9 | use crate::{ | 9 | use crate::{ |
10 | assist_context::{AssistContext, Assists}, | 10 | assist_context::{AssistContext, Assists}, |
11 | utils::next_prev, | ||
11 | AssistId, AssistKind, | 12 | AssistId, AssistKind, |
12 | }; | 13 | }; |
13 | 14 | ||
@@ -66,10 +67,6 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext) -> Option<() | |||
66 | ) | 67 | ) |
67 | } | 68 | } |
68 | 69 | ||
69 | fn next_prev() -> impl Iterator<Item = Direction> { | ||
70 | [Direction::Next, Direction::Prev].iter().copied() | ||
71 | } | ||
72 | |||
73 | fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option<ast::UseTree> { | 70 | fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option<ast::UseTree> { |
74 | let lhs_path = old.path()?; | 71 | let lhs_path = old.path()?; |
75 | let rhs_path = new.path()?; | 72 | let rhs_path = new.path()?; |
diff --git a/crates/assists/src/handlers/remove_dbg.rs b/crates/assists/src/handlers/remove_dbg.rs index f3dcca534..4e252edf0 100644 --- a/crates/assists/src/handlers/remove_dbg.rs +++ b/crates/assists/src/handlers/remove_dbg.rs | |||
@@ -82,9 +82,10 @@ fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<b | |||
82 | 82 | ||
83 | #[cfg(test)] | 83 | #[cfg(test)] |
84 | mod tests { | 84 | mod tests { |
85 | use super::*; | ||
86 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; | 85 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
87 | 86 | ||
87 | use super::*; | ||
88 | |||
88 | #[test] | 89 | #[test] |
89 | fn test_remove_dbg() { | 90 | fn test_remove_dbg() { |
90 | check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1"); | 91 | check_assist(remove_dbg, "<|>dbg!(1 + 1)", "1 + 1"); |
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 @@ | |||
1 | use ide_db::{defs::Definition, search::Reference}; | ||
2 | use syntax::{ | ||
3 | algo::find_node_at_range, | ||
4 | ast::{self, ArgListOwner}, | ||
5 | AstNode, SyntaxNode, TextRange, T, | ||
6 | }; | ||
7 | use test_utils::mark; | ||
8 | |||
9 | use 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 | // ``` | ||
32 | pub(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 | |||
67 | fn 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 | |||
87 | fn 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)] | ||
98 | mod 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#" | ||
108 | fn a() { foo(9, 2) } | ||
109 | fn foo(x: i32, <|>y: i32) { x; } | ||
110 | fn b() { foo(9, 2,) } | ||
111 | "#, | ||
112 | r#" | ||
113 | fn a() { foo(9) } | ||
114 | fn foo(x: i32) { x; } | ||
115 | fn 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#" | ||
126 | fn foo(x: i32, <|>y: i32) { y; } | ||
127 | fn main() { foo(9, 2) } | ||
128 | "#, | ||
129 | ); | ||
130 | } | ||
131 | } | ||