rust/crates/ide-assists/src/handlers/bind_unused_param.rs

160 lines
3.2 KiB
Rust
Raw Normal View History

2023-08-28 03:23:20 -05:00
use crate::assist_context::{AssistContext, Assists};
use ide_db::{
assists::{AssistId, AssistKind},
defs::Definition,
LineIndexDatabase,
};
use syntax::{
ast::{self, edit_in_place::Indent},
AstNode,
};
// Assist: bind_unused_param
//
// Binds unused function parameter to an underscore.
//
// ```
// fn some_function(x: i32$0) {}
// ```
// ->
// ```
// fn some_function(x: i32) {
// let _ = x;
// }
// ```
pub(crate) fn bind_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
let param: ast::Param = ctx.find_node_at_offset()?;
2023-08-29 01:39:56 -05:00
let Some(ast::Pat::IdentPat(ident_pat)) = param.pat() else { return None };
2023-08-28 03:23:20 -05:00
let param_def = {
let local = ctx.sema.to_def(&ident_pat)?;
Definition::Local(local)
};
if param_def.usages(&ctx.sema).at_least_one() {
cov_mark::hit!(keep_used);
return None;
}
2023-08-29 10:56:31 -05:00
let func = param.syntax().ancestors().find_map(ast::Fn::cast)?;
2023-08-28 03:23:20 -05:00
let stmt_list = func.body()?.stmt_list()?;
let l_curly_range = stmt_list.l_curly_token()?.text_range();
let r_curly_range = stmt_list.r_curly_token()?.text_range();
acc.add(
2023-08-29 01:39:56 -05:00
AssistId("bind_unused_param", AssistKind::QuickFix),
2023-08-28 03:23:20 -05:00
&format!("Bind as `let _ = {};`", &ident_pat),
param.syntax().text_range(),
|builder| {
2023-08-29 01:39:56 -05:00
let line_index = ctx.db().line_index(ctx.file_id());
2023-08-29 10:56:31 -05:00
let indent = func.indent_level();
let text_indent = indent + 1;
let mut text = format!("\n{text_indent}let _ = {ident_pat};");
2023-08-29 01:39:56 -05:00
let left_line = line_index.line_col(l_curly_range.end()).line;
let right_line = line_index.line_col(r_curly_range.start()).line;
if left_line == right_line {
cov_mark::hit!(single_line);
2023-08-29 10:56:31 -05:00
text.push_str(&format!("\n{indent}"));
2023-08-29 01:39:56 -05:00
}
2023-08-28 03:23:20 -05:00
builder.insert(l_curly_range.end(), text);
},
)
}
#[cfg(test)]
mod tests {
2023-08-28 03:30:44 -05:00
use crate::tests::{check_assist, check_assist_not_applicable};
2023-08-28 03:23:20 -05:00
use super::*;
#[test]
fn bind_unused_empty_block() {
2023-08-28 03:30:44 -05:00
cov_mark::check!(single_line);
2023-08-28 03:23:20 -05:00
check_assist(
bind_unused_param,
r#"
fn foo($0y: i32) {}
"#,
r#"
fn foo(y: i32) {
let _ = y;
}
"#,
);
}
#[test]
fn bind_unused_empty_block_with_newline() {
check_assist(
bind_unused_param,
r#"
fn foo($0y: i32) {
}
"#,
r#"
fn foo(y: i32) {
let _ = y;
}
"#,
);
}
#[test]
fn bind_unused_generic() {
check_assist(
bind_unused_param,
r#"
fn foo<T>($0y: T)
where T : Default {
}
"#,
r#"
fn foo<T>(y: T)
where T : Default {
let _ = y;
}
2023-08-28 03:30:44 -05:00
"#,
);
}
#[test]
fn trait_impl() {
2023-08-29 10:56:31 -05:00
check_assist(
2023-08-28 03:30:44 -05:00
bind_unused_param,
r#"
trait Trait {
fn foo(x: i32);
}
impl Trait for () {
fn foo($0x: i32) {}
}
2023-08-29 10:56:31 -05:00
"#,
r#"
trait Trait {
fn foo(x: i32);
}
impl Trait for () {
fn foo(x: i32) {
let _ = x;
}
}
2023-08-28 03:30:44 -05:00
"#,
);
}
#[test]
fn keep_used() {
cov_mark::check!(keep_used);
check_assist_not_applicable(
bind_unused_param,
r#"
fn foo(x: i32, $0y: i32) { y; }
2023-08-28 03:23:20 -05:00
"#,
);
}
}