Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/remove_underscore.rs')
| -rw-r--r-- | crates/ide-assists/src/handlers/remove_underscore.rs | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/crates/ide-assists/src/handlers/remove_underscore.rs b/crates/ide-assists/src/handlers/remove_underscore.rs new file mode 100644 index 0000000000..912e1936b5 --- /dev/null +++ b/crates/ide-assists/src/handlers/remove_underscore.rs @@ -0,0 +1,191 @@ +use ide_db::{ + assists::AssistId, + defs::{Definition, NameClass, NameRefClass}, +}; +use syntax::{AstNode, ast}; + +use crate::{AssistContext, Assists}; + +// Assist: remove_underscore_from_used_variables +// +// Removes underscore from used variables. +// +// ``` +// fn main() { +// let mut _$0foo = 1; +// _foo = 2; +// } +// ``` +// -> +// ``` +// fn main() { +// let mut foo = 1; +// foo = 2; +// } +// ``` +pub(crate) fn remove_underscore(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let (text, text_range, def) = if let Some(name_ref) = ctx.find_node_at_offset::<ast::Name>() { + let text = name_ref.text(); + if !text.starts_with('_') { + return None; + } + + let def = match NameClass::classify(&ctx.sema, &name_ref)? { + NameClass::Definition(def @ Definition::Local(_)) => def, + NameClass::PatFieldShorthand { local_def, .. } => Definition::Local(local_def), + _ => return None, + }; + (text.to_owned(), name_ref.syntax().text_range(), def) + } else if let Some(name_ref) = ctx.find_node_at_offset::<ast::NameRef>() { + let text = name_ref.text(); + if !text.starts_with('_') { + return None; + } + let def = match NameRefClass::classify(&ctx.sema, &name_ref)? { + NameRefClass::Definition(def @ Definition::Local(_), _) => def, + NameRefClass::FieldShorthand { local_ref, .. } => Definition::Local(local_ref), + _ => return None, + }; + (text.to_owned(), name_ref.syntax().text_range(), def) + } else { + return None; + }; + + if !def.usages(&ctx.sema).at_least_one() { + return None; + } + + let new_name = text.trim_start_matches('_'); + acc.add( + AssistId::refactor("remove_underscore_from_used_variables"), + "Remove underscore from a used variable", + text_range, + |builder| { + let changes = def.rename(&ctx.sema, new_name).unwrap(); + builder.source_change = changes; + }, + ) +} + +#[cfg(test)] +mod tests { + use crate::tests::{check_assist, check_assist_not_applicable}; + + use super::*; + + #[test] + fn remove_underscore_from_used_variable() { + check_assist( + remove_underscore, + r#" +fn main() { + let mut _$0foo = 1; + _foo = 2; +} +"#, + r#" +fn main() { + let mut foo = 1; + foo = 2; +} +"#, + ); + } + + #[test] + fn not_applicable_for_unused() { + check_assist_not_applicable( + remove_underscore, + r#" +fn main() { + let _$0unused = 1; +} +"#, + ); + } + + #[test] + fn not_applicable_for_no_underscore() { + check_assist_not_applicable( + remove_underscore, + r#" +fn main() { + let f$0oo = 1; + foo = 2; +} +"#, + ); + } + + #[test] + fn remove_multiple_underscores() { + check_assist( + remove_underscore, + r#" +fn main() { + let mut _$0_foo = 1; + __foo = 2; +} +"#, + r#" +fn main() { + let mut foo = 1; + foo = 2; +} +"#, + ); + } + + #[test] + fn remove_underscore_on_usage() { + check_assist( + remove_underscore, + r#" +fn main() { + let mut _foo = 1; + _$0foo = 2; +} +"#, + r#" +fn main() { + let mut foo = 1; + foo = 2; +} +"#, + ); + } + + #[test] + fn remove_underscore_in_function_parameter_usage() { + check_assist( + remove_underscore, + r#" +fn foo(_foo: i32) { + let bar = _$0foo + 1; +} +"#, + r#" +fn foo(foo: i32) { + let bar = foo + 1; +} +"#, + ) + } + + #[test] + fn remove_underscore_in_function_parameter() { + check_assist( + remove_underscore, + r#" +fn foo(_$0foo: i32) { + let bar = _foo + 1; +} +"#, + r#" +fn foo(foo: i32) { + let bar = foo + 1; +} +"#, + ) + } +} |