Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 829e777

Browse files
committed
Auto merge of rust-lang#15524 - vsrs:bind_unused_param, r=Veykril
Bind unused parameter assistant This PR introduces a new **Bind unused parameter assistant**. While we do have a QuickFix from `rustc` (prefixing the parameter with an underscore), it's sometimes more convenient to suppress the warning using the following approach: ```rust fn some_function(unused: i32) {} ``` -> ```rust fn some_function(unused: i32) { let _ = unused; } ```
2 parents 3325622 + 1eb6d2e commit 829e777

File tree

3 files changed

+176
-0
lines changed

3 files changed

+176
-0
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
use crate::assist_context::{AssistContext, Assists};
2+
use ide_db::{
3+
assists::{AssistId, AssistKind},
4+
defs::Definition,
5+
LineIndexDatabase,
6+
};
7+
use syntax::{
8+
ast::{self, edit_in_place::Indent},
9+
AstNode,
10+
};
11+
12+
// Assist: bind_unused_param
13+
//
14+
// Binds unused function parameter to an underscore.
15+
//
16+
// ```
17+
// fn some_function(x: i32$0) {}
18+
// ```
19+
// ->
20+
// ```
21+
// fn some_function(x: i32) {
22+
// let _ = x;
23+
// }
24+
// ```
25+
pub(crate) fn bind_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
26+
let param: ast::Param = ctx.find_node_at_offset()?;
27+
28+
let Some(ast::Pat::IdentPat(ident_pat)) = param.pat() else { return None };
29+
30+
let param_def = {
31+
let local = ctx.sema.to_def(&ident_pat)?;
32+
Definition::Local(local)
33+
};
34+
if param_def.usages(&ctx.sema).at_least_one() {
35+
cov_mark::hit!(keep_used);
36+
return None;
37+
}
38+
39+
let func = param.syntax().ancestors().find_map(ast::Fn::cast)?;
40+
let stmt_list = func.body()?.stmt_list()?;
41+
let l_curly_range = stmt_list.l_curly_token()?.text_range();
42+
let r_curly_range = stmt_list.r_curly_token()?.text_range();
43+
44+
acc.add(
45+
AssistId("bind_unused_param", AssistKind::QuickFix),
46+
&format!("Bind as `let _ = {};`", &ident_pat),
47+
param.syntax().text_range(),
48+
|builder| {
49+
let line_index = ctx.db().line_index(ctx.file_id());
50+
51+
let indent = func.indent_level();
52+
let text_indent = indent + 1;
53+
let mut text = format!("\n{text_indent}let _ = {ident_pat};");
54+
55+
let left_line = line_index.line_col(l_curly_range.end()).line;
56+
let right_line = line_index.line_col(r_curly_range.start()).line;
57+
58+
if left_line == right_line {
59+
cov_mark::hit!(single_line);
60+
text.push_str(&format!("\n{indent}"));
61+
}
62+
63+
builder.insert(l_curly_range.end(), text);
64+
},
65+
)
66+
}
67+
68+
#[cfg(test)]
69+
mod tests {
70+
use crate::tests::{check_assist, check_assist_not_applicable};
71+
72+
use super::*;
73+
74+
#[test]
75+
fn bind_unused_empty_block() {
76+
cov_mark::check!(single_line);
77+
check_assist(
78+
bind_unused_param,
79+
r#"
80+
fn foo($0y: i32) {}
81+
"#,
82+
r#"
83+
fn foo(y: i32) {
84+
let _ = y;
85+
}
86+
"#,
87+
);
88+
}
89+
90+
#[test]
91+
fn bind_unused_empty_block_with_newline() {
92+
check_assist(
93+
bind_unused_param,
94+
r#"
95+
fn foo($0y: i32) {
96+
}
97+
"#,
98+
r#"
99+
fn foo(y: i32) {
100+
let _ = y;
101+
}
102+
"#,
103+
);
104+
}
105+
106+
#[test]
107+
fn bind_unused_generic() {
108+
check_assist(
109+
bind_unused_param,
110+
r#"
111+
fn foo<T>($0y: T)
112+
where T : Default {
113+
}
114+
"#,
115+
r#"
116+
fn foo<T>(y: T)
117+
where T : Default {
118+
let _ = y;
119+
}
120+
"#,
121+
);
122+
}
123+
124+
#[test]
125+
fn trait_impl() {
126+
check_assist(
127+
bind_unused_param,
128+
r#"
129+
trait Trait {
130+
fn foo(x: i32);
131+
}
132+
impl Trait for () {
133+
fn foo($0x: i32) {}
134+
}
135+
"#,
136+
r#"
137+
trait Trait {
138+
fn foo(x: i32);
139+
}
140+
impl Trait for () {
141+
fn foo(x: i32) {
142+
let _ = x;
143+
}
144+
}
145+
"#,
146+
);
147+
}
148+
149+
#[test]
150+
fn keep_used() {
151+
cov_mark::check!(keep_used);
152+
check_assist_not_applicable(
153+
bind_unused_param,
154+
r#"
155+
fn foo(x: i32, $0y: i32) { y; }
156+
"#,
157+
);
158+
}
159+
}

crates/ide-assists/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ mod handlers {
114114
mod add_turbo_fish;
115115
mod apply_demorgan;
116116
mod auto_import;
117+
mod bind_unused_param;
117118
mod change_visibility;
118119
mod convert_bool_then;
119120
mod convert_comment_block;
@@ -225,6 +226,7 @@ mod handlers {
225226
add_turbo_fish::add_turbo_fish,
226227
apply_demorgan::apply_demorgan,
227228
auto_import::auto_import,
229+
bind_unused_param::bind_unused_param,
228230
change_visibility::change_visibility,
229231
convert_bool_then::convert_bool_then_to_if,
230232
convert_bool_then::convert_if_to_bool_then,

crates/ide-assists/src/tests/generated.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,21 @@ pub mod std { pub mod collections { pub struct HashMap { } } }
265265
)
266266
}
267267

268+
#[test]
269+
fn doctest_bind_unused_param() {
270+
check_doc_test(
271+
"bind_unused_param",
272+
r#####"
273+
fn some_function(x: i32$0) {}
274+
"#####,
275+
r#####"
276+
fn some_function(x: i32) {
277+
let _ = x;
278+
}
279+
"#####,
280+
)
281+
}
282+
268283
#[test]
269284
fn doctest_change_visibility() {
270285
check_doc_test(

0 commit comments

Comments
 (0)